Merge "Preparing for build system change. Fix the build error in http://b/issue?id=2781522."
diff --git a/Android.mk b/Android.mk
index ca81fc1..27f9e1e 100644
--- a/Android.mk
+++ b/Android.mk
@@ -24,7 +24,7 @@
 # Instead, it depends on the R.stamp file, which lists the corresponding
 # R.java file as a prerequisite.
 # TODO: find a more appropriate way to do this.
-framework-res-source-path := APPS/framework-res_intermediates/src
+framework_res_source_path := APPS/framework-res_intermediates/src
 
 # the library
 # ============================================================
@@ -189,9 +189,9 @@
 LOCAL_AIDL_INCLUDES += $(FRAMEWORKS_BASE_JAVA_SRC_DIRS)
 
 LOCAL_INTERMEDIATE_SOURCES := \
-			$(framework-res-source-path)/android/R.java \
-			$(framework-res-source-path)/android/Manifest.java \
-			$(framework-res-source-path)/com/android/internal/R.java
+			$(framework_res_source_path)/android/R.java \
+			$(framework_res_source_path)/android/Manifest.java \
+			$(framework_res_source_path)/com/android/internal/R.java
 
 LOCAL_NO_STANDARD_LIBRARIES := true
 LOCAL_JAVA_LIBRARIES := bouncycastle core core-junit ext
@@ -337,9 +337,9 @@
 	$(FRAMEWORKS_BASE_JAVA_SRC_DIRS)
 
 framework_docs_LOCAL_INTERMEDIATE_SOURCES := \
-			$(framework-res-source-path)/android/R.java \
-			$(framework-res-source-path)/android/Manifest.java \
-			$(framework-res-source-path)/com/android/internal/R.java
+			$(framework_res_source_path)/android/R.java \
+			$(framework_res_source_path)/android/Manifest.java \
+			$(framework_res_source_path)/com/android/internal/R.java
 
 framework_docs_LOCAL_JAVA_LIBRARIES := \
 			bouncycastle \
diff --git a/api/current.xml b/api/current.xml
index 1fadcfb..355b3cd 100644
--- a/api/current.xml
+++ b/api/current.xml
@@ -4893,6 +4893,17 @@
  visibility="public"
 >
 </field>
+<field name="immersive"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="16843457"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
 <field name="inAnimation"
  type="int"
  transient="false"
@@ -6092,17 +6103,6 @@
  visibility="public"
 >
 </field>
-<field name="kraken_resource_pad64"
- type="int"
- transient="false"
- volatile="false"
- value="16843457"
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
 <field name="kraken_resource_pad7"
  type="int"
  transient="false"
@@ -13955,7 +13955,7 @@
  value="17301636"
  static="true"
  final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
  visibility="public"
 >
 </field>
@@ -13966,7 +13966,7 @@
  value="17301637"
  static="true"
  final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
  visibility="public"
 >
 </field>
@@ -13977,7 +13977,7 @@
  value="17301638"
  static="true"
  final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
  visibility="public"
 >
 </field>
@@ -14021,7 +14021,7 @@
  value="17301671"
  static="true"
  final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
  visibility="public"
 >
 </field>
@@ -14032,7 +14032,7 @@
  value="17301672"
  static="true"
  final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
  visibility="public"
 >
 </field>
@@ -15341,6 +15341,17 @@
  visibility="public"
 >
 </field>
+<field name="list_content"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="17367073"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
 <field name="preference_category"
  type="int"
  transient="false"
@@ -19457,6 +19468,19 @@
  visibility="public"
 >
 </constructor>
+<method name="addTab"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="tab" type="android.app.ActionBar.Tab">
+</parameter>
+</method>
 <method name="finishContextMode"
  return="void"
  abstract="true"
@@ -19523,6 +19547,84 @@
  visibility="public"
 >
 </method>
+<method name="insertTab"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="tab" type="android.app.ActionBar.Tab">
+</parameter>
+<parameter name="position" type="int">
+</parameter>
+</method>
+<method name="newTab"
+ return="android.app.ActionBar.Tab"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="removeTab"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="tab" type="android.app.ActionBar.Tab">
+</parameter>
+</method>
+<method name="removeTabAt"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="position" type="int">
+</parameter>
+</method>
+<method name="selectTab"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="tab" type="android.app.ActionBar.Tab">
+</parameter>
+</method>
+<method name="selectTabAt"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="position" type="int">
+</parameter>
+</method>
 <method name="setBackgroundDrawable"
  return="void"
  abstract="true"
@@ -19644,6 +19746,30 @@
 <parameter name="subtitle" type="java.lang.CharSequence">
 </parameter>
 </method>
+<method name="setTabNavigationMode"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="setTabNavigationMode"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="containerViewId" type="int">
+</parameter>
+</method>
 <method name="setTitle"
  return="void"
  abstract="true"
@@ -19764,6 +19890,17 @@
  visibility="public"
 >
 </method>
+<method name="getCustomView"
+ return="android.view.View"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
 <method name="getMenu"
  return="android.view.Menu"
  abstract="true"
@@ -19775,6 +19912,28 @@
  visibility="public"
 >
 </method>
+<method name="getSubtitle"
+ return="java.lang.CharSequence"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getTitle"
+ return="java.lang.CharSequence"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
 <method name="invalidate"
  return="void"
  abstract="true"
@@ -19915,6 +20074,128 @@
 </parameter>
 </method>
 </interface>
+<class name="ActionBar.Tab"
+ extends="java.lang.Object"
+ abstract="true"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<constructor name="ActionBar.Tab"
+ type="android.app.ActionBar.Tab"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</constructor>
+<method name="getFragment"
+ return="android.app.Fragment"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getIcon"
+ return="android.graphics.drawable.Drawable"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getPosition"
+ return="int"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getText"
+ return="java.lang.CharSequence"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="select"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="setFragment"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="fragment" type="android.app.Fragment">
+</parameter>
+</method>
+<method name="setIcon"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="icon" type="android.graphics.drawable.Drawable">
+</parameter>
+</method>
+<method name="setText"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="text" type="java.lang.CharSequence">
+</parameter>
+</method>
+<field name="INVALID_POSITION"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="-1"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+</class>
 <class name="Activity"
  extends="android.view.ContextThemeWrapper"
  abstract="false"
@@ -20272,6 +20553,17 @@
  visibility="public"
 >
 </method>
+<method name="getLoaderManager"
+ return="android.app.LoaderManager"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
 <method name="getLocalClassName"
  return="java.lang.String"
  abstract="false"
@@ -20523,6 +20815,19 @@
 <parameter name="data" type="android.content.Intent">
 </parameter>
 </method>
+<method name="onAttachFragment"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="fragment" type="android.app.Fragment">
+</parameter>
+</method>
 <method name="onAttachedToWindow"
  return="void"
  abstract="false"
@@ -25740,6 +26045,17 @@
  visibility="public"
 >
 </method>
+<method name="getLoaderManager"
+ return="android.app.LoaderManager"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
 <method name="getRetainInstance"
  return="boolean"
  abstract="false"
@@ -25806,6 +26122,17 @@
  visibility="public"
 >
 </method>
+<method name="isResumed"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
 <method name="isVisible"
  return="boolean"
  abstract="false"
@@ -25817,6 +26144,19 @@
  visibility="public"
 >
 </method>
+<method name="onActivityCreated"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="savedInstanceState" type="android.os.Bundle">
+</parameter>
+</method>
 <method name="onActivityResult"
  return="void"
  abstract="false"
@@ -26076,19 +26416,6 @@
 <parameter name="menu" type="android.view.Menu">
 </parameter>
 </method>
-<method name="onReady"
- return="void"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="savedInstanceState" type="android.os.Bundle">
-</parameter>
-</method>
 <method name="onResume"
  return="void"
  abstract="false"
@@ -28182,7 +28509,18 @@
 >
 <parameter name="shown" type="boolean">
 </parameter>
-<parameter name="animate" type="boolean">
+</method>
+<method name="setListShownNoAnimation"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="shown" type="boolean">
 </parameter>
 </method>
 <method name="setSelection"
@@ -28199,6 +28537,112 @@
 </parameter>
 </method>
 </class>
+<interface name="LoaderManager"
+ abstract="true"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<method name="getLoader"
+ return="android.content.Loader&lt;D&gt;"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="id" type="int">
+</parameter>
+</method>
+<method name="initLoader"
+ return="android.content.Loader&lt;D&gt;"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="id" type="int">
+</parameter>
+<parameter name="args" type="android.os.Bundle">
+</parameter>
+<parameter name="callback" type="android.app.LoaderManager.LoaderCallbacks&lt;D&gt;">
+</parameter>
+</method>
+<method name="restartLoader"
+ return="android.content.Loader&lt;D&gt;"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="id" type="int">
+</parameter>
+<parameter name="args" type="android.os.Bundle">
+</parameter>
+<parameter name="callback" type="android.app.LoaderManager.LoaderCallbacks&lt;D&gt;">
+</parameter>
+</method>
+<method name="stopLoader"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="id" type="int">
+</parameter>
+</method>
+</interface>
+<interface name="LoaderManager.LoaderCallbacks"
+ abstract="true"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<method name="onCreateLoader"
+ return="android.content.Loader&lt;D&gt;"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="id" type="int">
+</parameter>
+<parameter name="args" type="android.os.Bundle">
+</parameter>
+</method>
+<method name="onLoadFinished"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="loader" type="android.content.Loader&lt;D&gt;">
+</parameter>
+<parameter name="data" type="D">
+</parameter>
+</method>
+</interface>
 <class name="LoaderManagingFragment"
  extends="android.app.Fragment"
  abstract="true"
@@ -28494,7 +28938,9 @@
 >
 <implements name="android.view.InputQueue.Callback">
 </implements>
-<implements name="android.view.SurfaceHolder.Callback">
+<implements name="android.view.SurfaceHolder.Callback2">
+</implements>
+<implements name="android.view.ViewTreeObserver.OnGlobalLayoutListener">
 </implements>
 <constructor name="NativeActivity"
  type="android.app.NativeActivity"
@@ -28504,6 +28950,17 @@
  visibility="public"
 >
 </constructor>
+<method name="onGlobalLayout"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
 <method name="onInputQueueCreated"
  return="void"
  abstract="false"
@@ -28575,6 +29032,19 @@
 <parameter name="holder" type="android.view.SurfaceHolder">
 </parameter>
 </method>
+<method name="surfaceRedrawNeeded"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="holder" type="android.view.SurfaceHolder">
+</parameter>
+</method>
 <field name="META_DATA_LIB_NAME"
  type="java.lang.String"
  transient="false"
@@ -68176,6 +68646,17 @@
  visibility="public"
 >
 </field>
+<field name="YV12"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="842094169"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
 </class>
 <class name="Interpolator"
  extends="java.lang.Object"
@@ -146736,6 +147217,19 @@
 <parameter name="holder" type="android.view.SurfaceHolder">
 </parameter>
 </method>
+<method name="onSurfaceRedrawNeeded"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="holder" type="android.view.SurfaceHolder">
+</parameter>
+</method>
 <method name="onTouchEvent"
  return="void"
  abstract="false"
@@ -158163,6 +158657,21 @@
 <parameter name="flags" type="int">
 </parameter>
 </method>
+<method name="setPackageObbPath"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="packageName" type="java.lang.String">
+</parameter>
+<parameter name="path" type="java.lang.String">
+</parameter>
+</method>
 </class>
 <class name="MockResources"
  extends="android.content.res.Resources"
@@ -165917,6 +166426,29 @@
 <parameter name="event" type="android.view.MotionEvent">
 </parameter>
 </method>
+<method name="setCursorController"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="cursorController" type="android.widget.TextView.CursorController">
+</parameter>
+</method>
+<field name="mCursorController"
+ type="android.widget.TextView.CursorController"
+ transient="false"
+ volatile="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="protected"
+>
+</field>
 </class>
 <class name="BaseKeyListener"
  extends="android.text.method.MetaKeyKeyListener"
@@ -173792,6 +174324,19 @@
 <parameter name="key" type="int">
 </parameter>
 </method>
+<method name="removeAt"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="index" type="int">
+</parameter>
+</method>
 <method name="setValueAt"
  return="void"
  abstract="false"
@@ -177948,6 +178493,171 @@
  visibility="public"
 >
 </field>
+<field name="KEYCODE_BUTTON_A"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="96"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="KEYCODE_BUTTON_B"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="97"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="KEYCODE_BUTTON_C"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="98"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="KEYCODE_BUTTON_L1"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="102"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="KEYCODE_BUTTON_L2"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="104"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="KEYCODE_BUTTON_MODE"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="110"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="KEYCODE_BUTTON_R1"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="103"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="KEYCODE_BUTTON_R2"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="105"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="KEYCODE_BUTTON_SELECT"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="109"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="KEYCODE_BUTTON_START"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="108"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="KEYCODE_BUTTON_THUMBL"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="106"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="KEYCODE_BUTTON_THUMBR"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="107"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="KEYCODE_BUTTON_X"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="99"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="KEYCODE_BUTTON_Y"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="100"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="KEYCODE_BUTTON_Z"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="101"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
 <field name="KEYCODE_C"
  type="int"
  transient="false"
@@ -182601,6 +183311,29 @@
 </parameter>
 </method>
 </interface>
+<interface name="SurfaceHolder.Callback2"
+ abstract="true"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<implements name="android.view.SurfaceHolder.Callback">
+</implements>
+<method name="surfaceRedrawNeeded"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="holder" type="android.view.SurfaceHolder">
+</parameter>
+</method>
+</interface>
 <class name="SurfaceView"
  extends="android.view.View"
  abstract="false"
@@ -183544,6 +184277,17 @@
  visibility="public"
 >
 </method>
+<method name="getAlpha"
+ return="float"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
 <method name="getAnimation"
  return="android.view.animation.Animation"
  abstract="false"
@@ -183977,6 +184721,17 @@
 <parameter name="location" type="int[]">
 </parameter>
 </method>
+<method name="getMatrix"
+ return="android.graphics.Matrix"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
 <method name="getMeasuredHeight"
  return="int"
  abstract="false"
@@ -184109,6 +184864,28 @@
  visibility="public"
 >
 </method>
+<method name="getPivotX"
+ return="float"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getPivotY"
+ return="float"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
 <method name="getResources"
  return="android.content.res.Resources"
  abstract="false"
@@ -184164,6 +184941,39 @@
  visibility="public"
 >
 </method>
+<method name="getRotation"
+ return="float"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getScaleX"
+ return="float"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getScaleY"
+ return="float"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
 <method name="getScrollBarStyle"
  return="int"
  abstract="false"
@@ -184410,6 +185220,28 @@
 <parameter name="outRect" type="android.graphics.Rect">
 </parameter>
 </method>
+<method name="getX"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getY"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
 <method name="hasFocus"
  return="boolean"
  abstract="false"
@@ -185740,6 +186572,19 @@
 <parameter name="event" type="android.view.accessibility.AccessibilityEvent">
 </parameter>
 </method>
+<method name="setAlpha"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="alpha" type="float">
+</parameter>
+</method>
 <method name="setAnimation"
  return="void"
  abstract="false"
@@ -185792,6 +186637,19 @@
 <parameter name="resid" type="int">
 </parameter>
 </method>
+<method name="setBottom"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="bottom" type="int">
+</parameter>
+</method>
 <method name="setClickable"
  return="void"
  abstract="false"
@@ -186000,6 +186858,19 @@
 <parameter name="params" type="android.view.ViewGroup.LayoutParams">
 </parameter>
 </method>
+<method name="setLeft"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="left" type="int">
+</parameter>
+</method>
 <method name="setLongClickable"
  return="void"
  abstract="false"
@@ -186203,6 +187074,32 @@
 <parameter name="bottom" type="int">
 </parameter>
 </method>
+<method name="setPivotX"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="pivotX" type="float">
+</parameter>
+</method>
+<method name="setPivotY"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="pivotY" type="float">
+</parameter>
+</method>
 <method name="setPressed"
  return="void"
  abstract="false"
@@ -186216,6 +187113,32 @@
 <parameter name="pressed" type="boolean">
 </parameter>
 </method>
+<method name="setRight"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="right" type="int">
+</parameter>
+</method>
+<method name="setRotation"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="rotation" type="float">
+</parameter>
+</method>
 <method name="setSaveEnabled"
  return="void"
  abstract="false"
@@ -186242,6 +187165,32 @@
 <parameter name="enabled" type="boolean">
 </parameter>
 </method>
+<method name="setScaleX"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="scaleX" type="float">
+</parameter>
+</method>
+<method name="setScaleY"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="scaleY" type="float">
+</parameter>
+</method>
 <method name="setScrollBarStyle"
  return="void"
  abstract="false"
@@ -186335,6 +187284,19 @@
 <parameter name="tag" type="java.lang.Object">
 </parameter>
 </method>
+<method name="setTop"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="top" type="int">
+</parameter>
+</method>
 <method name="setTouchDelegate"
  return="void"
  abstract="false"
@@ -186413,6 +187375,32 @@
 <parameter name="willNotDraw" type="boolean">
 </parameter>
 </method>
+<method name="setX"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="x" type="int">
+</parameter>
+</method>
+<method name="setY"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="y" type="int">
+</parameter>
+</method>
 <method name="showContextMenu"
  return="boolean"
  abstract="false"
@@ -191240,7 +192228,7 @@
  deprecated="not deprecated"
  visibility="public"
 >
-<parameter name="callback" type="android.view.SurfaceHolder.Callback">
+<parameter name="callback" type="android.view.SurfaceHolder.Callback2">
 </parameter>
 </method>
 <method name="togglePanel"
@@ -203758,6 +204746,36 @@
 <parameter name="outState" type="android.os.Bundle">
 </parameter>
 </method>
+<method name="saveWebArchive"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="filename" type="java.lang.String">
+</parameter>
+</method>
+<method name="saveWebArchive"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="basename" type="java.lang.String">
+</parameter>
+<parameter name="autoname" type="boolean">
+</parameter>
+<parameter name="callback" type="android.webkit.ValueCallback&lt;java.lang.String&gt;">
+</parameter>
+</method>
 <method name="setCertificate"
  return="void"
  abstract="false"
@@ -213462,6 +214480,19 @@
 <parameter name="d" type="android.graphics.drawable.Drawable">
 </parameter>
 </method>
+<method name="setContentWidth"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="width" type="int">
+</parameter>
+</method>
 <method name="setHeight"
  return="void"
  abstract="false"
@@ -222423,6 +223454,108 @@
 >
 </method>
 </class>
+<interface name="TextView.CursorController"
+ abstract="true"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<method name="draw"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="canvas" type="android.graphics.Canvas">
+</parameter>
+</method>
+<method name="getOffsetX"
+ return="float"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getOffsetY"
+ return="float"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="hide"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="onTouchEvent"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="event" type="android.view.MotionEvent">
+</parameter>
+</method>
+<method name="show"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="updatePosition"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="offset" type="int">
+</parameter>
+</method>
+<field name="FADE_OUT_DURATION"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="400"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+</interface>
 <interface name="TextView.OnEditorActionListener"
  abstract="true"
  static="true"
diff --git a/cmds/am/src/com/android/commands/am/Am.java b/cmds/am/src/com/android/commands/am/Am.java
index 301883f..fb60fdf 100644
--- a/cmds/am/src/com/android/commands/am/Am.java
+++ b/cmds/am/src/com/android/commands/am/Am.java
@@ -98,6 +98,8 @@
             sendBroadcast();
         } else if (op.equals("profile")) {
             runProfile();
+        } else if (op.equals("dumpheap")) {
+            runDumpHeap();
         } else {
             throw new IllegalArgumentException("Unknown command: " + op);
         }
@@ -424,6 +426,28 @@
         }
     }
 
+    private void runDumpHeap() throws Exception {
+        boolean managed = !"-n".equals(nextOption());
+        String process = nextArgRequired();
+        String heapFile = nextArgRequired();
+        ParcelFileDescriptor fd = null;
+
+        try {
+            fd = ParcelFileDescriptor.open(
+                    new File(heapFile),
+                    ParcelFileDescriptor.MODE_CREATE |
+                    ParcelFileDescriptor.MODE_TRUNCATE |
+                    ParcelFileDescriptor.MODE_READ_WRITE);
+        } catch (FileNotFoundException e) {
+            System.err.println("Error: Unable to open file: " + heapFile);
+            return;
+        }
+
+        if (!mAm.dumpHeap(process, managed, heapFile, fd)) {
+            throw new AndroidException("HEAP DUMP FAILED on process " + process);
+        }
+    }
+
     private class IntentReceiver extends IIntentReceiver.Stub {
         private boolean mFinished = false;
 
@@ -593,6 +617,8 @@
                 "\n" +
                 "    start profiling: am profile <PROCESS> start <FILE>\n" +
                 "    stop profiling: am profile <PROCESS> stop\n" +
+                "    dump heap: am dumpheap [flags] <PROCESS> <FILE>\n" +
+                "        -n: dump native heap instead of managed heap\n" +
                 "\n" +
                 "    <INTENT> specifications include these flags:\n" +
                 "        [-a <ACTION>] [-d <DATA_URI>] [-t <MIME_TYPE>]\n" +
diff --git a/cmds/surfaceflinger/Android.mk b/cmds/surfaceflinger/Android.mk
index bfa58a1..1df32bb 100644
--- a/cmds/surfaceflinger/Android.mk
+++ b/cmds/surfaceflinger/Android.mk
@@ -10,7 +10,7 @@
 	libutils
 
 LOCAL_C_INCLUDES := \
-	$(LOCAL_PATH)/../../libs/surfaceflinger
+	$(LOCAL_PATH)/../../services/surfaceflinger
 
 LOCAL_MODULE:= surfaceflinger
 
diff --git a/cmds/surfaceflinger/main_surfaceflinger.cpp b/cmds/surfaceflinger/main_surfaceflinger.cpp
index d650721..78b1007 100644
--- a/cmds/surfaceflinger/main_surfaceflinger.cpp
+++ b/cmds/surfaceflinger/main_surfaceflinger.cpp
@@ -1,18 +1,25 @@
-#include <binder/IPCThreadState.h>
-#include <binder/ProcessState.h>
-#include <binder/IServiceManager.h>
-#include <utils/Log.h>
+/*
+ * 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.
+ */
 
+#include <binder/BinderService.h>
 #include <SurfaceFlinger.h>
 
 using namespace android;
 
-int main(int argc, char** argv)
-{
-    sp<ProcessState> proc(ProcessState::self());
-    sp<IServiceManager> sm = defaultServiceManager();
-    LOGI("ServiceManager: %p", sm.get());
-    SurfaceFlinger::instantiate();
-    ProcessState::self()->startThreadPool();
-    IPCThreadState::self()->joinThreadPool();
+int main(int argc, char** argv) {
+    SurfaceFlinger::publishAndJoinThreadPool();
+    return 0;
 }
diff --git a/cmds/system_server/library/Android.mk b/cmds/system_server/library/Android.mk
index 1813d3e..a880a91 100644
--- a/cmds/system_server/library/Android.mk
+++ b/cmds/system_server/library/Android.mk
@@ -7,9 +7,9 @@
 base = $(LOCAL_PATH)/../../..
 
 LOCAL_C_INCLUDES := \
-	$(base)/camera/libcameraservice \
-	$(base)/libs/audioflinger \
-	$(base)/libs/surfaceflinger \
+	$(base)/services/camera/libcameraservice \
+	$(base)/services/audioflinger \
+	$(base)/services/surfaceflinger \
 	$(base)/media/libmediaplayerservice \
 	$(JNI_H_INCLUDE)
 
diff --git a/core/java/android/accounts/AccountManagerService.java b/core/java/android/accounts/AccountManagerService.java
index 2ead976..e6b1c08 100644
--- a/core/java/android/accounts/AccountManagerService.java
+++ b/core/java/android/accounts/AccountManagerService.java
@@ -399,19 +399,19 @@
 
     private boolean insertAccountIntoDatabase(Account account, String password, Bundle extras) {
         SQLiteDatabase db = mOpenHelper.getWritableDatabase();
+        if (account == null) {
+            return false;
+        }
+        final boolean noBroadcast = account.type.equals(GOOGLE_ACCOUNT_TYPE)
+                && extras != null && extras.getBoolean(NO_BROADCAST_FLAG, false);
+        // Remove the 'nobroadcast' flag since we don't want it to persist in the db. It is instead
+        // used as a control signal to indicate whether or not this insertion should result in
+        // an accounts changed broadcast being sent.
+        if (extras != null) {
+            extras.remove(NO_BROADCAST_FLAG);
+        }
         db.beginTransaction();
         try {
-            if (account == null) {
-                return false;
-            }
-            boolean noBroadcast = false;
-            if (account.type.equals(GOOGLE_ACCOUNT_TYPE)) {
-                // Look for the 'nobroadcast' flag and remove it since we don't want it to persist
-                // in the db.
-                noBroadcast = extras.getBoolean(NO_BROADCAST_FLAG, false);
-                extras.remove(NO_BROADCAST_FLAG);
-            }
-
             long numMatches = DatabaseUtils.longForQuery(db,
                     "select count(*) from " + TABLE_ACCOUNTS
                             + " WHERE " + ACCOUNTS_NAME + "=? AND " + ACCOUNTS_TYPE+ "=?",
@@ -436,13 +436,13 @@
                 }
             }
             db.setTransactionSuccessful();
-            if (!noBroadcast) {
-                sendAccountsChangedBroadcast();
-            }
-            return true;
         } finally {
             db.endTransaction();
         }
+        if (!noBroadcast) {
+            sendAccountsChangedBroadcast();
+        }
+        return true;
     }
 
     private long insertExtra(SQLiteDatabase db, long accountId, String key, String value) {
@@ -1681,11 +1681,11 @@
                 try {
                     db.execSQL("DELETE from " + TABLE_AUTHTOKENS);
                     db.execSQL("UPDATE " + TABLE_ACCOUNTS + " SET " + ACCOUNTS_PASSWORD + " = ''");
-                    sendAccountsChangedBroadcast();
                     db.setTransactionSuccessful();
                 } finally {
                     db.endTransaction();
                 }
+                sendAccountsChangedBroadcast();
             }
             setMetaValue("imsi", imsi);
         }
diff --git a/core/java/android/app/ActionBar.java b/core/java/android/app/ActionBar.java
index 67133e0..3cd2b9e 100644
--- a/core/java/android/app/ActionBar.java
+++ b/core/java/android/app/ActionBar.java
@@ -206,9 +206,11 @@
      *
      * @return The current navigation mode.
      * 
+     * @see #setStandardNavigationMode()
      * @see #setStandardNavigationMode(CharSequence)
      * @see #setStandardNavigationMode(CharSequence, CharSequence)
      * @see #setDropdownNavigationMode(SpinnerAdapter)
+     * @see #setTabNavigationMode()
      * @see #setCustomNavigationMode(View)
      */
     public abstract int getNavigationMode();
@@ -217,10 +219,98 @@
      * @return The current set of display options. 
      */
     public abstract int getDisplayOptions();
-    
+
+    /**
+     * Start a context mode controlled by <code>callback</code>.
+     * The {@link ContextModeCallback} will receive lifecycle events for the duration
+     * of the context mode.
+     *
+     * @param callback Callback handler that will manage this context mode.
+     */
     public abstract void startContextMode(ContextModeCallback callback);
+
+    /**
+     * Finish the current context mode.
+     */
     public abstract void finishContextMode();
-    
+
+    /**
+     * Set the action bar into tabbed navigation mode.
+     *
+     * @see #addTab(Tab)
+     * @see #insertTab(Tab, int)
+     * @see #removeTab(Tab)
+     * @see #removeTabAt(int)
+     */
+    public abstract void setTabNavigationMode();
+
+    /**
+     * Set the action bar into tabbed navigation mode.
+     *
+     * @param containerViewId Id of the container view where tab content fragments should appear.
+     *
+     * @see #addTab(Tab)
+     * @see #insertTab(Tab, int)
+     * @see #removeTab(Tab)
+     * @see #removeTabAt(int)
+     */
+    public abstract void setTabNavigationMode(int containerViewId);
+
+    /**
+     * Create and return a new {@link Tab}.
+     * This tab will not be included in the action bar until it is added.
+     *
+     * @return A new Tab
+     *
+     * @see #addTab(Tab)
+     * @see #insertTab(Tab, int)
+     */
+    public abstract Tab newTab();
+
+    /**
+     * Add a tab for use in tabbed navigation mode. The tab will be added at the end of the list.
+     *
+     * @param tab Tab to add
+     */
+    public abstract void addTab(Tab tab);
+
+    /**
+     * Insert a tab for use in tabbed navigation mode. The tab will be inserted at
+     * <code>position</code>.
+     *
+     * @param tab The tab to add
+     * @param position The new position of the tab
+     */
+    public abstract void insertTab(Tab tab, int position);
+
+    /**
+     * Remove a tab from the action bar.
+     *
+     * @param tab The tab to remove
+     */
+    public abstract void removeTab(Tab tab);
+
+    /**
+     * Remove a tab from the action bar.
+     *
+     * @param position Position of the tab to remove
+     */
+    public abstract void removeTabAt(int position);
+
+    /**
+     * Select the specified tab. If it is not a child of this action bar it will be added.
+     *
+     * @param tab Tab to select
+     */
+    public abstract void selectTab(Tab tab);
+
+    /**
+     * Select the tab at <code>position</code>
+     *
+     * @param position Position of the tab to select
+     */
+    public abstract void selectTabAt(int position);
+
     /**
      * Represents a contextual mode of the Action Bar. Context modes can be used for
      * modal interactions with activity content and replace the normal Action Bar until finished.
@@ -278,6 +368,24 @@
          * @return The context mode's menu.
          */
         public abstract Menu getMenu();
+
+        /**
+         * Returns the current title of this context mode.
+         * @return Title text
+         */
+        public abstract CharSequence getTitle();
+
+        /**
+         * Returns the current subtitle of this context mode.
+         * @return Subtitle text
+         */
+        public abstract CharSequence getSubtitle();
+
+        /**
+         * Returns the current custom view for this context mode.
+         * @return The current custom view
+         */
+        public abstract View getCustomView();
     }
     
     /**
@@ -350,4 +458,74 @@
          */
         public boolean onNavigationItemSelected(int itemPosition, long itemId);
     }
+
+    /**
+     * A tab in the action bar.
+     *
+     * <p>Tabs manage the hiding and showing of {@link Fragment}s.
+     */
+    public static abstract class Tab {
+        /**
+         * An invalid position for a tab.
+         *
+         * @see #getPosition()
+         */
+        public static final int INVALID_POSITION = -1;
+
+        /**
+         * Return the current position of this tab in the action bar.
+         *
+         * @return Current position, or {@link #INVALID_POSITION} if this tab is not currently in
+         *         the action bar.
+         */
+        public abstract int getPosition();
+
+        /**
+         * Return the icon associated with this tab.
+         *
+         * @return The tab's icon
+         */
+        public abstract Drawable getIcon();
+
+        /**
+         * Return the text of this tab.
+         *
+         * @return The tab's text
+         */
+        public abstract CharSequence getText();
+
+        /**
+         * Set the icon displayed on this tab.
+         *
+         * @param icon The drawable to use as an icon
+         */
+        public abstract void 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
+         */
+        public abstract void setText(CharSequence text);
+
+        /**
+         * Returns the fragment that will be shown when this tab is selected.
+         *
+         * @return Fragment associated with this tab
+         */
+        public abstract Fragment getFragment();
+
+        /**
+         * Set the fragment that will be shown when this tab is selected.
+         *
+         * @param fragment Fragment to associate with this tab
+         */
+        public abstract void setFragment(Fragment fragment);
+
+        /**
+         * Select this tab. Only valid if the tab has been added to the action bar.
+         */
+        public abstract void select();
+    }
 }
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index 8825b8c..1cdd423 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -71,6 +71,7 @@
 import android.view.ViewGroup.LayoutParams;
 import android.view.accessibility.AccessibilityEvent;
 import android.widget.AdapterView;
+import android.widget.FrameLayout;
 import android.widget.LinearLayout;
 
 import com.android.internal.app.ActionBarImpl;
@@ -635,6 +636,7 @@
     /*package*/ ActivityThread mMainThread;
     Activity mParent;
     boolean mCalled;
+    boolean mStarted;
     private boolean mResumed;
     private boolean mStopped;
     boolean mFinished;
@@ -649,6 +651,7 @@
         Object activity;
         HashMap<String, Object> children;
         ArrayList<Fragment> fragments;
+        SparseArray<LoaderManagerImpl> loaders;
     }
     /* package */ NonConfigurationInstances mLastNonConfigurationInstances;
     
@@ -666,6 +669,9 @@
 
     final FragmentManager mFragments = new FragmentManager();
     
+    SparseArray<LoaderManagerImpl> mAllLoaderManagers;
+    LoaderManagerImpl mLoaderManager;
+    
     private static final class ManagedCursor {
         ManagedCursor(Cursor cursor) {
             mCursor = cursor;
@@ -763,6 +769,29 @@
     }
 
     /**
+     * Return the LoaderManager for this fragment, creating it if needed.
+     */
+    public LoaderManager getLoaderManager() {
+        if (mLoaderManager != null) {
+            return mLoaderManager;
+        }
+        mLoaderManager = getLoaderManager(-1, false);
+        return mLoaderManager;
+    }
+    
+    LoaderManagerImpl getLoaderManager(int index, boolean started) {
+        if (mAllLoaderManagers == null) {
+            mAllLoaderManagers = new SparseArray<LoaderManagerImpl>();
+        }
+        LoaderManagerImpl lm = mAllLoaderManagers.get(index);
+        if (lm == null) {
+            lm = new LoaderManagerImpl(started);
+            mAllLoaderManagers.put(index, lm);
+        }
+        return lm;
+    }
+    
+    /**
      * Calls {@link android.view.Window#getCurrentFocus} on the
      * Window of this Activity to return the currently focused view.
      * 
@@ -816,6 +845,9 @@
     protected void onCreate(Bundle savedInstanceState) {
         mVisibleFromClient = !mWindow.getWindowStyle().getBoolean(
                 com.android.internal.R.styleable.Window_windowNoDisplay, false);
+        if (mLastNonConfigurationInstances != null) {
+            mAllLoaderManagers = mLastNonConfigurationInstances.loaders;
+        }
         if (savedInstanceState != null) {
             Parcelable p = savedInstanceState.getParcelable(FRAGMENTS_TAG);
             mFragments.restoreAllState(p, mLastNonConfigurationInstances != null
@@ -958,6 +990,10 @@
      */
     protected void onStart() {
         mCalled = true;
+        mStarted = true;
+        if (mLoaderManager != null) {
+            mLoaderManager.doStart();
+        }
     }
 
     /**
@@ -1235,19 +1271,37 @@
      * @see #onPause
      */
     public boolean onCreateThumbnail(Bitmap outBitmap, Canvas canvas) {
-        final View view = mDecor;
-        if (view == null) {
+        if (mDecor == null) {
             return false;
         }
 
-        final int vw = view.getWidth();
-        final int vh = view.getHeight();
-        final int dw = outBitmap.getWidth();
-        final int dh = outBitmap.getHeight();
+        int paddingLeft = 0;
+        int paddingRight = 0;
+        int paddingTop = 0;
+        int paddingBottom = 0;
+
+        // Find System window and use padding so we ignore space reserved for decorations
+        // like the status bar and such.
+        final FrameLayout top = (FrameLayout) mDecor;
+        for (int i = 0; i < top.getChildCount(); i++) {
+            View child = top.getChildAt(i);
+            if (child.isFitsSystemWindowsFlagSet()) {
+                paddingLeft = child.getPaddingLeft();
+                paddingRight = child.getPaddingRight();
+                paddingTop = child.getPaddingTop();
+                paddingBottom = child.getPaddingBottom();
+                break;
+            }
+        }
+        
+        final int visibleWidth = mDecor.getWidth() - paddingLeft - paddingRight;
+        final int visibleHeight = mDecor.getHeight() - paddingTop - paddingBottom;
 
         canvas.save();
-        canvas.scale(((float)dw)/vw, ((float)dh)/vh);
-        view.draw(canvas);
+        canvas.scale( (float) outBitmap.getWidth() / visibleWidth,
+                (float) outBitmap.getHeight() / visibleHeight);
+        canvas.translate(-paddingLeft, -paddingTop);
+        mDecor.draw(canvas);
         canvas.restore();
 
         return true;
@@ -1495,7 +1549,20 @@
         Object activity = onRetainNonConfigurationInstance();
         HashMap<String, Object> children = onRetainNonConfigurationChildInstances();
         ArrayList<Fragment> fragments = mFragments.retainNonConfig();
-        if (activity == null && children == null && fragments == null) {
+        boolean retainLoaders = false;
+        if (mAllLoaderManagers != null) {
+            // prune out any loader managers that were already stopped, so
+            // have nothing useful to retain.
+            for (int i=mAllLoaderManagers.size()-1; i>=0; i--) {
+                LoaderManagerImpl lm = mAllLoaderManagers.valueAt(i);
+                if (lm.mRetaining) {
+                    retainLoaders = true;
+                } else {
+                    mAllLoaderManagers.removeAt(i);
+                }
+            }
+        }
+        if (activity == null && children == null && fragments == null && !retainLoaders) {
             return null;
         }
         
@@ -1503,6 +1570,7 @@
         nci.activity = activity;
         nci.children = children;
         nci.fragments = fragments;
+        nci.loaders = mAllLoaderManagers;
         return nci;
     }
     
@@ -1518,6 +1586,20 @@
         return new BackStackEntry(mFragments);
     }
     
+    void invalidateFragmentIndex(int index) {
+        if (mAllLoaderManagers != null) {
+            mAllLoaderManagers.remove(index);
+        }
+    }
+    
+    /**
+     * Called when a Fragment is being attached to this activity, immediately
+     * after the call to its {@link Fragment#onAttach Fragment.onAttach()}
+     * method and before {@link Fragment#onCreate Fragment.onCreate()}.
+     */
+    public void onAttachFragment(Fragment fragment) {
+    }
+    
     /**
      * Wrapper around
      * {@link ContentResolver#query(android.net.Uri , String[], String, String[], String)}
@@ -1676,11 +1758,11 @@
      */
     private void initActionBar() {
         Window window = getWindow();
-        if (!window.hasFeature(Window.FEATURE_ACTION_BAR)) {
+        if (!window.hasFeature(Window.FEATURE_ACTION_BAR) || mActionBar != null) {
             return;
         }
         
-        mActionBar = new ActionBarImpl(getWindow().getDecorView());
+        mActionBar = new ActionBarImpl(this);
     }
     
     /**
@@ -2060,13 +2142,6 @@
     }
 
     public void onContentChanged() {
-        // First time content is available, let the fragment manager
-        // attach all of the fragments to it.  Don't do this if the
-        // activity is no longer attached (because it is being destroyed).
-        if (mFragments.mCurState < Fragment.CONTENT
-                && mFragments.mActivity != null) {
-            mFragments.moveToState(Fragment.CONTENT, false);
-        }
     }
 
     /**
@@ -4024,6 +4099,7 @@
 
     final void performCreate(Bundle icicle) {
         onCreate(icicle);
+        mFragments.dispatchActivityCreated();
     }
     
     final void performStart() {
@@ -4036,6 +4112,11 @@
                 " did not call through to super.onStart()");
         }
         mFragments.dispatchStart();
+        if (mAllLoaderManagers != null) {
+            for (int i=mAllLoaderManagers.size()-1; i>=0; i--) {
+                mAllLoaderManagers.valueAt(i).finishRetain();
+            }
+        }
     }
     
     final void performRestart() {
@@ -4107,6 +4188,17 @@
     }
     
     final void performStop() {
+        if (mStarted) {
+            mStarted = false;
+            if (mLoaderManager != null) {
+                if (!mChangingConfigurations) {
+                    mLoaderManager.doStop();
+                } else {
+                    mLoaderManager.doRetain();
+                }
+            }
+        }
+        
         if (!mStopped) {
             if (mWindow != null) {
                 mWindow.closeAllPanels();
diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java
index eb7520f..d66e98b 100644
--- a/core/java/android/app/ActivityManager.java
+++ b/core/java/android/app/ActivityManager.java
@@ -285,24 +285,54 @@
      * @param maxNum The maximum number of entries to return in the list.  The
      * actual number returned may be smaller, depending on how many tasks the
      * user has started.
-     * 
+     *
+     * @param flags Optional flags
+     * @param receiver Optional receiver for delayed thumbnails
+     *
      * @return Returns a list of RunningTaskInfo records describing each of
      * the running tasks.
      * 
+     * Some thumbnails may not be available at the time of this call. The optional
+     * receiver may be used to receive those thumbnails.
+     *
      * @throws SecurityException Throws SecurityException if the caller does
      * not hold the {@link android.Manifest.permission#GET_TASKS} permission.
+     *
+     * @hide
      */
-    public List<RunningTaskInfo> getRunningTasks(int maxNum)
+    public List<RunningTaskInfo> getRunningTasks(int maxNum, int flags, IThumbnailReceiver receiver)
             throws SecurityException {
         try {
-            return (List<RunningTaskInfo>)ActivityManagerNative.getDefault()
-                    .getTasks(maxNum, 0, null);
+            return ActivityManagerNative.getDefault().getTasks(maxNum, flags, receiver);
         } catch (RemoteException e) {
             // System dead, we will be dead too soon!
             return null;
         }
     }
-    
+
+    /**
+     * Return a list of the tasks that are currently running, with
+     * the most recent being first and older ones after in order.  Note that
+     * "running" does not mean any of the task's code is currently loaded or
+     * activity -- the task may have been frozen by the system, so that it
+     * can be restarted in its previous state when next brought to the
+     * foreground.
+     *
+     * @param maxNum The maximum number of entries to return in the list.  The
+     * actual number returned may be smaller, depending on how many tasks the
+     * user has started.
+     *
+     * @return Returns a list of RunningTaskInfo records describing each of
+     * the running tasks.
+     *
+     * @throws SecurityException Throws SecurityException if the caller does
+     * not hold the {@link android.Manifest.permission#GET_TASKS} permission.
+     */
+    public List<RunningTaskInfo> getRunningTasks(int maxNum)
+            throws SecurityException {
+        return getRunningTasks(maxNum, 0, null);
+    }
+
     /**
      * Information you can retrieve about a particular Service that is
      * currently running in the system.
diff --git a/core/java/android/app/ActivityManagerNative.java b/core/java/android/app/ActivityManagerNative.java
index 1fe85e6..43a08b5 100644
--- a/core/java/android/app/ActivityManagerNative.java
+++ b/core/java/android/app/ActivityManagerNative.java
@@ -1294,6 +1294,19 @@
             return true;
         }
 
+        case DUMP_HEAP_TRANSACTION: {
+            data.enforceInterface(IActivityManager.descriptor);
+            String process = data.readString();
+            boolean managed = data.readInt() != 0;
+            String path = data.readString();
+            ParcelFileDescriptor fd = data.readInt() != 0
+                    ? data.readFileDescriptor() : null;
+            boolean res = dumpHeap(process, managed, path, fd);
+            reply.writeNoException();
+            reply.writeInt(res ? 1 : 0);
+            return true;
+        }
+
         }
         
         return super.onTransact(code, data, reply, flags);
@@ -2874,6 +2887,28 @@
         data.recycle();
         reply.recycle();
     }
-    
+
+    public boolean dumpHeap(String process, boolean managed,
+            String path, ParcelFileDescriptor fd) throws RemoteException {
+        Parcel data = Parcel.obtain();
+        Parcel reply = Parcel.obtain();
+        data.writeInterfaceToken(IActivityManager.descriptor);
+        data.writeString(process);
+        data.writeInt(managed ? 1 : 0);
+        data.writeString(path);
+        if (fd != null) {
+            data.writeInt(1);
+            fd.writeToParcel(data, Parcelable.PARCELABLE_WRITE_RETURN_VALUE);
+        } else {
+            data.writeInt(0);
+        }
+        mRemote.transact(DUMP_HEAP_TRANSACTION, data, reply, 0);
+        reply.readException();
+        boolean res = reply.readInt() != 0;
+        reply.recycle();
+        data.recycle();
+        return res;
+    }
+
     private IBinder mRemote;
 }
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index d788be8..c800fbe 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -116,6 +116,7 @@
  */
 public final class ActivityThread {
     static final String TAG = "ActivityThread";
+    private static final android.graphics.Bitmap.Config THUMBNAIL_FORMAT = Bitmap.Config.RGB_565;
     private static final boolean DEBUG = false;
     static final boolean localLOGV = DEBUG ? Config.LOGD : Config.LOGV;
     static final boolean DEBUG_BROADCAST = false;
@@ -356,6 +357,11 @@
         ParcelFileDescriptor fd;
     }
 
+    private static final class DumpHeapData {
+        String path;
+        ParcelFileDescriptor fd;
+    }
+
     private final class ApplicationThread extends ApplicationThreadNative {
         private static final String HEAP_COLUMN = "%17s %8s %8s %8s %8s";
         private static final String ONE_COUNT_COLUMN = "%17s %8d";
@@ -623,6 +629,13 @@
             queueOrSendMessage(H.PROFILER_CONTROL, pcd, start ? 1 : 0);
         }
 
+        public void dumpHeap(boolean managed, String path, ParcelFileDescriptor fd) {
+            DumpHeapData dhd = new DumpHeapData();
+            dhd.path = path;
+            dhd.fd = fd;
+            queueOrSendMessage(H.DUMP_HEAP, dhd, managed ? 1 : 0);
+        }
+
         public void setSchedulingGroup(int group) {
             // Note: do this immediately, since going into the foreground
             // should happen regardless of what pending work we have to do
@@ -874,6 +887,7 @@
         public static final int ENABLE_JIT              = 132;
         public static final int DISPATCH_PACKAGE_BROADCAST = 133;
         public static final int SCHEDULE_CRASH          = 134;
+        public static final int DUMP_HEAP               = 135;
         String codeToString(int code) {
             if (localLOGV) {
                 switch (code) {
@@ -912,6 +926,7 @@
                     case ENABLE_JIT: return "ENABLE_JIT";
                     case DISPATCH_PACKAGE_BROADCAST: return "DISPATCH_PACKAGE_BROADCAST";
                     case SCHEDULE_CRASH: return "SCHEDULE_CRASH";
+                    case DUMP_HEAP: return "DUMP_HEAP";
                 }
             }
             return "(unknown)";
@@ -1037,6 +1052,9 @@
                     break;
                 case SCHEDULE_CRASH:
                     throw new RemoteServiceException((String)msg.obj);
+                case DUMP_HEAP:
+                    handleDumpHeap(msg.arg1 != 0, (DumpHeapData)msg.obj);
+                    break;
             }
         }
 
@@ -2228,13 +2246,24 @@
                 h = mThumbnailHeight;
             }
 
-            // XXX Only set hasAlpha if needed?
-            thumbnail = Bitmap.createBitmap(w, h, Bitmap.Config.RGB_565);
-            thumbnail.eraseColor(0);
-            Canvas cv = new Canvas(thumbnail);
-            if (!r.activity.onCreateThumbnail(thumbnail, cv)) {
-                thumbnail = null;
+            // On platforms where we don't want thumbnails, set dims to (0,0)
+            if ((w > 0) && (h > 0)) {
+                View topView = r.activity.getWindow().getDecorView();
+
+                // Maximize bitmap by capturing in native aspect.
+                if (topView.getWidth() >= topView.getHeight()) {
+                    thumbnail = Bitmap.createBitmap(w, h, THUMBNAIL_FORMAT);
+                } else {
+                    thumbnail = Bitmap.createBitmap(h, w, THUMBNAIL_FORMAT);
+                }
+
+                thumbnail.eraseColor(0);
+                Canvas cv = new Canvas(thumbnail);
+                if (!r.activity.onCreateThumbnail(thumbnail, cv)) {
+                    thumbnail = null;
+                }
             }
+
         } catch (Exception e) {
             if (!mInstrumentation.onException(r.activity, e)) {
                 throw new RuntimeException(
@@ -2365,7 +2394,7 @@
             if (info != null) {
                 try {
                     // First create a thumbnail for the activity...
-                    //info.thumbnail = createThumbnailBitmap(r);
+                    info.thumbnail = createThumbnailBitmap(r);
                     info.description = r.activity.onCreateDescription();
                 } catch (Exception e) {
                     if (!mInstrumentation.onException(r.activity, e)) {
@@ -3015,6 +3044,25 @@
         }
     }
 
+    final void handleDumpHeap(boolean managed, DumpHeapData dhd) {
+        if (managed) {
+            try {
+                Debug.dumpHprofData(dhd.path, dhd.fd.getFileDescriptor());
+            } catch (IOException e) {
+                Slog.w(TAG, "Managed heap dump failed on path " + dhd.path
+                        + " -- can the process access this path?");
+            } finally {
+                try {
+                    dhd.fd.close();
+                } catch (IOException e) {
+                    Slog.w(TAG, "Failure closing profile fd", e);
+                }
+            }
+        } else {
+            Debug.dumpNativeHeap(dhd.fd.getFileDescriptor());
+        }
+    }
+
     final void handleDispatchPackageBroadcast(int cmd, String[] packages) {
         boolean hasPkgInfo = false;
         if (packages != null) {
diff --git a/core/java/android/app/ApplicationThreadNative.java b/core/java/android/app/ApplicationThreadNative.java
index 1c20062..dc2145f 100644
--- a/core/java/android/app/ApplicationThreadNative.java
+++ b/core/java/android/app/ApplicationThreadNative.java
@@ -403,6 +403,17 @@
             scheduleCrash(msg);
             return true;
         }
+
+        case DUMP_HEAP_TRANSACTION:
+        {
+            data.enforceInterface(IApplicationThread.descriptor);
+            boolean managed = data.readInt() != 0;
+            String path = data.readString();
+            ParcelFileDescriptor fd = data.readInt() != 0
+                    ? data.readFileDescriptor() : null;
+            dumpHeap(managed, path, fd);
+            return true;
+        }
         }
 
         return super.onTransact(code, data, reply, flags);
@@ -829,5 +840,22 @@
         data.recycle();
         
     }
+
+    public void dumpHeap(boolean managed, String path,
+            ParcelFileDescriptor fd) throws RemoteException {
+        Parcel data = Parcel.obtain();
+        data.writeInterfaceToken(IApplicationThread.descriptor);
+        data.writeInt(managed ? 1 : 0);
+        data.writeString(path);
+        if (fd != null) {
+            data.writeInt(1);
+            fd.writeToParcel(data, Parcelable.PARCELABLE_WRITE_RETURN_VALUE);
+        } else {
+            data.writeInt(0);
+        }
+        mRemote.transact(DUMP_HEAP_TRANSACTION, data, null,
+                IBinder.FLAG_ONEWAY);
+        data.recycle();
+    }
 }
 
diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java
index 4ff8e1a..a2a74f8 100644
--- a/core/java/android/app/ContextImpl.java
+++ b/core/java/android/app/ContextImpl.java
@@ -53,7 +53,6 @@
 import android.content.pm.ProviderInfo;
 import android.content.pm.ResolveInfo;
 import android.content.pm.ServiceInfo;
-import android.content.pm.PackageParser.Package;
 import android.content.res.AssetManager;
 import android.content.res.Resources;
 import android.content.res.XmlResourceParser;
@@ -68,6 +67,7 @@
 import android.media.AudioManager;
 import android.net.ConnectivityManager;
 import android.net.IConnectivityManager;
+import android.net.DownloadManager;
 import android.net.ThrottleManager;
 import android.net.IThrottleManager;
 import android.net.Uri;
@@ -86,11 +86,9 @@
 import android.os.Process;
 import android.os.RemoteException;
 import android.os.ServiceManager;
-import android.os.StatFs;
 import android.os.Vibrator;
 import android.os.FileUtils.FileStatus;
 import android.os.storage.StorageManager;
-import android.provider.Settings;
 import android.telephony.TelephonyManager;
 import android.text.ClipboardManager;
 import android.util.AndroidRuntimeException;
@@ -200,6 +198,7 @@
     private DropBoxManager mDropBoxManager = null;
     private DevicePolicyManager mDevicePolicyManager = null;
     private UiModeManager mUiModeManager = null;
+    private DownloadManager mDownloadManager = null;
 
     private final Object mSync = new Object();
 
@@ -209,7 +208,7 @@
     private File mCacheDir;
     private File mExternalFilesDir;
     private File mExternalCacheDir;
-    
+
     private static long sInstanceCount = 0;
 
     private static final String[] EMPTY_FILE_LIST = {};
@@ -261,18 +260,18 @@
     public Looper getMainLooper() {
         return mMainThread.getLooper();
     }
-    
+
     @Override
     public Context getApplicationContext() {
         return (mPackageInfo != null) ?
                 mPackageInfo.getApplication() : mMainThread.getApplication();
     }
-    
+
     @Override
     public void setTheme(int resid) {
         mThemeResource = resid;
     }
-    
+
     @Override
     public Resources.Theme getTheme() {
         if (mTheme == null) {
@@ -322,7 +321,7 @@
         }
         throw new RuntimeException("Not supported in system context");
     }
-    
+
     private static File makeBackupFile(File prefsFile) {
         return new File(prefsFile.getPath() + ".bak");
     }
@@ -342,7 +341,7 @@
                 return sp;
             }
         }
-        
+
         FileInputStream str = null;
         File backup = makeBackupFile(f);
         if (backup.exists()) {
@@ -354,7 +353,7 @@
         if (f.exists() && !f.canRead()) {
             Log.w(TAG, "Attempt to read preferences file " + f + " without permission");
         }
-        
+
         Map map = null;
         if (f.exists() && f.canRead()) {
             try {
@@ -438,7 +437,7 @@
             }
             if (!mFilesDir.exists()) {
                 if(!mFilesDir.mkdirs()) {
-                    Log.w(TAG, "Unable to create files directory");
+                    Log.w(TAG, "Unable to create files directory " + mFilesDir.getPath());
                     return null;
                 }
                 FileUtils.setPermissions(
@@ -449,7 +448,7 @@
             return mFilesDir;
         }
     }
-    
+
     @Override
     public File getExternalFilesDir(String type) {
         synchronized (mSync) {
@@ -481,7 +480,7 @@
             return dir;
         }
     }
-    
+
     @Override
     public File getCacheDir() {
         synchronized (mSync) {
@@ -501,7 +500,7 @@
         }
         return mCacheDir;
     }
-    
+
     @Override
     public File getExternalCacheDir() {
         synchronized (mSync) {
@@ -523,7 +522,7 @@
             return mExternalCacheDir;
         }
     }
-    
+
     @Override
     public File getFileStreamPath(String name) {
         return makeFilename(getFilesDir(), name);
@@ -573,7 +572,7 @@
         return (list != null) ? list : EMPTY_FILE_LIST;
     }
 
-    
+
     private File getDatabasesDir() {
         synchronized (mSync) {
             if (mDatabasesDir == null) {
@@ -585,7 +584,7 @@
             return mDatabasesDir;
         }
     }
-    
+
     @Override
     public Drawable getWallpaper() {
         return getWallpaperManager().getDrawable();
@@ -654,7 +653,7 @@
         } catch (RemoteException e) {
         }
     }
-    
+
     @Override
     public void sendBroadcast(Intent intent) {
         String resolvedType = intent.resolveTypeIfNeeded(getContentResolver());
@@ -984,6 +983,8 @@
             return getDevicePolicyManager();
         } else if (UI_MODE_SERVICE.equals(name)) {
             return getUiModeManager();
+        } else if (DOWNLOAD_SERVICE.equals(name)) {
+            return getDownloadManager();
         }
 
         return null;
@@ -1202,6 +1203,15 @@
         return mUiModeManager;
     }
 
+    private DownloadManager getDownloadManager() {
+        synchronized (mSync) {
+            if (mDownloadManager == null) {
+                mDownloadManager = new DownloadManager(getContentResolver());
+            }
+        }
+        return mDownloadManager;
+    }
+
     @Override
     public int checkPermission(String permission, int pid, int uid) {
         if (permission == null) {
@@ -1556,15 +1566,15 @@
     final void setActivityToken(IBinder token) {
         mActivityToken = token;
     }
-    
+
     final void setOuterContext(Context context) {
         mOuterContext = context;
     }
-    
+
     final Context getOuterContext() {
         return mOuterContext;
     }
-    
+
     final IBinder getActivityToken() {
         return mActivityToken;
     }
@@ -1641,7 +1651,7 @@
         {
             return mMainThread.releaseProvider(provider);
         }
-        
+
         private final ActivityThread mMainThread;
     }
 
@@ -1674,7 +1684,7 @@
                 throw new RuntimeException("Package manager has died", e);
             }
         }
-        
+
         @Override
         public String[] canonicalToCurrentPackageNames(String[] names) {
             try {
@@ -1683,7 +1693,7 @@
                 throw new RuntimeException("Package manager has died", e);
             }
         }
-        
+
         @Override
         public Intent getLaunchIntentForPackage(String packageName) {
             // First see if the package has an INFO activity; the existence of
@@ -1705,8 +1715,9 @@
             if (resolveInfo == null) {
                 return null;
             }
-            Intent intent = new Intent(Intent.ACTION_MAIN);
-            intent.setClassName(packageName, resolveInfo.activityInfo.name);
+            Intent intent = new Intent(intentToResolve);
+            intent.setClassName(resolveInfo.activityInfo.applicationInfo.packageName,
+                                resolveInfo.activityInfo.name);
             intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
             return intent;
         }
@@ -1857,7 +1868,7 @@
                 throw new RuntimeException("Package manager has died", e);
             }
         }
-        
+
         @Override
         public boolean hasSystemFeature(String name) {
             try {
@@ -1866,7 +1877,7 @@
                 throw new RuntimeException("Package manager has died", e);
             }
         }
-        
+
         @Override
         public int checkPermission(String permName, String pkgName) {
             try {
@@ -1938,9 +1949,9 @@
                 throw new RuntimeException("Package manager has died", e);
             }
         }
-        
+
         @Override
-        public int getUidForSharedUser(String sharedUserName) 
+        public int getUidForSharedUser(String sharedUserName)
                 throws NameNotFoundException {
             try {
                 int uid = mPM.getUidForSharedUser(sharedUserName);
@@ -2344,7 +2355,7 @@
                 }
             }
         }
-        
+
         private static final class ResourceName {
             final String packageName;
             final int iconId;
@@ -2516,7 +2527,7 @@
             }
         }
         @Override
-        public void clearApplicationUserData(String packageName, 
+        public void clearApplicationUserData(String packageName,
                 IPackageDataObserver observer) {
             try {
                 mPM.clearApplicationUserData(packageName, observer);
@@ -2525,7 +2536,7 @@
             }
         }
         @Override
-        public void deleteApplicationCacheFiles(String packageName, 
+        public void deleteApplicationCacheFiles(String packageName,
                 IPackageDataObserver observer) {
             try {
                 mPM.deleteApplicationCacheFiles(packageName, observer);
@@ -2550,9 +2561,9 @@
                 // Should never happen!
             }
         }
-        
+
         @Override
-        public void getPackageSizeInfo(String packageName, 
+        public void getPackageSizeInfo(String packageName,
                 IPackageStatsObserver observer) {
             try {
                 mPM.getPackageSizeInfo(packageName, observer);
@@ -2597,7 +2608,7 @@
                 // Should never happen!
             }
         }
-        
+
         @Override
         public void replacePreferredActivity(IntentFilter filter,
                 int match, ComponentName[] set, ComponentName activity) {
@@ -2616,7 +2627,7 @@
                 // Should never happen!
             }
         }
-        
+
         @Override
         public int getPreferredActivities(List<IntentFilter> outFilters,
                 List<ComponentName> outActivities, String packageName) {
@@ -2627,7 +2638,7 @@
             }
             return 0;
         }
-        
+
         @Override
         public void setComponentEnabledSetting(ComponentName componentName,
                 int newState, int flags) {
@@ -2657,7 +2668,7 @@
                 // Should never happen!
             }
         }
-        
+
         @Override
         public int getApplicationEnabledSetting(String packageName) {
             try {
@@ -2668,6 +2679,15 @@
             return PackageManager.COMPONENT_ENABLED_STATE_DEFAULT;
         }
 
+        @Override
+        public void setPackageObbPath(String packageName, String path) {
+            try {
+                mPM.setPackageObbPath(packageName, path);
+            } catch (RemoteException e) {
+                // Should never happen!
+            }
+        }
+
         private final ContextImpl mContext;
         private final IPackageManager mPM;
 
@@ -2714,7 +2734,7 @@
                 return mTimestamp != mFileStatus.mtime;
             }
         }
-        
+
         public void replace(Map newContents) {
             if (newContents != null) {
                 synchronized (this) {
@@ -2722,7 +2742,7 @@
                 }
             }
         }
-        
+
         public void registerOnSharedPreferenceChangeListener(OnSharedPreferenceChangeListener listener) {
             synchronized(this) {
                 mListeners.put(listener, mContent);
@@ -2901,7 +2921,7 @@
         public Editor edit() {
             return new EditorImpl();
         }
-        
+
         private FileOutputStream createFileOutputStream(File file) {
             FileOutputStream str = null;
             try {
@@ -2938,7 +2958,7 @@
                     mFile.delete();
                 }
             }
-            
+
             // Attempt to write the file, delete the backup and return true as atomically as
             // possible.  If any exception occurs, delete the new file; next time we will restore
             // from the backup.
@@ -2953,7 +2973,7 @@
                 if (FileUtils.getFileStatus(mFile.getPath(), mFileStatus)) {
                     mTimestamp = mFileStatus.mtime;
                 }
-                
+
                 // Writing was successful, delete the backup file if there is one.
                 mBackupFile.delete();
                 return true;
diff --git a/core/java/android/app/Fragment.java b/core/java/android/app/Fragment.java
index 231d6ab..daf6ce0 100644
--- a/core/java/android/app/Fragment.java
+++ b/core/java/android/app/Fragment.java
@@ -134,14 +134,14 @@
  * that can be placed in an {@link Activity}.
  */
 public class Fragment implements ComponentCallbacks, OnCreateContextMenuListener {
-    private static final HashMap<String, Class> sClassMap =
-            new HashMap<String, Class>();
+    private static final HashMap<String, Class<?>> sClassMap =
+            new HashMap<String, Class<?>>();
     
-    static final int INITIALIZING = 0;  // Not yet created.
-    static final int CREATED = 1;       // Created.
-    static final int CONTENT = 2;       // View hierarchy content available.
-    static final int STARTED = 3;       // Created and started, not resumed.
-    static final int RESUMED = 4;       // Created started and resumed.
+    static final int INITIALIZING = 0;     // Not yet created.
+    static final int CREATED = 1;          // Created.
+    static final int ACTIVITY_CREATED = 2; // The activity has finished its creation.
+    static final int STARTED = 3;          // Created and started, not resumed.
+    static final int RESUMED = 4;          // Created started and resumed.
     
     int mState = INITIALIZING;
     
@@ -158,6 +158,9 @@
     // True if the fragment is in the list of added fragments.
     boolean mAdded;
     
+    // True if the fragment is in the resumed state.
+    boolean mResumed;
+    
     // Set to true if this fragment was instantiated from a layout file.
     boolean mFromLayout;
     
@@ -210,6 +213,17 @@
     // The View generated for this fragment.
     View mView;
     
+    LoaderManagerImpl mLoaderManager;
+    boolean mStarted;
+    
+    /**
+     * Default constructor.  <strong>Every</string> fragment must have an
+     * empty constructor, so it can be instantiated when restoring its
+     * activity's state.  It is strongly recommended that subclasses do not
+     * have other constructors with parameters, since these constructors
+     * will not be called when the fragment is re-instantiated; instead,
+     * retrieve such parameters from the activity in {@link #onAttach(Activity)}.
+     */
     public Fragment() {
     }
 
@@ -217,7 +231,7 @@
             throws NoSuchMethodException, ClassNotFoundException,
             IllegalArgumentException, InstantiationException,
             IllegalAccessException, InvocationTargetException {
-        Class clazz = sClassMap.get(fname);
+        Class<?> clazz = sClassMap.get(fname);
 
         if (clazz == null) {
             // Class not found in the cache, see if it's real, and try to add it
@@ -310,6 +324,14 @@
     }
     
     /**
+     * Return true if the fragment is in the resumed state.  This is true
+     * for the duration of {@link #onResume()} and {@link #onPause()} as well.
+     */
+    final public boolean isResumed() {
+        return mResumed;
+    }
+    
+    /**
      * Return true if the fragment is currently visible to the user.  This means
      * it: (1) has been added, (2) has its view attached to the window, and 
      * (3) is not hidden.
@@ -350,7 +372,7 @@
      * will be, because the fragment is being detached from its current activity).
      * <li> {@link #onCreate(Bundle)} will not be called since the fragment
      * is not being re-created.
-     * <li> {@link #onAttach(Activity)} and {@link #onReady(Bundle)} <b>will</b>
+     * <li> {@link #onAttach(Activity)} and {@link #onActivityCreated(Bundle)} <b>will</b>
      * still be called.
      * </ul>
      */
@@ -379,6 +401,17 @@
     }
     
     /**
+     * Return the LoaderManager for this fragment, creating it if needed.
+     */
+    public LoaderManager getLoaderManager() {
+        if (mLoaderManager != null) {
+            return mLoaderManager;
+        }
+        mLoaderManager = mActivity.getLoaderManager(mIndex, mStarted);
+        return mLoaderManager;
+    }
+    
+    /**
      * Call {@link Activity#startActivity(Intent)} on the fragment's
      * containing Activity.
      */
@@ -446,7 +479,15 @@
     
     /**
      * Called to do initial creation of a fragment.  This is called after
-     * {@link #onAttach(Activity)} and before {@link #onReady(Bundle)}.
+     * {@link #onAttach(Activity)} and before
+     * {@link #onCreateView(LayoutInflater, ViewGroup, Bundle)}.
+     * 
+     * <p>Note that this can be called while the fragment's activity is
+     * still in the process of being created.  As such, you can not rely
+     * on things like the activity's content view hierarchy being initialized
+     * at this point.  If you want to do work once the activity itself is
+     * created, see {@link #onActivityCreated(Bundle)}.
+     * 
      * @param savedInstanceState If the fragment is being re-created from
      * a previous saved state, this is the state.
      */
@@ -458,7 +499,7 @@
      * Called to have the fragment instantiate its user interface view.
      * This is optional, and non-graphical fragments can return null (which
      * is the default implementation).  This will be called between
-     * {@link #onCreate(Bundle)} and {@link #onReady(Bundle)}.
+     * {@link #onCreate(Bundle)} and {@link #onActivityCreated(Bundle)}.
      * 
      * <p>If you return a View from here, you will later be called in
      * {@link #onDestroyView} when the view is being released.
@@ -483,16 +524,19 @@
     }
     
     /**
-     * Called when the activity is ready for the fragment to run.  This is
-     * most useful for fragments that use {@link #setRetainInstance(boolean)}
-     * instance, as this tells the fragment when it is fully associated with
+     * Called when the fragment's activity has been created and this
+     * fragment's view hierarchy instantiated.  It can be used to do final
+     * initialization once these pieces are in place, such as retrieving
+     * views or restoring state.  It is also useful for fragments that use
+     * {@link #setRetainInstance(boolean)} to retain their instance,
+     * as this callback tells the fragment when it is fully associated with
      * the new activity instance.  This is called after {@link #onCreateView}
      * and before {@link #onStart()}.
      * 
      * @param savedInstanceState If the fragment is being re-created from
      * a previous saved state, this is the state.
      */
-    public void onReady(Bundle savedInstanceState) {
+    public void onActivityCreated(Bundle savedInstanceState) {
         mCalled = true;
     }
     
@@ -503,6 +547,10 @@
      */
     public void onStart() {
         mCalled = true;
+        mStarted = true;
+        if (mLoaderManager != null) {
+            mLoaderManager.doStart();
+        }
     }
     
     /**
@@ -561,6 +609,9 @@
      */
     public void onDestroy() {
         mCalled = true;
+        if (mLoaderManager != null) {
+            mLoaderManager.doDestroy();
+        }
     }
 
     /**
@@ -702,4 +753,18 @@
     public boolean onContextItemSelected(MenuItem item) {
         return false;
     }
+    
+    void performStop() {
+        onStop();
+        if (mStarted) {
+            mStarted = false;
+            if (mLoaderManager != null) {
+                if (mActivity == null || !mActivity.mChangingConfigurations) {
+                    mLoaderManager.doStop();
+                } else {
+                    mLoaderManager.doRetain();
+                }
+            }
+        }
+    }
 }
diff --git a/core/java/android/app/FragmentManager.java b/core/java/android/app/FragmentManager.java
index b8eeb094..4f3043c 100644
--- a/core/java/android/app/FragmentManager.java
+++ b/core/java/android/app/FragmentManager.java
@@ -162,6 +162,7 @@
                         throw new SuperNotCalledException("Fragment " + f
                                 + " did not call through to super.onAttach()");
                     }
+                    mActivity.onAttachFragment(f);
                     
                     if (!f.mRetaining) {
                         f.mCalled = false;
@@ -216,15 +217,15 @@
                         }
                         
                         f.mCalled = false;
-                        f.onReady(f.mSavedFragmentState);
+                        f.onActivityCreated(f.mSavedFragmentState);
                         if (!f.mCalled) {
                             throw new SuperNotCalledException("Fragment " + f
                                     + " did not call through to super.onReady()");
                         }
                         f.mSavedFragmentState = null;
                     }
-                case Fragment.CONTENT:
-                    if (newState > Fragment.CONTENT) {
+                case Fragment.ACTIVITY_CREATED:
+                    if (newState > Fragment.ACTIVITY_CREATED) {
                         if (DEBUG) Log.v(TAG, "moveto STARTED: " + f);
                         f.mCalled = false;
                         f.onStart();
@@ -237,6 +238,7 @@
                     if (newState > Fragment.STARTED) {
                         if (DEBUG) Log.v(TAG, "moveto RESUMED: " + f);
                         f.mCalled = false;
+                        f.mResumed = true;
                         f.onResume();
                         if (!f.mCalled) {
                             throw new SuperNotCalledException("Fragment " + f
@@ -255,19 +257,20 @@
                             throw new SuperNotCalledException("Fragment " + f
                                     + " did not call through to super.onPause()");
                         }
+                        f.mResumed = false;
                     }
                 case Fragment.STARTED:
                     if (newState < Fragment.STARTED) {
                         if (DEBUG) Log.v(TAG, "movefrom STARTED: " + f);
                         f.mCalled = false;
-                        f.onStop();
+                        f.performStop();
                         if (!f.mCalled) {
                             throw new SuperNotCalledException("Fragment " + f
                                     + " did not call through to super.onStop()");
                         }
                     }
-                case Fragment.CONTENT:
-                    if (newState < Fragment.CONTENT) {
+                case Fragment.ACTIVITY_CREATED:
+                    if (newState < Fragment.ACTIVITY_CREATED) {
                         if (DEBUG) Log.v(TAG, "movefrom CONTENT: " + f);
                         if (f.mView != null) {
                             f.mCalled = false;
@@ -373,6 +376,7 @@
             mAvailIndices = new ArrayList<Integer>();
         }
         mAvailIndices.add(f.mIndex);
+        mActivity.invalidateFragmentIndex(f.mIndex);
         f.clearIndex();
     }
     
@@ -783,6 +787,10 @@
         moveToState(Fragment.CREATED, false);
     }
     
+    public void dispatchActivityCreated() {
+        moveToState(Fragment.ACTIVITY_CREATED, false);
+    }
+    
     public void dispatchStart() {
         moveToState(Fragment.STARTED, false);
     }
@@ -796,7 +804,7 @@
     }
     
     public void dispatchStop() {
-        moveToState(Fragment.CONTENT, false);
+        moveToState(Fragment.ACTIVITY_CREATED, false);
     }
     
     public void dispatchDestroy() {
diff --git a/core/java/android/app/IActivityManager.java b/core/java/android/app/IActivityManager.java
index 20c9a80..8ea59a7 100644
--- a/core/java/android/app/IActivityManager.java
+++ b/core/java/android/app/IActivityManager.java
@@ -316,7 +316,11 @@
     
     public void crashApplication(int uid, int initialPid, String packageName,
             String message) throws RemoteException;
-    
+
+    // Cause the specified process to dump the specified heap.
+    public boolean dumpHeap(String process, boolean managed, String path,
+        ParcelFileDescriptor fd) throws RemoteException;
+
     /*
      * Private non-Binder interfaces
      */
@@ -533,4 +537,5 @@
     int SET_IMMERSIVE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+111;
     int IS_TOP_ACTIVITY_IMMERSIVE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+112;
     int CRASH_APPLICATION_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+113;
+    int DUMP_HEAP_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+114;
 }
diff --git a/core/java/android/app/IApplicationThread.java b/core/java/android/app/IApplicationThread.java
index c8ef17f..039bcb9 100644
--- a/core/java/android/app/IApplicationThread.java
+++ b/core/java/android/app/IApplicationThread.java
@@ -97,6 +97,8 @@
     void scheduleActivityConfigurationChanged(IBinder token) throws RemoteException;
     void profilerControl(boolean start, String path, ParcelFileDescriptor fd)
             throws RemoteException;
+    void dumpHeap(boolean managed, String path, ParcelFileDescriptor fd)
+            throws RemoteException;
     void setSchedulingGroup(int group) throws RemoteException;
     void getMemoryInfo(Debug.MemoryInfo outInfo) throws RemoteException;
     static final int PACKAGE_REMOVED = 0;
@@ -140,4 +142,5 @@
     int SCHEDULE_SUICIDE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+32;
     int DISPATCH_PACKAGE_BROADCAST_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+33;
     int SCHEDULE_CRASH_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+34;
+    int DUMP_HEAP_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+35;
 }
diff --git a/core/java/android/app/ListActivity.java b/core/java/android/app/ListActivity.java
index 4bf5518..d49968f 100644
--- a/core/java/android/app/ListActivity.java
+++ b/core/java/android/app/ListActivity.java
@@ -309,7 +309,7 @@
         if (mList != null) {
             return;
         }
-        setContentView(com.android.internal.R.layout.list_content);
+        setContentView(com.android.internal.R.layout.list_content_simple);
 
     }
 
diff --git a/core/java/android/app/ListFragment.java b/core/java/android/app/ListFragment.java
index a6be329..73ef869 100644
--- a/core/java/android/app/ListFragment.java
+++ b/core/java/android/app/ListFragment.java
@@ -160,7 +160,6 @@
     TextView mStandardEmptyView;
     View mProgressContainer;
     View mListContainer;
-    boolean mSetEmptyView;
     boolean mListShown;
 
     public ListFragment() {
@@ -173,11 +172,17 @@
      * is {@link android.R.id#list android.R.id.list} and can optionally
      * have a sibling view id {@link android.R.id#empty android.R.id.empty}
      * that is to be shown when the list is empty.
+     * 
+     * <p>If you are overriding this method with your own custom content,
+     * consider including the standard layout {@link android.R.layout#list_content}
+     * in your layout file, so that you continue to retain all of the standard
+     * behavior of ListFragment.  In particular, this is currently the only
+     * way to have the built-in indeterminant progress state be shown.
      */
     @Override
     public View onCreateView(LayoutInflater inflater, ViewGroup container,
             Bundle savedInstanceState) {
-        return inflater.inflate(com.android.internal.R.layout.list_content_rich,
+        return inflater.inflate(com.android.internal.R.layout.list_content,
                 container, false);
     }
 
@@ -185,8 +190,8 @@
      * Attach to list view once Fragment is ready to run.
      */
     @Override
-    public void onReady(Bundle savedInstanceState) {
-        super.onReady(savedInstanceState);
+    public void onActivityCreated(Bundle savedInstanceState) {
+        super.onActivityCreated(savedInstanceState);
         ensureList();
     }
 
@@ -218,9 +223,15 @@
      * Provide the cursor for the list view.
      */
     public void setListAdapter(ListAdapter adapter) {
+        boolean hadAdapter = mAdapter != null;
         mAdapter = adapter;
         if (mList != null) {
             mList.setAdapter(adapter);
+            if (!mListShown && !hadAdapter) {
+                // The list was hidden, and previously didn't have an
+                // adapter.  It is now time to show it.
+                setListShown(true, getView().getWindowToken() != null);
+            }
         }
     }
 
@@ -269,10 +280,33 @@
         if (mStandardEmptyView == null) {
             throw new IllegalStateException("Can't be used with a custom content view");
         }
-        if (!mSetEmptyView) {
-            mSetEmptyView = true;
-            mList.setEmptyView(mStandardEmptyView);
-        }
+        mList.setEmptyView(mStandardEmptyView);
+    }
+    
+    /**
+     * Control whether the list is being displayed.  You can make it not
+     * displayed if you are waiting for the initial data to show in it.  During
+     * this time an indeterminant progress indicator will be shown instead.
+     * 
+     * <p>Applications do not normally need to use this themselves.  The default
+     * behavior of ListFragment is to start with the list not being shown, only
+     * showing it once an adapter is given with {@link #setListAdapter(ListAdapter)}.
+     * If the list at that point had not been shown, when it does get shown
+     * it will be do without the user ever seeing the hidden state.
+     * 
+     * @param shown If true, the list view is shown; if false, the progress
+     * indicator.  The initial value is true.
+     */
+    public void setListShown(boolean shown) {
+        setListShown(shown, true);
+    }
+    
+    /**
+     * Like {@link #setListShown(boolean)}, but no animation is used when
+     * transitioning from the previous state.
+     */
+    public void setListShownNoAnimation(boolean shown) {
+        setListShown(shown, false);
     }
     
     /**
@@ -285,7 +319,7 @@
      * @param animate If true, an animation will be used to transition to the
      * new state.
      */
-    public void setListShown(boolean shown, boolean animate) {
+    private void setListShown(boolean shown, boolean animate) {
         ensureList();
         if (mProgressContainer == null) {
             throw new IllegalStateException("Can't be used with a custom content view");
@@ -360,6 +394,12 @@
         mList.setOnItemClickListener(mOnClickListener);
         if (mAdapter != null) {
             setListAdapter(mAdapter);
+        } else {
+            // We are starting without an adapter, so assume we won't
+            // have our data right away and start with the progress indicator.
+            if (mProgressContainer != null) {
+                setListShown(false, false);
+            }
         }
         mHandler.post(mRequestFocus);
     }
diff --git a/core/java/android/app/LoaderManager.java b/core/java/android/app/LoaderManager.java
new file mode 100644
index 0000000..c9fdfba
--- /dev/null
+++ b/core/java/android/app/LoaderManager.java
@@ -0,0 +1,337 @@
+/*
+ * 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.app;
+
+import android.content.Loader;
+import android.os.Bundle;
+import android.util.SparseArray;
+
+/**
+ * Interface associated with an {@link Activity} or {@link Fragment} for managing
+ * one or more {@link android.content.Loader} instances associated with it.
+ */
+public interface LoaderManager {
+    /**
+     * Callback interface for a client to interact with the manager.
+     */
+    public interface LoaderCallbacks<D> {
+        /**
+         * Instantiate and return a new Loader for the given ID.
+         *
+         * @param id The ID whose loader is to be created.
+         * @param args Any arguments supplied by the caller.
+         * @return Return a new Loader instance that is ready to start loading.
+         */
+        public Loader<D> onCreateLoader(int id, Bundle args);
+
+        /**
+         * Called when a previously created loader has finished its load.
+         * @param loader The Loader that has finished.
+         * @param data The data generated by the Loader.
+         */
+        public void onLoadFinished(Loader<D> loader, D data);
+    }
+    
+    /**
+     * Ensures a loader is initialized and active.  If the loader doesn't
+     * already exist, one is created and (if the activity/fragment is currently
+     * started) starts the loader.  Otherwise the last created
+     * loader is re-used.
+     *
+     * <p>In either case, the given callback is associated with the loader, and
+     * will be called as the loader state changes.  If at the point of call
+     * the caller is in its started state, and the requested loader
+     * already exists and has generated its data, then
+     * callback. {@link LoaderCallbacks#onLoadFinished} will
+     * be called immediately (inside of this function), so you must be prepared
+     * for this to happen.
+     */
+    public <D> Loader<D> initLoader(int id, Bundle args,
+            LoaderManager.LoaderCallbacks<D> callback);
+
+    /**
+     * Creates a new loader in this manager, registers the callbacks to it,
+     * and (if the activity/fragment is currently started) starts loading it.
+     * If a loader with the same id has previously been
+     * started it will automatically be destroyed when the new loader completes
+     * its work. The callback will be delivered before the old loader
+     * is destroyed.
+     */
+    public <D> Loader<D> restartLoader(int id, Bundle args,
+            LoaderManager.LoaderCallbacks<D> callback);
+
+    /**
+     * Stops and removes the loader with the given ID.
+     */
+    public void stopLoader(int id);
+
+    /**
+     * Return the Loader with the given id or null if no matching Loader
+     * is found.
+     */
+    public <D> Loader<D> getLoader(int id);
+}
+
+class LoaderManagerImpl implements LoaderManager {
+    final SparseArray<LoaderInfo> mLoaders = new SparseArray<LoaderInfo>();
+    final SparseArray<LoaderInfo> mInactiveLoaders = new SparseArray<LoaderInfo>();
+    boolean mStarted;
+    boolean mRetaining;
+    boolean mRetainingStarted;
+
+    final class LoaderInfo implements Loader.OnLoadCompleteListener<Object> {
+        final int mId;
+        final Bundle mArgs;
+        LoaderManager.LoaderCallbacks<Object> mCallbacks;
+        Loader<Object> mLoader;
+        Object mData;
+        boolean mStarted;
+        boolean mRetaining;
+        boolean mRetainingStarted;
+        boolean mDestroyed;
+        boolean mListenerRegistered;
+        
+        public LoaderInfo(int id, Bundle args, LoaderManager.LoaderCallbacks<Object> callbacks) {
+            mId = id;
+            mArgs = args;
+            mCallbacks = callbacks;
+        }
+        
+        void start() {
+            if (mRetaining && mRetainingStarted) {
+                // Our owner is started, but we were being retained from a
+                // previous instance in the started state...  so there is really
+                // nothing to do here, since the loaders are still started.
+                mStarted = true;
+                return;
+            }
+
+            if (mStarted) {
+                // If loader already started, don't restart.
+                return;
+            }
+
+            if (mLoader == null && mCallbacks != null) {
+               mLoader = mCallbacks.onCreateLoader(mId, mArgs);
+            }
+            if (mLoader != null) {
+                if (!mListenerRegistered) {
+                    mLoader.registerListener(mId, this);
+                    mListenerRegistered = true;
+                }
+                mLoader.startLoading();
+                mStarted = true;
+            }
+        }
+        
+        void retain() {
+            mRetaining = true;
+            mRetainingStarted = mStarted;
+            mStarted = false;
+            mCallbacks = null;
+        }
+        
+        void finishRetain() {
+            if (mRetaining) {
+                mRetaining = false;
+                if (mStarted != mRetainingStarted) {
+                    if (!mStarted) {
+                        // This loader was retained in a started state, but
+                        // at the end of retaining everything our owner is
+                        // no longer started...  so make it stop.
+                        stop();
+                    }
+                }
+                if (mStarted && mData != null && mCallbacks != null) {
+                    // This loader was retained, and now at the point of
+                    // finishing the retain we find we remain started, have
+                    // our data, and the owner has a new callback...  so
+                    // let's deliver the data now.
+                    mCallbacks.onLoadFinished(mLoader, mData);
+                }
+            }
+        }
+        
+        void stop() {
+            mStarted = false;
+            if (mLoader != null && mListenerRegistered) {
+                // Let the loader know we're done with it
+                mListenerRegistered = false;
+                mLoader.unregisterListener(this);
+            }
+        }
+        
+        void destroy() {
+            mDestroyed = true;
+            mCallbacks = null;
+            if (mLoader != null) {
+                if (mListenerRegistered) {
+                    mListenerRegistered = false;
+                    mLoader.unregisterListener(this);
+                }
+                mLoader.destroy();
+            }
+        }
+        
+        @Override public void onLoadComplete(Loader<Object> loader, Object data) {
+            if (mDestroyed) {
+                return;
+            }
+            
+            // Notify of the new data so the app can switch out the old data before
+            // we try to destroy it.
+            mData = data;
+            if (mCallbacks != null) {
+                mCallbacks.onLoadFinished(loader, data);
+            }
+
+            // Look for an inactive loader and destroy it if found
+            LoaderInfo info = mInactiveLoaders.get(mId);
+            if (info != null) {
+                Loader<Object> oldLoader = info.mLoader;
+                if (oldLoader != null) {
+                    if (info.mListenerRegistered) {
+                        oldLoader.unregisterListener(info);
+                    }
+                    oldLoader.destroy();
+                }
+                mInactiveLoaders.remove(mId);
+            }
+        }
+    }
+    
+    LoaderManagerImpl(boolean started) {
+        mStarted = started;
+    }
+    
+    private LoaderInfo createLoader(int id, Bundle args,
+            LoaderManager.LoaderCallbacks<Object> callback) {
+        LoaderInfo info = new LoaderInfo(id, args,  (LoaderManager.LoaderCallbacks<Object>)callback);
+        mLoaders.put(id, info);
+        Loader<Object> loader = callback.onCreateLoader(id, args);
+        info.mLoader = (Loader<Object>)loader;
+        if (mStarted) {
+            // The activity will start all existing loaders in it's onStart(),
+            // so only start them here if we're past that point of the activitiy's
+            // life cycle
+            info.start();
+        }
+        return info;
+    }
+    
+    @SuppressWarnings("unchecked")
+    public <D> Loader<D> initLoader(int id, Bundle args, LoaderManager.LoaderCallbacks<D> callback) {
+        LoaderInfo info = mLoaders.get(id);
+        
+        if (info == null) {
+            // Loader doesn't already exist; create.
+            info = createLoader(id, args,  (LoaderManager.LoaderCallbacks<Object>)callback);
+        } else {
+            info.mCallbacks = (LoaderManager.LoaderCallbacks<Object>)callback;
+        }
+        
+        if (info.mData != null && mStarted) {
+            // If the loader has already generated its data, report it now.
+            info.mCallbacks.onLoadFinished(info.mLoader, info.mData);
+        }
+        
+        return (Loader<D>)info.mLoader;
+    }
+    
+    @SuppressWarnings("unchecked")
+    public <D> Loader<D> restartLoader(int id, Bundle args, LoaderManager.LoaderCallbacks<D> callback) {
+        LoaderInfo info = mLoaders.get(id);
+        if (info != null) {
+            if (mInactiveLoaders.get(id) != null) {
+                // We already have an inactive loader for this ID that we are
+                // waiting for!  Now we have three active loaders... let's just
+                // drop the one in the middle, since we are still waiting for
+                // its result but that result is already out of date.
+                info.destroy();
+            } else {
+                // Keep track of the previous instance of this loader so we can destroy
+                // it when the new one completes.
+                mInactiveLoaders.put(id, info);
+            }
+        }
+        
+        info = createLoader(id, args,  (LoaderManager.LoaderCallbacks<Object>)callback);
+        return (Loader<D>)info.mLoader;
+    }
+    
+    public void stopLoader(int id) {
+        int idx = mLoaders.indexOfKey(id);
+        if (idx >= 0) {
+            LoaderInfo info = mLoaders.valueAt(idx);
+            mLoaders.removeAt(idx);
+            info.destroy();
+        }
+    }
+
+    @SuppressWarnings("unchecked")
+    public <D> Loader<D> getLoader(int id) {
+        LoaderInfo loaderInfo = mLoaders.get(id);
+        if (loaderInfo != null) {
+            return (Loader<D>)mLoaders.get(id).mLoader;
+        }
+        return null;
+    }
+ 
+    void doStart() {
+        // Call out to sub classes so they can start their loaders
+        // Let the existing loaders know that we want to be notified when a load is complete
+        for (int i = mLoaders.size()-1; i >= 0; i--) {
+            mLoaders.valueAt(i).start();
+        }
+        mStarted = true;
+    }
+    
+    void doStop() {
+        for (int i = mLoaders.size()-1; i >= 0; i--) {
+            mLoaders.valueAt(i).stop();
+        }
+        mStarted = false;
+    }
+    
+    void doRetain() {
+        mRetaining = true;
+        mStarted = false;
+        for (int i = mLoaders.size()-1; i >= 0; i--) {
+            mLoaders.valueAt(i).retain();
+        }
+    }
+    
+    void finishRetain() {
+        mRetaining = false;
+        for (int i = mLoaders.size()-1; i >= 0; i--) {
+            mLoaders.valueAt(i).finishRetain();
+        }
+    }
+    
+    void doDestroy() {
+        if (!mRetaining) {
+            for (int i = mLoaders.size()-1; i >= 0; i--) {
+                mLoaders.valueAt(i).destroy();
+            }
+        }
+        
+        for (int i = mInactiveLoaders.size()-1; i >= 0; i--) {
+            mInactiveLoaders.valueAt(i).destroy();
+        }
+        mInactiveLoaders.clear();
+    }
+}
diff --git a/core/java/android/app/NativeActivity.java b/core/java/android/app/NativeActivity.java
index d72dda7..ccc9ae3 100644
--- a/core/java/android/app/NativeActivity.java
+++ b/core/java/android/app/NativeActivity.java
@@ -2,6 +2,7 @@
 
 import dalvik.system.PathClassLoader;
 
+import android.content.Context;
 import android.content.pm.ActivityInfo;
 import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageManager;
@@ -11,12 +12,16 @@
 import android.os.Environment;
 import android.os.Looper;
 import android.os.MessageQueue;
+import android.util.AttributeSet;
 import android.view.InputChannel;
 import android.view.InputQueue;
 import android.view.KeyEvent;
 import android.view.Surface;
 import android.view.SurfaceHolder;
 import android.view.View;
+import android.view.WindowManager;
+import android.view.ViewTreeObserver.OnGlobalLayoutListener;
+import android.view.inputmethod.InputMethodManager;
 
 import java.io.File;
 
@@ -24,15 +29,26 @@
  * Convenience for implementing an activity that will be implemented
  * purely in native code.  That is, a game (or game-like thing).
  */
-public class NativeActivity extends Activity implements SurfaceHolder.Callback,
-        InputQueue.Callback {
+public class NativeActivity extends Activity implements SurfaceHolder.Callback2,
+        InputQueue.Callback, OnGlobalLayoutListener {
     public static final String META_DATA_LIB_NAME = "android.app.lib_name";
     
+    private NativeContentView mNativeContentView;
+    private InputMethodManager mIMM;
+
     private int mNativeHandle;
     
     private InputQueue mCurInputQueue;
     private SurfaceHolder mCurSurfaceHolder;
     
+    final int[] mLocation = new int[2];
+    int mLastContentX;
+    int mLastContentY;
+    int mLastContentWidth;
+    int mLastContentHeight;
+
+    private boolean mDispatchingUnhandledKey;
+
     private boolean mDestroyed;
     
     private native int loadNativeCode(String path, MessageQueue queue,
@@ -49,18 +65,44 @@
     private native void onSurfaceCreatedNative(int handle, Surface surface);
     private native void onSurfaceChangedNative(int handle, Surface surface,
             int format, int width, int height);
+    private native void onSurfaceRedrawNeededNative(int handle, Surface surface);
     private native void onSurfaceDestroyedNative(int handle);
     private native void onInputChannelCreatedNative(int handle, InputChannel channel);
     private native void onInputChannelDestroyedNative(int handle, InputChannel channel);
+    private native void onContentRectChangedNative(int handle, int x, int y, int w, int h);
+    private native void dispatchKeyEventNative(int handle, KeyEvent event);
+
+    static class NativeContentView extends View {
+        NativeActivity mActivity;
+
+        public NativeContentView(Context context) {
+            super(context);
+        }
+
+        public NativeContentView(Context context, AttributeSet attrs) {
+            super(context, attrs);
+        }
+    }
     
     @Override
     protected void onCreate(Bundle savedInstanceState) {
         String libname = "main";
         ActivityInfo ai;
         
+        mIMM = (InputMethodManager)getSystemService(Context.INPUT_METHOD_SERVICE);
+
         getWindow().takeSurface(this);
         getWindow().takeInputQueue(this);
         getWindow().setFormat(PixelFormat.RGB_565);
+        getWindow().setSoftInputMode(
+                WindowManager.LayoutParams.SOFT_INPUT_STATE_UNSPECIFIED
+                | WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE);
+
+        mNativeContentView = new NativeContentView(this);
+        mNativeContentView.mActivity = this;
+        setContentView(mNativeContentView);
+        mNativeContentView.requestFocus();
+        mNativeContentView.getViewTreeObserver().addOnGlobalLayoutListener(this);
         
         try {
             ai = getPackageManager().getActivityInfo(
@@ -165,6 +207,18 @@
         }
     }
     
+    @Override
+    public boolean dispatchKeyEvent(KeyEvent event) {
+        if (mDispatchingUnhandledKey) {
+            return super.dispatchKeyEvent(event);
+        } else {
+            // Key events from the IME do not go through the input channel;
+            // we need to intercept them here to hand to the application.
+            dispatchKeyEventNative(mNativeHandle, event);
+            return true;
+        }
+    }
+
     public void surfaceCreated(SurfaceHolder holder) {
         if (!mDestroyed) {
             mCurSurfaceHolder = holder;
@@ -179,6 +233,13 @@
         }
     }
     
+    public void surfaceRedrawNeeded(SurfaceHolder holder) {
+        if (!mDestroyed) {
+            mCurSurfaceHolder = holder;
+            onSurfaceRedrawNeededNative(mNativeHandle, holder.getSurface());
+        }
+    }
+
     public void surfaceDestroyed(SurfaceHolder holder) {
         mCurSurfaceHolder = null;
         if (!mDestroyed) {
@@ -200,10 +261,32 @@
         }
     }
     
+    public void onGlobalLayout() {
+        mNativeContentView.getLocationInWindow(mLocation);
+        int w = mNativeContentView.getWidth();
+        int h = mNativeContentView.getHeight();
+        if (mLocation[0] != mLastContentX || mLocation[1] != mLastContentY
+                || w != mLastContentWidth || h != mLastContentHeight) {
+            mLastContentX = mLocation[0];
+            mLastContentY = mLocation[1];
+            mLastContentWidth = w;
+            mLastContentHeight = h;
+            if (!mDestroyed) {
+                onContentRectChangedNative(mNativeHandle, mLastContentX,
+                        mLastContentY, mLastContentWidth, mLastContentHeight);
+            }
+        }
+    }
+
     void dispatchUnhandledKeyEvent(KeyEvent event) {
-        View decor = getWindow().getDecorView();
-        if (decor != null) {
-            decor.dispatchKeyEvent(event);
+        try {
+            mDispatchingUnhandledKey = true;
+            View decor = getWindow().getDecorView();
+            if (decor != null) {
+                decor.dispatchKeyEvent(event);
+            }
+        } finally {
+            mDispatchingUnhandledKey = false;
         }
     }
     
@@ -214,4 +297,12 @@
     void setWindowFormat(int format) {
         getWindow().setFormat(format);
     }
+
+    void showIme(int mode) {
+        mIMM.showSoftInput(mNativeContentView, mode);
+    }
+
+    void hideIme(int mode) {
+        mIMM.hideSoftInputFromWindow(mNativeContentView.getWindowToken(), mode);
+    }
 }
diff --git a/core/java/android/appwidget/AppWidgetManager.java b/core/java/android/appwidget/AppWidgetManager.java
index d4ce6a1..3f12bf9 100644
--- a/core/java/android/appwidget/AppWidgetManager.java
+++ b/core/java/android/appwidget/AppWidgetManager.java
@@ -22,7 +22,6 @@
 import android.os.RemoteException;
 import android.os.ServiceManager;
 import android.util.DisplayMetrics;
-import android.util.Log;
 import android.util.TypedValue;
 import android.widget.RemoteViews;
 
@@ -149,7 +148,7 @@
      *     instances as possible.</td>
      *  </tr>
      * </table>
-     * 
+     *
      * @see AppWidgetProvider#onUpdate AppWidgetProvider.onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds)
      */
     public static final String ACTION_APPWIDGET_UPDATE = "android.appwidget.action.APPWIDGET_UPDATE";
@@ -163,7 +162,7 @@
 
     /**
      * Sent when an instance of an AppWidget is removed from the last host.
-     * 
+     *
      * @see AppWidgetProvider#onEnabled AppWidgetProvider.onEnabled(Context context)
      */
     public static final String ACTION_APPWIDGET_DISABLED = "android.appwidget.action.APPWIDGET_DISABLED";
@@ -172,7 +171,7 @@
      * Sent when an instance of an AppWidget is added to a host for the first time.
      * This broadcast is sent at boot time if there is a AppWidgetHost installed with
      * an instance for this provider.
-     * 
+     *
      * @see AppWidgetProvider#onEnabled AppWidgetProvider.onEnabled(Context context)
      */
     public static final String ACTION_APPWIDGET_ENABLED = "android.appwidget.action.APPWIDGET_ENABLED";
@@ -183,20 +182,21 @@
      * @see AppWidgetProviderInfo
      */
     public static final String META_DATA_APPWIDGET_PROVIDER = "android.appwidget.provider";
-    
+
     /**
      * Field for the manifest meta-data tag used to indicate any previous name for the
      * app widget receiver.
      *
      * @see AppWidgetProviderInfo
-     * 
+     *
      * @hide Pending API approval
      */
     public static final String META_DATA_APPWIDGET_OLD_NAME = "android.appwidget.oldName";
 
-    static WeakHashMap<Context, WeakReference<AppWidgetManager>> sManagerCache = new WeakHashMap();
+    static WeakHashMap<Context, WeakReference<AppWidgetManager>> sManagerCache =
+        new WeakHashMap<Context, WeakReference<AppWidgetManager>>();
     static IAppWidgetService sService;
-    
+
     Context mContext;
 
     private DisplayMetrics mDisplayMetrics;
@@ -219,7 +219,7 @@
             }
             if (result == null) {
                 result = new AppWidgetManager(context);
-                sManagerCache.put(context, new WeakReference(result));
+                sManagerCache.put(context, new WeakReference<AppWidgetManager>(result));
             }
             return result;
         }
@@ -292,7 +292,15 @@
      */
     public List<AppWidgetProviderInfo> getInstalledProviders() {
         try {
-            return sService.getInstalledProviders();
+            List<AppWidgetProviderInfo> providers = sService.getInstalledProviders();
+            for (AppWidgetProviderInfo info : providers) {
+                // Converting complex to dp.
+                info.minWidth =
+                        TypedValue.complexToDimensionPixelSize(info.minWidth, mDisplayMetrics);
+                info.minHeight =
+                        TypedValue.complexToDimensionPixelSize(info.minHeight, mDisplayMetrics);
+            }
+            return providers;
         }
         catch (RemoteException e) {
             throw new RuntimeException("system server dead?", e);
@@ -310,7 +318,7 @@
             AppWidgetProviderInfo info = sService.getAppWidgetInfo(appWidgetId);
             if (info != null) {
                 // Converting complex to dp.
-                info.minWidth = 
+                info.minWidth =
                         TypedValue.complexToDimensionPixelSize(info.minWidth, mDisplayMetrics);
                 info.minHeight =
                         TypedValue.complexToDimensionPixelSize(info.minHeight, mDisplayMetrics);
@@ -344,7 +352,7 @@
     /**
      * Get the list of appWidgetIds that have been bound to the given AppWidget
      * provider.
-     * 
+     *
      * @param provider The {@link android.content.BroadcastReceiver} that is the
      *            AppWidget provider to find appWidgetIds for.
      */
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index 86ddee4..b49d801 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -1561,6 +1561,15 @@
     public static final String UI_MODE_SERVICE = "uimode";
 
     /**
+     * Use with {@link #getSystemService} to retrieve a
+     * {@link android.net.DownloadManager} for requesting HTTP downloads.
+     *
+     * @see #getSystemService
+     * @hide (TODO) for now
+     */
+    public static final String DOWNLOAD_SERVICE = "download";
+
+    /**
      * Determine whether the given permission is allowed for a particular
      * process and user ID running in the system.
      *
diff --git a/core/java/android/content/CursorLoader.java b/core/java/android/content/CursorLoader.java
index e230394..01bf968 100644
--- a/core/java/android/content/CursorLoader.java
+++ b/core/java/android/content/CursorLoader.java
@@ -50,7 +50,9 @@
     public void deliverResult(Cursor cursor) {
         if (mStopped) {
             // An async query came in while the loader is stopped
-            cursor.close();
+            if (cursor != null) {
+                cursor.close();
+            }
             return;
         }
         mCursor = cursor;
diff --git a/core/java/android/content/pm/IPackageManager.aidl b/core/java/android/content/pm/IPackageManager.aidl
index 9939478..160a481 100644
--- a/core/java/android/content/pm/IPackageManager.aidl
+++ b/core/java/android/content/pm/IPackageManager.aidl
@@ -319,4 +319,6 @@
 
     boolean setInstallLocation(int loc);
     int getInstallLocation();
+
+    void setPackageObbPath(String packageName, String path);
 }
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index 1a5b419..15a446b 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -2193,4 +2193,17 @@
      */
     public abstract void movePackage(
             String packageName, IPackageMoveObserver observer, int flags);
+
+    /**
+     * Sets the Opaque Binary Blob (OBB) file location.
+     * <p>
+     * NOTE: The existence or format of this file is not currently checked, but
+     * it may be in the future.
+     * 
+     * @param packageName Name of the package with which to associate the .obb
+     *            file
+     * @param path Path on the filesystem to the .obb file
+     * @hide
+     */
+    public abstract void setPackageObbPath(String packageName, String path);
 }
diff --git a/core/java/android/database/sqlite/SQLiteDatabase.java b/core/java/android/database/sqlite/SQLiteDatabase.java
index 3c5a029..c0226f8 100644
--- a/core/java/android/database/sqlite/SQLiteDatabase.java
+++ b/core/java/android/database/sqlite/SQLiteDatabase.java
@@ -613,7 +613,10 @@
 
             // This thread didn't already have the lock, so begin a database
             // transaction now.
-            if (exclusive) {
+            // STOPSHIP - uncomment the following 1 line
+            // if (exclusive) {
+            // STOPSHIP - remove the following 1 line
+            if (exclusive && mConnectionPool == null) {
                 execSQL("BEGIN EXCLUSIVE;");
             } else {
                 execSQL("BEGIN IMMEDIATE;");
@@ -946,7 +949,10 @@
             sBlockSize = new StatFs("/data").getBlockSize();
         }
         sqliteDatabase.setPageSize(sBlockSize);
-        sqliteDatabase.setJournalMode(path, "TRUNCATE");
+        //STOPSHIP - uncomment the following line
+        //sqliteDatabase.setJournalMode(path, "TRUNCATE");
+        // STOPSHIP remove the following lines
+        sqliteDatabase.enableWriteAheadLogging();
 
         // add this database to the list of databases opened in this process
         ActiveDatabases.addActiveDatabase(sqliteDatabase);
@@ -1041,6 +1047,7 @@
             closeClosable();
             // finalize ALL statements queued up so far
             closePendingStatements();
+            releaseCustomFunctions();
             // close this database instance - regardless of its reference count value
             dbclose();
             if (mConnectionPool != null) {
@@ -1077,6 +1084,54 @@
     private native void dbclose();
 
     /**
+     * A callback interface for a custom sqlite3 function.
+     * This can be used to create a function that can be called from
+     * sqlite3 database triggers.
+     * @hide
+     */
+    public interface CustomFunction {
+        public void callback(String[] args);
+    }
+
+    /**
+     * Registers a CustomFunction callback as a function that can be called from
+     * sqlite3 database triggers.
+     * @param name the name of the sqlite3 function
+     * @param numArgs the number of arguments for the function
+     * @param function callback to call when the function is executed
+     * @hide
+     */
+    public void addCustomFunction(String name, int numArgs, CustomFunction function) {
+        verifyDbIsOpen();
+        synchronized (mCustomFunctions) {
+            int ref = native_addCustomFunction(name, numArgs, function);
+            if (ref != 0) {
+                // save a reference to the function for cleanup later
+                mCustomFunctions.add(new Integer(ref));
+            } else {
+                throw new SQLiteException("failed to add custom function " + name);
+            }
+        }
+    }
+
+    private void releaseCustomFunctions() {
+        synchronized (mCustomFunctions) {
+            for (int i = 0; i < mCustomFunctions.size(); i++) {
+                Integer function = mCustomFunctions.get(i);
+                native_releaseCustomFunction(function.intValue());
+            }
+            mCustomFunctions.clear();
+        }
+    }
+
+    // list of CustomFunction references so we can clean up when the database closes
+    private final ArrayList<Integer> mCustomFunctions =
+            new ArrayList<Integer>();
+
+    private native int native_addCustomFunction(String name, int numArgs, CustomFunction function);
+    private native void native_releaseCustomFunction(int function);
+
+    /**
      * Gets the database version.
      *
      * @return the database version
@@ -1953,12 +2008,17 @@
     }
 
     @Override
-    protected void finalize() {
-        if (isOpen()) {
-            Log.e(TAG, "close() was never explicitly called on database '" +
-                    mPath + "' ", mStackTrace);
-            closeClosable();
-            onAllReferencesReleased();
+    protected void finalize() throws Throwable {
+        try {
+            if (isOpen()) {
+                Log.e(TAG, "close() was never explicitly called on database '" +
+                        mPath + "' ", mStackTrace);
+                closeClosable();
+                onAllReferencesReleased();
+                releaseCustomFunctions();
+            }
+        } finally {
+            super.finalize();
         }
     }
 
diff --git a/core/java/android/database/sqlite/SQLiteProgram.java b/core/java/android/database/sqlite/SQLiteProgram.java
index fb3f428..017b65f 100644
--- a/core/java/android/database/sqlite/SQLiteProgram.java
+++ b/core/java/android/database/sqlite/SQLiteProgram.java
@@ -17,6 +17,9 @@
 package android.database.sqlite;
 
 import android.util.Log;
+import android.util.Pair;
+
+import java.util.ArrayList;
 
 /**
  * A base class for compiled SQLite programs.
@@ -29,7 +32,7 @@
     private static final String TAG = "SQLiteProgram";
 
     /** the type of sql statement being processed by this object */
-    private static final int SELECT_STMT = 1;
+    /* package */ static final int SELECT_STMT = 1;
     private static final int UPDATE_STMT = 2;
     private static final int OTHER_STMT = 3;
 
@@ -63,24 +66,46 @@
     @Deprecated
     protected int nStatement = 0;
 
+    /**
+     * In the case of {@link SQLiteStatement}, this member stores the bindargs passed
+     * to the following methods, instead of actually doing the binding.
+     * <ul>
+     *   <li>{@link #bindBlob(int, byte[])}</li>
+     *   <li>{@link #bindDouble(int, double)}</li>
+     *   <li>{@link #bindLong(int, long)}</li>
+     *   <li>{@link #bindNull(int)}</li>
+     *   <li>{@link #bindString(int, String)}</li>
+     * </ul>
+     * <p>
+     * Each entry in the array is a Pair of
+     * <ol>
+     *   <li>bind arg position number</li>
+     *   <li>the value to be bound to the bindarg</li>
+     * </ol>
+     * <p>
+     * It is lazily initialized in the above bind methods
+     * and it is cleared in {@link #clearBindings()} method.
+     * <p>
+     * It is protected (in multi-threaded environment) by {@link SQLiteProgram}.this
+     */
+    private ArrayList<Pair<Integer, Object>> bindArgs = null;
+
     /* package */ SQLiteProgram(SQLiteDatabase db, String sql) {
         this(db, sql, true);
     }
 
     /* package */ SQLiteProgram(SQLiteDatabase db, String sql, boolean compileFlag) {
         mSql = sql.trim();
-        attachObjectToDatabase(db);
+        db.acquireReference();
+        db.addSQLiteClosable(this);
+        mDatabase = db;
+        nHandle = db.mNativeHandle;
         if (compileFlag) {
             compileSql();
         }
     }
 
     private void compileSql() {
-        if (nStatement > 0) {
-            // already compiled.
-            return;
-        }
-
         // only cache CRUD statements
         if (getSqlStatementType(mSql) == OTHER_STMT) {
             mCompiledSql = new SQLiteCompiledSql(mDatabase, mSql);
@@ -125,7 +150,7 @@
         nStatement = mCompiledSql.nStatement;
     }
 
-    private int getSqlStatementType(String sql) {
+    /* package */ int getSqlStatementType(String sql) {
         if (mSql.length() < 6) {
             return OTHER_STMT;
         }
@@ -141,42 +166,11 @@
         return OTHER_STMT;
     }
 
-    private synchronized void attachObjectToDatabase(SQLiteDatabase db) {
-        db.acquireReference();
-        db.addSQLiteClosable(this);
-        mDatabase = db;
-        nHandle = db.mNativeHandle;
-    }
-
-    private synchronized void detachObjectFromDatabase() {
-        mDatabase.removeSQLiteClosable(this);
-        mDatabase.releaseReference();
-    }
-
-    /* package */ synchronized void verifyDbAndCompileSql() {
-        mDatabase.verifyDbIsOpen();
-        // use pooled database connection handles for SELECT SQL statements
-        SQLiteDatabase db = (getSqlStatementType(mSql) != SELECT_STMT) ? mDatabase
-                : mDatabase.getDbConnection(mSql);
-        if (!db.equals(mDatabase)) {
-            // the database connection handle to be used is not the same as the one supplied
-            // in the constructor. do some housekeeping.
-            detachObjectFromDatabase();
-            attachObjectToDatabase(db);
-        }
-        // compile the sql statement
-        mDatabase.lock();
-        try {
-            compileSql();
-        } finally {
-            mDatabase.unlock();
-        }
-    }
-
     @Override
     protected void onAllReferencesReleased() {
         releaseCompiledSqlIfNotInCache();
-        detachObjectFromDatabase();
+        mDatabase.removeSQLiteClosable(this);
+        mDatabase.releaseReference();
     }
 
     @Override
@@ -247,11 +241,17 @@
      * @param index The 1-based index to the parameter to bind null to
      */
     public void bindNull(int index) {
+        mDatabase.verifyDbIsOpen();
         synchronized (this) {
-            verifyDbAndCompileSql();
             acquireReference();
             try {
-                native_bind_null(index);
+                if (this.nStatement == 0) {
+                    // since the SQL statement is not compiled, don't do the binding yet.
+                    // can be done before executing the SQL statement
+                    addToBindArgs(index, null);
+                } else {
+                    native_bind_null(index);
+                }
             } finally {
                 releaseReference();
             }
@@ -266,11 +266,15 @@
      * @param value The value to bind
      */
     public void bindLong(int index, long value) {
+        mDatabase.verifyDbIsOpen();
         synchronized (this) {
-            verifyDbAndCompileSql();
             acquireReference();
             try {
-                native_bind_long(index, value);
+                if (this.nStatement == 0) {
+                    addToBindArgs(index, value);
+                } else {
+                    native_bind_long(index, value);
+                }
             } finally {
                 releaseReference();
             }
@@ -285,11 +289,15 @@
      * @param value The value to bind
      */
     public void bindDouble(int index, double value) {
+        mDatabase.verifyDbIsOpen();
         synchronized (this) {
-            verifyDbAndCompileSql();
             acquireReference();
             try {
-                native_bind_double(index, value);
+                if (this.nStatement == 0) {
+                    addToBindArgs(index, value);
+                } else {
+                    native_bind_double(index, value);
+                }
             } finally {
                 releaseReference();
             }
@@ -307,11 +315,15 @@
         if (value == null) {
             throw new IllegalArgumentException("the bind value at index " + index + " is null");
         }
+        mDatabase.verifyDbIsOpen();
         synchronized (this) {
-            verifyDbAndCompileSql();
             acquireReference();
             try {
-                native_bind_string(index, value);
+                if (this.nStatement == 0) {
+                    addToBindArgs(index, value);
+                } else {
+                    native_bind_string(index, value);
+                }
             } finally {
                 releaseReference();
             }
@@ -329,11 +341,15 @@
         if (value == null) {
             throw new IllegalArgumentException("the bind value at index " + index + " is null");
         }
+        mDatabase.verifyDbIsOpen();
         synchronized (this) {
-            verifyDbAndCompileSql();
             acquireReference();
             try {
-                native_bind_blob(index, value);
+                if (this.nStatement == 0) {
+                    addToBindArgs(index, value);
+                } else {
+                    native_bind_blob(index, value);
+                }
             } finally {
                 releaseReference();
             }
@@ -345,6 +361,7 @@
      */
     public void clearBindings() {
         synchronized (this) {
+            bindArgs = null;
             if (this.nStatement == 0) {
                 return;
             }
@@ -363,6 +380,7 @@
      */
     public void close() {
         synchronized (this) {
+            bindArgs = null;
             if (nHandle == 0 || !mDatabase.isOpen()) {
                 return;
             }
@@ -370,6 +388,34 @@
         }
     }
 
+    private synchronized void addToBindArgs(int index, Object value) {
+        if (bindArgs == null) {
+            bindArgs = new ArrayList<Pair<Integer, Object>>();
+        }
+        bindArgs.add(new Pair<Integer, Object>(index, value));
+    }
+
+    /* package */ synchronized void compileAndbindAllArgs() {
+        assert nStatement == 0;
+        compileSql();
+        if (bindArgs == null) {
+            return;
+        }
+        for (Pair<Integer, Object> p : bindArgs) {
+            if (p.second == null) {
+                native_bind_null(p.first);
+            } else if (p.second instanceof Long) {
+                native_bind_long(p.first, (Long)p.second);
+            } else if (p.second instanceof Double) {
+                native_bind_double(p.first, (Double)p.second);
+            } else if (p.second instanceof byte[]) {
+                native_bind_blob(p.first, (byte[])p.second);
+            }  else {
+                native_bind_string(p.first, (String)p.second);
+            }
+        }
+    }
+
     /**
      * @deprecated This method is deprecated and must not be used.
      * Compiles SQL into a SQLite program.
diff --git a/core/java/android/database/sqlite/SQLiteStatement.java b/core/java/android/database/sqlite/SQLiteStatement.java
index 9664593..b902803 100644
--- a/core/java/android/database/sqlite/SQLiteStatement.java
+++ b/core/java/android/database/sqlite/SQLiteStatement.java
@@ -35,6 +35,8 @@
     private static final boolean READ = true;
     private static final boolean WRITE = false;
 
+    private SQLiteDatabase mOrigDb;
+
     /**
      * Don't use SQLiteStatement constructor directly, please use
      * {@link SQLiteDatabase#compileStatement(String)}
@@ -53,12 +55,14 @@
      *         some reason
      */
     public void execute() {
-        long timeStart = acquireAndLock(WRITE);
-        try {
-            native_execute();
-            mDatabase.logTimeStat(mSql, timeStart);
-        } finally {
-            releaseAndUnlock();
+        synchronized(this) {
+            long timeStart = acquireAndLock(WRITE);
+            try {
+                native_execute();
+                mDatabase.logTimeStat(mSql, timeStart);
+            } finally {
+                releaseAndUnlock();
+            }
         }
     }
 
@@ -72,13 +76,15 @@
      *         some reason
      */
     public long executeInsert() {
-        long timeStart = acquireAndLock(WRITE);
-        try {
-            native_execute();
-            mDatabase.logTimeStat(mSql, timeStart);
-            return (mDatabase.lastChangeCount() > 0) ? mDatabase.lastInsertRow() : -1;
-        } finally {
-            releaseAndUnlock();
+        synchronized(this) {
+            long timeStart = acquireAndLock(WRITE);
+            try {
+                native_execute();
+                mDatabase.logTimeStat(mSql, timeStart);
+                return (mDatabase.lastChangeCount() > 0) ? mDatabase.lastInsertRow() : -1;
+            } finally {
+                releaseAndUnlock();
+            }
         }
     }
 
@@ -91,13 +97,15 @@
      * @throws android.database.sqlite.SQLiteDoneException if the query returns zero rows
      */
     public long simpleQueryForLong() {
-        long timeStart = acquireAndLock(READ);
-        try {
-            long retValue = native_1x1_long();
-            mDatabase.logTimeStat(mSql, timeStart);
-            return retValue;
-        } finally {
-            releaseAndUnlock();
+        synchronized(this) {
+            long timeStart = acquireAndLock(READ);
+            try {
+                long retValue = native_1x1_long();
+                mDatabase.logTimeStat(mSql, timeStart);
+                return retValue;
+            } finally {
+                releaseAndUnlock();
+            }
         }
     }
 
@@ -110,13 +118,15 @@
      * @throws android.database.sqlite.SQLiteDoneException if the query returns zero rows
      */
     public String simpleQueryForString() {
-        long timeStart = acquireAndLock(READ);
-        try {
-            String retValue = native_1x1_string();
-            mDatabase.logTimeStat(mSql, timeStart);
-            return retValue;
-        } finally {
-            releaseAndUnlock();
+        synchronized(this) {
+            long timeStart = acquireAndLock(READ);
+            try {
+                String retValue = native_1x1_string();
+                mDatabase.logTimeStat(mSql, timeStart);
+                return retValue;
+            } finally {
+                releaseAndUnlock();
+            }
         }
     }
 
@@ -125,6 +135,7 @@
      * this method does the following:
      * <ul>
      *   <li>make sure the database is open</li>
+     *   <li>get a database connection from the connection pool,if possible</li>
      *   <li>notifies {@link BlockGuard} of read/write</li>
      *   <li>get lock on the database</li>
      *   <li>acquire reference on this object</li>
@@ -135,7 +146,14 @@
      * methods in this class.
      */
     private long acquireAndLock(boolean rwFlag) {
-        verifyDbAndCompileSql();
+        // use pooled database connection handles for SELECT SQL statements
+        mDatabase.verifyDbIsOpen();
+        SQLiteDatabase db = (getSqlStatementType(mSql) != SELECT_STMT) ? mDatabase
+                : mDatabase.getDbConnection(mSql);
+        // use the database connection obtained above
+        mOrigDb = mDatabase;
+        mDatabase = db;
+        nHandle = mDatabase.mNativeHandle;
         if (rwFlag == WRITE) {
             BlockGuard.getThreadPolicy().onWriteToDisk();
         } else {
@@ -145,6 +163,7 @@
         mDatabase.lock();
         acquireReference();
         mDatabase.closePendingStatements();
+        compileAndbindAllArgs();
         return startTime;
     }
 
@@ -158,6 +177,9 @@
         // release the compiled sql statement so that the caller's SQLiteStatement no longer
         // has a hard reference to a database object that may get deallocated at any point.
         releaseCompiledSqlIfNotInCache();
+        // restore the database connection handle to the original value
+        mDatabase = mOrigDb;
+        nHandle = mDatabase.mNativeHandle;
     }
 
     private final native void native_execute();
diff --git a/core/java/android/hardware/SensorEvent.java b/core/java/android/hardware/SensorEvent.java
index 70519ff..aaf3898 100644
--- a/core/java/android/hardware/SensorEvent.java
+++ b/core/java/android/hardware/SensorEvent.java
@@ -84,14 +84,14 @@
      * sensor itself (<b>Fs</b>) using the relation:
      * </p>
      * 
-     * <b><center>Ad = - ·Fs / mass</center></b>
+     * <b><center>Ad = - &#8721;Fs / mass</center></b>
      * 
      * <p>
      * In particular, the force of gravity is always influencing the measured
      * acceleration:
      * </p>
      * 
-     * <b><center>Ad = -g - ·F / mass</center></b>
+     * <b><center>Ad = -g - &#8721;F / mass</center></b>
      * 
      * <p>
      * For this reason, when the device is sitting on a table (and obviously not
diff --git a/core/java/android/net/DownloadManager.java b/core/java/android/net/DownloadManager.java
new file mode 100644
index 0000000..00b6864
--- /dev/null
+++ b/core/java/android/net/DownloadManager.java
@@ -0,0 +1,729 @@
+/*
+ * 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.net;
+
+import android.content.ContentResolver;
+import android.content.ContentValues;
+import android.database.Cursor;
+import android.database.CursorWrapper;
+import android.os.ParcelFileDescriptor;
+import android.provider.Downloads;
+import android.util.Log;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * The download manager is a system service that handles long-running HTTP downloads. Clients may
+ * request that a URI be downloaded to a particular destination file. The download manager will
+ * conduct the download in the background, taking care of HTTP interactions and retrying downloads
+ * after failures or across connectivity changes and system reboots.
+ *
+ * Instances of this class should be obtained through
+ * {@link android.content.Context#getSystemService(String)} by passing
+ * {@link android.content.Context#DOWNLOAD_SERVICE}.
+ *
+ * @hide
+ */
+public class DownloadManager {
+    /**
+     * An identifier for a particular download, unique across the system.  Clients use this ID to
+     * make subsequent calls related to the download.
+     */
+    public final static String COLUMN_ID = "id";
+
+    /**
+     * The client-supplied title for this download.  This will be displayed in system notifications,
+     * if enabled.
+     */
+    public final static String COLUMN_TITLE = "title";
+
+    /**
+     * The client-supplied description of this download.  This will be displayed in system
+     * notifications, if enabled.
+     */
+    public final static String COLUMN_DESCRIPTION = "description";
+
+    /**
+     * URI to be downloaded.
+     */
+    public final static String COLUMN_URI = "uri";
+
+    /**
+     * Internet Media Type of the downloaded file.  This will be filled in based on the server's
+     * response once the download has started.
+     *
+     * @see <a href="http://www.ietf.org/rfc/rfc1590.txt">RFC 1590, defining Media Types</a>
+     */
+    public final static String COLUMN_MEDIA_TYPE = "media_type";
+
+    /**
+     * Total size of the download in bytes.  This will be filled in once the download starts.
+     */
+    public final static String COLUMN_TOTAL_SIZE_BYTES = "total_size";
+
+    /**
+     * Uri where downloaded file will be stored.  If a destination is supplied by client, that URI
+     * will be used here.  Otherwise, the value will be filled in with a generated URI once the
+     * download has started.
+     */
+    public final static String COLUMN_LOCAL_URI = "local_uri";
+
+    /**
+     * Current status of the download, as one of the STATUS_* constants.
+     */
+    public final static String COLUMN_STATUS = "status";
+
+    /**
+     * Indicates the type of error that occurred, when {@link #COLUMN_STATUS} is
+     * {@link #STATUS_FAILED}.  If an HTTP error occurred, this will hold the HTTP status code as
+     * defined in RFC 2616.  Otherwise, it will hold one of the ERROR_* constants.
+     *
+     * If {@link #COLUMN_STATUS} is not {@link #STATUS_FAILED}, this column's value is undefined.
+     *
+     * @see <a href="http://www.w3.org/Protocols/rfc2616/rfc2616-sec6.html#sec6.1.1">RFC 2616
+     * status codes</a>
+     */
+    public final static String COLUMN_ERROR_CODE = "error_code";
+
+    /**
+     * Number of bytes download so far.
+     */
+    public final static String COLUMN_BYTES_DOWNLOADED_SO_FAR = "bytes_so_far";
+
+    /**
+     * Timestamp when the download was last modified, in {@link System#currentTimeMillis
+     * System.currentTimeMillis()} (wall clock time in UTC).
+     */
+    public final static String COLUMN_LAST_MODIFIED_TIMESTAMP = "last_modified_timestamp";
+
+
+    /**
+     * Value of {@link #COLUMN_STATUS} when the download is waiting to start.
+     */
+    public final static int STATUS_PENDING = 1 << 0;
+
+    /**
+     * Value of {@link #COLUMN_STATUS} when the download is currently running.
+     */
+    public final static int STATUS_RUNNING = 1 << 1;
+
+    /**
+     * Value of {@link #COLUMN_STATUS} when the download is waiting to retry or resume.
+     */
+    public final static int STATUS_PAUSED = 1 << 2;
+
+    /**
+     * Value of {@link #COLUMN_STATUS} when the download has successfully completed.
+     */
+    public final static int STATUS_SUCCESSFUL = 1 << 3;
+
+    /**
+     * Value of {@link #COLUMN_STATUS} when the download has failed (and will not be retried).
+     */
+    public final static int STATUS_FAILED = 1 << 4;
+
+
+    /**
+     * Value of COLUMN_ERROR_CODE when the download has completed with an error that doesn't fit
+     * under any other error code.
+     */
+    public final static int ERROR_UNKNOWN = 1000;
+
+    /**
+     * Value of {@link #COLUMN_ERROR_CODE} when a storage issue arises which doesn't fit under any
+     * other error code. Use the more specific {@link #ERROR_INSUFFICIENT_SPACE} and
+     * {@link #ERROR_DEVICE_NOT_FOUND} when appropriate.
+     */
+    public final static int ERROR_FILE_ERROR = 1001;
+
+    /**
+     * Value of {@link #COLUMN_ERROR_CODE} when an HTTP code was received that download manager
+     * can't handle.
+     */
+    public final static int ERROR_UNHANDLED_HTTP_CODE = 1002;
+
+    /**
+     * Value of {@link #COLUMN_ERROR_CODE} when an error receiving or processing data occurred at
+     * the HTTP level.
+     */
+    public final static int ERROR_HTTP_DATA_ERROR = 1004;
+
+    /**
+     * Value of {@link #COLUMN_ERROR_CODE} when there were too many redirects.
+     */
+    public final static int ERROR_TOO_MANY_REDIRECTS = 1005;
+
+    /**
+     * Value of {@link #COLUMN_ERROR_CODE} when there was insufficient storage space. Typically,
+     * this is because the SD card is full.
+     */
+    public final static int ERROR_INSUFFICIENT_SPACE = 1006;
+
+    /**
+     * Value of {@link #COLUMN_ERROR_CODE} when no external storage device was found. Typically,
+     * this is because the SD card is not mounted.
+     */
+    public final static int ERROR_DEVICE_NOT_FOUND = 1007;
+
+
+    // this array must contain all public columns
+    private static final String[] COLUMNS = new String[] {
+        COLUMN_ID,
+        COLUMN_TITLE,
+        COLUMN_DESCRIPTION,
+        COLUMN_URI,
+        COLUMN_MEDIA_TYPE,
+        COLUMN_TOTAL_SIZE_BYTES,
+        COLUMN_LOCAL_URI,
+        COLUMN_STATUS,
+        COLUMN_ERROR_CODE,
+        COLUMN_BYTES_DOWNLOADED_SO_FAR,
+        COLUMN_LAST_MODIFIED_TIMESTAMP
+    };
+
+    // columns to request from DownloadProvider
+    private static final String[] UNDERLYING_COLUMNS = new String[] {
+        Downloads.Impl._ID,
+        Downloads.COLUMN_TITLE,
+        Downloads.COLUMN_DESCRIPTION,
+        Downloads.COLUMN_URI,
+        Downloads.COLUMN_MIME_TYPE,
+        Downloads.COLUMN_TOTAL_BYTES,
+        Downloads._DATA,
+        Downloads.COLUMN_STATUS,
+        Downloads.COLUMN_CURRENT_BYTES,
+        Downloads.COLUMN_LAST_MODIFICATION,
+    };
+
+    private static final Set<String> LONG_COLUMNS = new HashSet<String>(
+            Arrays.asList(COLUMN_ID, COLUMN_TOTAL_SIZE_BYTES, COLUMN_STATUS, COLUMN_ERROR_CODE,
+                          COLUMN_BYTES_DOWNLOADED_SO_FAR, COLUMN_LAST_MODIFIED_TIMESTAMP));
+
+    /**
+     * This class contains all the information necessary to request a new download.  The URI is the
+     * only required parameter.
+     */
+    public static class Request {
+        /**
+         * Bit flag for setShowNotification indicated a notification should be created while the
+         * download is running.
+         */
+        private static final int NOTIFICATION_WHEN_RUNNING = 1;
+
+        Uri mUri;
+        Uri mDestinationUri;
+        Map<String, String> mRequestHeaders = new HashMap<String, String>();
+        String mTitle;
+        String mDescription;
+        int mNotificationFlags;
+
+        private String mMediaType;
+
+        /**
+         * @param uri the HTTP URI to download.
+         */
+        public Request(Uri uri) {
+            if (uri == null) {
+                throw new NullPointerException();
+            }
+            String scheme = uri.getScheme();
+            if (scheme == null || !scheme.equals("http")) {
+                throw new IllegalArgumentException("Can only download HTTP URIs: " + uri);
+            }
+            mUri = uri;
+        }
+
+        /**
+         * Set the local destination for the downloaded data. Must be a file URI to a path on
+         * external storage, and the calling application must have the WRITE_EXTERNAL_STORAGE
+         * permission.
+         *
+         *  By default, downloads are saved to a generated file in the download cache and may be
+         * deleted by the download manager at any time.
+         *
+         * @return this object
+         */
+        public Request setDestinationUri(Uri uri) {
+            mDestinationUri = uri;
+            return this;
+        }
+
+        /**
+         * Set an HTTP header to be included with the download request.
+         * @param header HTTP header name
+         * @param value header value
+         * @return this object
+         */
+        public Request setRequestHeader(String header, String value) {
+            mRequestHeaders.put(header, value);
+            return this;
+        }
+
+        /**
+         * Set the title of this download, to be displayed in notifications (if enabled)
+         * @return this object
+         */
+        public Request setTitle(String title) {
+            mTitle = title;
+            return this;
+        }
+
+        /**
+         * Set a description of this download, to be displayed in notifications (if enabled)
+         * @return this object
+         */
+        public Request setDescription(String description) {
+            mDescription = description;
+            return this;
+        }
+
+        /**
+         * Set the Internet Media Type of this download.  This will override the media type declared
+         * in the server's response.
+         * @see <a href="http://www.ietf.org/rfc/rfc1590.txt">RFC 1590, defining Media Types</a>
+         * @return this object
+         */
+        public Request setMediaType(String mediaType) {
+            mMediaType = mediaType;
+            return this;
+        }
+
+        /**
+         * Control system notifications posted by the download manager for this download.  If
+         * enabled, the download manager posts notifications about downloads through the system
+         * {@link android.app.NotificationManager}.
+         *
+         * @param flags any combination of the NOTIFICATION_* bit flags
+         * @return this object
+         */
+        public Request setShowNotification(int flags) {
+            mNotificationFlags = flags;
+            return this;
+        }
+
+        public Request setAllowedNetworkTypes(int flags) {
+            // TODO allowed networks support
+            throw new UnsupportedOperationException();
+        }
+
+        public Request setAllowedOverRoaming(boolean allowed) {
+            // TODO roaming support
+            throw new UnsupportedOperationException();
+        }
+
+        /**
+         * @return ContentValues to be passed to DownloadProvider.insert()
+         */
+        ContentValues toContentValues() {
+            ContentValues values = new ContentValues();
+            assert mUri != null;
+            values.put(Downloads.COLUMN_URI, mUri.toString());
+
+            if (mDestinationUri != null) {
+                values.put(Downloads.COLUMN_DESTINATION, Downloads.Impl.DESTINATION_FILE_URI);
+                values.put(Downloads.COLUMN_FILE_NAME_HINT, mDestinationUri.toString());
+            } else {
+                values.put(Downloads.COLUMN_DESTINATION,
+                           Downloads.DESTINATION_CACHE_PARTITION_PURGEABLE);
+            }
+
+            if (!mRequestHeaders.isEmpty()) {
+                encodeHttpHeaders(values);
+            }
+
+            putIfNonNull(values, Downloads.COLUMN_TITLE, mTitle);
+            putIfNonNull(values, Downloads.COLUMN_DESCRIPTION, mDescription);
+            putIfNonNull(values, Downloads.COLUMN_MIME_TYPE, mMediaType);
+
+            int visibility = Downloads.VISIBILITY_HIDDEN;
+            if ((mNotificationFlags & NOTIFICATION_WHEN_RUNNING) != 0) {
+                visibility = Downloads.VISIBILITY_VISIBLE;
+            }
+            values.put(Downloads.COLUMN_VISIBILITY, visibility);
+
+            return values;
+        }
+
+        private void encodeHttpHeaders(ContentValues values) {
+            int index = 0;
+            for (Map.Entry<String, String> entry : mRequestHeaders.entrySet()) {
+                String headerString = entry.getKey() + ": " + entry.getValue();
+                values.put(Downloads.Impl.RequestHeaders.INSERT_KEY_PREFIX + index, headerString);
+                index++;
+            }
+        }
+
+        private void putIfNonNull(ContentValues contentValues, String key, String value) {
+            if (value != null) {
+                contentValues.put(key, value);
+            }
+        }
+    }
+
+    /**
+     * This class may be used to filter download manager queries.
+     */
+    public static class Query {
+        private Long mId;
+        private Integer mStatusFlags = null;
+
+        /**
+         * Include only the download with the given ID.
+         * @return this object
+         */
+        public Query setFilterById(long id) {
+            mId = id;
+            return this;
+        }
+
+        /**
+         * Include only downloads with status matching any the given status flags.
+         * @param flags any combination of the STATUS_* bit flags
+         * @return this object
+         */
+        public Query setFilterByStatus(int flags) {
+            mStatusFlags = flags;
+            return this;
+        }
+
+        /**
+         * Run this query using the given ContentResolver.
+         * @param projection the projection to pass to ContentResolver.query()
+         * @return the Cursor returned by ContentResolver.query()
+         */
+        Cursor runQuery(ContentResolver resolver, String[] projection) {
+            Uri uri = Downloads.CONTENT_URI;
+            String selection = null;
+
+            if (mId != null) {
+                uri = Uri.withAppendedPath(uri, mId.toString());
+            }
+
+            if (mStatusFlags != null) {
+                List<String> parts = new ArrayList<String>();
+                if ((mStatusFlags & STATUS_PENDING) != 0) {
+                    parts.add(statusClause("=", Downloads.STATUS_PENDING));
+                }
+                if ((mStatusFlags & STATUS_RUNNING) != 0) {
+                    parts.add(statusClause("=", Downloads.STATUS_RUNNING));
+                }
+                if ((mStatusFlags & STATUS_PAUSED) != 0) {
+                    parts.add(statusClause("=", Downloads.STATUS_PENDING_PAUSED));
+                    parts.add(statusClause("=", Downloads.STATUS_RUNNING_PAUSED));
+                }
+                if ((mStatusFlags & STATUS_SUCCESSFUL) != 0) {
+                    parts.add(statusClause("=", Downloads.STATUS_SUCCESS));
+                }
+                if ((mStatusFlags & STATUS_FAILED) != 0) {
+                    parts.add("(" + statusClause(">=", 400)
+                              + " AND " + statusClause("<", 600) + ")");
+                }
+                selection = joinStrings(" OR ", parts);
+                Log.w("DownloadManagerPublic", selection);
+            }
+            String orderBy = Downloads.COLUMN_LAST_MODIFICATION + " DESC";
+            return resolver.query(uri, projection, selection, null, orderBy);
+        }
+
+        private String joinStrings(String joiner, Iterable<String> parts) {
+            StringBuilder builder = new StringBuilder();
+            boolean first = true;
+            for (String part : parts) {
+                if (!first) {
+                    builder.append(joiner);
+                }
+                builder.append(part);
+                first = false;
+            }
+            return builder.toString();
+        }
+
+        private String statusClause(String operator, int value) {
+            return Downloads.COLUMN_STATUS + operator + "'" + value + "'";
+        }
+    }
+
+    private ContentResolver mResolver;
+
+    /**
+     * @hide
+     */
+    public DownloadManager(ContentResolver resolver) {
+        mResolver = resolver;
+    }
+
+    /**
+     * Enqueue a new download.  The download will start automatically once the download manager is
+     * ready to execute it and connectivity is available.
+     *
+     * @param request the parameters specifying this download
+     * @return an ID for the download, unique across the system.  This ID is used to make future
+     * calls related to this download.
+     */
+    public long enqueue(Request request) {
+        ContentValues values = request.toContentValues();
+        Uri downloadUri = mResolver.insert(Downloads.CONTENT_URI, values);
+        long id = Long.parseLong(downloadUri.getLastPathSegment());
+        return id;
+    }
+
+    /**
+     * Cancel a download and remove it from the download manager.  The download will be stopped if
+     * it was running, and it will no longer be accessible through the download manager.  If a file
+     * was already downloaded, it will not be deleted.
+     *
+     * @param id the ID of the download
+     */
+    public void remove(long id) {
+        int numDeleted = mResolver.delete(getDownloadUri(id), null, null);
+        if (numDeleted == 0) {
+            throw new IllegalArgumentException("Download " + id + " does not exist");
+        }
+    }
+
+    /**
+     * Query the download manager about downloads that have been requested.
+     * @param query parameters specifying filters for this query
+     * @return a Cursor over the result set of downloads, with columns consisting of all the
+     * COLUMN_* constants.
+     */
+    public Cursor query(Query query) {
+        Cursor underlyingCursor = query.runQuery(mResolver, UNDERLYING_COLUMNS);
+        return new CursorTranslator(underlyingCursor);
+    }
+
+    /**
+     * Open a downloaded file for reading.  The download must have completed.
+     * @param id the ID of the download
+     * @return a read-only {@link ParcelFileDescriptor}
+     * @throws FileNotFoundException if the destination file does not already exist
+     */
+    public ParcelFileDescriptor openDownloadedFile(long id) throws FileNotFoundException {
+        return mResolver.openFileDescriptor(getDownloadUri(id), "r");
+    }
+
+    /**
+     * Get the DownloadProvider URI for the download with the given ID.
+     */
+    private Uri getDownloadUri(long id) {
+        Uri downloadUri = Uri.withAppendedPath(Downloads.CONTENT_URI, Long.toString(id));
+        return downloadUri;
+    }
+
+    /**
+     * This class wraps a cursor returned by DownloadProvider -- the "underlying cursor" -- and
+     * presents a different set of columns, those defined in the DownloadManager.COLUMN_* constants.
+     * Some columns correspond directly to underlying values while others are computed from
+     * underlying data.
+     */
+    private static class CursorTranslator extends CursorWrapper {
+        public CursorTranslator(Cursor cursor) {
+            super(cursor);
+        }
+
+        @Override
+        public int getColumnIndex(String columnName) {
+            return Arrays.asList(COLUMNS).indexOf(columnName);
+        }
+
+        @Override
+        public int getColumnIndexOrThrow(String columnName) throws IllegalArgumentException {
+            int index = getColumnIndex(columnName);
+            if (index == -1) {
+                throw new IllegalArgumentException();
+            }
+            return index;
+        }
+
+        @Override
+        public String getColumnName(int columnIndex) {
+            int numColumns = COLUMNS.length;
+            if (columnIndex < 0 || columnIndex >= numColumns) {
+                throw new IllegalArgumentException("Invalid column index " + columnIndex + ", "
+                                                   + numColumns + " columns exist");
+            }
+            return COLUMNS[columnIndex];
+        }
+
+        @Override
+        public String[] getColumnNames() {
+            String[] returnColumns = new String[COLUMNS.length];
+            System.arraycopy(COLUMNS, 0, returnColumns, 0, COLUMNS.length);
+            return returnColumns;
+        }
+
+        @Override
+        public int getColumnCount() {
+            return COLUMNS.length;
+        }
+
+        @Override
+        public byte[] getBlob(int columnIndex) {
+            throw new UnsupportedOperationException();
+        }
+
+        @Override
+        public double getDouble(int columnIndex) {
+            return getLong(columnIndex);
+        }
+
+        private boolean isLongColumn(String column) {
+            return LONG_COLUMNS.contains(column);
+        }
+
+        @Override
+        public float getFloat(int columnIndex) {
+            return (float) getDouble(columnIndex);
+        }
+
+        @Override
+        public int getInt(int columnIndex) {
+            return (int) getLong(columnIndex);
+        }
+
+        @Override
+        public long getLong(int columnIndex) {
+            return translateLong(getColumnName(columnIndex));
+        }
+
+        @Override
+        public short getShort(int columnIndex) {
+            return (short) getLong(columnIndex);
+        }
+
+        @Override
+        public String getString(int columnIndex) {
+            return translateString(getColumnName(columnIndex));
+        }
+
+        private String translateString(String column) {
+            if (isLongColumn(column)) {
+                return Long.toString(translateLong(column));
+            }
+            if (column.equals(COLUMN_TITLE)) {
+                return getUnderlyingString(Downloads.COLUMN_TITLE);
+            }
+            if (column.equals(COLUMN_DESCRIPTION)) {
+                return getUnderlyingString(Downloads.COLUMN_DESCRIPTION);
+            }
+            if (column.equals(COLUMN_URI)) {
+                return getUnderlyingString(Downloads.COLUMN_URI);
+            }
+            if (column.equals(COLUMN_MEDIA_TYPE)) {
+                return getUnderlyingString(Downloads.COLUMN_MIME_TYPE);
+            }
+            assert column.equals(COLUMN_LOCAL_URI);
+            return Uri.fromFile(new File(getUnderlyingString(Downloads._DATA))).toString();
+        }
+
+        private long translateLong(String column) {
+            if (!isLongColumn(column)) {
+                // mimic behavior of underlying cursor -- most likely, throw NumberFormatException
+                return Long.valueOf(translateString(column));
+            }
+
+            if (column.equals(COLUMN_ID)) {
+                return getUnderlyingLong(Downloads.Impl._ID);
+            }
+            if (column.equals(COLUMN_TOTAL_SIZE_BYTES)) {
+                return getUnderlyingLong(Downloads.COLUMN_TOTAL_BYTES);
+            }
+            if (column.equals(COLUMN_STATUS)) {
+                return translateStatus((int) getUnderlyingLong(Downloads.COLUMN_STATUS));
+            }
+            if (column.equals(COLUMN_ERROR_CODE)) {
+                return translateErrorCode((int) getUnderlyingLong(Downloads.COLUMN_STATUS));
+            }
+            if (column.equals(COLUMN_BYTES_DOWNLOADED_SO_FAR)) {
+                return getUnderlyingLong(Downloads.COLUMN_CURRENT_BYTES);
+            }
+            assert column.equals(COLUMN_LAST_MODIFIED_TIMESTAMP);
+            return getUnderlyingLong(Downloads.COLUMN_LAST_MODIFICATION);
+        }
+
+        private long translateErrorCode(int status) {
+            if (translateStatus(status) != STATUS_FAILED) {
+                return 0; // arbitrary value when status is not an error
+            }
+            if ((400 <= status && status < 490) || (500 <= status && status < 600)) {
+                // HTTP status code
+                return status;
+            }
+
+            switch (status) {
+                case Downloads.STATUS_FILE_ERROR:
+                    return ERROR_FILE_ERROR;
+
+                case Downloads.STATUS_UNHANDLED_HTTP_CODE:
+                case Downloads.STATUS_UNHANDLED_REDIRECT:
+                    return ERROR_UNHANDLED_HTTP_CODE;
+
+                case Downloads.STATUS_HTTP_DATA_ERROR:
+                    return ERROR_HTTP_DATA_ERROR;
+
+                case Downloads.STATUS_TOO_MANY_REDIRECTS:
+                    return ERROR_TOO_MANY_REDIRECTS;
+
+                case Downloads.STATUS_INSUFFICIENT_SPACE_ERROR:
+                    return ERROR_INSUFFICIENT_SPACE;
+
+                case Downloads.STATUS_DEVICE_NOT_FOUND_ERROR:
+                    return ERROR_DEVICE_NOT_FOUND;
+
+                default:
+                    return ERROR_UNKNOWN;
+            }
+        }
+
+        private long getUnderlyingLong(String column) {
+            return super.getLong(super.getColumnIndex(column));
+        }
+
+        private String getUnderlyingString(String column) {
+            return super.getString(super.getColumnIndex(column));
+        }
+
+        private long translateStatus(int status) {
+            switch (status) {
+                case Downloads.STATUS_PENDING:
+                    return STATUS_PENDING;
+
+                case Downloads.STATUS_RUNNING:
+                    return STATUS_RUNNING;
+
+                case Downloads.STATUS_PENDING_PAUSED:
+                case Downloads.STATUS_RUNNING_PAUSED:
+                    return STATUS_PAUSED;
+
+                case Downloads.STATUS_SUCCESS:
+                    return STATUS_SUCCESSFUL;
+
+                default:
+                    assert Downloads.isStatusError(status);
+                    return STATUS_FAILED;
+            }
+        }
+    }
+}
diff --git a/core/java/android/net/MobileDataStateTracker.java b/core/java/android/net/MobileDataStateTracker.java
index 5fd5315..f067392 100644
--- a/core/java/android/net/MobileDataStateTracker.java
+++ b/core/java/android/net/MobileDataStateTracker.java
@@ -29,6 +29,7 @@
 import com.android.internal.telephony.TelephonyIntents;
 import android.net.NetworkInfo.DetailedState;
 import android.net.NetworkInfo;
+import android.net.NetworkProperties;
 import android.telephony.TelephonyManager;
 import android.util.Log;
 import android.text.TextUtils;
@@ -55,7 +56,7 @@
     private boolean mTeardownRequested = false;
     private Handler mTarget;
     private Context mContext;
-    private String mInterfaceName;
+    private NetworkProperties mNetworkProperties;
     private boolean mPrivateDnsRouteSet = false;
     private int mDefaultGatewayAddr = 0;
     private boolean mDefaultRouteSet = false;
@@ -101,14 +102,6 @@
         return sDnsPropNames;
     }
 
-    /**
-     * Return the name of our network interface.
-     * @return the name of our interface.
-     */
-    public String getInterfaceName() {
-        return mInterfaceName;
-    }
-
     public boolean isPrivateDnsRouteSet() {
         return mPrivateDnsRouteSet;
     }
@@ -211,9 +204,11 @@
                                 }
 
                                 setDetailedState(DetailedState.DISCONNECTED, reason, apnName);
-                                if (mInterfaceName != null) {
-                                    NetworkUtils.resetConnections(mInterfaceName);
+                                if (mNetworkProperties != null) {
+                                    String iface = mNetworkProperties.getInterfaceName();
+                                    if (iface != null) NetworkUtils.resetConnections(iface);
                                 }
+                                // TODO - check this
                                 // can't do this here - ConnectivityService needs it to clear stuff
                                 // it's ok though - just leave it to be refreshed next time
                                 // we connect.
@@ -229,9 +224,11 @@
                                 setDetailedState(DetailedState.SUSPENDED, reason, apnName);
                                 break;
                             case CONNECTED:
-                                mInterfaceName = intent.getStringExtra(Phone.DATA_IFACE_NAME_KEY);
-                                if (mInterfaceName == null) {
-                                    Log.d(TAG, "CONNECTED event did not supply interface name.");
+                                mNetworkProperties = intent.getParcelableExtra(
+                                        Phone.DATA_NETWORK_PROPERTIES_KEY);
+                                if (mNetworkProperties == null) {
+                                    Log.d(TAG,
+                                            "CONNECTED event did not supply network properties.");
                                 }
                                 setDetailedState(DetailedState.CONNECTED, reason, apnName);
                                 break;
@@ -565,4 +562,8 @@
                 return null;
         }
     }
+
+    public NetworkProperties getNetworkProperties() {
+        return mNetworkProperties;
+    }
 }
diff --git a/core/java/android/net/NetworkProperties.aidl b/core/java/android/net/NetworkProperties.aidl
new file mode 100644
index 0000000..07aac6e
--- /dev/null
+++ b/core/java/android/net/NetworkProperties.aidl
@@ -0,0 +1,22 @@
+/*
+**
+** Copyright (C) 2009 Qualcomm Innovation Center, Inc.  All Rights Reserved.
+** Copyright (C) 2009 The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+
+package android.net;
+
+parcelable NetworkProperties;
+
diff --git a/core/java/android/net/NetworkProperties.java b/core/java/android/net/NetworkProperties.java
new file mode 100644
index 0000000..56e1f1a
--- /dev/null
+++ b/core/java/android/net/NetworkProperties.java
@@ -0,0 +1,196 @@
+/*
+ * 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.net;
+
+import android.os.Parcelable;
+import android.os.Parcel;
+import android.util.Log;
+
+import java.net.InetAddress;
+import java.net.NetworkInterface;
+import java.net.SocketException;
+import java.net.UnknownHostException;
+import java.util.ArrayList;
+import java.util.Collection;
+
+/**
+ * Describes the properties of a network interface or single address
+ * of an interface.
+ * TODO - consider adding optional fields like Apn and ApnType
+ * @hide
+ */
+public class NetworkProperties implements Parcelable {
+
+    private NetworkInterface mIface;
+    private Collection<InetAddress> mAddresses;
+    private Collection<InetAddress> mDnses;
+    private InetAddress mGateway;
+    private ProxyProperties mHttpProxy;
+
+    public NetworkProperties() {
+        clear();
+    }
+
+    public synchronized void setInterface(NetworkInterface iface) {
+        mIface = iface;
+    }
+    public synchronized NetworkInterface getInterface() {
+        return mIface;
+    }
+    public synchronized String getInterfaceName() {
+        return (mIface == null ? null : mIface.getName());
+    }
+
+    public synchronized void addAddress(InetAddress address) {
+        mAddresses.add(address);
+    }
+    public synchronized Collection<InetAddress> getAddresses() {
+        return mAddresses;
+    }
+
+    public synchronized void addDns(InetAddress dns) {
+        mDnses.add(dns);
+    }
+    public synchronized Collection<InetAddress> getDnses() {
+        return mDnses;
+    }
+
+    public synchronized void setGateway(InetAddress gateway) {
+        mGateway = gateway;
+    }
+    public synchronized InetAddress getGateway() {
+        return mGateway;
+    }
+
+    public synchronized void setHttpProxy(ProxyProperties proxy) {
+        mHttpProxy = proxy;
+    }
+    public synchronized ProxyProperties getHttpProxy() {
+        return mHttpProxy;
+    }
+
+    public synchronized void clear() {
+        mIface = null;
+        mAddresses = new ArrayList<InetAddress>();
+        mDnses = new ArrayList<InetAddress>();
+        mGateway = null;
+        mHttpProxy = null;
+    }
+
+    /**
+     * Implement the Parcelable interface
+     * @hide
+     */
+    public int describeContents() {
+        return 0;
+    }
+
+    public synchronized String toString() {
+        String ifaceName = (mIface == null ? "" : "InterfaceName: " + mIface.getName() + " ");
+
+        String ip = "IpAddresses: [";
+        for (InetAddress addr : mAddresses) ip +=  addr.toString() + ",";
+        ip += "] ";
+
+        String dns = "DnsAddresses: [";
+        for (InetAddress addr : mDnses) dns += addr.toString() + ",";
+        dns += "] ";
+
+        String proxy = (mHttpProxy == null ? "" : "HttpProxy: " + mHttpProxy.toString() + " ");
+        String gateway = (mGateway == null ? "" : "Gateway: " + mGateway.toString() + " ");
+
+        return ifaceName + ip + gateway + dns + proxy;
+    }
+
+    /**
+     * Implement the Parcelable interface.
+     * @hide
+     */
+    public synchronized void writeToParcel(Parcel dest, int flags) {
+        dest.writeString(getInterfaceName());
+        dest.writeInt(mAddresses.size());
+        for(InetAddress a : mAddresses) {
+            dest.writeString(a.getHostName());
+            dest.writeByteArray(a.getAddress());
+        }
+        dest.writeInt(mDnses.size());
+        for(InetAddress d : mDnses) {
+            dest.writeString(d.getHostName());
+            dest.writeByteArray(d.getAddress());
+        }
+        if (mGateway != null) {
+            dest.writeByte((byte)1);
+            dest.writeString(mGateway.getHostName());
+            dest.writeByteArray(mGateway.getAddress());
+        } else {
+            dest.writeByte((byte)0);
+        }
+        if (mHttpProxy != null) {
+            dest.writeByte((byte)1);
+            dest.writeParcelable(mHttpProxy, flags);
+        } else {
+            dest.writeByte((byte)0);
+        }
+    }
+
+    /**
+     * Implement the Parcelable interface.
+     * @hide
+     */
+    public static final Creator<NetworkProperties> CREATOR =
+        new Creator<NetworkProperties>() {
+            public NetworkProperties createFromParcel(Parcel in) {
+                NetworkProperties netProp = new NetworkProperties();
+                String iface = in.readString();
+                if (iface != null) {
+                    try {
+                        netProp.setInterface(NetworkInterface.getByName(iface));
+                    } catch (Exception e) {
+                        return null;
+                    }
+                }
+                int addressCount = in.readInt();
+                for (int i=0; i<addressCount; i++) {
+                    try {
+                        netProp.addAddress(InetAddress.getByAddress(in.readString(),
+                                in.createByteArray()));
+                    } catch (UnknownHostException e) { }
+                }
+                addressCount = in.readInt();
+                for (int i=0; i<addressCount; i++) {
+                    try {
+                        netProp.addDns(InetAddress.getByAddress(in.readString(),
+                                in.createByteArray()));
+                    } catch (UnknownHostException e) { }
+                }
+                if (in.readByte() == 1) {
+                    try {
+                        netProp.setGateway(InetAddress.getByAddress(in.readString(),
+                                in.createByteArray()));
+                    } catch (UnknownHostException e) {}
+                }
+                if (in.readByte() == 1) {
+                    netProp.setHttpProxy((ProxyProperties)in.readParcelable(null));
+                }
+                return netProp;
+            }
+
+            public NetworkProperties[] newArray(int size) {
+                return new NetworkProperties[size];
+            }
+        };
+}
diff --git a/core/java/android/net/NetworkStateTracker.java b/core/java/android/net/NetworkStateTracker.java
index cd8e7f1..44215e7 100644
--- a/core/java/android/net/NetworkStateTracker.java
+++ b/core/java/android/net/NetworkStateTracker.java
@@ -46,22 +46,17 @@
     public NetworkInfo getNetworkInfo();
 
     /**
+     * Fetch NetworkProperties for the network
+     */
+    public NetworkProperties getNetworkProperties();
+
+    /**
      * Return the system properties name associated with the tcp buffer sizes
      * for this network.
      */
     public String getTcpBufferSizesPropName();
 
     /**
-     * Return the DNS property names for this network.
-     */
-    public String[] getDnsPropNames();
-
-    /**
-     * Fetch interface name of the interface
-     */
-    public String getInterfaceName();
-
-    /**
      * Check if private DNS route is set for the network
      */
     public boolean isPrivateDnsRouteSet();
diff --git a/core/java/android/net/NetworkUtils.java b/core/java/android/net/NetworkUtils.java
index a3ae01b..564bc1f 100644
--- a/core/java/android/net/NetworkUtils.java
+++ b/core/java/android/net/NetworkUtils.java
@@ -32,13 +32,37 @@
     public native static int disableInterface(String interfaceName);
 
     /** Add a route to the specified host via the named interface. */
-    public native static int addHostRoute(String interfaceName, int hostaddr);
+    public static int addHostRoute(String interfaceName, InetAddress hostaddr) {
+        int v4Int = v4StringToInt(hostaddr.getHostAddress());
+        if (v4Int != 0) {
+            return addHostRouteNative(interfaceName, v4Int);
+        } else {
+            return -1;
+        }
+    }
+    private native static int addHostRouteNative(String interfaceName, int hostaddr);
 
     /** Add a default route for the named interface. */
-    public native static int setDefaultRoute(String interfaceName, int gwayAddr);
+    public static int setDefaultRoute(String interfaceName, InetAddress gwayAddr) {
+        int v4Int = v4StringToInt(gwayAddr.getHostAddress());
+        if (v4Int != 0) {
+            return setDefaultRouteNative(interfaceName, v4Int);
+        } else {
+            return -1;
+        }
+    }
+    private native static int setDefaultRouteNative(String interfaceName, int hostaddr);
 
     /** Return the gateway address for the default route for the named interface. */
-    public native static int getDefaultRoute(String interfaceName);
+    public static InetAddress getDefaultRoute(String interfaceName) {
+        int addr = getDefaultRouteNative(interfaceName);
+        try {
+            return InetAddress.getByAddress(v4IntToArray(addr));
+        } catch (UnknownHostException e) {
+            return null;
+        }
+    }
+    private native static int getDefaultRouteNative(String interfaceName);
 
     /** Remove host routes that uses the named interface. */
     public native static int removeHostRoutes(String interfaceName);
@@ -105,27 +129,30 @@
     private native static boolean configureNative(
         String interfaceName, int ipAddress, int netmask, int gateway, int dns1, int dns2);
 
-    /**
-     * Look up a host name and return the result as an int. Works if the argument
-     * is an IP address in dot notation. Obviously, this can only be used for IPv4
-     * addresses.
-     * @param hostname the name of the host (or the IP address)
-     * @return the IP address as an {@code int} in network byte order
-     */
-    public static int lookupHost(String hostname) {
-        InetAddress inetAddress;
+    // The following two functions are glue to tie the old int-based address scheme
+    // to the new InetAddress scheme.  They should go away when we go fully to InetAddress
+    // TODO - remove when we switch fully to InetAddress
+    public static byte[] v4IntToArray(int addr) {
+        byte[] addrBytes = new byte[4];
+        addrBytes[0] = (byte)(addr & 0xff);
+        addrBytes[1] = (byte)((addr >> 8) & 0xff);
+        addrBytes[2] = (byte)((addr >> 16) & 0xff);
+        addrBytes[3] = (byte)((addr >> 24) & 0xff);
+        return addrBytes;
+    }
+
+    public static int v4StringToInt(String str) {
+        int result = 0;
+        String[] array = str.split("\\.");
+        if (array.length != 4) return 0;
         try {
-            inetAddress = InetAddress.getByName(hostname);
-        } catch (UnknownHostException e) {
-            return -1;
+            result = Integer.parseInt(array[3]);
+            result = (result << 8) + Integer.parseInt(array[2]);
+            result = (result << 8) + Integer.parseInt(array[1]);
+            result = (result << 8) + Integer.parseInt(array[0]);
+        } catch (NumberFormatException e) {
+            return 0;
         }
-        byte[] addrBytes;
-        int addr;
-        addrBytes = inetAddress.getAddress();
-        addr = ((addrBytes[3] & 0xff) << 24)
-                | ((addrBytes[2] & 0xff) << 16)
-                | ((addrBytes[1] & 0xff) << 8)
-                |  (addrBytes[0] & 0xff);
-        return addr;
+        return result;
     }
 }
diff --git a/core/java/android/net/ProxyProperties.java b/core/java/android/net/ProxyProperties.java
new file mode 100644
index 0000000..6828dd4
--- /dev/null
+++ b/core/java/android/net/ProxyProperties.java
@@ -0,0 +1,108 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net;
+
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+
+/**
+ * A container class for the http proxy info
+ * @hide
+ */
+public class ProxyProperties implements Parcelable {
+
+    private InetAddress mProxy;
+    private int mPort;
+    private String mExclusionList;
+
+    public ProxyProperties() {
+    }
+
+    public synchronized InetAddress getAddress() {
+        return mProxy;
+    }
+    public synchronized void setAddress(InetAddress proxy) {
+        mProxy = proxy;
+    }
+
+    public synchronized int getPort() {
+        return mPort;
+    }
+    public synchronized void setPort(int port) {
+        mPort = port;
+    }
+
+    public synchronized String getExclusionList() {
+        return mExclusionList;
+    }
+    public synchronized void setExclusionList(String exclusionList) {
+        mExclusionList = exclusionList;
+    }
+
+    /**
+     * Implement the Parcelable interface
+     * @hide
+     */
+    public int describeContents() {
+        return 0;
+    }
+
+    /**
+     * Implement the Parcelable interface.
+     * @hide
+     */
+    public synchronized void writeToParcel(Parcel dest, int flags) {
+        if (mProxy != null) {
+            dest.writeByte((byte)1);
+            dest.writeString(mProxy.getHostName());
+            dest.writeByteArray(mProxy.getAddress());
+        } else {
+            dest.writeByte((byte)0);
+        }
+        dest.writeInt(mPort);
+        dest.writeString(mExclusionList);
+    }
+
+    /**
+     * Implement the Parcelable interface.
+     * @hide
+     */
+    public static final Creator<ProxyProperties> CREATOR =
+        new Creator<ProxyProperties>() {
+            public ProxyProperties createFromParcel(Parcel in) {
+                ProxyProperties proxyProperties = new ProxyProperties();
+                if (in.readByte() == 1) {
+                    try {
+                        proxyProperties.setAddress(InetAddress.getByAddress(in.readString(),
+                                in.createByteArray()));
+                    } catch (UnknownHostException e) {}
+                }
+                proxyProperties.setPort(in.readInt());
+                proxyProperties.setExclusionList(in.readString());
+                return proxyProperties;
+            }
+
+            public ProxyProperties[] newArray(int size) {
+                return new ProxyProperties[size];
+            }
+        };
+
+};
diff --git a/core/java/android/net/SSLCertificateSocketFactory.java b/core/java/android/net/SSLCertificateSocketFactory.java
index 9ad125b..31acb5b 100644
--- a/core/java/android/net/SSLCertificateSocketFactory.java
+++ b/core/java/android/net/SSLCertificateSocketFactory.java
@@ -247,13 +247,16 @@
     /**
      * {@inheritDoc}
      *
-     * <p>This method verifies the peer's certificate hostname after connecting.
+     * <p>This method verifies the peer's certificate hostname after connecting
+     * (unless created with {@link #getInsecure(int, SSLSessionCache)}).
      */
     @Override
     public Socket createSocket(Socket k, String host, int port, boolean close) throws IOException {
         OpenSSLSocketImpl s = (OpenSSLSocketImpl) getDelegate().createSocket(k, host, port, close);
         s.setHandshakeTimeout(mHandshakeTimeoutMillis);
-        verifyHostname(s, host);
+        if (mSecure) {
+            verifyHostname(s, host);
+        }
         return s;
     }
 
@@ -305,7 +308,8 @@
     /**
      * {@inheritDoc}
      *
-     * <p>This method verifies the peer's certificate hostname after connecting.
+     * <p>This method verifies the peer's certificate hostname after connecting
+     * (unless created with {@link #getInsecure(int, SSLSessionCache)}).
      */
     @Override
     public Socket createSocket(String host, int port, InetAddress localAddr, int localPort)
@@ -313,20 +317,25 @@
         OpenSSLSocketImpl s = (OpenSSLSocketImpl) getDelegate().createSocket(
                 host, port, localAddr, localPort);
         s.setHandshakeTimeout(mHandshakeTimeoutMillis);
-        verifyHostname(s, host);
+        if (mSecure) {
+            verifyHostname(s, host);
+        }
         return s;
     }
 
     /**
      * {@inheritDoc}
      *
-     * <p>This method verifies the peer's certificate hostname after connecting.
+     * <p>This method verifies the peer's certificate hostname after connecting
+     * (unless created with {@link #getInsecure(int, SSLSessionCache)}).
      */
     @Override
     public Socket createSocket(String host, int port) throws IOException {
         OpenSSLSocketImpl s = (OpenSSLSocketImpl) getDelegate().createSocket(host, port);
         s.setHandshakeTimeout(mHandshakeTimeoutMillis);
-        verifyHostname(s, host);
+        if (mSecure) {
+            verifyHostname(s, host);
+        }
         return s;
     }
 
diff --git a/core/java/android/os/Debug.java b/core/java/android/os/Debug.java
index 2e14667..d23b161 100644
--- a/core/java/android/os/Debug.java
+++ b/core/java/android/os/Debug.java
@@ -730,7 +730,7 @@
     }
 
     /**
-     * Dump "hprof" data to the specified file.  This will cause a GC.
+     * Dump "hprof" data to the specified file.  This may cause a GC.
      *
      * @param fileName Full pathname of output file (e.g. "/sdcard/dump.hprof").
      * @throws UnsupportedOperationException if the VM was built without
@@ -742,11 +742,24 @@
     }
 
     /**
-     * Collect "hprof" and send it to DDMS.  This will cause a GC.
+     * Like dumpHprofData(String), but takes an already-opened
+     * FileDescriptor to which the trace is written.  The file name is also
+     * supplied simply for logging.  Makes a dup of the file descriptor.
+     *
+     * Primarily for use by the "am" shell command.
+     *
+     * @hide
+     */
+    public static void dumpHprofData(String fileName, FileDescriptor fd)
+            throws IOException {
+        VMDebug.dumpHprofData(fileName, fd);
+    }
+
+    /**
+     * Collect "hprof" and send it to DDMS.  This may cause a GC.
      *
      * @throws UnsupportedOperationException if the VM was built without
      *         HPROF support.
-     *
      * @hide
      */
     public static void dumpHprofDataDdms() {
@@ -754,6 +767,13 @@
     }
 
     /**
+     * Writes native heap data to the specified file descriptor.
+     *
+     * @hide
+     */
+    public static native void dumpNativeHeap(FileDescriptor fd);
+
+    /**
      * Returns the number of sent transactions from this process.
      * @return The number of sent transactions or -1 if it could not read t.
      */
diff --git a/core/java/android/provider/Calendar.java b/core/java/android/provider/Calendar.java
index a23a5a7..10f1d2b 100644
--- a/core/java/android/provider/Calendar.java
+++ b/core/java/android/provider/Calendar.java
@@ -289,6 +289,7 @@
                 DatabaseUtils.cursorStringToContentValuesIfPresent(cursor, cv, Calendars.SYNC1);
                 DatabaseUtils.cursorStringToContentValuesIfPresent(cursor, cv, Calendars.SYNC2);
                 DatabaseUtils.cursorStringToContentValuesIfPresent(cursor, cv, Calendars.SYNC3);
+                DatabaseUtils.cursorStringToContentValuesIfPresent(cursor, cv, Calendars.SYNC4);
 
                 DatabaseUtils.cursorStringToContentValuesIfPresent(cursor, cv, Calendars.NAME);
                 DatabaseUtils.cursorStringToContentValuesIfPresent(cursor, cv,
diff --git a/core/java/android/provider/Downloads.java b/core/java/android/provider/Downloads.java
index 348e9e8..2a612fe 100644
--- a/core/java/android/provider/Downloads.java
+++ b/core/java/android/provider/Downloads.java
@@ -899,6 +899,12 @@
         public static final int DESTINATION_CACHE_PARTITION_NOROAMING = 3;
 
         /**
+         * This download will be saved to the location given by the file URI in
+         * {@link #COLUMN_FILE_NAME_HINT}.
+         */
+        public static final int DESTINATION_FILE_URI = 4;
+
+        /**
          * This download is allowed to run.
          */
         public static final int CONTROL_RUN = 0;
@@ -1109,5 +1115,26 @@
          * This download doesn't show in the UI or in the notifications.
          */
         public static final int VISIBILITY_HIDDEN = 2;
+
+        /**
+         * Constants related to HTTP request headers associated with each download.
+         */
+        public static class RequestHeaders {
+            public static final String HEADERS_DB_TABLE = "request_headers";
+            public static final String COLUMN_DOWNLOAD_ID = "download_id";
+            public static final String COLUMN_HEADER = "header";
+            public static final String COLUMN_VALUE = "value";
+
+            /**
+             * Path segment to add to a download URI to retrieve request headers
+             */
+            public static final String URI_SEGMENT = "headers";
+
+            /**
+             * Prefix for ContentValues keys that contain HTTP header lines, to be passed to
+             * DownloadProvider.insert().
+             */
+            public static final String INSERT_KEY_PREFIX = "http_header_";
+        }
     }
 }
diff --git a/core/java/android/provider/MediaStore.java b/core/java/android/provider/MediaStore.java
index 9a3c618..293d31c 100644
--- a/core/java/android/provider/MediaStore.java
+++ b/core/java/android/provider/MediaStore.java
@@ -237,8 +237,67 @@
          * <P>Type: TEXT</P>
          */
         public static final String MIME_TYPE = "mime_type";
+
+        /**
+         * The MTP object handle of a newly transfered file.
+         * Used internally by the MediaScanner
+         * <P>Type: INTEGER</P>
+         * @hide
+         */
+        public static final String MTP_OBJECT_HANDLE = "mtp_object_handle";
      }
 
+
+
+    /**
+     * Media provider interface used by MTP implementation.
+     * @hide
+     */
+    public static final class MtpObjects {
+
+        public static Uri getContentUri(String volumeName) {
+            return Uri.parse(CONTENT_AUTHORITY_SLASH + volumeName +
+                    "/object");
+        }
+
+        public static final Uri getContentUri(String volumeName,
+                long objectId) {
+            return Uri.parse(CONTENT_AUTHORITY_SLASH + volumeName
+                    + "/object/" + objectId);
+        }
+
+        /**
+         * Fields for master table for all media files.
+         * Table also contains MediaColumns._ID, DATA, SIZE and DATE_MODIFIED.
+         */
+        public interface ObjectColumns extends MediaColumns {
+            /**
+             * The MTP format code of the file
+             * <P>Type: INTEGER</P>
+             */
+            public static final String FORMAT = "format";
+
+            /**
+             * The index of the parent directory of the file
+             * <P>Type: INTEGER</P>
+             */
+            public static final String PARENT = "parent";
+
+            /**
+             * Identifier for the media table containing the object.
+             * Used internally by MediaProvider
+             * <P>Type: INTEGER</P>
+             */
+            public static final String MEDIA_TABLE = "media_table";
+
+            /**
+             * The ID of the object in its media table.
+             * <P>Type: INTEGER</P>
+             */
+            public static final String MEDIA_ID = "media_id";
+        }
+    }
+
     /**
      * This class is used internally by Images.Thumbnails and Video.Thumbnails, it's not intended
      * to be accessed elsewhere.
diff --git a/core/java/android/server/BluetoothService.java b/core/java/android/server/BluetoothService.java
index ec99b0d..23219a3 100644
--- a/core/java/android/server/BluetoothService.java
+++ b/core/java/android/server/BluetoothService.java
@@ -1340,9 +1340,7 @@
 
     }
 
-    /*package*/ void handleInputDevicePropertyChange(String path, boolean connected) {
-        String address = getAddressFromObjectPath(path);
-        if (address == null) return;
+    /*package*/ void handleInputDevicePropertyChange(String address, boolean connected) {
         int state = connected ? BluetoothInputDevice.STATE_CONNECTED :
             BluetoothInputDevice.STATE_DISCONNECTED;
         BluetoothDevice device = mAdapter.getRemoteDevice(address);
diff --git a/core/java/android/service/wallpaper/WallpaperService.java b/core/java/android/service/wallpaper/WallpaperService.java
index 249ad62..e26a090 100644
--- a/core/java/android/service/wallpaper/WallpaperService.java
+++ b/core/java/android/service/wallpaper/WallpaperService.java
@@ -216,20 +216,7 @@
             @Override
             public void handleTouch(MotionEvent event, Runnable finishedCallback) {
                 try {
-                    synchronized (mLock) {
-                        if (event.getAction() == MotionEvent.ACTION_MOVE) {
-                            if (mPendingMove != null) {
-                                mCaller.removeMessages(MSG_TOUCH_EVENT, mPendingMove);
-                                mPendingMove.recycle();
-                            }
-                            mPendingMove = event;
-                        } else {
-                            mPendingMove = null;
-                        }
-                        Message msg = mCaller.obtainMessageO(MSG_TOUCH_EVENT,
-                                event);
-                        mCaller.sendMessage(msg);
-                    }
+                    dispatchPointer(event);
                 } finally {
                     finishedCallback.run();
                 }
@@ -238,26 +225,6 @@
         
         final BaseIWindow mWindow = new BaseIWindow() {
             @Override
-            public boolean onDispatchPointer(MotionEvent event, long eventTime,
-                    boolean callWhenDone) {
-                synchronized (mLock) {
-                    if (event.getAction() == MotionEvent.ACTION_MOVE) {
-                        if (mPendingMove != null) {
-                            mCaller.removeMessages(MSG_TOUCH_EVENT, mPendingMove);
-                            mPendingMove.recycle();
-                        }
-                        mPendingMove = event;
-                    } else {
-                        mPendingMove = null;
-                    }
-                    Message msg = mCaller.obtainMessageO(MSG_TOUCH_EVENT,
-                            event);
-                    mCaller.sendMessage(msg);
-                }
-                return false;
-            }
-            
-            @Override
             public void resized(int w, int h, Rect coveredInsets,
                     Rect visibleInsets, boolean reportDraw, Configuration newConfig) {
                 Message msg = mCaller.obtainMessageI(MSG_WINDOW_RESIZED,
@@ -369,7 +336,7 @@
                     ? (mWindowFlags&~WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE)
                     : (mWindowFlags|WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE);
             if (mCreated) {
-                updateSurface(false, false);
+                updateSurface(false, false, false);
             }
         }
         
@@ -454,6 +421,13 @@
         }
 
         /**
+         * Convenience for {@link SurfaceHolder.Callback2#surfaceRedrawNeeded
+         * SurfaceHolder.Callback.surfaceRedrawNeeded()}.
+         */
+        public void onSurfaceRedrawNeeded(SurfaceHolder holder) {
+        }
+
+        /**
          * Convenience for {@link SurfaceHolder.Callback#surfaceCreated
          * SurfaceHolder.Callback.surfaceCreated()}.
          */
@@ -466,8 +440,24 @@
          */
         public void onSurfaceDestroyed(SurfaceHolder holder) {
         }
+        
+        private void dispatchPointer(MotionEvent event) {
+            synchronized (mLock) {
+                if (event.getAction() == MotionEvent.ACTION_MOVE) {
+                    if (mPendingMove != null) {
+                        mCaller.removeMessages(MSG_TOUCH_EVENT, mPendingMove);
+                        mPendingMove.recycle();
+                    }
+                    mPendingMove = event;
+                } else {
+                    mPendingMove = null;
+                }
+                Message msg = mCaller.obtainMessageO(MSG_TOUCH_EVENT, event);
+                mCaller.sendMessage(msg);
+            }
+        }
 
-        void updateSurface(boolean forceRelayout, boolean forceReport) {
+        void updateSurface(boolean forceRelayout, boolean forceReport, boolean redrawNeeded) {
             if (mDestroyed) {
                 Log.w(TAG, "Ignoring updateSurface: destroyed");
             }
@@ -484,7 +474,7 @@
             final boolean typeChanged = mType != mSurfaceHolder.getRequestedType();
             final boolean flagsChanged = mCurWindowFlags != mWindowFlags;
             if (forceRelayout || creating || surfaceCreating || formatChanged || sizeChanged
-                    || typeChanged || flagsChanged) {
+                    || typeChanged || flagsChanged || redrawNeeded) {
 
                 if (DEBUG) Log.v(TAG, "Changes: creating=" + creating
                         + " format=" + formatChanged + " size=" + sizeChanged);
@@ -523,10 +513,8 @@
                                 mInputChannel);
                         mCreated = true;
 
-                        if (WindowManagerPolicy.ENABLE_NATIVE_INPUT_DISPATCH) {
-                            InputQueue.registerInputChannel(mInputChannel, mInputHandler,
-                                    Looper.myQueue());
-                        }
+                        InputQueue.registerInputChannel(mInputChannel, mInputHandler,
+                                Looper.myQueue());
                     }
                     
                     mSurfaceHolder.mSurfaceLock.lock();
@@ -574,6 +562,10 @@
                                 }
                             }
                         }
+
+                        redrawNeeded |= creating
+                                || (relayoutResult&WindowManagerImpl.RELAYOUT_FIRST_TIME) != 0;
+
                         if (forceReport || creating || surfaceCreating
                                 || formatChanged || sizeChanged) {
                             if (DEBUG) {
@@ -597,10 +589,24 @@
                                 }
                             }
                         }
+
+                        if (redrawNeeded) {
+                            onSurfaceRedrawNeeded(mSurfaceHolder);
+                            SurfaceHolder.Callback callbacks[] = mSurfaceHolder.getCallbacks();
+                            if (callbacks != null) {
+                                for (SurfaceHolder.Callback c : callbacks) {
+                                    if (c instanceof SurfaceHolder.Callback2) {
+                                        ((SurfaceHolder.Callback2)c).surfaceRedrawNeeded(
+                                                mSurfaceHolder);
+                                    }
+                                }
+                            }
+                        }
+
                     } finally {
                         mIsCreating = false;
                         mSurfaceCreated = true;
-                        if (creating || (relayoutResult&WindowManagerImpl.RELAYOUT_FIRST_TIME) != 0) {
+                        if (redrawNeeded) {
                             mSession.finishDrawing(mWindow);
                         }
                     }
@@ -637,7 +643,7 @@
             onCreate(mSurfaceHolder);
             
             mInitializing = false;
-            updateSurface(false, false);
+            updateSurface(false, false, false);
         }
         
         void doDesiredSizeChanged(int desiredWidth, int desiredHeight) {
@@ -666,7 +672,7 @@
                         // If becoming visible, in preview mode the surface
                         // may have been destroyed so now we need to make
                         // sure it is re-created.
-                        updateSurface(false, false);
+                        updateSurface(false, false, false);
                     }
                     onVisibilityChanged(visible);
                 }
@@ -770,10 +776,8 @@
                     if (DEBUG) Log.v(TAG, "Removing window and destroying surface "
                             + mSurfaceHolder.getSurface() + " of: " + this);
                     
-                    if (WindowManagerPolicy.ENABLE_NATIVE_INPUT_DISPATCH) {
-                        if (mInputChannel != null) {
-                            InputQueue.unregisterInputChannel(mInputChannel);
-                        }
+                    if (mInputChannel != null) {
+                        InputQueue.unregisterInputChannel(mInputChannel);
                     }
                     
                     mSession.remove(mWindow);
@@ -782,13 +786,11 @@
                 mSurfaceHolder.mSurface.release();
                 mCreated = false;
                 
-                if (WindowManagerPolicy.ENABLE_NATIVE_INPUT_DISPATCH) {
-                    // Dispose the input channel after removing the window so the Window Manager
-                    // doesn't interpret the input channel being closed as an abnormal termination.
-                    if (mInputChannel != null) {
-                        mInputChannel.dispose();
-                        mInputChannel = null;
-                    }
+                // Dispose the input channel after removing the window so the Window Manager
+                // doesn't interpret the input channel being closed as an abnormal termination.
+                if (mInputChannel != null) {
+                    mInputChannel.dispose();
+                    mInputChannel = null;
                 }
             }
         }
@@ -841,7 +843,7 @@
 
         public void dispatchPointer(MotionEvent event) {
             if (mEngine != null) {
-                mEngine.mWindow.onDispatchPointer(event, event.getEventTime(), false);
+                mEngine.dispatchPointer(event);
             }
         }
         
@@ -875,7 +877,7 @@
                     return;
                 }
                 case MSG_UPDATE_SURFACE:
-                    mEngine.updateSurface(true, false);
+                    mEngine.updateSurface(true, false, false);
                     break;
                 case MSG_VISIBILITY_CHANGED:
                     if (DEBUG) Log.v(TAG, "Visibility change in " + mEngine
@@ -891,14 +893,8 @@
                 } break;
                 case MSG_WINDOW_RESIZED: {
                     final boolean reportDraw = message.arg1 != 0;
-                    mEngine.updateSurface(true, false);
+                    mEngine.updateSurface(true, false, reportDraw);
                     mEngine.doOffsetsChanged();
-                    if (reportDraw) {
-                        try {
-                            mEngine.mSession.finishDrawing(mEngine.mWindow);
-                        } catch (RemoteException e) {
-                        }
-                    }
                 } break;
                 case MSG_TOUCH_EVENT: {
                     MotionEvent ev = (MotionEvent)message.obj;
diff --git a/core/java/android/text/Selection.java b/core/java/android/text/Selection.java
index bb98bce..13cb5e6 100644
--- a/core/java/android/text/Selection.java
+++ b/core/java/android/text/Selection.java
@@ -417,8 +417,8 @@
         }
     }
 
-    private static final class START implements NoCopySpan { };
-    private static final class END implements NoCopySpan { };
+    private static final class START implements NoCopySpan { }
+    private static final class END implements NoCopySpan { }
     
     /*
      * Public constants
diff --git a/core/java/android/text/TextLine.java b/core/java/android/text/TextLine.java
index 33c9554..0e3522e 100644
--- a/core/java/android/text/TextLine.java
+++ b/core/java/android/text/TextLine.java
@@ -21,8 +21,8 @@
 import android.graphics.Bitmap;
 import android.graphics.Canvas;
 import android.graphics.Paint;
-import android.graphics.RectF;
 import android.graphics.Paint.FontMetricsInt;
+import android.graphics.RectF;
 import android.text.Layout.Directions;
 import android.text.Layout.TabStops;
 import android.text.style.CharacterStyle;
@@ -583,7 +583,7 @@
     /**
      * Returns the next valid offset within this directional run, skipping
      * conjuncts and zero-width characters.  This should not be called to walk
-     * off the end of the line, since the the returned values might not be valid
+     * off the end of the line, since the returned values might not be valid
      * on neighboring lines.  If the returned offset is less than zero or
      * greater than the line length, the offset should be recomputed on the
      * preceding or following line, respectively.
diff --git a/core/java/android/text/format/Time.java b/core/java/android/text/format/Time.java
index 8eae111..c05a8fe 100644
--- a/core/java/android/text/format/Time.java
+++ b/core/java/android/text/format/Time.java
@@ -32,7 +32,7 @@
     private static final String Y_M_D_T_H_M_S_000 = "%Y-%m-%dT%H:%M:%S.000";
     private static final String Y_M_D_T_H_M_S_000_Z = "%Y-%m-%dT%H:%M:%S.000Z";
     private static final String Y_M_D = "%Y-%m-%d";
-    
+
     public static final String TIMEZONE_UTC = "UTC";
 
     /**
@@ -170,11 +170,11 @@
     public Time() {
         this(TimeZone.getDefault().getID());
     }
-    
+
     /**
      * A copy constructor.  Construct a Time object by copying the given
      * Time object.  No normalization occurs.
-     * 
+     *
      * @param other
      */
     public Time(Time other) {
@@ -185,17 +185,17 @@
      * Ensures the values in each field are in range. For example if the
      * current value of this calendar is March 32, normalize() will convert it
      * to April 1. It also fills in weekDay, yearDay, isDst and gmtoff.
-     * 
+     *
      * <p>
      * If "ignoreDst" is true, then this method sets the "isDst" field to -1
      * (the "unknown" value) before normalizing.  It then computes the
      * correct value for "isDst".
-     * 
+     *
      * <p>
      * See {@link #toMillis(boolean)} for more information about when to
      * use <tt>true</tt> or <tt>false</tt> for "ignoreDst".
-     * 
-     * @return the UTC milliseconds since the epoch 
+     *
+     * @return the UTC milliseconds since the epoch
      */
     native public long normalize(boolean ignoreDst);
 
@@ -379,13 +379,13 @@
      * Parses a date-time string in either the RFC 2445 format or an abbreviated
      * format that does not include the "time" field.  For example, all of the
      * following strings are valid:
-     * 
+     *
      * <ul>
      *   <li>"20081013T160000Z"</li>
      *   <li>"20081013T160000"</li>
      *   <li>"20081013"</li>
      * </ul>
-     * 
+     *
      * Returns whether or not the time is in UTC (ends with Z).  If the string
      * ends with "Z" then the timezone is set to UTC.  If the date-time string
      * included only a date and no time field, then the <code>allDay</code>
@@ -396,10 +396,10 @@
      * <code>yearDay</code>, and <code>gmtoff</code> are always set to zero,
      * and the field <code>isDst</code> is set to -1 (unknown).  To set those
      * fields, call {@link #normalize(boolean)} after parsing.
-     * 
+     *
      * To parse a date-time string and convert it to UTC milliseconds, do
      * something like this:
-     * 
+     *
      * <pre>
      *   Time time = new Time();
      *   String date = "20081013T160000Z";
@@ -428,25 +428,25 @@
      * Parse a time in RFC 3339 format.  This method also parses simple dates
      * (that is, strings that contain no time or time offset).  For example,
      * all of the following strings are valid:
-     * 
+     *
      * <ul>
      *   <li>"2008-10-13T16:00:00.000Z"</li>
      *   <li>"2008-10-13T16:00:00.000+07:00"</li>
      *   <li>"2008-10-13T16:00:00.000-07:00"</li>
      *   <li>"2008-10-13"</li>
      * </ul>
-     * 
+     *
      * <p>
      * If the string contains a time and time offset, then the time offset will
      * be used to convert the time value to UTC.
      * </p>
-     * 
+     *
      * <p>
      * If the given string contains just a date (with no time field), then
      * the {@link #allDay} field is set to true and the {@link #hour},
      * {@link #minute}, and  {@link #second} fields are set to zero.
      * </p>
-     * 
+     *
      * <p>
      * Returns true if the resulting time value is in UTC time.
      * </p>
@@ -462,7 +462,7 @@
          }
          return false;
      }
-     
+
      native private boolean nativeParse3339(String s);
 
     /**
@@ -484,13 +484,13 @@
      * <em>not</em> change any of the fields in this Time object.  If you want
      * to normalize the fields in this Time object and also get the milliseconds
      * then use {@link #normalize(boolean)}.
-     * 
+     *
      * <p>
      * If "ignoreDst" is false, then this method uses the current setting of the
      * "isDst" field and will adjust the returned time if the "isDst" field is
      * wrong for the given time.  See the sample code below for an example of
      * this.
-     * 
+     *
      * <p>
      * If "ignoreDst" is true, then this method ignores the current setting of
      * the "isDst" field in this Time object and will instead figure out the
@@ -499,27 +499,27 @@
      * correct value of the "isDst" field is when the time is inherently
      * ambiguous because it falls in the hour that is repeated when switching
      * from Daylight-Saving Time to Standard Time.
-     * 
+     *
      * <p>
      * Here is an example where <tt>toMillis(true)</tt> adjusts the time,
      * assuming that DST changes at 2am on Sunday, Nov 4, 2007.
-     * 
+     *
      * <pre>
      * Time time = new Time();
-     * time.set(2007, 10, 4);  // set the date to Nov 4, 2007, 12am
+     * time.set(4, 10, 2007);  // set the date to Nov 4, 2007, 12am
      * time.normalize();       // this sets isDst = 1
      * time.monthDay += 1;     // changes the date to Nov 5, 2007, 12am
      * millis = time.toMillis(false);   // millis is Nov 4, 2007, 11pm
      * millis = time.toMillis(true);    // millis is Nov 5, 2007, 12am
      * </pre>
-     * 
+     *
      * <p>
      * To avoid this problem, use <tt>toMillis(true)</tt>
      * after adding or subtracting days or explicitly setting the "monthDay"
      * field.  On the other hand, if you are adding
      * or subtracting hours or minutes, then you should use
      * <tt>toMillis(false)</tt>.
-     * 
+     *
      * <p>
      * You should also use <tt>toMillis(false)</tt> if you want
      * to read back the same milliseconds that you set with {@link #set(long)}
@@ -531,14 +531,14 @@
      * Sets the fields in this Time object given the UTC milliseconds.  After
      * this method returns, all the fields are normalized.
      * This also sets the "isDst" field to the correct value.
-     * 
+     *
      * @param millis the time in UTC milliseconds since the epoch.
      */
     native public void set(long millis);
 
     /**
      * Format according to RFC 2445 DATETIME type.
-     * 
+     *
      * <p>
      * The same as format("%Y%m%dT%H%M%S").
      */
@@ -584,7 +584,7 @@
      * Sets the date from the given fields.  Also sets allDay to true.
      * Sets weekDay, yearDay and gmtoff to 0, and isDst to -1.
      * Call {@link #normalize(boolean)} if you need those.
-     * 
+     *
      * @param monthDay the day of the month (in the range [1,31])
      * @param month the zero-based month number (in the range [0,11])
      * @param year the year
@@ -606,7 +606,7 @@
     /**
      * Returns true if the time represented by this Time object occurs before
      * the given time.
-     * 
+     *
      * @param that a given Time object to compare against
      * @return true if this time is less than the given time
      */
@@ -618,7 +618,7 @@
     /**
      * Returns true if the time represented by this Time object occurs after
      * the given time.
-     * 
+     *
      * @param that a given Time object to compare against
      * @return true if this time is greater than the given time
      */
@@ -632,12 +632,12 @@
      * closest Thursday yearDay.
      */
     private static final int[] sThursdayOffset = { -3, 3, 2, 1, 0, -1, -2 };
-        
+
     /**
      * Computes the week number according to ISO 8601.  The current Time
      * object must already be normalized because this method uses the
      * yearDay and weekDay fields.
-     * 
+     *
      * <p>
      * In IS0 8601, weeks start on Monday.
      * The first week of the year (week 1) is defined by ISO 8601 as the
@@ -645,12 +645,12 @@
      * Or equivalently, the week containing January 4.  Or equivalently,
      * the week with the year's first Thursday in it.
      * </p>
-     * 
+     *
      * <p>
      * The week number can be calculated by counting Thursdays.  Week N
      * contains the Nth Thursday of the year.
      * </p>
-     *   
+     *
      * @return the ISO week number.
      */
     public int getWeekNumber() {
@@ -661,7 +661,7 @@
         if (closestThursday >= 0 && closestThursday <= 364) {
             return closestThursday / 7 + 1;
         }
-        
+
         // The week crosses a year boundary.
         Time temp = new Time(this);
         temp.monthDay += sThursdayOffset[weekDay];
@@ -670,7 +670,7 @@
     }
 
     /**
-     * Return a string in the RFC 3339 format. 
+     * Return a string in the RFC 3339 format.
      * <p>
      * If allDay is true, expresses the time as Y-M-D</p>
      * <p>
@@ -691,13 +691,13 @@
             int offset = (int)Math.abs(gmtoff);
             int minutes = (offset % 3600) / 60;
             int hours = offset / 3600;
-            
+
             return String.format("%s%s%02d:%02d", base, sign, hours, minutes);
         }
     }
-    
+
     /**
-     * Returns true if the day of the given time is the epoch on the Julian Calendar 
+     * Returns true if the day of the given time is the epoch on the Julian Calendar
      * (January 1, 1970 on the Gregorian calendar).
      *
      * @param time the time to test
@@ -707,7 +707,7 @@
         long millis = time.toMillis(true);
         return getJulianDay(millis, 0) == EPOCH_JULIAN_DAY;
     }
-    
+
     /**
      * Computes the Julian day number, given the UTC milliseconds
      * and the offset (in seconds) from UTC.  The Julian day for a given
@@ -716,10 +716,10 @@
      * what timezone is being used.  The Julian day is useful for testing
      * if two events occur on the same day and for determining the relative
      * time of an event from the present ("yesterday", "3 days ago", etc.).
-     * 
+     *
      * <p>
      * Use {@link #toMillis(boolean)} to get the milliseconds.
-     * 
+     *
      * @param millis the time in UTC milliseconds
      * @param gmtoff the offset from UTC in seconds
      * @return the Julian day
@@ -729,7 +729,7 @@
         long julianDay = (millis + offsetMillis) / DateUtils.DAY_IN_MILLIS;
         return (int) julianDay + EPOCH_JULIAN_DAY;
     }
-    
+
     /**
      * <p>Sets the time from the given Julian day number, which must be based on
      * the same timezone that is set in this Time object.  The "gmtoff" field
@@ -738,7 +738,7 @@
      * After this method returns all the fields will be normalized and the time
      * will be set to 12am at the beginning of the given Julian day.
      * </p>
-     * 
+     *
      * <p>
      * The only exception to this is if 12am does not exist for that day because
      * of daylight saving time.  For example, Cairo, Eqypt moves time ahead one
@@ -746,7 +746,7 @@
      * also change daylight saving time at 12am.  In those cases, the time
      * will be set to 1am.
      * </p>
-     * 
+     *
      * @param julianDay the Julian day in the timezone for this Time object
      * @return the UTC milliseconds for the beginning of the Julian day
      */
@@ -756,13 +756,13 @@
         // the day.
         long millis = (julianDay - EPOCH_JULIAN_DAY) * DateUtils.DAY_IN_MILLIS;
         set(millis);
-        
+
         // Figure out how close we are to the requested Julian day.
         // We can't be off by more than a day.
         int approximateDay = getJulianDay(millis, gmtoff);
         int diff = julianDay - approximateDay;
         monthDay += diff;
-        
+
         // Set the time to 12am and re-normalize.
         hour = 0;
         minute = 0;
diff --git a/core/java/android/text/method/ArrowKeyMovementMethod.java b/core/java/android/text/method/ArrowKeyMovementMethod.java
index 9af42cc..79a0c37 100644
--- a/core/java/android/text/method/ArrowKeyMovementMethod.java
+++ b/core/java/android/text/method/ArrowKeyMovementMethod.java
@@ -16,30 +16,38 @@
 
 package android.text.method;
 
-import android.util.Log;
+import android.text.Layout;
+import android.text.Selection;
+import android.text.Spannable;
 import android.view.KeyEvent;
-import android.graphics.Rect;
-import android.text.*;
-import android.widget.TextView;
-import android.view.View;
-import android.view.ViewConfiguration;
 import android.view.MotionEvent;
+import android.view.View;
+import android.widget.TextView;
+import android.widget.TextView.CursorController;
 
 // XXX this doesn't extend MetaKeyKeyListener because the signatures
 // don't match.  Need to figure that out.  Meanwhile the meta keys
 // won't work in fields that don't take input.
 
-public class
-ArrowKeyMovementMethod
-implements MovementMethod
-{
+public class ArrowKeyMovementMethod implements MovementMethod {
+    /**
+     * An optional controller for the cursor.
+     * Use {@link #setCursorController(CursorController)} to set this field.
+     */
+    protected CursorController mCursorController;
+
+    private boolean isCap(Spannable buffer) {
+        return ((MetaKeyKeyListener.getMetaState(buffer, KeyEvent.META_SHIFT_ON) == 1) ||
+                (MetaKeyKeyListener.getMetaState(buffer, MetaKeyKeyListener.META_SELECTING) != 0));
+    }
+
+    private boolean isAlt(Spannable buffer) {
+        return MetaKeyKeyListener.getMetaState(buffer, KeyEvent.META_ALT_ON) == 1;
+    }
+
     private boolean up(TextView widget, Spannable buffer) {
-        boolean cap = (MetaKeyKeyListener.getMetaState(buffer,
-                        KeyEvent.META_SHIFT_ON) == 1) ||
-                      (MetaKeyKeyListener.getMetaState(buffer,
-                        MetaKeyKeyListener.META_SELECTING) != 0);
-        boolean alt = MetaKeyKeyListener.getMetaState(buffer,
-                        KeyEvent.META_ALT_ON) == 1;
+        boolean cap = isCap(buffer);
+        boolean alt = isAlt(buffer);
         Layout layout = widget.getLayout();
 
         if (cap) {
@@ -60,12 +68,8 @@
     }
 
     private boolean down(TextView widget, Spannable buffer) {
-        boolean cap = (MetaKeyKeyListener.getMetaState(buffer,
-                        KeyEvent.META_SHIFT_ON) == 1) ||
-                      (MetaKeyKeyListener.getMetaState(buffer,
-                        MetaKeyKeyListener.META_SELECTING) != 0);
-        boolean alt = MetaKeyKeyListener.getMetaState(buffer,
-                        KeyEvent.META_ALT_ON) == 1;
+        boolean cap = isCap(buffer);
+        boolean alt = isAlt(buffer);
         Layout layout = widget.getLayout();
 
         if (cap) {
@@ -86,12 +90,8 @@
     }
 
     private boolean left(TextView widget, Spannable buffer) {
-        boolean cap = (MetaKeyKeyListener.getMetaState(buffer,
-                        KeyEvent.META_SHIFT_ON) == 1) ||
-                      (MetaKeyKeyListener.getMetaState(buffer,
-                        MetaKeyKeyListener.META_SELECTING) != 0);
-        boolean alt = MetaKeyKeyListener.getMetaState(buffer,
-                        KeyEvent.META_ALT_ON) == 1;
+        boolean cap = isCap(buffer);
+        boolean alt = isAlt(buffer);
         Layout layout = widget.getLayout();
 
         if (cap) {
@@ -110,12 +110,8 @@
     }
 
     private boolean right(TextView widget, Spannable buffer) {
-        boolean cap = (MetaKeyKeyListener.getMetaState(buffer,
-                        KeyEvent.META_SHIFT_ON) == 1) ||
-                      (MetaKeyKeyListener.getMetaState(buffer,
-                        MetaKeyKeyListener.META_SELECTING) != 0);
-        boolean alt = MetaKeyKeyListener.getMetaState(buffer,
-                        KeyEvent.META_ALT_ON) == 1;
+        boolean cap = isCap(buffer);
+        boolean alt = isAlt(buffer);
         Layout layout = widget.getLayout();
 
         if (cap) {
@@ -133,35 +129,6 @@
         }
     }
 
-    private int getOffset(int x, int y, TextView widget){
-      // Converts the absolute X,Y coordinates to the character offset for the
-      // character whose position is closest to the specified
-      // horizontal position.
-      x -= widget.getTotalPaddingLeft();
-      y -= widget.getTotalPaddingTop();
-
-      // Clamp the position to inside of the view.
-      if (x < 0) {
-          x = 0;
-      } else if (x >= (widget.getWidth()-widget.getTotalPaddingRight())) {
-          x = widget.getWidth()-widget.getTotalPaddingRight() - 1;
-      }
-      if (y < 0) {
-          y = 0;
-      } else if (y >= (widget.getHeight()-widget.getTotalPaddingBottom())) {
-          y = widget.getHeight()-widget.getTotalPaddingBottom() - 1;
-      }
-
-      x += widget.getScrollX();
-      y += widget.getScrollY();
-
-      Layout layout = widget.getLayout();
-      int line = layout.getLineForVertical(y);
-
-      int offset = layout.getOffsetForHorizontal(line, x);
-      return offset;
-    }
-
     public boolean onKeyDown(TextView widget, Spannable buffer, int keyCode, KeyEvent event) {
         if (executeDown(widget, buffer, keyCode)) {
             MetaKeyKeyListener.adjustMetaAfterKeypress(buffer);
@@ -193,10 +160,9 @@
             break;
 
         case KeyEvent.KEYCODE_DPAD_CENTER:
-            if (MetaKeyKeyListener.getMetaState(buffer, MetaKeyKeyListener.META_SELECTING) != 0) {
-                if (widget.showContextMenu()) {
+            if ((MetaKeyKeyListener.getMetaState(buffer, MetaKeyKeyListener.META_SELECTING) != 0) &&
+                (widget.showContextMenu())) {
                     handled = true;
-                }
             }
         }
 
@@ -214,8 +180,7 @@
 
     public boolean onKeyOther(TextView view, Spannable text, KeyEvent event) {
         int code = event.getKeyCode();
-        if (code != KeyEvent.KEYCODE_UNKNOWN
-                && event.getAction() == KeyEvent.ACTION_MULTIPLE) {
+        if (code != KeyEvent.KEYCODE_UNKNOWN && event.getAction() == KeyEvent.ACTION_MULTIPLE) {
             int repeat = event.getRepeatCount();
             boolean handled = false;
             while ((--repeat) > 0) {
@@ -226,13 +191,22 @@
         return false;
     }
 
-    public boolean onTrackballEvent(TextView widget, Spannable text,
-            MotionEvent event) {
+    public boolean onTrackballEvent(TextView widget, Spannable text, MotionEvent event) {
+        if (mCursorController != null) {
+            mCursorController.hide();
+        }
         return false;
     }
 
-    public boolean onTouchEvent(TextView widget, Spannable buffer,
-                                MotionEvent event) {
+    public boolean onTouchEvent(TextView widget, Spannable buffer, MotionEvent event) {
+        if (mCursorController != null) {
+            return onTouchEventCursor(widget, buffer, event);
+        } else {
+            return onTouchEventStandard(widget, buffer, event);
+        }
+    }
+
+    private boolean onTouchEventStandard(TextView widget, Spannable buffer, MotionEvent event) {
         int initialScrollX = -1, initialScrollY = -1;
         if (event.getAction() == MotionEvent.ACTION_UP) {
             initialScrollX = Touch.getInitialScrollX(widget, buffer);
@@ -243,53 +217,20 @@
 
         if (widget.isFocused() && !widget.didTouchFocusSelect()) {
             if (event.getAction() == MotionEvent.ACTION_DOWN) {
-              boolean cap = (MetaKeyKeyListener.getMetaState(buffer,
-                              KeyEvent.META_SHIFT_ON) == 1) ||
-                            (MetaKeyKeyListener.getMetaState(buffer,
-                              MetaKeyKeyListener.META_SELECTING) != 0);
-              int x = (int) event.getX();
-              int y = (int) event.getY();
-              int offset = getOffset(x, y, widget);
-
+              boolean cap = isCap(buffer);
               if (cap) {
-                  buffer.setSpan(LAST_TAP_DOWN, offset, offset,
-                                 Spannable.SPAN_POINT_POINT);
+                  int offset = widget.getOffset((int) event.getX(), (int) event.getY());
+                  
+                  buffer.setSpan(LAST_TAP_DOWN, offset, offset, Spannable.SPAN_POINT_POINT);
 
                   // Disallow intercepting of the touch events, so that
                   // users can scroll and select at the same time.
                   // without this, users would get booted out of select
                   // mode once the view detected it needed to scroll.
                   widget.getParent().requestDisallowInterceptTouchEvent(true);
-              } else {
-                  OnePointFiveTapState[] tap = buffer.getSpans(0, buffer.length(),
-                      OnePointFiveTapState.class);
-
-                  if (tap.length > 0) {
-                      if (event.getEventTime() - tap[0].mWhen <=
-                          ViewConfiguration.getDoubleTapTimeout() &&
-                          sameWord(buffer, offset, Selection.getSelectionEnd(buffer))) {
-
-                          tap[0].active = true;
-                          MetaKeyKeyListener.startSelecting(widget, buffer);
-                          widget.getParent().requestDisallowInterceptTouchEvent(true);
-                          buffer.setSpan(LAST_TAP_DOWN, offset, offset,
-                              Spannable.SPAN_POINT_POINT);
-                      }
-
-                      tap[0].mWhen = event.getEventTime();
-                  } else {
-                      OnePointFiveTapState newtap = new OnePointFiveTapState();
-                      newtap.mWhen = event.getEventTime();
-                      newtap.active = false;
-                      buffer.setSpan(newtap, 0, buffer.length(),
-                          Spannable.SPAN_INCLUSIVE_INCLUSIVE);
-                  }
               }
             } else if (event.getAction() == MotionEvent.ACTION_MOVE) {
-                boolean cap = (MetaKeyKeyListener.getMetaState(buffer,
-                                KeyEvent.META_SHIFT_ON) == 1) ||
-                              (MetaKeyKeyListener.getMetaState(buffer,
-                                MetaKeyKeyListener.META_SELECTING) != 0);
+                boolean cap = isCap(buffer);
 
                 if (cap && handled) {
                     // Before selecting, make sure we've moved out of the "slop".
@@ -297,45 +238,15 @@
                     // OUT of the slop
 
                     // Turn long press off while we're selecting. User needs to
-                    // re-tap on the selection to enable longpress
+                    // re-tap on the selection to enable long press
                     widget.cancelLongPress();
 
                     // Update selection as we're moving the selection area.
 
                     // Get the current touch position
-                    int x = (int) event.getX();
-                    int y = (int) event.getY();
-                    int offset = getOffset(x, y, widget);
+                    int offset = widget.getOffset((int) event.getX(), (int) event.getY());
 
-                    final OnePointFiveTapState[] tap = buffer.getSpans(0, buffer.length(),
-                            OnePointFiveTapState.class);
-
-                    if (tap.length > 0 && tap[0].active) {
-                        // Get the last down touch position (the position at which the
-                        // user started the selection)
-                        int lastDownOffset = buffer.getSpanStart(LAST_TAP_DOWN);
-
-                        // Compute the selection boundaries
-                        int spanstart;
-                        int spanend;
-                        if (offset >= lastDownOffset) {
-                            // Expand from word start of the original tap to new word
-                            // end, since we are selecting "forwards"
-                            spanstart = findWordStart(buffer, lastDownOffset);
-                            spanend = findWordEnd(buffer, offset);
-                        } else {
-                            // Expand to from new word start to word end of the original
-                            // tap since we are selecting "backwards".
-                            // The spanend will always need to be associated with the touch
-                            // up position, so that refining the selection with the
-                            // trackball will work as expected.
-                            spanstart = findWordEnd(buffer, lastDownOffset);
-                            spanend = findWordStart(buffer, offset);
-                        }
-                        Selection.setSelection(buffer, spanstart, spanend);
-                    } else {
-                        Selection.extendSelection(buffer, offset);
-                    }
+                    Selection.extendSelection(buffer, offset);
                     return true;
                 }
             } else if (event.getAction() == MotionEvent.ACTION_UP) {
@@ -344,70 +255,17 @@
                 // the current scroll offset to avoid the scroll jumping later
                 // to show it.
                 if ((initialScrollY >= 0 && initialScrollY != widget.getScrollY()) ||
-                        (initialScrollX >= 0 && initialScrollX != widget.getScrollX())) {
+                    (initialScrollX >= 0 && initialScrollX != widget.getScrollX())) {
                     widget.moveCursorToVisibleOffset();
                     return true;
                 }
 
-                int x = (int) event.getX();
-                int y = (int) event.getY();
-                int off = getOffset(x, y, widget);
-
-                // XXX should do the same adjust for x as we do for the line.
-
-                OnePointFiveTapState[] onepointfivetap = buffer.getSpans(0, buffer.length(),
-                    OnePointFiveTapState.class);
-                if (onepointfivetap.length > 0 && onepointfivetap[0].active &&
-                    Selection.getSelectionStart(buffer) == Selection.getSelectionEnd(buffer)) {
-                    // If we've set select mode, because there was a onepointfivetap,
-                    // but there was no ensuing swipe gesture, undo the select mode
-                    // and remove reference to the last onepointfivetap.
-                    MetaKeyKeyListener.stopSelecting(widget, buffer);
-                    for (int i=0; i < onepointfivetap.length; i++) {
-                        buffer.removeSpan(onepointfivetap[i]);
-                    }
+                int offset = widget.getOffset((int) event.getX(), (int) event.getY());
+                if (isCap(buffer)) {
                     buffer.removeSpan(LAST_TAP_DOWN);
-                }
-                boolean cap = (MetaKeyKeyListener.getMetaState(buffer,
-                                KeyEvent.META_SHIFT_ON) == 1) ||
-                              (MetaKeyKeyListener.getMetaState(buffer,
-                                MetaKeyKeyListener.META_SELECTING) != 0);
-
-                DoubleTapState[] tap = buffer.getSpans(0, buffer.length(),
-                                                       DoubleTapState.class);
-                boolean doubletap = false;
-
-                if (tap.length > 0) {
-                    if (event.getEventTime() - tap[0].mWhen <=
-                        ViewConfiguration.getDoubleTapTimeout() &&
-                        sameWord(buffer, off, Selection.getSelectionEnd(buffer))) {
-
-                        doubletap = true;
-                    }
-
-                    tap[0].mWhen = event.getEventTime();
+                    Selection.extendSelection(buffer, offset);
                 } else {
-                    DoubleTapState newtap = new DoubleTapState();
-                    newtap.mWhen = event.getEventTime();
-                    buffer.setSpan(newtap, 0, buffer.length(),
-                                   Spannable.SPAN_INCLUSIVE_INCLUSIVE);
-                }
-
-                if (cap) {
-                    buffer.removeSpan(LAST_TAP_DOWN);
-                    if (onepointfivetap.length > 0 && onepointfivetap[0].active) {
-                        // If we selecting something with the onepointfivetap-and
-                        // swipe gesture, stop it on finger up.
-                        MetaKeyKeyListener.stopSelecting(widget, buffer);
-                    } else {
-                        Selection.extendSelection(buffer, off);
-                    }
-                } else if (doubletap) {
-                    Selection.setSelection(buffer,
-                                           findWordStart(buffer, off),
-                                           findWordEnd(buffer, off));
-                } else {
-                    Selection.setSelection(buffer, off);
+                    Selection.setSelection(buffer, offset);
                 }
 
                 MetaKeyKeyListener.adjustMetaAfterKeypress(buffer);
@@ -420,73 +278,36 @@
         return handled;
     }
 
-    private static class DoubleTapState implements NoCopySpan {
-        long mWhen;
-    }
+    private boolean onTouchEventCursor(TextView widget, Spannable buffer, MotionEvent event) {
+        if (widget.isFocused() && !widget.didTouchFocusSelect()) {
+            switch (event.getActionMasked()) {
+                case MotionEvent.ACTION_MOVE:
+                    widget.cancelLongPress();
 
-    /* We check for a onepointfive tap. This is similar to
-    *  doubletap gesture (where a finger goes down, up, down, up, in a short
-    *  time period), except in the onepointfive tap, a users finger only needs
-    *  to go down, up, down in a short time period. We detect this type of tap
-    *  to implement the onepointfivetap-and-swipe selection gesture.
-    *  This gesture allows users to select a segment of text without going
-    *  through the "select text" option in the context menu.
-    */
-    private static class OnePointFiveTapState implements NoCopySpan {
-        long mWhen;
-        boolean active;
-    }
+                    // Offset the current touch position (from controller to cursor)
+                    final float x = event.getX() + mCursorController.getOffsetX();
+                    final float y = event.getY() + mCursorController.getOffsetY();
+                    int offset = widget.getOffset((int) x, (int) y);
+                    mCursorController.updatePosition(offset);
+                    return true;
 
-    private static boolean sameWord(CharSequence text, int one, int two) {
-        int start = findWordStart(text, one);
-        int end = findWordEnd(text, one);
-
-        if (end == start) {
-            return false;
-        }
-
-        return start == findWordStart(text, two) &&
-               end == findWordEnd(text, two);
-    }
-
-    // TODO: Unify with TextView.getWordForDictionary()
-    private static int findWordStart(CharSequence text, int start) {
-        for (; start > 0; start--) {
-            char c = text.charAt(start - 1);
-            int type = Character.getType(c);
-
-            if (c != '\'' &&
-                type != Character.UPPERCASE_LETTER &&
-                type != Character.LOWERCASE_LETTER &&
-                type != Character.TITLECASE_LETTER &&
-                type != Character.MODIFIER_LETTER &&
-                type != Character.DECIMAL_DIGIT_NUMBER) {
-                break;
+                case MotionEvent.ACTION_UP:
+                case MotionEvent.ACTION_CANCEL:
+                    mCursorController = null;
+                    return true;
             }
         }
-
-        return start;
+        return false;
     }
 
-    // TODO: Unify with TextView.getWordForDictionary()
-    private static int findWordEnd(CharSequence text, int end) {
-        int len = text.length();
-
-        for (; end < len; end++) {
-            char c = text.charAt(end);
-            int type = Character.getType(c);
-
-            if (c != '\'' &&
-                type != Character.UPPERCASE_LETTER &&
-                type != Character.LOWERCASE_LETTER &&
-                type != Character.TITLECASE_LETTER &&
-                type != Character.MODIFIER_LETTER &&
-                type != Character.DECIMAL_DIGIT_NUMBER) {
-                break;
-            }
-        }
-
-        return end;
+    /**
+     * Defines the cursor controller.
+     *
+     * When set, this object can be used to handle events, that can be translated in cursor updates.
+     * @param cursorController A cursor controller implementation
+     */
+    public void setCursorController(CursorController cursorController) {
+        mCursorController = cursorController;
     }
 
     public boolean canSelectArbitrarily() {
@@ -525,8 +346,9 @@
     }
 
     public static MovementMethod getInstance() {
-        if (sInstance == null)
+        if (sInstance == null) {
             sInstance = new ArrowKeyMovementMethod();
+        }
 
         return sInstance;
     }
diff --git a/core/java/android/text/method/Touch.java b/core/java/android/text/method/Touch.java
index c30db20..3b98fc3 100644
--- a/core/java/android/text/method/Touch.java
+++ b/core/java/android/text/method/Touch.java
@@ -17,9 +17,9 @@
 package android.text.method;
 
 import android.text.Layout;
+import android.text.Layout.Alignment;
 import android.text.NoCopySpan;
 import android.text.Spannable;
-import android.text.Layout.Alignment;
 import android.view.KeyEvent;
 import android.view.MotionEvent;
 import android.view.ViewConfiguration;
@@ -102,7 +102,7 @@
                                        MotionEvent event) {
         DragState[] ds;
 
-        switch (event.getAction()) {
+        switch (event.getActionMasked()) {
         case MotionEvent.ACTION_DOWN:
             ds = buffer.getSpans(0, buffer.length(), DragState.class);
 
diff --git a/core/java/android/util/SparseArray.java b/core/java/android/util/SparseArray.java
index 1c8b330..7fc43b9 100644
--- a/core/java/android/util/SparseArray.java
+++ b/core/java/android/util/SparseArray.java
@@ -90,6 +90,16 @@
         delete(key);
     }
 
+    /**
+     * Removes the mapping at the specified index.
+     */
+    public void removeAt(int index) {
+        if (mValues[index] != DELETED) {
+            mValues[index] = DELETED;
+            mGarbage = true;
+        }
+    }
+    
     private void gc() {
         // Log.e("SparseArray", "gc start with " + mSize);
 
diff --git a/core/java/android/view/AbsSavedState.java b/core/java/android/view/AbsSavedState.java
index 840d7c1..6ad33dd 100644
--- a/core/java/android/view/AbsSavedState.java
+++ b/core/java/android/view/AbsSavedState.java
@@ -54,7 +54,7 @@
      */
     protected AbsSavedState(Parcel source) {
         // FIXME need class loader
-        Parcelable superState = (Parcelable) source.readParcelable(null);
+        Parcelable superState = source.readParcelable(null);
          
         mSuperState = superState != null ? superState : EMPTY_STATE;
     }
@@ -75,7 +75,7 @@
         = new Parcelable.Creator<AbsSavedState>() {
         
         public AbsSavedState createFromParcel(Parcel in) {
-            Parcelable superState = (Parcelable) in.readParcelable(null);
+            Parcelable superState = in.readParcelable(null);
             if (superState != null) {
                 throw new IllegalStateException("superState must be null");
             }
diff --git a/core/java/android/view/GLES20Canvas.java b/core/java/android/view/GLES20Canvas.java
index 00dc128..a2ab8bd 100644
--- a/core/java/android/view/GLES20Canvas.java
+++ b/core/java/android/view/GLES20Canvas.java
@@ -17,16 +17,21 @@
 package android.view;
 
 import android.graphics.Bitmap;
+import android.graphics.BitmapShader;
 import android.graphics.Canvas;
 import android.graphics.DrawFilter;
+import android.graphics.LinearGradient;
 import android.graphics.Matrix;
 import android.graphics.Paint;
 import android.graphics.Path;
 import android.graphics.Picture;
 import android.graphics.PorterDuff;
+import android.graphics.RadialGradient;
 import android.graphics.Rect;
 import android.graphics.RectF;
 import android.graphics.Region;
+import android.graphics.Shader;
+import android.graphics.SweepGradient;
 
 import javax.microedition.khronos.opengles.GL;
 
@@ -45,6 +50,10 @@
     
     private final float[] mPoint = new float[2];
     private final float[] mLine = new float[4];
+    
+    private final Rect mClipBounds = new Rect();
+
+    private DrawFilter mFilter;
 
     ///////////////////////////////////////////////////////////////////////////
     // Constructors
@@ -164,6 +173,7 @@
 
     @Override
     public boolean clipRect(Rect rect, Region.Op op) {
+        // TODO: Implement
         throw new UnsupportedOperationException();
     }
 
@@ -174,6 +184,7 @@
 
     @Override
     public boolean clipRect(RectF rect, Region.Op op) {
+        // TODO: Implement
         throw new UnsupportedOperationException();
     }
 
@@ -336,12 +347,14 @@
 
     @Override
     public void setDrawFilter(DrawFilter filter) {
-        throw new UnsupportedOperationException();
+        // Don't crash, but ignore the draw filter
+        // TODO: Implement PaintDrawFilter
+        mFilter = filter;
     }
 
     @Override
     public DrawFilter getDrawFilter() {
-        throw new UnsupportedOperationException();
+        return mFilter;
     }
 
     ///////////////////////////////////////////////////////////////////////////
@@ -361,71 +374,77 @@
 
     @Override
     public void drawPatch(Bitmap bitmap, byte[] chunks, RectF dst, Paint paint) {
+        // Shaders are ignored when drawing patches
         final int nativePaint = paint == null ? 0 : paint.mNativePaint;
-        nDrawPatch(mRenderer, bitmap.mNativeBitmap, chunks, dst.left, dst.top, dst.right,
-                dst.bottom, nativePaint, bitmap.getDensity(), mDensity, mScreenDensity);
+        nDrawPatch(mRenderer, bitmap.mNativeBitmap, chunks, dst.left, dst.top,
+                dst.right, dst.bottom, nativePaint);
     }
 
     private native void nDrawPatch(int renderer, int bitmap, byte[] chunks, float left, float top,
-            float right, float bottom, int paint, int bitmapDensity, int canvasDensity, int screenDensity);
+            float right, float bottom, int paint);
 
     @Override
     public void drawBitmap(Bitmap bitmap, float left, float top, Paint paint) {
+        // Shaders are ignored when drawing bitmaps
         final int nativePaint = paint == null ? 0 : paint.mNativePaint;
-        nDrawBitmap(mRenderer, bitmap.mNativeBitmap, left, top, nativePaint,
-                bitmap.getDensity(), mDensity, mScreenDensity);
+        nDrawBitmap(mRenderer, bitmap.mNativeBitmap, left, top, nativePaint);
     }
 
+    private native void nDrawBitmap(int renderer, int bitmap, float left, float top, int paint);
+
     @Override
     public void drawBitmap(Bitmap bitmap, Matrix matrix, Paint paint) {
+        // Shaders are ignored when drawing bitmaps
         final int nativePaint = paint == null ? 0 : paint.mNativePaint;
-        nDrawBitmap(mRenderer, bitmap.mNativeBitmap, matrix.native_instance, nativePaint,
-                bitmap.getDensity(), mDensity, mScreenDensity);
+        nDrawBitmap(mRenderer, bitmap.mNativeBitmap, matrix.native_instance, nativePaint);
     }
 
-    private native void nDrawBitmap(int renderer, int bitmap, int matrix, int paint,
-            int bitmapDensity, int canvasDensity, int screenDensity);
+    private native void nDrawBitmap(int renderer, int bitmap, int matrix, int paint);
 
     @Override
     public void drawBitmap(Bitmap bitmap, Rect src, Rect dst, Paint paint) {
+        // Shaders are ignored when drawing bitmaps
         final int nativePaint = paint == null ? 0 : paint.mNativePaint;
         nDrawBitmap(mRenderer, bitmap.mNativeBitmap, src.left, src.top, src.right, src.bottom,
-                dst.left, dst.top, dst.right, dst.bottom, nativePaint,
-                bitmap.getDensity(), mDensity, mScreenDensity);
+                dst.left, dst.top, dst.right, dst.bottom, nativePaint
+        );
     }
 
     @Override
     public void drawBitmap(Bitmap bitmap, Rect src, RectF dst, Paint paint) {
+        // Shaders are ignored when drawing bitmaps
         final int nativePaint = paint == null ? 0 : paint.mNativePaint;
         nDrawBitmap(mRenderer, bitmap.mNativeBitmap, src.left, src.top, src.right, src.bottom,
-                dst.left, dst.top, dst.right, dst.bottom, nativePaint,
-                bitmap.getDensity(), mDensity, mScreenDensity);
+                dst.left, dst.top, dst.right, dst.bottom, nativePaint
+        );
     }
 
-    private native void nDrawBitmap(int renderer, int bitmap, float left, float top, int paint,
-            int bitmapDensity, int canvasDensity, int screenDensity);
-
     private native void nDrawBitmap(int renderer, int bitmap,
             float srcLeft, float srcTop, float srcRight, float srcBottom,
-            float left, float top, float right, float bottom, int paint,
-            int bitmapDensity, int canvasDensity, int screenDensity);
+            float left, float top, float right, float bottom, int paint);
 
     @Override
     public void drawBitmap(int[] colors, int offset, int stride, float x, float y,
             int width, int height, boolean hasAlpha, Paint paint) {
-        // TODO: Implement
+        // Shaders are ignored when drawing bitmaps
+        final Bitmap.Config config = hasAlpha ? Bitmap.Config.ARGB_8888 : Bitmap.Config.RGB_565;
+        final Bitmap b = Bitmap.createBitmap(colors, offset, stride, width, height, config);
+        final int nativePaint = paint == null ? 0 : paint.mNativePaint;
+        nDrawBitmap(mRenderer, b.mNativeBitmap, x, y, nativePaint);
+        b.recycle();
     }
 
     @Override
     public void drawBitmap(int[] colors, int offset, int stride, int x, int y,
             int width, int height, boolean hasAlpha, Paint paint) {
+        // Shaders are ignored when drawing bitmaps
         drawBitmap(colors, offset, stride, (float) x, (float) y, width, height, hasAlpha, paint);
     }
 
     @Override
     public void drawBitmapMesh(Bitmap bitmap, int meshWidth, int meshHeight, float[] verts,
             int vertOffset, int[] colors, int colorOffset, Paint paint) {
-        throw new UnsupportedOperationException();
+        // TODO: Implement
     }
 
     @Override
@@ -471,7 +490,9 @@
 
     @Override
     public void drawPaint(Paint paint) {
-        // TODO: Implement
+        final Rect r = mClipBounds;
+        nGetClipBounds(mRenderer, r);
+        drawRect(r.left, r.top, r.right, r.bottom, paint);
     }
 
     @Override
@@ -523,7 +544,9 @@
 
     @Override
     public void drawRect(float left, float top, float right, float bottom, Paint paint) {
+        boolean hasShader = setupShader(paint);
         nDrawRect(mRenderer, left, top, right, bottom, paint.mNativePaint);
+        if (hasShader) nResetShader(mRenderer);
     }
 
     private native void nDrawRect(int renderer, float left, float top, float right, float bottom,
@@ -546,7 +569,7 @@
 
     @Override
     public void drawRoundRect(RectF rect, float rx, float ry, Paint paint) {
-        throw new UnsupportedOperationException();
+        // TODO: Implement
     }
 
     @Override
@@ -596,6 +619,29 @@
     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) {
-        throw new UnsupportedOperationException();
+        // TODO: Implement
     }
+
+    private boolean setupShader(Paint paint) {
+        final Shader shader = paint.getShader();
+        if (shader != null) {
+            if (shader instanceof BitmapShader) {
+                final BitmapShader bs = (BitmapShader) shader;
+                nSetupBitmapShader(mRenderer, bs.native_instance, bs.mBitmap.mNativeBitmap,
+                        bs.mTileX, bs.mTileY, bs.mLocalMatrix);
+                return true;
+            } else if (shader instanceof LinearGradient) {
+                // TODO: Implement
+            } else if (shader instanceof RadialGradient) {
+                // TODO: Implement
+            } else if (shader instanceof SweepGradient) {
+                // TODO: Implement
+            }
+        }
+        return false;
+    }
+    
+    private native void nSetupBitmapShader(int renderer, int shader, int bitmap,
+            int tileX, int tileY, int matrix);
+    private native void nResetShader(int renderer);  
 }
diff --git a/core/java/android/view/HardwareRenderer.java b/core/java/android/view/HardwareRenderer.java
index d30bce9..090a743 100644
--- a/core/java/android/view/HardwareRenderer.java
+++ b/core/java/android/view/HardwareRenderer.java
@@ -17,10 +17,8 @@
 
 package android.view;
 
-import android.content.res.CompatibilityInfo;
 import android.graphics.Canvas;
 import android.os.SystemClock;
-import android.util.DisplayMetrics;
 import android.util.Log;
 
 import javax.microedition.khronos.egl.EGL10;
@@ -74,14 +72,8 @@
      * 
      * @param view The view to draw.
      * @param attachInfo AttachInfo tied to the specified view.
-     * @param translator Translator used to draw applications in compatibility mode.
-     * @param yoff The vertical offset for the drawing.
-     * @param density The density of the application
-     * @param scalingRequired Whether drawing should be scaled.
      */
-    abstract void draw(View view, View.AttachInfo attachInfo,
-            CompatibilityInfo.Translator translator, int yoff, int density,
-            boolean scalingRequired);
+    abstract void draw(View view, View.AttachInfo attachInfo, int yOffset);
 
     /**
      * Initializes the hardware renderer for the specified surface and setup the
@@ -371,9 +363,7 @@
         }
 
         @Override
-        void draw(View view, View.AttachInfo attachInfo, CompatibilityInfo.Translator translator,
-                int yoff, int density, boolean scalingRequired) {
-
+        void draw(View view, View.AttachInfo attachInfo, int yOffset) {
             if (canDraw()) {
                 attachInfo.mDrawingTime = SystemClock.uptimeMillis();
                 attachInfo.mIgnoreDirtyState = true;
@@ -383,14 +373,9 @@
 
                 Canvas canvas = mCanvas;
                 int saveCount = canvas.save(Canvas.MATRIX_SAVE_FLAG);
+                canvas.translate(0, -yOffset);
+
                 try {
-                    canvas.translate(0, -yoff);
-                    if (translator != null) {
-                        translator.translateCanvas(canvas);
-                    }
-                    canvas.setDensity(density);
-                    canvas.setScreenDensity(scalingRequired ? DisplayMetrics.DENSITY_DEVICE : 0);
-    
                     view.draw(canvas);
                 } finally {
                     canvas.restoreToCount(saveCount);
diff --git a/core/java/android/view/IWindow.aidl b/core/java/android/view/IWindow.aidl
index 3b09808..921018a 100644
--- a/core/java/android/view/IWindow.aidl
+++ b/core/java/android/view/IWindow.aidl
@@ -46,9 +46,6 @@
 
     void resized(int w, int h, in Rect coveredInsets, in Rect visibleInsets,
             boolean reportDraw, in Configuration newConfig);
-    void dispatchKey(in KeyEvent event);
-    void dispatchPointer(in MotionEvent event, long eventTime, boolean callWhenDone);
-    void dispatchTrackball(in MotionEvent event, long eventTime, boolean callWhenDone);
     void dispatchAppVisibility(boolean visible);
     void dispatchGetNewSurface();
 
diff --git a/core/java/android/view/IWindowSession.aidl b/core/java/android/view/IWindowSession.aidl
index 4647fb4..7f10b76 100644
--- a/core/java/android/view/IWindowSession.aidl
+++ b/core/java/android/view/IWindowSession.aidl
@@ -109,10 +109,6 @@
     void getDisplayFrame(IWindow window, out Rect outDisplayFrame);
     
     void finishDrawing(IWindow window);
-
-    void finishKey(IWindow window);
-    MotionEvent getPendingPointerMove(IWindow window);
-    MotionEvent getPendingTrackballMove(IWindow window);
     
     void setInTouchMode(boolean showFocus);
     boolean getInTouchMode();
diff --git a/core/java/android/view/KeyEvent.java b/core/java/android/view/KeyEvent.java
index 0bfb6d6..9c05008 100755
--- a/core/java/android/view/KeyEvent.java
+++ b/core/java/android/view/KeyEvent.java
@@ -124,11 +124,27 @@
     public static final int KEYCODE_PAGE_DOWN       = 93;
     public static final int KEYCODE_PICTSYMBOLS     = 94;   // switch symbol-sets (Emoji,Kao-moji)
     public static final int KEYCODE_SWITCH_CHARSET  = 95;   // switch char-sets (Kanji,Katakana)
+    public static final int KEYCODE_BUTTON_A        = 96;
+    public static final int KEYCODE_BUTTON_B        = 97;
+    public static final int KEYCODE_BUTTON_C        = 98;
+    public static final int KEYCODE_BUTTON_X        = 99;
+    public static final int KEYCODE_BUTTON_Y        = 100;
+    public static final int KEYCODE_BUTTON_Z        = 101;
+    public static final int KEYCODE_BUTTON_L1       = 102;
+    public static final int KEYCODE_BUTTON_R1       = 103;
+    public static final int KEYCODE_BUTTON_L2       = 104;
+    public static final int KEYCODE_BUTTON_R2       = 105;
+    public static final int KEYCODE_BUTTON_THUMBL   = 106;
+    public static final int KEYCODE_BUTTON_THUMBR   = 107;
+    public static final int KEYCODE_BUTTON_START    = 108;
+    public static final int KEYCODE_BUTTON_SELECT   = 109;
+    public static final int KEYCODE_BUTTON_MODE     = 110;
 
     // NOTE: If you add a new keycode here you must also add it to:
     //  isSystem()
     //  native/include/android/keycodes.h
     //  frameworks/base/include/ui/KeycodeLabels.h
+    //  external/webkit/WebKit/android/plugins/ANPKeyCodes.h
     //  tools/puppet_master/PuppetMaster/nav_keys.py
     //  frameworks/base/core/res/res/values/attrs.xml
     //  commands/monkey/Monkey.java
diff --git a/core/java/android/view/MotionEvent.java b/core/java/android/view/MotionEvent.java
index ae8c21d..35e229a 100644
--- a/core/java/android/view/MotionEvent.java
+++ b/core/java/android/view/MotionEvent.java
@@ -722,7 +722,7 @@
      * 
      * @param pointerId The identifier of the pointer to be found.
      * @return Returns either the index of the pointer (for use with
-     * {@link #getX(int) et al.), or -1 if there is no data available for
+     * {@link #getX(int)} et al.), or -1 if there is no data available for
      * that pointer identifier.
      */
     public final int findPointerIndex(int pointerId) {
diff --git a/core/java/android/view/RawInputEvent.java b/core/java/android/view/RawInputEvent.java
deleted file mode 100644
index 3bbfea8..0000000
--- a/core/java/android/view/RawInputEvent.java
+++ /dev/null
@@ -1,201 +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.view;
-
-/**
- * @hide
- * This really belongs in services.jar; WindowManagerPolicy should go there too.
- */
-public class RawInputEvent {
-    // Event class as defined by EventHub.
-    public static final int CLASS_KEYBOARD = 0x00000001;
-    public static final int CLASS_ALPHAKEY = 0x00000002;
-    public static final int CLASS_TOUCHSCREEN = 0x00000004;
-    public static final int CLASS_TRACKBALL = 0x00000008;
-    public static final int CLASS_TOUCHSCREEN_MT = 0x00000010;
-    public static final int CLASS_DPAD = 0x00000020;
-    
-    // More special classes for QueuedEvent below.
-    public static final int CLASS_CONFIGURATION_CHANGED = 0x10000000;
-    
-    // Event types.
-
-    public static final int EV_SYN = 0x00;
-    public static final int EV_KEY = 0x01;
-    public static final int EV_REL = 0x02;
-    public static final int EV_ABS = 0x03;
-    public static final int EV_MSC = 0x04;
-    public static final int EV_SW = 0x05;
-    public static final int EV_LED = 0x11;
-    public static final int EV_SND = 0x12;
-    public static final int EV_REP = 0x14;
-    public static final int EV_FF = 0x15;
-    public static final int EV_PWR = 0x16;
-    public static final int EV_FF_STATUS = 0x17;
-
-    // Platform-specific event types.
-    
-    public static final int EV_DEVICE_ADDED = 0x10000000;
-    public static final int EV_DEVICE_REMOVED = 0x20000000;
-    
-    // Special key (EV_KEY) scan codes for pointer buttons.
-
-    public static final int BTN_FIRST = 0x100;
-
-    public static final int BTN_MISC = 0x100;
-    public static final int BTN_0 = 0x100;
-    public static final int BTN_1 = 0x101;
-    public static final int BTN_2 = 0x102;
-    public static final int BTN_3 = 0x103;
-    public static final int BTN_4 = 0x104;
-    public static final int BTN_5 = 0x105;
-    public static final int BTN_6 = 0x106;
-    public static final int BTN_7 = 0x107;
-    public static final int BTN_8 = 0x108;
-    public static final int BTN_9 = 0x109;
-
-    public static final int BTN_MOUSE = 0x110;
-    public static final int BTN_LEFT = 0x110;
-    public static final int BTN_RIGHT = 0x111;
-    public static final int BTN_MIDDLE = 0x112;
-    public static final int BTN_SIDE = 0x113;
-    public static final int BTN_EXTRA = 0x114;
-    public static final int BTN_FORWARD = 0x115;
-    public static final int BTN_BACK = 0x116;
-    public static final int BTN_TASK = 0x117;
-
-    public static final int BTN_JOYSTICK = 0x120;
-    public static final int BTN_TRIGGER = 0x120;
-    public static final int BTN_THUMB = 0x121;
-    public static final int BTN_THUMB2 = 0x122;
-    public static final int BTN_TOP = 0x123;
-    public static final int BTN_TOP2 = 0x124;
-    public static final int BTN_PINKIE = 0x125;
-    public static final int BTN_BASE = 0x126;
-    public static final int BTN_BASE2 = 0x127;
-    public static final int BTN_BASE3 = 0x128;
-    public static final int BTN_BASE4 = 0x129;
-    public static final int BTN_BASE5 = 0x12a;
-    public static final int BTN_BASE6 = 0x12b;
-    public static final int BTN_DEAD = 0x12f;
-
-    public static final int BTN_GAMEPAD = 0x130;
-    public static final int BTN_A = 0x130;
-    public static final int BTN_B = 0x131;
-    public static final int BTN_C = 0x132;
-    public static final int BTN_X = 0x133;
-    public static final int BTN_Y = 0x134;
-    public static final int BTN_Z = 0x135;
-    public static final int BTN_TL = 0x136;
-    public static final int BTN_TR = 0x137;
-    public static final int BTN_TL2 = 0x138;
-    public static final int BTN_TR2 = 0x139;
-    public static final int BTN_SELECT = 0x13a;
-    public static final int BTN_START = 0x13b;
-    public static final int BTN_MODE = 0x13c;
-    public static final int BTN_THUMBL = 0x13d;
-    public static final int BTN_THUMBR = 0x13e;
-
-    public static final int BTN_DIGI = 0x140;
-    public static final int BTN_TOOL_PEN = 0x140;
-    public static final int BTN_TOOL_RUBBER = 0x141;
-    public static final int BTN_TOOL_BRUSH = 0x142;
-    public static final int BTN_TOOL_PENCIL = 0x143;
-    public static final int BTN_TOOL_AIRBRUSH = 0x144;
-    public static final int BTN_TOOL_FINGER = 0x145;
-    public static final int BTN_TOOL_MOUSE = 0x146;
-    public static final int BTN_TOOL_LENS = 0x147;
-    public static final int BTN_TOUCH = 0x14a;
-    public static final int BTN_STYLUS = 0x14b;
-    public static final int BTN_STYLUS2 = 0x14c;
-    public static final int BTN_TOOL_DOUBLETAP = 0x14d;
-    public static final int BTN_TOOL_TRIPLETAP = 0x14e;
-
-    public static final int BTN_WHEEL = 0x150;
-    public static final int BTN_GEAR_DOWN = 0x150;
-    public static final int BTN_GEAR_UP = 0x151;
-
-    public static final int BTN_LAST = 0x15f;
-
-    // Relative axes (EV_REL) scan codes.
-
-    public static final int REL_X = 0x00;
-    public static final int REL_Y = 0x01;
-    public static final int REL_Z = 0x02;
-    public static final int REL_RX = 0x03;
-    public static final int REL_RY = 0x04;
-    public static final int REL_RZ = 0x05;
-    public static final int REL_HWHEEL = 0x06;
-    public static final int REL_DIAL = 0x07;
-    public static final int REL_WHEEL = 0x08;
-    public static final int REL_MISC = 0x09;
-    public static final int REL_MAX = 0x0f;
-
-    // Absolute axes (EV_ABS) scan codes.
-
-    public static final int ABS_X = 0x00;
-    public static final int ABS_Y = 0x01;
-    public static final int ABS_Z = 0x02;
-    public static final int ABS_RX = 0x03;
-    public static final int ABS_RY = 0x04;
-    public static final int ABS_RZ = 0x05;
-    public static final int ABS_THROTTLE = 0x06;
-    public static final int ABS_RUDDER = 0x07;
-    public static final int ABS_WHEEL = 0x08;
-    public static final int ABS_GAS = 0x09;
-    public static final int ABS_BRAKE = 0x0a;
-    public static final int ABS_HAT0X = 0x10;
-    public static final int ABS_HAT0Y = 0x11;
-    public static final int ABS_HAT1X = 0x12;
-    public static final int ABS_HAT1Y = 0x13;
-    public static final int ABS_HAT2X = 0x14;
-    public static final int ABS_HAT2Y = 0x15;
-    public static final int ABS_HAT3X = 0x16;
-    public static final int ABS_HAT3Y = 0x17;
-    public static final int ABS_PRESSURE = 0x18;
-    public static final int ABS_DISTANCE = 0x19;
-    public static final int ABS_TILT_X = 0x1a;
-    public static final int ABS_TILT_Y = 0x1b;
-    public static final int ABS_TOOL_WIDTH = 0x1c;
-    public static final int ABS_VOLUME = 0x20;
-    public static final int ABS_MISC = 0x28;
-    public static final int ABS_MT_TOUCH_MAJOR = 0x30;
-    public static final int ABS_MT_TOUCH_MINOR = 0x31;
-    public static final int ABS_MT_WIDTH_MAJOR = 0x32;
-    public static final int ABS_MT_WIDTH_MINOR = 0x33;
-    public static final int ABS_MT_ORIENTATION = 0x34;
-    public static final int ABS_MT_POSITION_X = 0x35;
-    public static final int ABS_MT_POSITION_Y = 0x36;
-    public static final int ABS_MT_TOOL_TYPE = 0x37;
-    public static final int ABS_MT_BLOB_ID = 0x38;
-    public static final int ABS_MAX = 0x3f;
-
-    // Switch events
-    public static final int SW_LID = 0x00;
-
-    public static final int SYN_REPORT = 0;
-    public static final int SYN_CONFIG = 1;
-    public static final int SYN_MT_REPORT = 2;
-    
-    public int deviceId;
-    public int type;
-    public int scancode;
-    public int keycode;
-    public int flags;
-    public int value;
-    public long when;
-}
diff --git a/core/java/android/view/SurfaceHolder.java b/core/java/android/view/SurfaceHolder.java
index 34e4638..0d38f7b 100644
--- a/core/java/android/view/SurfaceHolder.java
+++ b/core/java/android/view/SurfaceHolder.java
@@ -119,6 +119,23 @@
     }
 
     /**
+     * Additional callbacks that can be received for {@link Callback}.
+     */
+    public interface Callback2 extends Callback {
+        /**
+         * Called when the application needs to redraw the content of its
+         * surface, after it is resized or for some other reason.  By not
+         * returning here until the redraw is complete, you can ensure that
+         * the user will not see your surface in a bad state (at its new
+         * size before it has been correctly drawn that way).  This will
+         * typically be preceeded by a call to {@link #surfaceChanged}.
+         *
+         * @param holder The SurfaceHolder whose surface has changed.
+         */
+        public void surfaceRedrawNeeded(SurfaceHolder holder);
+    }
+
+    /**
      * Add a Callback interface for this holder.  There can several Callback
      * interfaces associated to a holder.
      * 
diff --git a/core/java/android/view/SurfaceView.java b/core/java/android/view/SurfaceView.java
index d1a0f75..54cb4ca 100644
--- a/core/java/android/view/SurfaceView.java
+++ b/core/java/android/view/SurfaceView.java
@@ -123,7 +123,7 @@
                     handleGetNewSurface();
                 } break;
                 case UPDATE_WINDOW_MSG: {
-                    updateWindow(false);
+                    updateWindow(false, false);
                 } break;
             }
         }
@@ -132,7 +132,7 @@
     final ViewTreeObserver.OnScrollChangedListener mScrollChangedListener
             = new ViewTreeObserver.OnScrollChangedListener() {
                     public void onScrollChanged() {
-                        updateWindow(false);
+                        updateWindow(false, false);
                     }
             };
             
@@ -210,7 +210,7 @@
         super.onWindowVisibilityChanged(visibility);
         mWindowVisibility = visibility == VISIBLE;
         mRequestedVisible = mWindowVisibility && mViewVisibility;
-        updateWindow(false);
+        updateWindow(false, false);
     }
 
     @Override
@@ -218,7 +218,7 @@
         super.setVisibility(visibility);
         mViewVisibility = visibility == VISIBLE;
         mRequestedVisible = mWindowVisibility && mViewVisibility;
-        updateWindow(false);
+        updateWindow(false, false);
     }
 
     /**
@@ -232,7 +232,7 @@
      */
     protected void showSurface() {
         if (mSession != null) {
-            updateWindow(true);
+            updateWindow(true, false);
         }
     }
 
@@ -265,7 +265,7 @@
     protected void onDetachedFromWindow() {
         getViewTreeObserver().removeOnScrollChangedListener(mScrollChangedListener);
         mRequestedVisible = false;
-        updateWindow(false);
+        updateWindow(false, false);
         mHaveFrame = false;
         if (mWindow != null) {
             try {
@@ -290,7 +290,7 @@
     @Override
     protected void onSizeChanged(int w, int h, int oldw, int oldh) {
         super.onSizeChanged(w, h, oldw, oldh);
-        updateWindow(false);
+        updateWindow(false, false);
     }
 
     @Override
@@ -343,7 +343,7 @@
         }
         // reposition ourselves where the surface is 
         mHaveFrame = true;
-        updateWindow(false);
+        updateWindow(false, false);
         super.dispatchDraw(canvas);
     }
 
@@ -397,7 +397,7 @@
         mWindowType = type;
     }
 
-    private void updateWindow(boolean force) {
+    private void updateWindow(boolean force, boolean redrawNeeded) {
         if (!mHaveFrame) {
             return;
         }
@@ -425,7 +425,7 @@
         final boolean typeChanged = mType != mRequestedType;
         if (force || creating || formatChanged || sizeChanged || visibleChanged
             || typeChanged || mLeft != mLocation[0] || mTop != mLocation[1]
-            || mUpdateWindowNeeded || mReportDrawNeeded) {
+            || mUpdateWindowNeeded || mReportDrawNeeded || redrawNeeded) {
 
             if (localLOGV) Log.i(TAG, "Changes: creating=" + creating
                     + " format=" + formatChanged + " size=" + sizeChanged
@@ -524,6 +524,8 @@
                 }
 
                 try {
+                    redrawNeeded |= creating | reportDrawNeeded;
+
                     if (visible) {
                         mDestroyReportNeeded = true;
 
@@ -545,12 +547,20 @@
                                 c.surfaceChanged(mSurfaceHolder, mFormat, myWidth, myHeight);
                             }
                         }
+                        if (redrawNeeded) {
+                            for (SurfaceHolder.Callback c : callbacks) {
+                                if (c instanceof SurfaceHolder.Callback2) {
+                                    ((SurfaceHolder.Callback2)c).surfaceRedrawNeeded(
+                                            mSurfaceHolder);
+                                }
+                            }
+                        }
                     } else {
                         mSurface.release();
                     }
                 } finally {
                     mIsCreating = false;
-                    if (creating || reportDrawNeeded) {
+                    if (redrawNeeded) {
                         mSession.finishDrawing(mWindow);
                     }
                 }
@@ -580,7 +590,7 @@
 
     void handleGetNewSurface() {
         mNewSurfaceNeeded = true;
-        updateWindow(false);
+        updateWindow(false, false);
     }
 
     /**
@@ -625,41 +635,6 @@
             }
         }
 
-        public void dispatchKey(KeyEvent event) {
-            SurfaceView surfaceView = mSurfaceView.get();
-            if (surfaceView != null) {
-                //Log.w("SurfaceView", "Unexpected key event in surface: " + event);
-                if (surfaceView.mSession != null && surfaceView.mSurface != null) {
-                    try {
-                        surfaceView.mSession.finishKey(surfaceView.mWindow);
-                    } catch (RemoteException ex) {
-                    }
-                }
-            }
-        }
-
-        public void dispatchPointer(MotionEvent event, long eventTime,
-                boolean callWhenDone) {
-            Log.w("SurfaceView", "Unexpected pointer event in surface: " + event);
-            //if (mSession != null && mSurface != null) {
-            //    try {
-            //        //mSession.finishKey(mWindow);
-            //    } catch (RemoteException ex) {
-            //    }
-            //}
-        }
-
-        public void dispatchTrackball(MotionEvent event, long eventTime,
-                boolean callWhenDone) {
-            Log.w("SurfaceView", "Unexpected trackball event in surface: " + event);
-            //if (mSession != null && mSurface != null) {
-            //    try {
-            //        //mSession.finishKey(mWindow);
-            //    } catch (RemoteException ex) {
-            //    }
-            //}
-        }
-
         public void dispatchAppVisibility(boolean visible) {
             // The point of SurfaceView is to let the app control the surface.
         }
@@ -686,7 +661,6 @@
     private SurfaceHolder mSurfaceHolder = new SurfaceHolder() {
         
         private static final String LOG_TAG = "SurfaceHolder";
-        private int mSaveCount;
         
         public boolean isCreating() {
             return mIsCreating;
@@ -732,7 +706,7 @@
 
             mRequestedFormat = format;
             if (mWindow != null) {
-                updateWindow(false);
+                updateWindow(false, false);
             }
         }
 
@@ -749,7 +723,7 @@
             case SURFACE_TYPE_PUSH_BUFFERS:
                 mRequestedType = type;
                 if (mWindow != null) {
-                    updateWindow(false);
+                    updateWindow(false, false);
                 }
                 break;
             }
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 3461cbf..3a3ad8c9 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -16,6 +16,7 @@
 
 package android.view;
 
+import android.graphics.RectF;
 import com.android.internal.R;
 import com.android.internal.view.menu.MenuBuilder;
 
@@ -1585,6 +1586,87 @@
     int mViewFlags;
 
     /**
+     * The transform matrix for the View. This transform is calculated internally
+     * based on the rotation, scaleX, and scaleY properties. The identity matrix
+     * is used by default. Do *not* use this variable directly; instead call
+     * getMatrix(), which will automatically recalculate the matrix if necessary
+     * to get the correct matrix based on the latest rotation and scale properties.
+     */
+    private final Matrix mMatrix = new Matrix();
+
+    /**
+     * The transform matrix for the View. This transform is calculated internally
+     * based on the rotation, scaleX, and scaleY properties. The identity matrix
+     * is used by default. Do *not* use this variable directly; instead call
+     * getMatrix(), which will automatically recalculate the matrix if necessary
+     * to get the correct matrix based on the latest rotation and scale properties.
+     */
+    private Matrix mInverseMatrix;
+
+    /**
+     * An internal variable that tracks whether we need to recalculate the
+     * transform matrix, based on whether the rotation or scaleX/Y properties
+     * have changed since the matrix was last calculated.
+     */
+    private boolean mMatrixDirty = false;
+
+    /**
+     * An internal variable that tracks whether we need to recalculate the
+     * transform matrix, based on whether the rotation or scaleX/Y properties
+     * have changed since the matrix was last calculated.
+     */
+    private boolean mInverseMatrixDirty = true;
+
+    /**
+     * A variable that tracks whether we need to recalculate the
+     * transform matrix, based on whether the rotation or scaleX/Y properties
+     * have changed since the matrix was last calculated. This variable
+     * is only valid after a call to getMatrix().
+     */
+    boolean mMatrixIsIdentity = true;
+
+    /**
+     * The degrees rotation around the pivot point.
+     */
+    @ViewDebug.ExportedProperty
+    private float mRotation = 0f;
+
+    /**
+     * The amount of scale in the x direction around the pivot point. A
+     * value of 1 means no scaling is applied.
+     */
+    @ViewDebug.ExportedProperty
+    private float mScaleX = 1f;
+
+    /**
+     * The amount of scale in the y direction around the pivot point. A
+     * value of 1 means no scaling is applied.
+     */
+    @ViewDebug.ExportedProperty
+    private float mScaleY = 1f;
+
+    /**
+     * The amount of scale in the x direction around the pivot point. A
+     * value of 1 means no scaling is applied.
+     */
+    @ViewDebug.ExportedProperty
+    private float mPivotX = 0f;
+
+    /**
+     * The amount of scale in the y direction around the pivot point. A
+     * value of 1 means no scaling is applied.
+     */
+    @ViewDebug.ExportedProperty
+    private float mPivotY = 0f;
+
+    /**
+     * The opacity of the View. This is a value from 0 to 1, where 0 means
+     * completely transparent and 1 means completely opaque.
+     */
+    @ViewDebug.ExportedProperty
+    private float mAlpha = 1f;
+
+    /**
      * The distance in pixels from the left edge of this view's parent
      * to the left edge of this view.
      * {@hide}
@@ -3019,6 +3101,16 @@
     }
 
     /**
+     * Determine if this view has the FITS_SYSTEM_WINDOWS flag set.
+     * @return True if window has FITS_SYSTEM_WINDOWS set
+     *
+     * @hide
+     */
+    public boolean isFitsSystemWindowsFlagSet() {
+        return (mViewFlags & FITS_SYSTEM_WINDOWS) == FITS_SYSTEM_WINDOWS;
+    }
+
+    /**
      * Returns the visibility status for this view.
      *
      * @return One of {@link #VISIBLE}, {@link #INVISIBLE}, or {@link #GONE}.
@@ -4406,9 +4498,7 @@
                     final int y = (int) event.getY();
 
                     // Be lenient about moving outside of buttons
-                    int slop = mTouchSlop;
-                    if ((x < 0 - slop) || (x >= getWidth() + slop) ||
-                            (y < 0 - slop) || (y >= getHeight() + slop)) {
+                    if (!pointInView(x, y, mTouchSlop)) {
                         // Outside button
                         removeTapCallback();
                         if ((mPrivateFlags & PRESSED) != 0) {
@@ -4754,6 +4844,234 @@
     }
 
     /**
+     * The transform matrix of this view, which is calculated based on the current
+     * roation, scale, and pivot properties.
+     *
+     * @see #getRotation()
+     * @see #getScaleX()
+     * @see #getScaleY()
+     * @see #getPivotX()
+     * @see #getPivotY()
+     * @return The current transform matrix for the view
+     */
+    public Matrix getMatrix() {
+        if (mMatrixDirty) {
+            // transform-related properties have changed since the last time someone
+            // asked for the matrix; recalculate it with the current values
+            mMatrix.reset();
+            mMatrix.setRotate(mRotation, mPivotX, mPivotY);
+            mMatrix.preScale(mScaleX, mScaleY, mPivotX, mPivotY);
+            mMatrixDirty = false;
+            mMatrixIsIdentity = mMatrix.isIdentity();
+            mInverseMatrixDirty = true;
+        }
+        return mMatrix;
+    }
+
+    /**
+     * Utility method to retrieve the inverse of the current mMatrix property.
+     * We cache the matrix to avoid recalculating it when transform properties
+     * have not changed.
+     *
+     * @return The inverse of the current matrix of this view.
+     */
+    Matrix getInverseMatrix() {
+        if (mInverseMatrixDirty) {
+            if (mInverseMatrix == null) {
+                mInverseMatrix = new Matrix();
+            }
+            mMatrix.invert(mInverseMatrix);
+            mInverseMatrixDirty = false;
+        }
+        return mInverseMatrix;
+    }
+
+    /**
+     * The degrees that the view is rotated around the pivot point.
+     *
+     * @see #getPivotX()
+     * @see #getPivotY()
+     * @return The degrees of rotation.
+     */
+    public float getRotation() {
+        return mRotation;
+    }
+
+    /**
+     * Sets the degrees that the view is rotated around the pivot point.
+     *
+     * @param rotation The degrees of rotation.
+     * @see #getPivotX()
+     * @see #getPivotY()
+     */
+    public void setRotation(float rotation) {
+        if (mRotation != rotation) {
+            // Double-invalidation is necessary to capture view's old and new areas
+            invalidate();
+            mRotation = rotation;
+            mMatrixDirty = true;
+            mPrivateFlags |= DRAWN; // force another invalidation with the new orientation
+            invalidate();
+        }
+    }
+
+    /**
+     * The amount that the view is scaled in x around the pivot point, as a proportion of
+     * the view's unscaled width. A value of 1, the default, means that no scaling is applied.
+     *
+     * @default 1.0f
+     * @see #getPivotX()
+     * @see #getPivotY()
+     * @return The scaling factor.
+     */
+    public float getScaleX() {
+        return mScaleX;
+    }
+
+    /**
+     * Sets the amount that the view is scaled in x around the pivot point, as a proportion of
+     * the view's unscaled width. A value of 1 means that no scaling is applied.
+     *
+     * @param scaleX The scaling factor.
+     * @see #getPivotX()
+     * @see #getPivotY()
+     */
+    public void setScaleX(float scaleX) {
+        if (mScaleX != scaleX) {
+            // Double-invalidation is necessary to capture view's old and new areas
+            invalidate();
+            mScaleX = scaleX;
+            mMatrixDirty = true;
+            mPrivateFlags |= DRAWN; // force another invalidation with the new orientation
+            invalidate();
+        }
+    }
+
+    /**
+     * The amount that the view is scaled in y around the pivot point, as a proportion of
+     * the view's unscaled height. A value of 1, the default, means that no scaling is applied.
+     *
+     * @default 1.0f
+     * @see #getPivotX()
+     * @see #getPivotY()
+     * @return The scaling factor.
+     */
+    public float getScaleY() {
+        return mScaleY;
+    }
+
+    /**
+     * Sets the amount that the view is scaled in Y around the pivot point, as a proportion of
+     * the view's unscaled width. A value of 1 means that no scaling is applied.
+     *
+     * @param scaleY The scaling factor.
+     * @see #getPivotX()
+     * @see #getPivotY()
+     */
+    public void setScaleY(float scaleY) {
+        if (mScaleY != scaleY) {
+            // Double-invalidation is necessary to capture view's old and new areas
+            invalidate();
+            mScaleY = scaleY;
+            mMatrixDirty = true;
+            mPrivateFlags |= DRAWN; // force another invalidation with the new orientation
+            invalidate();
+        }
+    }
+
+    /**
+     * The x location of the point around which the view is {@link #setRotation(float) rotated}
+     * and {@link #setScaleX(float) scaled}.
+     *
+     * @see #getRotation()
+     * @see #getScaleX()
+     * @see #getScaleY()
+     * @see #getPivotY()
+     * @return The x location of the pivot point.
+     */
+    public float getPivotX() {
+        return mPivotX;
+    }
+
+    /**
+     * Sets the x location of the point around which the view is
+     * {@link #setRotation(float) rotated} and {@link #setScaleX(float) scaled}.
+     *
+     * @param pivotX The x location of the pivot point.
+     * @see #getRotation()
+     * @see #getScaleX()
+     * @see #getScaleY()
+     * @see #getPivotY()
+     */
+    public void setPivotX(float pivotX) {
+        if (mPivotX != pivotX) {
+            // Double-invalidation is necessary to capture view's old and new areas
+            invalidate();
+            mPivotX = pivotX;
+            mMatrixDirty = true;
+            mPrivateFlags |= DRAWN; // force another invalidation with the new orientation
+            invalidate();
+        }
+    }
+
+    /**
+     * The y location of the point around which the view is {@link #setRotation(float) rotated}
+     * and {@link #setScaleY(float) scaled}.
+     *
+     * @see #getRotation()
+     * @see #getScaleX()
+     * @see #getScaleY()
+     * @see #getPivotY()
+     * @return The y location of the pivot point.
+     */
+    public float getPivotY() {
+        return mPivotY;
+    }
+
+    /**
+     * Sets the y location of the point around which the view is {@link #setRotation(float) rotated}
+     * and {@link #setScaleY(float) scaled}.
+     *
+     * @param pivotY The y location of the pivot point.
+     * @see #getRotation()
+     * @see #getScaleX()
+     * @see #getScaleY()
+     * @see #getPivotY()
+     */
+    public void setPivotY(float pivotY) {
+        if (mPivotY != pivotY) {
+            // Double-invalidation is necessary to capture view's old and new areas
+            invalidate();
+            mPivotY = pivotY;
+            mMatrixDirty = true;
+            mPrivateFlags |= DRAWN; // force another invalidation with the new orientation
+            invalidate();
+        }
+    }
+
+    /**
+     * The opacity of the view. This is a value from 0 to 1, where 0 means the view is
+     * completely transparent and 1 means the view is completely opaque.
+     *
+     * @default 1.0f
+     * @return The opacity of the view.
+     */
+    public float getAlpha() {
+        return mAlpha;
+    }
+
+    /**
+     * Sets the opacity of the view. This is a value from 0 to 1, where 0 means the view is
+     * completely transparent and 1 means the view is completely opaque.
+     *
+     * @param alpha The opacity of the view.
+     */
+    public void setAlpha(float alpha) {
+        mAlpha = alpha;
+        invalidate();
+    }
+
+    /**
      * Top position of this view relative to its parent.
      *
      * @return The top of this view, in pixels.
@@ -4764,6 +5082,37 @@
     }
 
     /**
+     * Sets the top position of this view relative to its parent.
+     *
+     * @param top The top of this view, in pixels.
+     */
+    public final void setTop(int top) {
+        if (top != mTop) {
+            Matrix m = getMatrix();
+            if (mMatrixIsIdentity) {
+                final ViewParent p = mParent;
+                if (p != null && mAttachInfo != null) {
+                    final int[] location = mAttachInfo.mInvalidateChildLocation;
+                    final Rect r = mAttachInfo.mTmpInvalRect;
+                    int minTop = Math.min(mTop, top);
+                    location[0] = mLeft;
+                    location[1] = minTop;
+                    r.set(0, 0, mRight - mLeft, mBottom - minTop);
+                    p.invalidateChildInParent(location, r);
+                }
+            } else {
+                // Double-invalidation is necessary to capture view's old and new areas
+                invalidate();
+            }
+            mTop = top;
+            if (!mMatrixIsIdentity) {
+                mPrivateFlags |= DRAWN; // force another invalidation with the new orientation
+                invalidate();
+            }
+        }
+    }
+
+    /**
      * Bottom position of this view relative to its parent.
      *
      * @return The bottom of this view, in pixels.
@@ -4774,6 +5123,37 @@
     }
 
     /**
+     * Sets the bottom position of this view relative to its parent.
+     *
+     * @param bottom The bottom of this view, in pixels.
+     */
+    public final void setBottom(int bottom) {
+        if (bottom != mBottom) {
+            Matrix m = getMatrix();
+            if (mMatrixIsIdentity) {
+                final ViewParent p = mParent;
+                if (p != null && mAttachInfo != null) {
+                    final int[] location = mAttachInfo.mInvalidateChildLocation;
+                    final Rect r = mAttachInfo.mTmpInvalRect;
+                    int maxBottom = Math.max(mBottom, bottom);
+                    location[0] = mLeft;
+                    location[1] = mTop;
+                    r.set(0, 0, mRight - mLeft, maxBottom - mTop);
+                    p.invalidateChildInParent(location, r);
+                }
+            } else {
+                // Double-invalidation is necessary to capture view's old and new areas
+                invalidate();
+            }
+            mBottom = bottom;
+            if (!mMatrixIsIdentity) {
+                mPrivateFlags |= DRAWN; // force another invalidation with the new orientation
+                invalidate();
+            }
+        }
+    }
+
+    /**
      * Left position of this view relative to its parent.
      *
      * @return The left edge of this view, in pixels.
@@ -4784,6 +5164,37 @@
     }
 
     /**
+     * Sets the left position of this view relative to its parent.
+     *
+     * @param left The bottom of this view, in pixels.
+     */
+    public final void setLeft(int left) {
+        if (left != mLeft) {
+            Matrix m = getMatrix();
+            if (mMatrixIsIdentity) {
+                final ViewParent p = mParent;
+                if (p != null && mAttachInfo != null) {
+                    final int[] location = mAttachInfo.mInvalidateChildLocation;
+                    final Rect r = mAttachInfo.mTmpInvalRect;
+                    int minLeft = Math.min(mLeft, left);
+                    location[0] = minLeft;
+                    location[1] = mTop;
+                    r.set(0, 0, mRight - minLeft, mBottom - mTop);
+                    p.invalidateChildInParent(location, r);
+                }
+            } else {
+                // Double-invalidation is necessary to capture view's old and new areas
+                invalidate();
+            }
+            mLeft = left;
+            if (!mMatrixIsIdentity) {
+                mPrivateFlags |= DRAWN; // force another invalidation with the new orientation
+                invalidate();
+            }
+        }
+    }
+
+    /**
      * Right position of this view relative to its parent.
      *
      * @return The right edge of this view, in pixels.
@@ -4794,12 +5205,149 @@
     }
 
     /**
+     * Sets the right position of this view relative to its parent.
+     *
+     * @param right The bottom of this view, in pixels.
+     */
+    public final void setRight(int right) {
+        if (right != mRight) {
+            Matrix m = getMatrix();
+            if (mMatrixIsIdentity) {
+                final ViewParent p = mParent;
+                if (p != null && mAttachInfo != null) {
+                    final int[] location = mAttachInfo.mInvalidateChildLocation;
+                    final Rect r = mAttachInfo.mTmpInvalRect;
+                    int maxRight = Math.max(mRight, right);
+                    location[0] = mLeft;
+                    location[1] = mTop;
+                    r.set(0, 0, maxRight - mLeft, mBottom - mTop);
+                    p.invalidateChildInParent(location, r);
+                }
+            } else {
+                // Double-invalidation is necessary to capture view's old and new areas
+                invalidate();
+            }
+            mRight = right;
+            if (!mMatrixIsIdentity) {
+                mPrivateFlags |= DRAWN; // force another invalidation with the new orientation
+                invalidate();
+            }
+        }
+    }
+
+    /**
+     * The horizontal location of this view relative to its parent. This value is equivalent to the
+     * {@link #getLeft() left} property.
+     *
+     * @return The horizontal position of this view, in pixels.
+     */
+    public int getX() {
+        return mLeft;
+    }
+
+    /**
+     * Sets the horizontal location of this view relative to its parent. Setting this value will
+     * affect both the {@link #setLeft(int) left} and {@link #setRight(int) right} properties
+     * of this view.
+     *
+     * @param x The horizontal position of this view, in pixels.
+     */
+    public void setX(int x) {
+        offsetLeftAndRight(x - mLeft);
+    }
+
+    /**
+     * The vertical location of this view relative to its parent. This value is equivalent to the
+     * {@link #getTop() left} property.
+     *
+     * @return The vertical position of this view, in pixels.
+     */
+    public int getY() {
+        return mTop;
+    }
+
+    /**
+     * Sets the vertical location of this view relative to its parent. Setting this value will
+     * affect both the {@link #setTop(int) left} and {@link #setBottom(int) right} properties
+     * of this view.
+     *
+     * @param y The vertical position of this view, in pixels.
+     */
+    public void setY(int y) {
+        offsetTopAndBottom(y - mTop);
+    }
+
+    /**
      * Hit rectangle in parent's coordinates
      *
      * @param outRect The hit rectangle of the view.
      */
     public void getHitRect(Rect outRect) {
-        outRect.set(mLeft, mTop, mRight, mBottom);
+        Matrix m = getMatrix();
+        if (mMatrixIsIdentity || mAttachInfo == null) {
+            outRect.set(mLeft, mTop, mRight, mBottom);
+        } else {
+            final RectF tmpRect = mAttachInfo.mTmpTransformRect;
+            tmpRect.set(-mPivotX, -mPivotY,
+                    getWidth() - mPivotX, getHeight() - mPivotY);
+            m.mapRect(tmpRect);
+            outRect.set((int)tmpRect.left + mLeft, (int)tmpRect.top + mTop,
+                    (int)tmpRect.right + mLeft, (int)tmpRect.bottom + mTop);
+        }
+    }
+
+    /**
+     * This method detects whether the given event is inside the view and, if so,
+     * handles it via the dispatchEvent(MotionEvent) method.
+     *
+     * @param ev The event that is being dispatched.
+     * @param parentX The x location of the event in the parent's coordinates.
+     * @param parentY The y location of the event in the parent's coordinates.
+     * @return true if the event was inside this view, false otherwise.
+     */
+    boolean dispatchTouchEvent(MotionEvent ev, float parentX, float parentY) {
+        float localX = parentX - mLeft;
+        float localY = parentY - mTop;
+        Matrix m = getMatrix();
+        if (!mMatrixIsIdentity && mAttachInfo != null) {
+            // non-identity matrix: transform the point into the view's coordinates
+            final float[] localXY = mAttachInfo.mTmpTransformLocation;
+            localXY[0] = localX;
+            localXY[1] = localY;
+            getInverseMatrix().mapPoints(localXY);
+            localX = localXY[0];
+            localY = localXY[1];
+        }
+        if (localX >= 0 && localY >= 0 &&
+                localX < (mRight - mLeft) && localY < (mBottom - mTop)) {
+            ev.setLocation(localX, localY);
+            return dispatchTouchEvent(ev);
+        }
+        return false;
+    }
+
+    /**
+     * Utility method to determine whether the given point, in local coordinates,
+     * is inside the view, where the area of the view is expanded by the slop factor.
+     * This method is called while processing touch-move events to determine if the event
+     * is still within the view.
+     */
+    private boolean pointInView(float localX, float localY, float slop) {
+        Matrix m = getMatrix();
+        if (!mMatrixIsIdentity && mAttachInfo != null) {
+            // non-identity matrix: transform the point into the view's coordinates
+            final float[] localXY = mAttachInfo.mTmpTransformLocation;
+            localXY[0] = localX;
+            localXY[1] = localY;
+            getInverseMatrix().mapPoints(localXY);
+            localX = localXY[0];
+            localY = localXY[1];
+        }
+        if (localX > -slop && localY > -slop &&
+                localX < ((mRight - mLeft) + slop) && localY < ((mBottom - mTop) + slop)) {
+            return true;
+        }
+        return false;
     }
 
     /**
@@ -4862,8 +5410,30 @@
      * @param offset the number of pixels to offset the view by
      */
     public void offsetTopAndBottom(int offset) {
-        mTop += offset;
-        mBottom += offset;
+        if (offset != 0) {
+            Matrix m = getMatrix();
+            if (mMatrixIsIdentity) {
+                final ViewParent p = mParent;
+                if (p != null && mAttachInfo != null) {
+                    final int[] location = mAttachInfo.mInvalidateChildLocation;
+                    final Rect r = mAttachInfo.mTmpInvalRect;
+                    int minTop = offset < 0 ? mTop + offset : mTop;
+                    int maxBottom = offset < 0 ? mBottom : mBottom + offset;
+                    location[0] = mLeft;
+                    location[1] = minTop;
+                    r.set(0, 0, mRight - mLeft, maxBottom - minTop);
+                    p.invalidateChildInParent(location, r);
+                }
+            } else {
+                invalidate();
+            }
+            mTop += offset;
+            mBottom += offset;
+            if (!mMatrixIsIdentity) {
+                mPrivateFlags |= DRAWN; // force another invalidation with the new orientation
+                invalidate();
+            }
+        }
     }
 
     /**
@@ -4872,8 +5442,30 @@
      * @param offset the numer of pixels to offset the view by
      */
     public void offsetLeftAndRight(int offset) {
-        mLeft += offset;
-        mRight += offset;
+        if (offset != 0) {
+            Matrix m = getMatrix();
+            if (mMatrixIsIdentity) {
+                final ViewParent p = mParent;
+                if (p != null && mAttachInfo != null) {
+                    final int[] location = mAttachInfo.mInvalidateChildLocation;
+                    final Rect r = mAttachInfo.mTmpInvalRect;
+                    int minLeft = offset < 0 ? mLeft + offset : mLeft;
+                    int maxRight = offset < 0 ? mRight : mRight + offset;
+                    location[0] = minLeft;
+                    location[1] = mTop;
+                    r.set(0, 0, maxRight - minLeft, mBottom - mTop);
+                    p.invalidateChildInParent(location, r);
+                }
+            } else {
+                invalidate();
+            }
+            mLeft += offset;
+            mRight += offset;
+            if (!mMatrixIsIdentity) {
+                mPrivateFlags |= DRAWN; // force another invalidation with the new orientation
+                invalidate();
+            }
+        }
     }
 
     /**
@@ -6848,16 +7440,16 @@
 
         if (verticalEdges) {
             topFadeStrength = Math.max(0.0f, Math.min(1.0f, getTopFadingEdgeStrength()));
-            drawTop = topFadeStrength >= 0.0f;
+            drawTop = topFadeStrength > 0.0f;
             bottomFadeStrength = Math.max(0.0f, Math.min(1.0f, getBottomFadingEdgeStrength()));
-            drawBottom = bottomFadeStrength >= 0.0f;
+            drawBottom = bottomFadeStrength > 0.0f;
         }
 
         if (horizontalEdges) {
             leftFadeStrength = Math.max(0.0f, Math.min(1.0f, getLeftFadingEdgeStrength()));
-            drawLeft = leftFadeStrength >= 0.0f;
+            drawLeft = leftFadeStrength > 0.0f;
             rightFadeStrength = Math.max(0.0f, Math.min(1.0f, getRightFadingEdgeStrength()));
-            drawRight = rightFadeStrength >= 0.0f;
+            drawRight = rightFadeStrength > 0.0f;
         }
 
         saveCount = canvas.getSaveCount();
@@ -7936,7 +8528,9 @@
      * without resorting to another data structure.
      *
      * The specified key should be an id declared in the resources of the
-     * application to ensure it is unique. Keys identified as belonging to
+     * application to ensure it is unique (see the <a
+     * href={@docRoot}guide/topics/resources/more-resources.html#Id">ID resource type</a>).
+     * Keys identified as belonging to
      * the Android framework or not associated with any package will cause
      * an {@link IllegalArgumentException} to be thrown.
      *
@@ -9191,6 +9785,13 @@
          */
         final int[] mInvalidateChildLocation = new int[2];
 
+
+        /**
+         * Global to the view hierarchy used as a temporary for dealing with
+         * x/y location when view is transformed.
+         */
+        final float[] mTmpTransformLocation = new float[2];
+
         /**
          * The view tree observer used to dispatch global events like
          * layout, pre-draw, touch mode change, etc.
@@ -9227,6 +9828,16 @@
         final Rect mTmpInvalRect = new Rect();
 
         /**
+         * Temporary for use in computing hit areas with transformed views
+         */
+        final RectF mTmpTransformRect = new RectF();
+
+        /**
+         * Temporary for use in computing invalidation areas with transformed views
+         */
+        final float[] mTmpTransformBounds = new float[8];
+
+        /**
          * Temporary list for use in collecting focusable descendents of a view.
          */
         final ArrayList<View> mFocusablesTempList = new ArrayList<View>(24);
diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java
index 34777ce..22ad27a 100644
--- a/core/java/android/view/ViewGroup.java
+++ b/core/java/android/view/ViewGroup.java
@@ -16,6 +16,7 @@
 
 package android.view;
 
+import android.graphics.Matrix;
 import com.android.internal.R;
 
 import android.content.Context;
@@ -867,21 +868,10 @@
                     final View child = children[i];
                     if ((child.mViewFlags & VISIBILITY_MASK) == VISIBLE
                             || child.getAnimation() != null) {
-                        child.getHitRect(frame);
-                        if (frame.contains(scrolledXInt, scrolledYInt)) {
-                            // offset the event to the view's coordinate system
-                            final float xc = scrolledXFloat - child.mLeft;
-                            final float yc = scrolledYFloat - child.mTop;
-                            ev.setLocation(xc, yc);
+                        if (child.dispatchTouchEvent(ev, scrolledXFloat, scrolledYFloat)) {
                             child.mPrivateFlags &= ~CANCEL_NEXT_UP_EVENT;
-                            if (child.dispatchTouchEvent(ev))  {
-                                // Event handled, we have a target now.
-                                mMotionTarget = child;
-                                return true;
-                            }
-                            // The event didn't get handled, try the next view.
-                            // Don't reset the event's location, it's not
-                            // necessary here.
+                            mMotionTarget = child;
+                            return true;
                         }
                     }
                 }
@@ -937,8 +927,21 @@
 
         // finally offset the event to the target's coordinate system and
         // dispatch the event.
-        final float xc = scrolledXFloat - (float) target.mLeft;
-        final float yc = scrolledYFloat - (float) target.mTop;
+        float xc;
+        float yc;
+        Matrix m = getMatrix();
+        if (mMatrixIsIdentity || mAttachInfo == null) {
+            xc = scrolledXFloat - (float) target.mLeft;
+            yc = scrolledYFloat - (float) target.mTop;
+        } else {
+            // non-identity matrix: transform the point into the view's coordinates
+            final float[] localXY = mAttachInfo.mTmpTransformLocation;
+            localXY[0] = scrolledXFloat;
+            localXY[1] = scrolledYFloat;
+            getInverseMatrix().mapPoints(localXY);
+            xc = localXY[0] - (float) target.mLeft;
+            yc = localXY[1] - (float) target.mTop;
+        }
         ev.setLocation(xc, yc);
 
         if ((target.mPrivateFlags & CANCEL_NEXT_UP_EVENT) != 0) {
@@ -1609,25 +1612,36 @@
             }
         }
 
-        float alpha = 1.0f;
+        float alpha = child.getAlpha();
+        Matrix childMatrix = child.getMatrix();
 
-        if (transformToApply != null) {
-            if (concatMatrix) {
-                int transX = 0;
-                int transY = 0;
-                if (hasNoCache) {
-                    transX = -sx;
-                    transY = -sy;
-                }
-                // 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;
+        if (transformToApply != null || alpha < 1.0f || !child.mMatrixIsIdentity) {
+            int transX = 0;
+            int transY = 0;
+            if (hasNoCache) {
+                transX = -sx;
+                transY = -sy;
             }
-
-            alpha = transformToApply.getAlpha();
+            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 (!child.mMatrixIsIdentity) {
+                canvas.translate(-transX, -transY);
+                canvas.concat(child.getMatrix());
+                canvas.translate(transX, transY);
+            }
             if (alpha < 1.0f) {
                 mGroupFlags |= FLAG_CLEAR_TRANSFORMATION;
             }
@@ -2498,6 +2512,41 @@
             final int[] location = attachInfo.mInvalidateChildLocation;
             location[CHILD_LEFT_INDEX] = child.mLeft;
             location[CHILD_TOP_INDEX] = child.mTop;
+            Matrix childMatrix = child.getMatrix();
+            if (!childMatrix.isIdentity()) {
+                float[] boundingRectPoints = attachInfo.mTmpTransformBounds;
+                boundingRectPoints[0] = dirty.left; // upper left
+                boundingRectPoints[1] = dirty.top;
+                boundingRectPoints[2] = dirty.right; // upper right
+                boundingRectPoints[3] = dirty.top;
+                boundingRectPoints[4] = dirty.right; // lower right
+                boundingRectPoints[5] = dirty.bottom;
+                boundingRectPoints[6] = dirty.left; // lower left
+                boundingRectPoints[7] = dirty.bottom;
+                childMatrix.mapPoints(boundingRectPoints);
+                // find the mind/max points to get the bounding rect
+                float left = Float.MAX_VALUE;
+                float top = Float.MAX_VALUE;
+                float right = -Float.MAX_VALUE;
+                float bottom = -Float.MAX_VALUE;
+                for (int i = 0; i < 8; i += 2) {
+                    float x = boundingRectPoints[i];
+                    float y = boundingRectPoints[i+1];
+                    if (x < left) {
+                        left = x;
+                    }
+                    if (x > right) {
+                        right = x;
+                    }
+                    if (y < top) {
+                        top = y;
+                    }
+                    if (y > bottom) {
+                        bottom = y;
+                    }
+                }
+                dirty.set((int)left, (int)top, (int)(right + .5f), (int)(bottom + .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
@@ -2532,6 +2581,39 @@
                 }
 
                 parent = parent.invalidateChildInParent(location, dirty);
+                Matrix m = getMatrix();
+                if (!m.isIdentity()) {
+                    float[] boundingRectPoints = {
+                            dirty.left - mLeft, dirty.top - mTop, // upper left 
+                            dirty.right - mLeft, dirty.top - mTop, // upper right
+                            dirty.right - mLeft, dirty.bottom - mTop, // lower right
+                            dirty.left - mLeft, dirty.bottom - mTop // lower left
+                    };
+                    m.mapPoints(boundingRectPoints);
+                    // find the mind/max points to get the bounding rect
+                    float left = Float.MAX_VALUE;
+                    float top = Float.MAX_VALUE;
+                    float right = Float.MIN_VALUE;
+                    float bottom = Float.MIN_VALUE;
+                    for (int i = 0; i < 8; i += 2) {
+                        float x = boundingRectPoints[i];
+                        float y = boundingRectPoints[i+1];
+                        if (x < left) {
+                            left = x;
+                        }
+                        if (x > right) {
+                            right = x;
+                        }
+                        if (y < top) {
+                            top = y;
+                        }
+                        if (y > bottom) {
+                            bottom = y;
+                        }
+                    }
+                    dirty.set((int)left + mLeft, (int)top + mTop, (int)(right + .5f) + mLeft,
+                            (int)(bottom + .5f) + mTop);
+                }
             } while (parent != null);
         }
     }
diff --git a/core/java/android/view/ViewRoot.java b/core/java/android/view/ViewRoot.java
index e63ecef..a89e7f6 100644
--- a/core/java/android/view/ViewRoot.java
+++ b/core/java/android/view/ViewRoot.java
@@ -130,7 +130,7 @@
     int mViewVisibility;
     boolean mAppVisible = true;
 
-    SurfaceHolder.Callback mSurfaceHolderCallback;
+    SurfaceHolder.Callback2 mSurfaceHolderCallback;
     BaseSurfaceHolder mSurfaceHolder;
     boolean mIsCreating;
     boolean mDrawingAllowed;
@@ -336,6 +336,7 @@
                             ((RootViewSurfaceTaker)view).willYouTakeTheSurface();
                     if (mSurfaceHolderCallback != null) {
                         mSurfaceHolder = new TakenSurfaceHolder();
+                        mSurfaceHolder.setFormat(PixelFormat.UNKNOWN);
                     }
                 }
                 Resources resources = mView.getContext().getResources();
@@ -440,18 +441,16 @@
                         "Unable to add window -- unknown error code " + res);
                 }
 
-                if (WindowManagerPolicy.ENABLE_NATIVE_INPUT_DISPATCH) {
-                    if (view instanceof RootViewSurfaceTaker) {
-                        mInputQueueCallback =
-                            ((RootViewSurfaceTaker)view).willYouTakeTheInputQueue();
-                    }
-                    if (mInputQueueCallback != null) {
-                        mInputQueue = new InputQueue(mInputChannel);
-                        mInputQueueCallback.onInputQueueCreated(mInputQueue);
-                    } else {
-                        InputQueue.registerInputChannel(mInputChannel, mInputHandler,
-                                Looper.myQueue());
-                    }
+                if (view instanceof RootViewSurfaceTaker) {
+                    mInputQueueCallback =
+                        ((RootViewSurfaceTaker)view).willYouTakeTheInputQueue();
+                }
+                if (mInputQueueCallback != null) {
+                    mInputQueue = new InputQueue(mInputChannel);
+                    mInputQueueCallback.onInputQueueCreated(mInputQueue);
+                } else {
+                    InputQueue.registerInputChannel(mInputChannel, mInputHandler,
+                            Looper.myQueue());
                 }
                 
                 view.assignParent(this);
@@ -652,7 +651,7 @@
             // object is not initialized to its backing store, but soon it
             // will be (assuming the window is visible).
             attachInfo.mSurface = mSurface;
-            attachInfo.mTranslucentWindow = lp.format != PixelFormat.OPAQUE;
+            attachInfo.mTranslucentWindow = PixelFormat.formatHasAlpha(lp.format);
             attachInfo.mHasWindowFocus = false;
             attachInfo.mWindowVisibility = viewVisibility;
             attachInfo.mRecomputeGlobalAttributes = false;
@@ -818,8 +817,6 @@
             if (mSurfaceHolder != null) {
                 mSurfaceHolder.mSurfaceLock.lock();
                 mDrawingAllowed = true;
-                lp.format = mSurfaceHolder.getRequestedFormat();
-                lp.type = mSurfaceHolder.getRequestedType();
             }
 
             boolean hwIntialized = false;
@@ -1155,6 +1152,18 @@
                     Log.v("ViewRoot", "FINISHED DRAWING: " + mWindowAttributes.getTitle());
                 }
                 mReportNextDraw = false;
+                if (mSurfaceHolder != null && mSurface.isValid()) {
+                    mSurfaceHolderCallback.surfaceRedrawNeeded(mSurfaceHolder);
+                    SurfaceHolder.Callback callbacks[] = mSurfaceHolder.getCallbacks();
+                    if (callbacks != null) {
+                        for (SurfaceHolder.Callback c : callbacks) {
+                            if (c instanceof SurfaceHolder.Callback2) {
+                                ((SurfaceHolder.Callback2)c).surfaceRedrawNeeded(
+                                        mSurfaceHolder);
+                            }
+                        }
+                    }
+                }
                 try {
                     sWindowSession.finishDrawing(mWindow);
                 } catch (RemoteException e) {
@@ -1264,7 +1273,7 @@
         
         if (mHwRenderer != null && mHwRenderer.isEnabled()) {
             if (!dirty.isEmpty()) {
-                mHwRenderer.draw(mView, mAttachInfo, mTranslator, yoff, mDensity, scalingRequired);
+                mHwRenderer.draw(mView, mAttachInfo, yoff);
             }
 
             if (scrolling) {
@@ -1596,16 +1605,12 @@
         }
         mSurface.release();
 
-        if (WindowManagerPolicy.ENABLE_NATIVE_INPUT_DISPATCH) {
-            if (mInputChannel != null) {
-                if (mInputQueueCallback != null) {
-                    mInputQueueCallback.onInputQueueDestroyed(mInputQueue);
-                    mInputQueueCallback = null;
-                } else {
-                    InputQueue.unregisterInputChannel(mInputChannel);
-                }
-                mInputChannel.dispose();
-                mInputChannel = null;
+        if (mInputChannel != null) {
+            if (mInputQueueCallback != null) {
+                mInputQueueCallback.onInputQueueDestroyed(mInputQueue);
+                mInputQueueCallback = null;
+            } else {
+                InputQueue.unregisterInputChannel(mInputChannel);
             }
         }
         
@@ -1614,13 +1619,11 @@
         } catch (RemoteException e) {
         }
         
-        if (WindowManagerPolicy.ENABLE_NATIVE_INPUT_DISPATCH) {
-            // Dispose the input channel after removing the window so the Window Manager
-            // doesn't interpret the input channel being closed as an abnormal termination.
-            if (mInputChannel != null) {
-                mInputChannel.dispose();
-                mInputChannel = null;
-            }
+        // Dispose the input channel after removing the window so the Window Manager
+        // doesn't interpret the input channel being closed as an abnormal termination.
+        if (mInputChannel != null) {
+            mInputChannel.dispose();
+            mInputChannel = null;
         }
     }
 
@@ -1720,109 +1723,22 @@
             deliverKeyEvent((KeyEvent)msg.obj, true);
             break;
         case DISPATCH_POINTER: {
-            MotionEvent event = (MotionEvent)msg.obj;
-            boolean callWhenDone = msg.arg1 != 0;
-            
-            if (event == null) {
-                long timeBeforeGettingEvents;
-                if (MEASURE_LATENCY) {
-                    timeBeforeGettingEvents = System.nanoTime();
-                }
-
-                event = getPendingPointerMotionEvent();
-
-                if (MEASURE_LATENCY && event != null) {
-                    lt.sample("9 Client got events      ",
-                            System.nanoTime() - event.getEventTimeNano());
-                    lt.sample("8 Client getting events  ",
-                            timeBeforeGettingEvents - event.getEventTimeNano());
-                }
-                callWhenDone = false;
-            }
-            if (event != null && mTranslator != null) {
-                mTranslator.translateEventInScreenToAppWindow(event);
-            }
+            MotionEvent event = (MotionEvent) msg.obj;
             try {
-                boolean handled;
-                if (mView != null && mAdded && event != null) {
-
-                    // enter touch mode on the down
-                    boolean isDown = event.getAction() == MotionEvent.ACTION_DOWN;
-                    if (isDown) {
-                        ensureTouchMode(true);
-                    }
-                    if(Config.LOGV) {
-                        captureMotionLog("captureDispatchPointer", event);
-                    }
-                    if (mCurScrollY != 0) {
-                        event.offsetLocation(0, mCurScrollY);
-                    }
-                    if (MEASURE_LATENCY) {
-                        lt.sample("A Dispatching TouchEvents",
-                                System.nanoTime() - event.getEventTimeNano());
-                    }
-                    handled = mView.dispatchTouchEvent(event);
-                    if (MEASURE_LATENCY) {
-                        lt.sample("B Dispatched TouchEvents ",
-                                System.nanoTime() - event.getEventTimeNano());
-                    }
-                    if (!handled && isDown) {
-                        int edgeSlop = mViewConfiguration.getScaledEdgeSlop();
-
-                        final int edgeFlags = event.getEdgeFlags();
-                        int direction = View.FOCUS_UP;
-                        int x = (int)event.getX();
-                        int y = (int)event.getY();
-                        final int[] deltas = new int[2];
-
-                        if ((edgeFlags & MotionEvent.EDGE_TOP) != 0) {
-                            direction = View.FOCUS_DOWN;
-                            if ((edgeFlags & MotionEvent.EDGE_LEFT) != 0) {
-                                deltas[0] = edgeSlop;
-                                x += edgeSlop;
-                            } else if ((edgeFlags & MotionEvent.EDGE_RIGHT) != 0) {
-                                deltas[0] = -edgeSlop;
-                                x -= edgeSlop;
-                            }
-                        } else if ((edgeFlags & MotionEvent.EDGE_BOTTOM) != 0) {
-                            direction = View.FOCUS_UP;
-                            if ((edgeFlags & MotionEvent.EDGE_LEFT) != 0) {
-                                deltas[0] = edgeSlop;
-                                x += edgeSlop;
-                            } else if ((edgeFlags & MotionEvent.EDGE_RIGHT) != 0) {
-                                deltas[0] = -edgeSlop;
-                                x -= edgeSlop;
-                            }
-                        } else if ((edgeFlags & MotionEvent.EDGE_LEFT) != 0) {
-                            direction = View.FOCUS_RIGHT;
-                        } else if ((edgeFlags & MotionEvent.EDGE_RIGHT) != 0) {
-                            direction = View.FOCUS_LEFT;
-                        }
-
-                        if (edgeFlags != 0 && mView instanceof ViewGroup) {
-                            View nearest = FocusFinder.getInstance().findNearestTouchable(
-                                    ((ViewGroup) mView), x, y, direction, deltas);
-                            if (nearest != null) {
-                                event.offsetLocation(deltas[0], deltas[1]);
-                                event.setEdgeFlags(0);
-                                mView.dispatchTouchEvent(event);
-                            }
-                        }
-                    }
-                }
+                deliverPointerEvent(event);
             } finally {
-                if (callWhenDone) {
-                    finishMotionEvent();
-                }
-                recycleMotionEvent(event);
+                event.recycle();
                 if (LOCAL_LOGV || WATCH_POINTER) Log.i(TAG, "Done dispatching!");
-                // Let the exception fall through -- the looper will catch
-                // it and take care of the bad app for us.
             }
         } break;
-        case DISPATCH_TRACKBALL:
-            deliverTrackballEvent((MotionEvent)msg.obj, msg.arg1 != 0);
-            break;
+        case DISPATCH_TRACKBALL: {
+            MotionEvent event = (MotionEvent) msg.obj;
+            try {
+                deliverTrackballEvent(event);
+            } finally {
+                event.recycle();
+            }
+        } break;
         case DISPATCH_APP_VISIBILITY:
             handleAppVisibility(msg.arg1 != 0);
             break;
@@ -1945,61 +1861,12 @@
     }
     
     private void finishKeyEvent(KeyEvent event) {
-        if (WindowManagerPolicy.ENABLE_NATIVE_INPUT_DISPATCH) {
-            if (mFinishedCallback != null) {
-                mFinishedCallback.run();
-                mFinishedCallback = null;
-            }
-        } else {
-            try {
-                sWindowSession.finishKey(mWindow);
-            } catch (RemoteException e) {
-            }
+        if (mFinishedCallback != null) {
+            mFinishedCallback.run();
+            mFinishedCallback = null;
         }
     }
     
-    private void finishMotionEvent() {
-        if (WindowManagerPolicy.ENABLE_NATIVE_INPUT_DISPATCH) {
-            throw new IllegalStateException("Should not be reachable with native input dispatch.");
-        }
-        
-        try {
-            sWindowSession.finishKey(mWindow);
-        } catch (RemoteException e) {
-        }
-    }
-
-    private void recycleMotionEvent(MotionEvent event) {
-        if (event != null) {
-            event.recycle();
-        }
-    }
-    
-    private MotionEvent getPendingPointerMotionEvent() {
-        if (WindowManagerPolicy.ENABLE_NATIVE_INPUT_DISPATCH) {
-            throw new IllegalStateException("Should not be reachable with native input dispatch.");
-        }
-        
-        try {
-            return sWindowSession.getPendingPointerMove(mWindow);
-        } catch (RemoteException e) {
-            return null;
-        }
-    }
-
-    private MotionEvent getPendingTrackballMotionEvent() {
-        if (WindowManagerPolicy.ENABLE_NATIVE_INPUT_DISPATCH) {
-            throw new IllegalStateException("Should not be reachable with native input dispatch.");
-        }
-        
-        try {
-            return sWindowSession.getPendingTrackballMove(mWindow);
-        } catch (RemoteException e) {
-            return null;
-        }
-    }
-    
-    
     /**
      * Something in the current window tells us we need to change the touch mode.  For
      * example, we are not in touch mode, and the user touches the screen.
@@ -2121,42 +1988,95 @@
         return false;
     }
 
-
-    private void deliverTrackballEvent(MotionEvent event, boolean callWhenDone) {
-        if (event == null) {
-            event = getPendingTrackballMotionEvent();
-            callWhenDone = false;
+    private void deliverPointerEvent(MotionEvent event) {
+        if (mTranslator != null) {
+            mTranslator.translateEventInScreenToAppWindow(event);
         }
+        
+        boolean handled;
+        if (mView != null && mAdded) {
 
+            // enter touch mode on the down
+            boolean isDown = event.getAction() == MotionEvent.ACTION_DOWN;
+            if (isDown) {
+                ensureTouchMode(true);
+            }
+            if(Config.LOGV) {
+                captureMotionLog("captureDispatchPointer", event);
+            }
+            if (mCurScrollY != 0) {
+                event.offsetLocation(0, mCurScrollY);
+            }
+            if (MEASURE_LATENCY) {
+                lt.sample("A Dispatching TouchEvents", System.nanoTime() - event.getEventTimeNano());
+            }
+            handled = mView.dispatchTouchEvent(event);
+            if (MEASURE_LATENCY) {
+                lt.sample("B Dispatched TouchEvents ", System.nanoTime() - event.getEventTimeNano());
+            }
+            if (!handled && isDown) {
+                int edgeSlop = mViewConfiguration.getScaledEdgeSlop();
+
+                final int edgeFlags = event.getEdgeFlags();
+                int direction = View.FOCUS_UP;
+                int x = (int)event.getX();
+                int y = (int)event.getY();
+                final int[] deltas = new int[2];
+
+                if ((edgeFlags & MotionEvent.EDGE_TOP) != 0) {
+                    direction = View.FOCUS_DOWN;
+                    if ((edgeFlags & MotionEvent.EDGE_LEFT) != 0) {
+                        deltas[0] = edgeSlop;
+                        x += edgeSlop;
+                    } else if ((edgeFlags & MotionEvent.EDGE_RIGHT) != 0) {
+                        deltas[0] = -edgeSlop;
+                        x -= edgeSlop;
+                    }
+                } else if ((edgeFlags & MotionEvent.EDGE_BOTTOM) != 0) {
+                    direction = View.FOCUS_UP;
+                    if ((edgeFlags & MotionEvent.EDGE_LEFT) != 0) {
+                        deltas[0] = edgeSlop;
+                        x += edgeSlop;
+                    } else if ((edgeFlags & MotionEvent.EDGE_RIGHT) != 0) {
+                        deltas[0] = -edgeSlop;
+                        x -= edgeSlop;
+                    }
+                } else if ((edgeFlags & MotionEvent.EDGE_LEFT) != 0) {
+                    direction = View.FOCUS_RIGHT;
+                } else if ((edgeFlags & MotionEvent.EDGE_RIGHT) != 0) {
+                    direction = View.FOCUS_LEFT;
+                }
+
+                if (edgeFlags != 0 && mView instanceof ViewGroup) {
+                    View nearest = FocusFinder.getInstance().findNearestTouchable(
+                            ((ViewGroup) mView), x, y, direction, deltas);
+                    if (nearest != null) {
+                        event.offsetLocation(deltas[0], deltas[1]);
+                        event.setEdgeFlags(0);
+                        mView.dispatchTouchEvent(event);
+                    }
+                }
+            }
+        }
+    }
+
+    private void deliverTrackballEvent(MotionEvent event) {
         if (DEBUG_TRACKBALL) Log.v(TAG, "Motion event:" + event);
 
         boolean handled = false;
-        try {
-            if (event == null) {
-                handled = true;
-            } else if (mView != null && mAdded) {
-                handled = mView.dispatchTrackballEvent(event);
-                if (!handled) {
-                    // we could do something here, like changing the focus
-                    // or something?
-                }
-            }
-        } finally {
+        if (mView != null && mAdded) {
+            handled = mView.dispatchTrackballEvent(event);
             if (handled) {
-                if (callWhenDone) {
-                    finishMotionEvent();
-                }
-                recycleMotionEvent(event);
                 // If we reach this, we delivered a trackball event to mView and
                 // mView consumed it. Because we will not translate the trackball
                 // event into a key event, touch mode will not exit, so we exit
                 // touch mode here.
                 ensureTouchMode(false);
-                //noinspection ReturnInsideFinallyBlock
                 return;
             }
-            // Let the exception fall through -- the looper will catch
-            // it and take care of the bad app for us.
+            
+            // Otherwise we could do something here, like changing the focus
+            // or something?
         }
 
         final TrackballAxis x = mTrackballAxisX;
@@ -2171,95 +2091,86 @@
             mLastTrackballTime = curTime;
         }
 
-        try {
-            final int action = event.getAction();
-            final int metastate = event.getMetaState();
-            switch (action) {
-                case MotionEvent.ACTION_DOWN:
-                    x.reset(2);
-                    y.reset(2);
-                    deliverKeyEvent(new KeyEvent(curTime, curTime,
-                            KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_DPAD_CENTER,
-                            0, metastate), false);
-                    break;
-                case MotionEvent.ACTION_UP:
-                    x.reset(2);
-                    y.reset(2);
-                    deliverKeyEvent(new KeyEvent(curTime, curTime,
-                            KeyEvent.ACTION_UP, KeyEvent.KEYCODE_DPAD_CENTER,
-                            0, metastate), false);
-                    break;
-            }
+        final int action = event.getAction();
+        final int metastate = event.getMetaState();
+        switch (action) {
+            case MotionEvent.ACTION_DOWN:
+                x.reset(2);
+                y.reset(2);
+                deliverKeyEvent(new KeyEvent(curTime, curTime,
+                        KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_DPAD_CENTER,
+                        0, metastate), false);
+                break;
+            case MotionEvent.ACTION_UP:
+                x.reset(2);
+                y.reset(2);
+                deliverKeyEvent(new KeyEvent(curTime, curTime,
+                        KeyEvent.ACTION_UP, KeyEvent.KEYCODE_DPAD_CENTER,
+                        0, metastate), false);
+                break;
+        }
 
-            if (DEBUG_TRACKBALL) Log.v(TAG, "TB X=" + x.position + " step="
-                    + x.step + " dir=" + x.dir + " acc=" + x.acceleration
-                    + " move=" + event.getX()
-                    + " / Y=" + y.position + " step="
-                    + y.step + " dir=" + y.dir + " acc=" + y.acceleration
-                    + " move=" + event.getY());
-            final float xOff = x.collect(event.getX(), event.getEventTime(), "X");
-            final float yOff = y.collect(event.getY(), event.getEventTime(), "Y");
+        if (DEBUG_TRACKBALL) Log.v(TAG, "TB X=" + x.position + " step="
+                + x.step + " dir=" + x.dir + " acc=" + x.acceleration
+                + " move=" + event.getX()
+                + " / Y=" + y.position + " step="
+                + y.step + " dir=" + y.dir + " acc=" + y.acceleration
+                + " move=" + event.getY());
+        final float xOff = x.collect(event.getX(), event.getEventTime(), "X");
+        final float yOff = y.collect(event.getY(), event.getEventTime(), "Y");
 
-            // Generate DPAD events based on the trackball movement.
-            // We pick the axis that has moved the most as the direction of
-            // the DPAD.  When we generate DPAD events for one axis, then the
-            // other axis is reset -- we don't want to perform DPAD jumps due
-            // to slight movements in the trackball when making major movements
-            // along the other axis.
-            int keycode = 0;
-            int movement = 0;
-            float accel = 1;
-            if (xOff > yOff) {
-                movement = x.generate((2/event.getXPrecision()));
-                if (movement != 0) {
-                    keycode = movement > 0 ? KeyEvent.KEYCODE_DPAD_RIGHT
-                            : KeyEvent.KEYCODE_DPAD_LEFT;
-                    accel = x.acceleration;
-                    y.reset(2);
-                }
-            } else if (yOff > 0) {
-                movement = y.generate((2/event.getYPrecision()));
-                if (movement != 0) {
-                    keycode = movement > 0 ? KeyEvent.KEYCODE_DPAD_DOWN
-                            : KeyEvent.KEYCODE_DPAD_UP;
-                    accel = y.acceleration;
-                    x.reset(2);
-                }
+        // Generate DPAD events based on the trackball movement.
+        // We pick the axis that has moved the most as the direction of
+        // the DPAD.  When we generate DPAD events for one axis, then the
+        // other axis is reset -- we don't want to perform DPAD jumps due
+        // to slight movements in the trackball when making major movements
+        // along the other axis.
+        int keycode = 0;
+        int movement = 0;
+        float accel = 1;
+        if (xOff > yOff) {
+            movement = x.generate((2/event.getXPrecision()));
+            if (movement != 0) {
+                keycode = movement > 0 ? KeyEvent.KEYCODE_DPAD_RIGHT
+                        : KeyEvent.KEYCODE_DPAD_LEFT;
+                accel = x.acceleration;
+                y.reset(2);
             }
+        } else if (yOff > 0) {
+            movement = y.generate((2/event.getYPrecision()));
+            if (movement != 0) {
+                keycode = movement > 0 ? KeyEvent.KEYCODE_DPAD_DOWN
+                        : KeyEvent.KEYCODE_DPAD_UP;
+                accel = y.acceleration;
+                x.reset(2);
+            }
+        }
 
-            if (keycode != 0) {
-                if (movement < 0) movement = -movement;
-                int accelMovement = (int)(movement * accel);
-                if (DEBUG_TRACKBALL) Log.v(TAG, "Move: movement=" + movement
-                        + " accelMovement=" + accelMovement
-                        + " accel=" + accel);
-                if (accelMovement > movement) {
-                    if (DEBUG_TRACKBALL) Log.v("foo", "Delivering fake DPAD: "
-                            + keycode);
-                    movement--;
-                    deliverKeyEvent(new KeyEvent(curTime, curTime,
-                            KeyEvent.ACTION_MULTIPLE, keycode,
-                            accelMovement-movement, metastate), false);
-                }
-                while (movement > 0) {
-                    if (DEBUG_TRACKBALL) Log.v("foo", "Delivering fake DPAD: "
-                            + keycode);
-                    movement--;
-                    curTime = SystemClock.uptimeMillis();
-                    deliverKeyEvent(new KeyEvent(curTime, curTime,
-                            KeyEvent.ACTION_DOWN, keycode, 0, event.getMetaState()), false);
-                    deliverKeyEvent(new KeyEvent(curTime, curTime,
-                            KeyEvent.ACTION_UP, keycode, 0, metastate), false);
-                }
-                mLastTrackballTime = curTime;
+        if (keycode != 0) {
+            if (movement < 0) movement = -movement;
+            int accelMovement = (int)(movement * accel);
+            if (DEBUG_TRACKBALL) Log.v(TAG, "Move: movement=" + movement
+                    + " accelMovement=" + accelMovement
+                    + " accel=" + accel);
+            if (accelMovement > movement) {
+                if (DEBUG_TRACKBALL) Log.v("foo", "Delivering fake DPAD: "
+                        + keycode);
+                movement--;
+                deliverKeyEvent(new KeyEvent(curTime, curTime,
+                        KeyEvent.ACTION_MULTIPLE, keycode,
+                        accelMovement-movement, metastate), false);
             }
-        } finally {
-            if (callWhenDone) {
-                finishMotionEvent();
-                recycleMotionEvent(event);
+            while (movement > 0) {
+                if (DEBUG_TRACKBALL) Log.v("foo", "Delivering fake DPAD: "
+                        + keycode);
+                movement--;
+                curTime = SystemClock.uptimeMillis();
+                deliverKeyEvent(new KeyEvent(curTime, curTime,
+                        KeyEvent.ACTION_DOWN, keycode, 0, event.getMetaState()), false);
+                deliverKeyEvent(new KeyEvent(curTime, curTime,
+                        KeyEvent.ACTION_UP, keycode, 0, metastate), false);
             }
-            // Let the exception fall through -- the looper will catch
-            // it and take care of the bad app for us.
+            mLastTrackballTime = curTime;
         }
     }
 
@@ -2704,45 +2615,20 @@
     private final InputHandler mInputHandler = new InputHandler() {
         public void handleKey(KeyEvent event, Runnable finishedCallback) {
             mFinishedCallback = finishedCallback;
-            
-            if (event.getAction() == KeyEvent.ACTION_DOWN) {
-                //noinspection ConstantConditions
-                if (false && event.getKeyCode() == KeyEvent.KEYCODE_CAMERA) {
-                    if (Config.LOGD) Log.d("keydisp",
-                            "===================================================");
-                    if (Config.LOGD) Log.d("keydisp", "Focused view Hierarchy is:");
-                    debug();
 
-                    if (Config.LOGD) Log.d("keydisp",
-                            "===================================================");
-                }
-            }
-
-            Message msg = obtainMessage(DISPATCH_KEY);
-            msg.obj = event;
-
-            if (LOCAL_LOGV) Log.v(
-                "ViewRoot", "sending key " + event + " to " + mView);
-
-            sendMessageAtTime(msg, event.getEventTime());
+            dispatchKey(event);
         }
 
         public void handleTouch(MotionEvent event, Runnable finishedCallback) {
             finishedCallback.run();
             
-            Message msg = obtainMessage(DISPATCH_POINTER);
-            msg.obj = event;
-            msg.arg1 = 0;
-            sendMessageAtTime(msg, event.getEventTime());
+            dispatchPointer(event);
         }
 
         public void handleTrackball(MotionEvent event, Runnable finishedCallback) {
             finishedCallback.run();
             
-            Message msg = obtainMessage(DISPATCH_TRACKBALL);
-            msg.obj = event;
-            msg.arg1 = 0;
-            sendMessageAtTime(msg, event.getEventTime());
+            dispatchTrackball(event);
         }
     };
 
@@ -2768,22 +2654,18 @@
         sendMessageAtTime(msg, event.getEventTime());
     }
 
-    public void dispatchPointer(MotionEvent event, long eventTime,
-            boolean callWhenDone) {
+    public void dispatchPointer(MotionEvent event) {
         Message msg = obtainMessage(DISPATCH_POINTER);
         msg.obj = event;
-        msg.arg1 = callWhenDone ? 1 : 0;
-        sendMessageAtTime(msg, eventTime);
+        sendMessageAtTime(msg, event.getEventTime());
     }
 
-    public void dispatchTrackball(MotionEvent event, long eventTime,
-            boolean callWhenDone) {
+    public void dispatchTrackball(MotionEvent event) {
         Message msg = obtainMessage(DISPATCH_TRACKBALL);
         msg.obj = event;
-        msg.arg1 = callWhenDone ? 1 : 0;
-        sendMessageAtTime(msg, eventTime);
+        sendMessageAtTime(msg, event.getEventTime());
     }
-
+    
     public void dispatchAppVisibility(boolean visible) {
         Message msg = obtainMessage(DISPATCH_APP_VISIBILITY);
         msg.arg1 = visible ? 1 : 0;
@@ -2914,56 +2796,11 @@
         }
     }
 
-    class EventCompletion extends Handler {
-        final IWindow mWindow;
-        final KeyEvent mKeyEvent;
-        final boolean mIsPointer;
-        final MotionEvent mMotionEvent;
-
-        EventCompletion(Looper looper, IWindow window, KeyEvent key,
-                boolean isPointer, MotionEvent motion) {
-            super(looper);
-            mWindow = window;
-            mKeyEvent = key;
-            mIsPointer = isPointer;
-            mMotionEvent = motion;
-            sendEmptyMessage(0);
-        }
-
-        @Override
-        public void handleMessage(Message msg) {
-            if (mKeyEvent != null) {
-                finishKeyEvent(mKeyEvent);
-           } else if (mIsPointer) {
-                boolean didFinish;
-                MotionEvent event = mMotionEvent;
-                if (event == null) {
-                    event = getPendingPointerMotionEvent();
-                    didFinish = true;
-                } else {
-                    didFinish = event.getAction() == MotionEvent.ACTION_OUTSIDE;
-                }
-                if (!didFinish) {
-                    finishMotionEvent();
-                }
-            } else {
-                MotionEvent event = mMotionEvent;
-                if (event == null) {
-                    event = getPendingTrackballMotionEvent();
-                } else {
-                    finishMotionEvent();
-                }
-            }
-        }
-    }
-
     static class W extends IWindow.Stub {
         private final WeakReference<ViewRoot> mViewRoot;
-        private final Looper mMainLooper;
 
         public W(ViewRoot viewRoot, Context context) {
             mViewRoot = new WeakReference<ViewRoot>(viewRoot);
-            mMainLooper = context.getMainLooper();
         }
 
         public void resized(int w, int h, Rect coveredInsets,
@@ -2975,40 +2812,6 @@
             }
         }
 
-        public void dispatchKey(KeyEvent event) {
-            final ViewRoot viewRoot = mViewRoot.get();
-            if (viewRoot != null) {
-                viewRoot.dispatchKey(event);
-            } else {
-                Log.w("ViewRoot.W", "Key event " + event + " but no ViewRoot available!");
-                viewRoot.new EventCompletion(mMainLooper, this, event, false, null);
-            }
-        }
-
-        public void dispatchPointer(MotionEvent event, long eventTime,
-                boolean callWhenDone) {
-            final ViewRoot viewRoot = mViewRoot.get();
-            if (viewRoot != null) {                
-                if (MEASURE_LATENCY) {
-                    // Note: eventTime is in milliseconds
-                    ViewRoot.lt.sample("* ViewRoot b4 dispatchPtr", System.nanoTime() - eventTime * 1000000);
-                }
-                viewRoot.dispatchPointer(event, eventTime, callWhenDone);
-            } else {
-                viewRoot.new EventCompletion(mMainLooper, this, null, true, event);
-            }
-        }
-
-        public void dispatchTrackball(MotionEvent event, long eventTime,
-                boolean callWhenDone) {
-            final ViewRoot viewRoot = mViewRoot.get();
-            if (viewRoot != null) {
-                viewRoot.dispatchTrackball(event, eventTime, callWhenDone);
-            } else {
-                viewRoot.new EventCompletion(mMainLooper, this, null, false, event);
-            }
-        }
-
         public void dispatchAppVisibility(boolean visible) {
             final ViewRoot viewRoot = mViewRoot.get();
             if (viewRoot != null) {
diff --git a/core/java/android/view/Window.java b/core/java/android/view/Window.java
index 9b31b9c..be681cc 100644
--- a/core/java/android/view/Window.java
+++ b/core/java/android/view/Window.java
@@ -485,7 +485,7 @@
      * to operate (such as for receiving input events).  The given SurfaceHolder
      * callback will be used to tell you about state changes to the surface.
      */
-    public abstract void takeSurface(SurfaceHolder.Callback callback);
+    public abstract void takeSurface(SurfaceHolder.Callback2 callback);
     
     /**
      * Take ownership of this window's InputQueue.  The window will no
diff --git a/core/java/android/view/WindowManagerPolicy.java b/core/java/android/view/WindowManagerPolicy.java
index be1f6d2..33757f0 100644
--- a/core/java/android/view/WindowManagerPolicy.java
+++ b/core/java/android/view/WindowManagerPolicy.java
@@ -78,12 +78,6 @@
     public final static int FLAG_BRIGHT_HERE = 0x20000000;
 
     public final static boolean WATCH_POINTER = false;
-    
-    /**
-     * Temporary flag added during the transition to the new native input dispatcher.
-     * This will be removed when the old input dispatch code is deleted.
-     */
-    public final static boolean ENABLE_NATIVE_INPUT_DISPATCH = true;
 
     // flags for interceptKeyTq
     /**
@@ -555,23 +549,26 @@
     public Animation createForceHideEnterAnimation();
     
     /**
-     * Called from the key queue thread before a key is dispatched to the
-     * input thread.
+     * Called from the input reader thread before a key is enqueued.
      *
      * <p>There are some actions that need to be handled here because they
      * affect the power state of the device, for example, the power keys.
      * 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 keyCode The key code.
+     * @param down True if the key is down.
+     * @param policyFlags The policy flags associated with the key.
+     * @param isScreenOn True if the screen is already on
      *
-     * @param event the raw input event as read from the driver
-     * @param screenIsOn 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 interceptKeyTq(RawInputEvent event, boolean screenIsOn);
+    public int interceptKeyBeforeQueueing(long whenNanos, int keyCode, boolean down, int policyFlags,
+            boolean isScreenOn);
     
     /**
-     * Called from the input thread before a key is dispatched to a window.
+     * Called from the input dispatcher thread before a key is dispatched to a window.
      *
      * <p>Allows you to define
      * behavior for keys that can not be overridden by applications or redirect
@@ -583,16 +580,17 @@
      * 
      * @param win The window that currently has focus.  This is where the key
      *            event will normally go.
-     * @param code Key code.
-     * @param metaKeys bit mask of meta keys that are held.
-     * @param down Is this a key press (true) or release (false)?
+     * @param action The key event action.
+     * @param flags The key event flags.
+     * @param keyCode The key code.
+     * @param metaState bit mask of meta keys that are held.
      * @param repeatCount Number of times a key down has repeated.
-     * @param flags event's flags.
+     * @param policyFlags The policy flags associated with the key.
      * @return Returns true if the policy consumed the event and it should
      * not be further dispatched.
      */
-    public boolean interceptKeyTi(WindowState win, int code,
-                               int metaKeys, boolean down, int repeatCount, int flags);
+    public boolean interceptKeyBeforeDispatching(WindowState win, int action, int flags,
+            int keyCode, int metaState, int repeatCount, int policyFlags);
 
     /**
      * Called when layout of the windows is about to start.
@@ -701,85 +699,15 @@
      * Return whether the screen is currently on.
      */
     public boolean isScreenOn();
-    
+
     /**
-     * Perform any initial processing of a low-level input event before the
-     * window manager handles special keys and generates a high-level event
-     * that is dispatched to the application.
-     * 
-     * @param event The input event that has occurred.
-     * 
-     * @return Return true if you have consumed the event and do not want
-     * further processing to occur; return false for normal processing.
+     * Tell the policy that the lid switch has changed state.
+     * @param whenNanos The time when the change occurred in uptime nanoseconds.
+     * @param lidOpen True if the lid is now open.
      */
-    public boolean preprocessInputEventTq(RawInputEvent event);
-    
     public void notifyLidSwitchChanged(long whenNanos, boolean lidOpen);
     
     /**
-     * Determine whether a given key code is used to cause an app switch
-     * to occur (most often the HOME key, also often ENDCALL).  If you return
-     * true, then the system will go into a special key processing state
-     * where it drops any pending events that it cans and adjusts timeouts to
-     * try to get to this key as quickly as possible.
-     * 
-     * <p>Note that this function is called from the low-level input queue
-     * thread, with either/or the window or input lock held; be very careful
-     * about what you do here.  You absolutely should never acquire a lock
-     * that you would ever hold elsewhere while calling out into the window
-     * manager or view hierarchy.
-     * 
-     * @param keycode The key that should be checked for performing an
-     * app switch before delivering to the application.
-     * 
-     * @return Return true if this is an app switch key and special processing
-     * should happen; return false for normal processing.
-     */
-    public boolean isAppSwitchKeyTqTiLwLi(int keycode);
-    
-    /**
-     * Determine whether a given key code is used for movement within a UI,
-     * and does not generally cause actions to be performed (normally the DPAD
-     * movement keys, NOT the DPAD center press key).  This is called
-     * when {@link #isAppSwitchKeyTiLi} returns true to remove any pending events
-     * in the key queue that are not needed to switch applications.
-     * 
-     * <p>Note that this function is called from the low-level input queue
-     * thread; be very careful about what you do here.
-     * 
-     * @param keycode The key that is waiting to be delivered to the
-     * application.
-     * 
-     * @return Return true if this is a purely navigation key and can be
-     * dropped without negative consequences; return false to keep it.
-     */
-    public boolean isMovementKeyTi(int keycode);
-    
-    /**
-     * Given the current state of the world, should this relative movement
-     * wake up the device?
-     * 
-     * @param device The device the movement came from.
-     * @param classes The input classes associated with the device.
-     * @param event The input event that occurred.
-     * @return
-     */
-    public boolean isWakeRelMovementTq(int device, int classes,
-            RawInputEvent event);
-    
-    /**
-     * Given the current state of the world, should this absolute movement
-     * wake up the device?
-     * 
-     * @param device The device the movement came from.
-     * @param classes The input classes associated with the device.
-     * @param event The input event that occurred.
-     * @return
-     */
-    public boolean isWakeAbsMovementTq(int device, int classes,
-            RawInputEvent event);
-    
-    /**
      * Tell the policy if anyone is requesting that keyguard not come on.
      *
      * @param enabled Whether keyguard can be on or not.  does not actually
@@ -852,18 +780,6 @@
     public void enableScreenAfterBoot();
     
     /**
-     * Returns true if the user's cheek has been pressed against the phone. This is 
-     * determined by comparing the event's size attribute with a threshold value.
-     * For example for a motion event like down or up or move, if the size exceeds
-     * the threshold, it is considered as cheek press.
-     * @param ev the motion event generated when the cheek is pressed 
-     * against the phone
-     * @return Returns true if the user's cheek has been pressed against the phone
-     * screen resulting in an invalid motion event
-     */
-    public boolean isCheekPressedAgainstScreen(MotionEvent ev);
-    
-    /**
      * Called every time the window manager is dispatching a pointer event.
      */
     public void dispatchedPointerEventLw(MotionEvent ev, int targetX, int targetY);
@@ -876,13 +792,6 @@
     public boolean performHapticFeedbackLw(WindowState win, int effectId, boolean always);
     
     /**
-     * A special function that is called from the very low-level input queue
-     * to provide feedback to the user.  Currently only called for virtual
-     * keys.
-     */
-    public void keyFeedbackFromInput(KeyEvent event);
-    
-    /**
      * Called when we have stopped keeping the screen on because a window
      * requesting this is no longer visible.
      */
diff --git a/core/java/android/webkit/BrowserFrame.java b/core/java/android/webkit/BrowserFrame.java
index 7b1aab2..b021ded 100644
--- a/core/java/android/webkit/BrowserFrame.java
+++ b/core/java/android/webkit/BrowserFrame.java
@@ -301,6 +301,18 @@
     }
 
     /**
+     * Saves the contents of the frame as a web archive.
+     *
+     * @param basename The filename where the archive should be placed.
+     * @param autoname If false, takes filename to be a file. If true, filename
+     *                 is assumed to be a directory in which a filename will be
+     *                 chosen according to the url of the current page.
+     */
+    /* package */ String saveWebArchive(String basename, boolean autoname) {
+        return nativeSaveWebArchive(basename, autoname);
+    }
+
+    /**
      * Go back or forward the number of steps given.
      * @param steps A negative or positive number indicating the direction
      *              and number of steps to move.
@@ -1040,5 +1052,7 @@
      */
     private native HashMap getFormTextData();
 
+    private native String nativeSaveWebArchive(String basename, boolean autoname);
+
     private native void nativeOrientationChanged(int orientation);
 }
diff --git a/core/java/android/webkit/MimeTypeMap.java b/core/java/android/webkit/MimeTypeMap.java
index c1ac180..6e9c70a 100644
--- a/core/java/android/webkit/MimeTypeMap.java
+++ b/core/java/android/webkit/MimeTypeMap.java
@@ -363,6 +363,7 @@
             sMimeTypeMap.loadEntry("application/x-wais-source", "src");
             sMimeTypeMap.loadEntry("application/x-wingz", "wz");
             sMimeTypeMap.loadEntry("application/x-webarchive", "webarchive");
+            sMimeTypeMap.loadEntry("application/x-webarchive-xml", "webarchivexml");
             sMimeTypeMap.loadEntry("application/x-x509-ca-cert", "crt");
             sMimeTypeMap.loadEntry("application/x-x509-user-cert", "crt");
             sMimeTypeMap.loadEntry("application/x-xcf", "xcf");
diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java
index d5136ae9..0c8fc79 100644
--- a/core/java/android/webkit/WebView.java
+++ b/core/java/android/webkit/WebView.java
@@ -22,14 +22,15 @@
 import android.content.DialogInterface;
 import android.content.Intent;
 import android.content.DialogInterface.OnCancelListener;
-import android.content.pm.PackageManager;
 import android.database.DataSetObserver;
 import android.graphics.Bitmap;
 import android.graphics.Canvas;
 import android.graphics.Color;
 import android.graphics.CornerPathEffect;
+import android.graphics.DrawFilter;
 import android.graphics.Interpolator;
 import android.graphics.Paint;
+import android.graphics.PaintFlagsDrawFilter;
 import android.graphics.Picture;
 import android.graphics.Point;
 import android.graphics.Rect;
@@ -454,10 +455,6 @@
     // true if onPause has been called (and not onResume)
     private boolean mIsPaused;
 
-    // true if, during a transition to a new page, we're delaying
-    // deleting a root layer until there's something to draw of the new page.
-    private boolean mDelayedDeleteRootLayer;
-
     /**
      * Customizable constant
      */
@@ -584,8 +581,8 @@
     static final int SHOW_FULLSCREEN                    = 120;
     static final int HIDE_FULLSCREEN                    = 121;
     static final int DOM_FOCUS_CHANGED                  = 122;
-    static final int IMMEDIATE_REPAINT_MSG_ID           = 123;
-    static final int SET_ROOT_LAYER_MSG_ID              = 124;
+    static final int REPLACE_BASE_CONTENT               = 123;
+    // 124;
     static final int RETURN_LABEL                       = 125;
     static final int FIND_AGAIN                         = 126;
     static final int CENTER_FIT_RECT                    = 127;
@@ -593,6 +590,7 @@
     static final int SET_SCROLLBAR_MODES                = 129;
     static final int SELECTION_STRING_CHANGED           = 130;
     static final int SET_TOUCH_HIGHLIGHT_RECTS          = 131;
+    static final int SAVE_WEBARCHIVE_FINISHED           = 132;
 
     private static final int FIRST_PACKAGE_MSG_ID = SCROLL_TO_MSG_ID;
     private static final int LAST_PACKAGE_MSG_ID = SET_TOUCH_HIGHLIGHT_RECTS;
@@ -633,15 +631,16 @@
         "SHOW_FULLSCREEN", //                = 120;
         "HIDE_FULLSCREEN", //                = 121;
         "DOM_FOCUS_CHANGED", //              = 122;
-        "IMMEDIATE_REPAINT_MSG_ID", //       = 123;
-        "SET_ROOT_LAYER_MSG_ID", //          = 124;
+        "REPLACE_BASE_CONTENT", //           = 123;
+        "124", //                            = 124;
         "RETURN_LABEL", //                   = 125;
         "FIND_AGAIN", //                     = 126;
         "CENTER_FIT_RECT", //                = 127;
         "REQUEST_KEYBOARD_WITH_SELECTION_MSG_ID", // = 128;
         "SET_SCROLLBAR_MODES", //            = 129;
         "SELECTION_STRING_CHANGED", //       = 130;
-        "SET_TOUCH_HIGHLIGHT_RECTS" //       = 131;
+        "SET_TOUCH_HIGHLIGHT_RECTS", //      = 131;
+        "SAVE_WEBARCHIVE_FINISHED" //        = 132;
     };
 
     // If the site doesn't use the viewport meta tag to specify the viewport,
@@ -1523,6 +1522,45 @@
     }
 
     /**
+     * Saves the current view as a web archive.
+     *
+     * @param filename The filename where the archive should be placed.
+     */
+    public void saveWebArchive(String filename) {
+        saveWebArchive(filename, false, null);
+    }
+
+    /* package */ static class SaveWebArchiveMessage {
+        SaveWebArchiveMessage (String basename, boolean autoname, ValueCallback<String> callback) {
+            mBasename = basename;
+            mAutoname = autoname;
+            mCallback = callback;
+        }
+
+        /* package */ final String mBasename;
+        /* package */ final boolean mAutoname;
+        /* package */ final ValueCallback<String> mCallback;
+        /* package */ String mResultFile;
+    }
+
+    /**
+     * Saves the current view as a web archive.
+     *
+     * @param basename The filename where the archive should be placed.
+     * @param autoname If false, takes basename to be a file. If true, basename
+     *                 is assumed to be a directory in which a filename will be
+     *                 chosen according to the url of the current page.
+     * @param callback Called after the web archive has been saved. The
+     *                 parameter for onReceiveValue will either be the filename
+     *                 under which the file was saved, or null if saving the
+     *                 file failed.
+     */
+    public void saveWebArchive(String basename, boolean autoname, ValueCallback<String> callback) {
+        mWebViewCore.sendMessage(EventHub.SAVE_WEBARCHIVE,
+            new SaveWebArchiveMessage(basename, autoname, callback));
+    }
+
+    /**
      * Stop the current load.
      */
     public void stopLoading() {
@@ -1691,6 +1729,7 @@
     public void clearView() {
         mContentWidth = 0;
         mContentHeight = 0;
+        nativeSetBaseLayer(0);
         mWebViewCore.sendMessage(EventHub.CLEAR_CONTENT);
     }
 
@@ -1704,8 +1743,9 @@
      *         bounds of the view.
      */
     public Picture capturePicture() {
-        if (null == mWebViewCore) return null; // check for out of memory tab
-        return mWebViewCore.copyContentPicture();
+        Picture result = new Picture();
+        nativeCopyBaseContentToPicture(result);
+        return result;
     }
 
     /**
@@ -3232,16 +3272,6 @@
         }
     }
 
-    private void drawExtras(Canvas canvas, int extras, boolean animationsRunning) {
-        // If mNativeClass is 0, we should not reach here, so we do not
-        // need to check it again.
-        if (animationsRunning) {
-            canvas.setDrawFilter(mWebViewCore.mZoomFilter);
-        }
-        nativeDrawExtras(canvas, extras);
-        canvas.setDrawFilter(null);
-    }
-
     private void onZoomAnimationStart() {
         // If it is in password mode, turn it off so it does not draw misplaced.
         if (inEditingMode() && nativeFocusCandidateIsPassword()) {
@@ -3268,6 +3298,18 @@
         onZoomAnimationEnd();
     }
 
+    private static final int ZOOM_BITS = Paint.FILTER_BITMAP_FLAG |
+                                         Paint.DITHER_FLAG |
+                                         Paint.SUBPIXEL_TEXT_FLAG;
+    private static final int SCROLL_BITS = Paint.FILTER_BITMAP_FLAG |
+                                           Paint.DITHER_FLAG;
+
+    private final DrawFilter mZoomFilter =
+            new PaintFlagsDrawFilter(ZOOM_BITS, Paint.LINEAR_TEXT_FLAG);
+    // If we need to trade better quality for speed, set mScrollFilter to null
+    private final DrawFilter mScrollFilter =
+            new PaintFlagsDrawFilter(SCROLL_BITS, 0);
+
     private void drawCoreAndCursorRing(Canvas canvas, int color,
         boolean drawCursorRing) {
         if (mDrawHistory) {
@@ -3275,6 +3317,7 @@
             canvas.drawPicture(mHistoryPicture);
             return;
         }
+        if (mNativeClass == 0) return;
 
         boolean animateZoom = mZoomManager.isFixedLengthAnimationInProgress();
         boolean animateScroll = ((!mScroller.isFinished()
@@ -3309,10 +3352,7 @@
             // we ask for a repaint.
             invalidate();
         }
-        mWebViewCore.drawContentPicture(canvas, color,
-                (mZoomManager.isZoomAnimating() || UIAnimationsRunning),
-                animateScroll);
-        if (mNativeClass == 0) return;
+
         // decide which adornments to draw
         int extras = DRAW_EXTRAS_NONE;
         if (DebugFlags.WEB_VIEW) {
@@ -3332,7 +3372,18 @@
         } else if (drawCursorRing) {
             extras = DRAW_EXTRAS_CURSOR_RING;
         }
-        drawExtras(canvas, extras, UIAnimationsRunning);
+        DrawFilter df = null;
+        if (mZoomManager.isZoomAnimating() || UIAnimationsRunning) {
+            df = mZoomFilter;
+        } else if (animateScroll) {
+            df = mScrollFilter;
+        }
+        canvas.setDrawFilter(df);
+        int content = nativeDraw(canvas, color, extras, true);
+        canvas.setDrawFilter(null);
+        if (content != 0) {
+            mWebViewCore.sendMessage(EventHub.SPLIT_PICTURE_SET, content, 0);
+        }
 
         if (extras == DRAW_EXTRAS_CURSOR_RING) {
             if (mTouchMode == TOUCH_SHORTPRESS_START_MODE) {
@@ -3368,7 +3419,7 @@
     // Should only be called in UI thread
     void switchOutDrawHistory() {
         if (null == mWebViewCore) return; // CallbackProxy may trigger this
-        if (mDrawHistory && mWebViewCore.pictureReady()) {
+        if (mDrawHistory && (getProgress() == 100 || nativeHasContent())) {
             mDrawHistory = false;
             mHistoryPicture = null;
             invalidate();
@@ -6036,16 +6087,14 @@
                     mZoomManager.updateZoomRange(viewState, getViewWidth(), viewState.mScrollX);
                     break;
                 }
+                case REPLACE_BASE_CONTENT: {
+                    nativeReplaceBaseContent(msg.arg1);
+                    break;
+                }
                 case NEW_PICTURE_MSG_ID: {
-                    // If we've previously delayed deleting a root
-                    // layer, do it now.
-                    if (mDelayedDeleteRootLayer) {
-                        mDelayedDeleteRootLayer = false;
-                        nativeSetRootLayer(0);
-                    }
                     // called for new content
                     final WebViewCore.DrawData draw = (WebViewCore.DrawData) msg.obj;
-
+                    nativeSetBaseLayer(draw.mBaseLayer);
                     final Point viewSize = draw.mViewPoint;
                     WebViewCore.ViewState viewState = draw.mViewState;
                     boolean isPictureAfterFirstLayout = viewState != null;
@@ -6166,23 +6215,6 @@
                     }
                     break;
                 }
-                case IMMEDIATE_REPAINT_MSG_ID: {
-                    invalidate();
-                    break;
-                }
-                case SET_ROOT_LAYER_MSG_ID: {
-                    if (0 == msg.arg1) {
-                        // Null indicates deleting the old layer, but
-                        // don't actually do so until we've got the
-                        // new page to display.
-                        mDelayedDeleteRootLayer = true;
-                    } else {
-                        mDelayedDeleteRootLayer = false;
-                        nativeSetRootLayer(msg.arg1);
-                        invalidate();
-                    }
-                    break;
-                }
                 case REQUEST_FORM_DATA:
                     AutoCompleteAdapter adapter = (AutoCompleteAdapter) msg.obj;
                     if (mWebTextView.isSameTextField(msg.arg1)) {
@@ -6444,6 +6476,13 @@
                     }
                     break;
 
+                case SAVE_WEBARCHIVE_FINISHED:
+                    SaveWebArchiveMessage saveMessage = (SaveWebArchiveMessage)msg.obj;
+                    if (saveMessage.mCallback != null) {
+                        saveMessage.mCallback.onReceiveValue(saveMessage.mResultFile);
+                    }
+                    break;
+
                 default:
                     super.handleMessage(msg);
                     break;
@@ -6944,7 +6983,7 @@
      * @hide only needs to be accessible to Browser and testing
      */
     public void drawPage(Canvas canvas) {
-        mWebViewCore.drawContentPicture(canvas, 0, false, false);
+        nativeDraw(canvas, 0, 0, false);
     }
 
     /**
@@ -6988,7 +7027,15 @@
     private native boolean  nativeCursorWantsKeyEvents();
     private native void     nativeDebugDump();
     private native void     nativeDestroy();
-    private native void     nativeDrawExtras(Canvas canvas, int extra);
+
+    /**
+     * Draw the picture set with a background color and extra. If
+     * "splitIfNeeded" is true and the return value is not 0, the return value
+     * MUST be passed to WebViewCore with SPLIT_PICTURE_SET message so that the
+     * native allocation can be freed.
+     */
+    private native int nativeDraw(Canvas canvas, int color, int extra,
+            boolean splitIfNeeded);
     private native void     nativeDumpDisplayTree(String urlOrNull);
     private native boolean  nativeEvaluateLayersAnimations();
     private native void     nativeExtendSelection(int x, int y);
@@ -7053,7 +7100,10 @@
     private native void     nativeSetFindIsUp(boolean isUp);
     private native void     nativeSetFollowedLink(boolean followed);
     private native void     nativeSetHeightCanMeasure(boolean measure);
-    private native void     nativeSetRootLayer(int layer);
+    private native void     nativeSetBaseLayer(int layer);
+    private native void     nativeReplaceBaseContent(int content);
+    private native void     nativeCopyBaseContentToPicture(Picture pict);
+    private native boolean  nativeHasContent();
     private native void     nativeSetSelectionPointer(boolean set,
             float scale, int x, int y);
     private native boolean  nativeStartSelection(int x, int y);
diff --git a/core/java/android/webkit/WebViewCore.java b/core/java/android/webkit/WebViewCore.java
index 54699d6..21af570 100644
--- a/core/java/android/webkit/WebViewCore.java
+++ b/core/java/android/webkit/WebViewCore.java
@@ -19,11 +19,6 @@
 import android.content.Context;
 import android.content.pm.PackageManager.NameNotFoundException;
 import android.database.Cursor;
-import android.graphics.Canvas;
-import android.graphics.DrawFilter;
-import android.graphics.Paint;
-import android.graphics.PaintFlagsDrawFilter;
-import android.graphics.Picture;
 import android.graphics.Point;
 import android.graphics.Rect;
 import android.graphics.Region;
@@ -33,7 +28,6 @@
 import android.os.Message;
 import android.os.Process;
 import android.provider.MediaStore;
-import android.provider.MediaStore.Images.Media;
 import android.util.Log;
 import android.util.SparseBooleanArray;
 import android.view.KeyEvent;
@@ -443,35 +437,18 @@
     private native void nativeClearContent();
 
     /**
-     * Create a flat picture from the set of pictures.
-     */
-    private native void nativeCopyContentToPicture(Picture picture);
-
-    /**
-     * Draw the picture set with a background color. Returns true
-     * if some individual picture took too long to draw and can be
-     * split into parts. Called from the UI thread.
-     */
-    private native boolean nativeDrawContent(Canvas canvas, int color);
-
-    /**
-     * check to see if picture is blank and in progress
-     */
-    private native boolean nativePictureReady();
-
-    /**
      * Redraw a portion of the picture set. The Point wh returns the
      * width and height of the overall picture.
      */
-    private native boolean nativeRecordContent(Region invalRegion, Point wh);
+    private native int nativeRecordContent(Region invalRegion, Point wh);
 
     private native boolean nativeFocusBoundsChanged();
 
     /**
-     * Splits slow parts of the picture set. Called from the webkit
-     * thread after nativeDrawContent returns true.
+     * Splits slow parts of the picture set. Called from the webkit thread after
+     * WebView.nativeDraw() returns content to be split.
      */
-    private native void nativeSplitContent();
+    private native void nativeSplitContent(int content);
 
     private native boolean nativeKey(int keyCode, int unichar,
             int repeatCount, boolean isShift, boolean isAlt, boolean isSym,
@@ -797,6 +774,7 @@
             "ON_RESUME",    // = 144
             "FREE_MEMORY",  // = 145
             "VALID_NODE_BOUNDS", // = 146
+            "SAVE_WEBARCHIVE", // = 147
         };
 
     class EventHub {
@@ -863,6 +841,9 @@
         static final int FREE_MEMORY = 145;
         static final int VALID_NODE_BOUNDS = 146;
 
+        // Load and save web archives
+        static final int SAVE_WEBARCHIVE = 147;
+
         // Network-based messaging
         static final int CLEAR_SSL_PREF_TABLE = 150;
 
@@ -1323,6 +1304,15 @@
                             nativeSetJsFlags((String)msg.obj);
                             break;
 
+                        case SAVE_WEBARCHIVE:
+                            WebView.SaveWebArchiveMessage saveMessage =
+                                (WebView.SaveWebArchiveMessage)msg.obj;
+                            saveMessage.mResultFile =
+                                saveWebArchive(saveMessage.mBasename, saveMessage.mAutoname);
+                            mWebView.mPrivateHandler.obtainMessage(
+                                WebView.SAVE_WEBARCHIVE_FINISHED, saveMessage).sendToTarget();
+                            break;
+
                         case GEOLOCATION_PERMISSIONS_PROVIDE:
                             GeolocationPermissionsData data =
                                     (GeolocationPermissionsData) msg.obj;
@@ -1336,7 +1326,9 @@
                             break;
 
                         case SPLIT_PICTURE_SET:
-                            nativeSplitContent();
+                            nativeSplitContent(msg.arg1);
+                            mWebView.mPrivateHandler.obtainMessage(
+                                    WebView.REPLACE_BASE_CONTENT, msg.arg1, 0);
                             mSplitPictureIsScheduled = false;
                             break;
 
@@ -1622,6 +1614,13 @@
         mBrowserFrame.loadUrl(url, extraHeaders);
     }
 
+    private String saveWebArchive(String filename, boolean autoname) {
+        if (DebugFlags.WEB_VIEW_CORE) {
+            Log.v(LOGTAG, " CORE saveWebArchive " + filename + " " + autoname);
+        }
+        return mBrowserFrame.saveWebArchive(filename, autoname);
+    }
+
     private void key(KeyEvent evt, boolean isDown) {
         if (DebugFlags.WEB_VIEW_CORE) {
             Log.v(LOGTAG, "CORE key at " + System.currentTimeMillis() + ", "
@@ -1736,6 +1735,14 @@
         return usedQuota;
     }
 
+    // called from UI thread
+    void splitContent(int content) {
+        if (!mSplitPictureIsScheduled) {
+            mSplitPictureIsScheduled = true;
+            sendMessage(EventHub.SPLIT_PICTURE_SET, content, 0);
+        }
+    }
+
     // Used to avoid posting more than one draw message.
     private boolean mDrawIsScheduled;
 
@@ -1762,9 +1769,11 @@
 
     static class DrawData {
         DrawData() {
+            mBaseLayer = 0;
             mInvalRegion = new Region();
             mWidthHeight = new Point();
         }
+        int mBaseLayer;
         Region mInvalRegion;
         Point mViewPoint;
         Point mWidthHeight;
@@ -1778,8 +1787,8 @@
         mDrawIsScheduled = false;
         DrawData draw = new DrawData();
         if (DebugFlags.WEB_VIEW_CORE) Log.v(LOGTAG, "webkitDraw start");
-        if (nativeRecordContent(draw.mInvalRegion, draw.mWidthHeight)
-                == false) {
+        draw.mBaseLayer = nativeRecordContent(draw.mInvalRegion, draw.mWidthHeight);
+        if (draw.mBaseLayer == 0) {
             if (DebugFlags.WEB_VIEW_CORE) Log.v(LOGTAG, "webkitDraw abort");
             return;
         }
@@ -1812,51 +1821,6 @@
         }
     }
 
-    ///////////////////////////////////////////////////////////////////////////
-    // These are called from the UI thread, not our thread
-
-    static final int ZOOM_BITS = Paint.FILTER_BITMAP_FLAG |
-                                         Paint.DITHER_FLAG |
-                                         Paint.SUBPIXEL_TEXT_FLAG;
-    static final int SCROLL_BITS = Paint.FILTER_BITMAP_FLAG |
-                                           Paint.DITHER_FLAG;
-
-    final DrawFilter mZoomFilter =
-                    new PaintFlagsDrawFilter(ZOOM_BITS, Paint.LINEAR_TEXT_FLAG);
-    // If we need to trade better quality for speed, set mScrollFilter to null
-    final DrawFilter mScrollFilter =
-                new PaintFlagsDrawFilter(SCROLL_BITS, 0);
-
-    /* package */ void drawContentPicture(Canvas canvas, int color,
-                                          boolean animatingZoom,
-                                          boolean animatingScroll) {
-        DrawFilter df = null;
-        if (animatingZoom) {
-            df = mZoomFilter;
-        } else if (animatingScroll) {
-            df = mScrollFilter;
-        }
-        canvas.setDrawFilter(df);
-        boolean tookTooLong = nativeDrawContent(canvas, color);
-        canvas.setDrawFilter(null);
-        if (tookTooLong && mSplitPictureIsScheduled == false) {
-            mSplitPictureIsScheduled = true;
-            sendMessage(EventHub.SPLIT_PICTURE_SET);
-        }
-    }
-
-    /* package */ synchronized boolean pictureReady() {
-        return 0 != mNativeClass ? nativePictureReady() : false;
-    }
-
-    /*package*/ synchronized Picture copyContentPicture() {
-        Picture result = new Picture();
-        if (0 != mNativeClass) {
-            nativeCopyContentToPicture(result);
-        }
-        return result;
-    }
-
     static void reducePriority() {
         // remove the pending REDUCE_PRIORITY and RESUME_PRIORITY messages
         sWebCoreHandler.removeMessages(WebCoreThread.REDUCE_PRIORITY);
@@ -2038,24 +2002,6 @@
         mRepaintScheduled = false;
     }
 
-    // called by JNI
-    private void sendImmediateRepaint() {
-        if (mWebView != null && !mRepaintScheduled) {
-            mRepaintScheduled = true;
-            Message.obtain(mWebView.mPrivateHandler,
-                           WebView.IMMEDIATE_REPAINT_MSG_ID).sendToTarget();
-        }
-    }
-
-    // called by JNI
-    private void setRootLayer(int layer) {
-        if (mWebView != null) {
-            Message.obtain(mWebView.mPrivateHandler,
-                           WebView.SET_ROOT_LAYER_MSG_ID,
-                           layer, 0).sendToTarget();
-        }
-    }
-
     /* package */ WebView getWebView() {
         return mWebView;
     }
diff --git a/core/java/android/webruntime/WebRuntimeActivity.java b/core/java/android/webruntime/WebRuntimeActivity.java
index 07d9908..ec8c60c 100644
--- a/core/java/android/webruntime/WebRuntimeActivity.java
+++ b/core/java/android/webruntime/WebRuntimeActivity.java
@@ -141,7 +141,7 @@
 
             @Override
             public void onPageFinished(WebView view, String url) {
-                if (mSplashScreen.getVisibility() == View.VISIBLE) {
+                if (mSplashScreen != null && mSplashScreen.getVisibility() == View.VISIBLE) {
                     mSplashScreen.setVisibility(View.GONE);
                     mSplashScreen = null;
                 }
diff --git a/core/java/android/widget/AbsListView.java b/core/java/android/widget/AbsListView.java
index 1d5c5f9..70c1e15 100644
--- a/core/java/android/widget/AbsListView.java
+++ b/core/java/android/widget/AbsListView.java
@@ -2651,7 +2651,8 @@
             mMode = MOVE_OFFSET;
 
             final int firstPos = mFirstPosition;
-            final int lastPos = firstPos + getChildCount() - 1;
+            final int childCount = getChildCount();
+            final int lastPos = firstPos + childCount - 1;
 
             int viewTravelCount = 0;
             if (position < firstPos) {
@@ -2665,7 +2666,10 @@
                 return;
             }
 
-            mScrollDuration = SCROLL_DURATION / viewTravelCount;
+            // Estimate how many screens we should travel
+            final float screenTravelCount = viewTravelCount / childCount;
+            mScrollDuration = (int) (SCROLL_DURATION / screenTravelCount);
+            mLastSeenPos = INVALID_POSITION;
             post(this);
         }
 
@@ -2674,6 +2678,10 @@
         }
 
         public void run() {
+            if (mTouchMode != TOUCH_MODE_FLING && mLastSeenPos != INVALID_POSITION) {
+                return;
+            }
+
             final int listHeight = getHeight();
             final int firstPos = mFirstPosition;
             
@@ -2799,23 +2807,17 @@
             }
 
             case MOVE_OFFSET: {
-                if (firstPos == mLastSeenPos) {
-                    // No new views, let things keep going.
-                    post(this);
-                }
+                final int childCount = getChildCount();
 
+                mLastSeenPos = firstPos;
                 final int position = mTargetPos;
-                final int lastPos = firstPos + getChildCount() - 1;
+                final int lastPos = firstPos + childCount - 1;
 
                 if (position < firstPos) {
-                    final View firstView = getChildAt(0);
-                    final int firstViewPixelsShowing = firstView.getHeight() + firstView.getTop();
-                    smoothScrollBy(-firstViewPixelsShowing, mScrollDuration);
+                    smoothScrollBy(-getHeight(), mScrollDuration);
                     post(this);
                 } else if (position > lastPos) {
-                    final View lastView = getChildAt(getChildCount() - 1);
-                    final int lastViewPixelsShowing = lastView.getBottom() - lastView.getHeight();
-                    smoothScrollBy(lastViewPixelsShowing, mScrollDuration);
+                    smoothScrollBy(getHeight(), mScrollDuration);
                     post(this);
                 } else {
                     // On-screen, just scroll.
@@ -3249,6 +3251,7 @@
 
         mResurrectToPosition = INVALID_POSITION;
         removeCallbacks(mFlingRunnable);
+        removeCallbacks(mPositionScroller);
         mTouchMode = TOUCH_MODE_REST;
         clearScrollingCache();
         mSpecificTop = selectedTop;
@@ -4284,7 +4287,7 @@
                     final ArrayList<View> scrap = mScrapViews[i];
                     final int scrapCount = scrap.size();
                     for (int j = 0; j < scrapCount; j++) {
-                        scrap.get(i).setDrawingCacheBackgroundColor(color);
+                        scrap.get(j).setDrawingCacheBackgroundColor(color);
                     }
                 }
             }
diff --git a/core/java/android/widget/ListPopupWindow.java b/core/java/android/widget/ListPopupWindow.java
index e9de385..5c34c2c 100644
--- a/core/java/android/widget/ListPopupWindow.java
+++ b/core/java/android/widget/ListPopupWindow.java
@@ -78,7 +78,7 @@
     private AdapterView.OnItemClickListener mItemClickListener;
     private AdapterView.OnItemSelectedListener mItemSelectedListener;
 
-    private final  ResizePopupRunnable mResizePopupRunnable = new ResizePopupRunnable();
+    private final ResizePopupRunnable mResizePopupRunnable = new ResizePopupRunnable();
     private final PopupTouchInterceptor mTouchInterceptor = new PopupTouchInterceptor();
     private final PopupScrollListener mScrollListener = new PopupScrollListener();
     private final ListSelectorHider mHideSelector = new ListSelectorHider();
@@ -432,6 +432,19 @@
     }
 
     /**
+     * Sets the width of the popup window by the size of its content. The final width may be
+     * larger to accommodate styled window dressing.
+     *
+     * @param width Desired width of content in pixels.
+     */
+    public void setContentWidth(int width) {
+        Drawable popupBackground = mPopup.getBackground();
+        if (popupBackground != null) {
+            mDropDownWidth = popupBackground.getIntrinsicWidth() + width;
+        }
+    }
+
+    /**
      * @return The height of the popup window in pixels.
      */
     public int getHeight() {
diff --git a/core/java/android/widget/ListView.java b/core/java/android/widget/ListView.java
index 91f4946..86913ae 100644
--- a/core/java/android/widget/ListView.java
+++ b/core/java/android/widget/ListView.java
@@ -2968,7 +2968,7 @@
             // fill a rect where the dividers would be for non-selectable items
             // If the list is opaque and the background is also opaque, we don't
             // need to draw anything since the background will do it for us
-            final boolean fillForMissingDividers = drawDividers && isOpaque() && !super.isOpaque();
+            final boolean fillForMissingDividers = isOpaque() && !super.isOpaque();
 
             if (fillForMissingDividers && mDividerPaint == null && mIsCacheColorOpaque) {
                 mDividerPaint = new Paint();
@@ -2978,7 +2978,7 @@
 
             final int listBottom = mBottom - mTop - mListPadding.bottom + mScrollY;
             if (!mStackFromBottom) {
-                int bottom = 0;
+                int bottom;
                 
                 final int scrollY = mScrollY;
                 for (int i = 0; i < count; i++) {
@@ -2987,18 +2987,16 @@
                         View child = getChildAt(i);
                         bottom = child.getBottom();
                         // Don't draw dividers next to items that are not enabled
-                        if (drawDividers) {
-                            if ((areAllItemsSelectable ||
-                                    (adapter.isEnabled(first + i) && (i == count - 1 ||
-                                            adapter.isEnabled(first + i + 1))))) {
-                                bounds.top = bottom;
-                                bounds.bottom = bottom + dividerHeight;
-                                drawDivider(canvas, bounds, i);
-                            } else if (fillForMissingDividers) {
-                                bounds.top = bottom;
-                                bounds.bottom = bottom + dividerHeight;
-                                canvas.drawRect(bounds, paint);
-                            }
+                        if ((areAllItemsSelectable ||
+                                (adapter.isEnabled(first + i) && (i == count - 1 ||
+                                        adapter.isEnabled(first + i + 1))))) {
+                            bounds.top = bottom;
+                            bounds.bottom = bottom + dividerHeight;
+                            drawDivider(canvas, bounds, i);
+                        } else if (fillForMissingDividers) {
+                            bounds.top = bottom;
+                            bounds.bottom = bottom + dividerHeight;
+                            canvas.drawRect(bounds, paint);
                         }
                     }
                 }
@@ -3014,7 +3012,7 @@
                         View child = getChildAt(i);
                         top = child.getTop();
                         // Don't draw dividers next to items that are not enabled
-                        if (drawDividers && top > listTop) {
+                        if (top > listTop) {
                             if ((areAllItemsSelectable ||
                                     (adapter.isEnabled(first + i) && (i == count - 1 ||
                                             adapter.isEnabled(first + i + 1))))) {
@@ -3034,7 +3032,7 @@
                     }
                 }
                 
-                if (count > 0 && scrollY > 0 && drawDividers) {
+                if (count > 0 && scrollY > 0) {
                     bounds.top = listBottom;
                     bounds.bottom = listBottom + dividerHeight;
                     drawDivider(canvas, bounds, -1);
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index 17967d9..0ce8164 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -61,6 +61,7 @@
 import android.text.TextPaint;
 import android.text.TextUtils;
 import android.text.TextWatcher;
+import android.text.method.ArrowKeyMovementMethod;
 import android.text.method.DateKeyListener;
 import android.text.method.DateTimeKeyListener;
 import android.text.method.DialerKeyListener;
@@ -89,10 +90,11 @@
 import android.view.MenuItem;
 import android.view.MotionEvent;
 import android.view.View;
+import android.view.ViewConfiguration;
 import android.view.ViewDebug;
+import android.view.ViewGroup.LayoutParams;
 import android.view.ViewRoot;
 import android.view.ViewTreeObserver;
-import android.view.ViewGroup.LayoutParams;
 import android.view.accessibility.AccessibilityEvent;
 import android.view.accessibility.AccessibilityManager;
 import android.view.animation.AnimationUtils;
@@ -185,7 +187,7 @@
  */
 @RemoteView
 public class TextView extends View implements ViewTreeObserver.OnPreDrawListener {
-    static final String TAG = "TextView";
+    static final String LOG_TAG = "TextView";
     static final boolean DEBUG_EXTRACT = false;
     
     private static int PRIORITY = 100;
@@ -696,9 +698,9 @@
                 try {
                     setInputExtras(a.getResourceId(attr, 0));
                 } catch (XmlPullParserException e) {
-                    Log.w("TextView", "Failure reading input extras", e);
+                    Log.w(LOG_TAG, "Failure reading input extras", e);
                 } catch (IOException e) {
-                    Log.w("TextView", "Failure reading input extras", e);
+                    Log.w(LOG_TAG, "Failure reading input extras", e);
                 }
                 break;
             }
@@ -924,6 +926,8 @@
         setFocusable(focusable);
         setClickable(clickable);
         setLongClickable(longClickable);
+
+        prepareCursorController();
     }
 
     private void setTypefaceByIndex(int typefaceIndex, int styleIndex) {
@@ -1129,6 +1133,7 @@
             setText(mText);
 
         fixFocusableAndClickableSettings();
+        prepareCursorController();
     }
 
     private void fixFocusableAndClickableSettings() {
@@ -2371,8 +2376,8 @@
         int end = 0;
 
         if (mText != null) {
-            start = Selection.getSelectionStart(mText);
-            end = Selection.getSelectionEnd(mText);
+            start = getSelectionStart();
+            end = getSelectionEnd();
             if (start >= 0 || end >= 0) {
                 // Or save state if there is a selection
                 save = true;
@@ -2444,7 +2449,7 @@
                         restored = "(restored) ";
                     }
 
-                    Log.e("TextView", "Saved cursor position " + ss.selStart +
+                    Log.e(LOG_TAG, "Saved cursor position " + ss.selStart +
                           "/" + ss.selEnd + " out of range for " + restored +
                           "text " + mText);
                 } else {
@@ -2696,6 +2701,9 @@
         if (needEditableForNotification) {
             sendAfterTextChanged((Editable) text);
         }
+
+        // Depends on canSelectText, which depends on text
+        prepareCursorController();
     }
 
     /**
@@ -3009,7 +3017,7 @@
         } else {
             input = TextKeyListener.getInstance();
         }
-        mInputType = type;
+        setRawInputType(type);
         if (direct) mInput = input;
         else {
             setKeyListenerOnly(input);
@@ -3613,7 +3621,7 @@
     }
 
     private void invalidateCursor() {
-        int where = Selection.getSelectionEnd(mText);
+        int where = getSelectionEnd();
 
         invalidateCursor(where, where, where);
     }
@@ -3689,7 +3697,18 @@
         boolean changed = false;
 
         if (mMovement != null) {
-            int curs = Selection.getSelectionEnd(mText);
+            /* This code also provides auto-scrolling when a cursor is moved using a
+             * CursorController (insertion point or selection limits).
+             * For selection, ensure start or end is visible depending on controller's state.
+             */
+            int curs = getSelectionEnd();
+            if (mSelectionModifierCursorController != null) {
+                SelectionModifierCursorController selectionController =
+                    (SelectionModifierCursorController) mSelectionModifierCursorController;
+                if (selectionController.isSelectionStartDragged()) {
+                    curs = getSelectionStart();
+                }
+            }
 
             /*
              * TODO: This should really only keep the end in view if
@@ -3982,8 +4001,8 @@
         //  XXX This is not strictly true -- a program could set the
         //  selection manually if it really wanted to.
         if (mMovement != null && (isFocused() || isPressed())) {
-            selStart = Selection.getSelectionStart(mText);
-            selEnd = Selection.getSelectionEnd(mText);
+            selStart = getSelectionStart();
+            selEnd = getSelectionEnd();
 
             if (mCursorVisible && selStart >= 0 && isEnabled()) {
                 if (mHighlightPath == null)
@@ -4089,6 +4108,13 @@
         */
 
         canvas.restore();
+
+        if (mInsertionPointCursorController != null) {
+            mInsertionPointCursorController.draw(canvas);
+        }
+        if (mSelectionModifierCursorController != null) {
+            mSelectionModifierCursorController.draw(canvas);
+        }
     }
 
     @Override
@@ -4503,8 +4529,8 @@
             outAttrs.hintText = mHint;
             if (mText instanceof Editable) {
                 InputConnection ic = new EditableInputConnection(this);
-                outAttrs.initialSelStart = Selection.getSelectionStart(mText);
-                outAttrs.initialSelEnd = Selection.getSelectionEnd(mText);
+                outAttrs.initialSelStart = getSelectionStart();
+                outAttrs.initialSelEnd = getSelectionEnd();
                 outAttrs.initialCapsMode = ic.getCursorCapsMode(mInputType);
                 return ic;
             }
@@ -4589,8 +4615,8 @@
                 outText.flags |= ExtractedText.FLAG_SINGLE_LINE;
             }
             outText.startOffset = 0;
-            outText.selectionStart = Selection.getSelectionStart(content);
-            outText.selectionEnd = Selection.getSelectionEnd(content);
+            outText.selectionStart = getSelectionStart();
+            outText.selectionEnd = getSelectionEnd();
             return true;
         }
         return false;
@@ -4607,7 +4633,7 @@
                 if (req != null) {
                     InputMethodManager imm = InputMethodManager.peekInstance();
                     if (imm != null) {
-                        if (DEBUG_EXTRACT) Log.v(TAG, "Retrieving extracted start="
+                        if (DEBUG_EXTRACT) Log.v(LOG_TAG, "Retrieving extracted start="
                                 + ims.mChangedStart + " end=" + ims.mChangedEnd
                                 + " delta=" + ims.mChangedDelta);
                         if (ims.mChangedStart < 0 && !contentChanged) {
@@ -4615,7 +4641,7 @@
                         }
                         if (extractTextInternal(req, ims.mChangedStart, ims.mChangedEnd,
                                 ims.mChangedDelta, ims.mTmpExtracted)) {
-                            if (DEBUG_EXTRACT) Log.v(TAG, "Reporting extracted start="
+                            if (DEBUG_EXTRACT) Log.v(LOG_TAG, "Reporting extracted start="
                                     + ims.mTmpExtracted.partialStartOffset
                                     + " end=" + ims.mTmpExtracted.partialEndOffset
                                     + ": " + ims.mTmpExtracted.text);
@@ -4769,7 +4795,7 @@
     
     void updateAfterEdit() {
         invalidate();
-        int curs = Selection.getSelectionStart(mText);
+        int curs = getSelectionStart();
 
         if (curs >= 0 || (mGravity & Gravity.VERTICAL_GRAVITY_MASK) ==
                              Gravity.BOTTOM) {
@@ -4784,7 +4810,7 @@
                 makeBlink();
             }
         }
-        
+
         checkForResize();
     }
     
@@ -4913,7 +4939,6 @@
                                 w, alignment, mSpacingMult, mSpacingAdd,
                                 boring, mIncludePad);
                     }
-                    // Log.e("aaa", "Boring: " + mTransformed);
 
                     mSavedLayout = (BoringLayout) mLayout;
                 } else if (shouldEllipsize && boring.width <= w) {
@@ -5508,7 +5533,7 @@
         // FIXME: Is it okay to truncate this, or should we round?
         final int x = (int)mLayout.getPrimaryHorizontal(offset);
         final int top = mLayout.getLineTop(line);
-        final int bottom = mLayout.getLineTop(line+1);
+        final int bottom = mLayout.getLineTop(line + 1);
 
         int left = (int) FloatMath.floor(mLayout.getLineLeft(line));
         int right = (int) FloatMath.ceil(mLayout.getLineRight(line));
@@ -5645,8 +5670,8 @@
             // viewport coordinates, but requestRectangleOnScreen()
             // is in terms of content coordinates.
 
-            Rect r = new Rect();
-            getInterestingRect(r, x, top, bottom, line);
+            Rect r = new Rect(x, top, x + 1, bottom);
+            getInterestingRect(r, line);
             r.offset(mScrollX, mScrollY);
 
             if (requestRectangleOnScreen(r)) {
@@ -5669,8 +5694,8 @@
         if (!(mText instanceof Spannable)) {
             return false;
         }
-        int start = Selection.getSelectionStart(mText);
-        int end = Selection.getSelectionEnd(mText);
+        int start = getSelectionStart();
+        int end = getSelectionEnd();
         if (start != end) {
             return false;
         }
@@ -5680,7 +5705,7 @@
         int line = mLayout.getLineForOffset(start);
 
         final int top = mLayout.getLineTop(line);
-        final int bottom = mLayout.getLineTop(line+1);
+        final int bottom = mLayout.getLineTop(line + 1);
         final int vspace = mBottom - mTop - getExtendedPaddingTop() - getExtendedPaddingBottom();
         int vslack = (bottom - top) / 2;
         if (vslack > vspace / 4)
@@ -5730,22 +5755,28 @@
         }
     }
 
-    private void getInterestingRect(Rect r, int h, int top, int bottom,
-                                    int line) {
+    private void getInterestingRect(Rect r, int line) {
+        convertFromViewportToContentCoordinates(r);
+
+        // Rectangle can can be expanded on first and last line to take
+        // padding into account.
+        // TODO Take left/right padding into account too?
+        if (line == 0) r.top -= getExtendedPaddingTop();
+        if (line == mLayout.getLineCount() - 1) r.bottom += getExtendedPaddingBottom();
+    }
+
+    private void convertFromViewportToContentCoordinates(Rect r) {
         int paddingTop = getExtendedPaddingTop();
         if ((mGravity & Gravity.VERTICAL_GRAVITY_MASK) != Gravity.TOP) {
             paddingTop += getVerticalOffset(false);
         }
-        top += paddingTop;
-        bottom += paddingTop;
-        h += getCompoundPaddingLeft();
+        r.top += paddingTop;
+        r.bottom += paddingTop;
 
-        if (line == 0)
-            top -= getExtendedPaddingTop();
-        if (line == mLayout.getLineCount() - 1)
-            bottom += getExtendedPaddingBottom();
+        int paddingLeft = getCompoundPaddingLeft();
+        r.left += paddingLeft;
+        r.right += paddingLeft;
 
-        r.set(h, top, h+1, bottom);
         r.offset(-mScrollX, -mScrollY);
     }
 
@@ -5913,6 +5944,7 @@
         } else if (mBlink != null) {
             mBlink.removeCallbacks(mBlink);
         }
+        prepareCursorController();
     }
 
     private boolean canMarquee() {
@@ -6327,7 +6359,7 @@
                         }
                     }
                 } else {
-                    if (DEBUG_EXTRACT) Log.v(TAG, "Span change outside of batch: "
+                    if (DEBUG_EXTRACT) Log.v(LOG_TAG, "Span change outside of batch: "
                             + oldStart + "-" + oldEnd + ","
                             + newStart + "-" + newEnd + what);
                     ims.mContentChanged = true;
@@ -6343,7 +6375,7 @@
 
         public void beforeTextChanged(CharSequence buffer, int start,
                                       int before, int after) {
-            if (DEBUG_EXTRACT) Log.v(TAG, "beforeTextChanged start=" + start
+            if (DEBUG_EXTRACT) Log.v(LOG_TAG, "beforeTextChanged start=" + start
                     + " before=" + before + " after=" + after + ": " + buffer);
 
             if (AccessibilityManager.getInstance(mContext).isEnabled()
@@ -6356,7 +6388,7 @@
 
         public void onTextChanged(CharSequence buffer, int start,
                                   int before, int after) {
-            if (DEBUG_EXTRACT) Log.v(TAG, "onTextChanged start=" + start
+            if (DEBUG_EXTRACT) Log.v(LOG_TAG, "onTextChanged start=" + start
                     + " before=" + before + " after=" + after + ": " + buffer);
             TextView.this.handleTextChanged(buffer, start, before, after);
 
@@ -6366,10 +6398,15 @@
                 sendAccessibilityEventTypeViewTextChanged(mBeforeText, start, before, after);
                 mBeforeText = null;
             }
+
+            // TODO. The cursor controller should hide as soon as text is typed.
+            // But this method is also used for cosmetic changes (underline current word when
+            // spell corrections are displayed. There is currently no way to make the difference
+            // between these cosmetic changes and actual text modifications.
         }
 
         public void afterTextChanged(Editable buffer) {
-            if (DEBUG_EXTRACT) Log.v(TAG, "afterTextChanged: " + buffer);
+            if (DEBUG_EXTRACT) Log.v(LOG_TAG, "afterTextChanged: " + buffer);
             TextView.this.sendAfterTextChanged(buffer);
 
             if (MetaKeyKeyListener.getMetaState(buffer,
@@ -6380,19 +6417,19 @@
 
         public void onSpanChanged(Spannable buf,
                                   Object what, int s, int e, int st, int en) {
-            if (DEBUG_EXTRACT) Log.v(TAG, "onSpanChanged s=" + s + " e=" + e
+            if (DEBUG_EXTRACT) Log.v(LOG_TAG, "onSpanChanged s=" + s + " e=" + e
                     + " st=" + st + " en=" + en + " what=" + what + ": " + buf);
             TextView.this.spanChange(buf, what, s, st, e, en);
         }
 
         public void onSpanAdded(Spannable buf, Object what, int s, int e) {
-            if (DEBUG_EXTRACT) Log.v(TAG, "onSpanAdded s=" + s + " e=" + e
+            if (DEBUG_EXTRACT) Log.v(LOG_TAG, "onSpanAdded s=" + s + " e=" + e
                     + " what=" + what + ": " + buf);
             TextView.this.spanChange(buf, what, -1, s, -1, e);
         }
 
         public void onSpanRemoved(Spannable buf, Object what, int s, int e) {
-            if (DEBUG_EXTRACT) Log.v(TAG, "onSpanRemoved s=" + s + " e=" + e
+            if (DEBUG_EXTRACT) Log.v(LOG_TAG, "onSpanRemoved s=" + s + " e=" + e
                     + " what=" + what + ": " + buf);
             TextView.this.spanChange(buf, what, s, -1, e, -1);
         }
@@ -6502,6 +6539,13 @@
             }
             // Don't leave us in the middle of a batch edit.
             onEndBatchEdit();
+
+            if (mInsertionPointCursorController != null) {
+                mInsertionPointCursorController.hide();
+            }
+            if (mSelectionModifierCursorController != null) {
+                mSelectionModifierCursorController.hide();
+            }
         }
 
         startStopMarquee(focused);
@@ -6589,6 +6633,8 @@
             if (resultCode == InputMethodManager.RESULT_SHOWN) {
                 start = mPrevStart;
                 end = mPrevEnd;
+            } else if (mInsertionPointCursorController != null) {
+                mInsertionPointCursorController.show();
             }
 
             final int len = mText.length();
@@ -6629,20 +6675,27 @@
             
             boolean handled = false;
             
-            int oldSelStart = Selection.getSelectionStart(mText);
-            int oldSelEnd = Selection.getSelectionEnd(mText);
-            
+            int oldSelStart = getSelectionStart();
+            int oldSelEnd = getSelectionEnd();
+
+            if (mInsertionPointCursorController != null) {
+                mInsertionPointCursorController.onTouchEvent(event);
+            }
+            if (mSelectionModifierCursorController != null) {
+                mSelectionModifierCursorController.onTouchEvent(event);
+            }
+
             if (mMovement != null) {
                 handled |= mMovement.onTouchEvent(this, (Spannable) mText, event);
             }
 
-            if (mText instanceof Editable && onCheckIsTextEditor()) {
+            if (isTextEditable()) {
                 if (action == MotionEvent.ACTION_UP && isFocused() && !mScrolled) {
                     InputMethodManager imm = (InputMethodManager)
                             getContext().getSystemService(Context.INPUT_METHOD_SERVICE);
 
-                    final int newSelStart = Selection.getSelectionStart(mText);
-                    final int newSelEnd = Selection.getSelectionEnd(mText);
+                    final int newSelStart = getSelectionStart();
+                    final int newSelEnd = getSelectionEnd();
 
                     CommitSelectionReceiver csr = null;
                     if (newSelStart != oldSelStart || newSelEnd != oldSelEnd) {
@@ -6650,7 +6703,7 @@
                                 newSelStart, newSelEnd);
                     }
 
-                    handled = imm.showSoftInput(this, 0, csr) && (csr != null);
+                    handled |= imm.showSoftInput(this, 0, csr) && (csr != null);
                 }
             }
 
@@ -6662,6 +6715,47 @@
         return superResult;
     }
 
+    private void prepareCursorController() {
+        boolean atLeastOneController = false;
+
+        // TODO Add an extra android:cursorController flag to disable the controller?
+        if (mCursorVisible) {
+            atLeastOneController = true;
+            if (mInsertionPointCursorController == null) {
+                mInsertionPointCursorController = new InsertionPointCursorController();
+            }
+        } else {
+            mInsertionPointCursorController = null;
+        }
+
+        if (canSelectText()) {
+            atLeastOneController = true;
+            if (mSelectionModifierCursorController == null) {
+                mSelectionModifierCursorController = new SelectionModifierCursorController();
+            }
+        } else {
+            mSelectionModifierCursorController = null;
+        }
+
+        if (atLeastOneController) {
+            if (sCursorControllerTempRect == null) {
+                sCursorControllerTempRect = new Rect();
+            }
+            Resources res = mContext.getResources();
+            mCursorControllerVerticalOffset = res.getDimensionPixelOffset(
+                    com.android.internal.R.dimen.cursor_controller_vertical_offset);
+        } else {
+            sCursorControllerTempRect = null;
+        }
+    }
+
+    /**
+     * @return True iff this TextView contains a text that can be edited.
+     */
+    private boolean isTextEditable() {
+        return mText instanceof Editable && onCheckIsTextEditor();
+    }
+
     /**
      * Returns true, only while processing a touch gesture, if the initial
      * touch down event caused focus to move to the text view and as a result
@@ -6712,8 +6806,8 @@
             TextView tv = mView.get();
 
             if (tv != null && tv.isFocused()) {
-                int st = Selection.getSelectionStart(tv.mText);
-                int en = Selection.getSelectionEnd(tv.mText);
+                int st = tv.getSelectionStart();
+                int en = tv.getSelectionEnd();
 
                 if (st == en && st >= 0 && en >= 0) {
                     if (tv.mLayout != null) {
@@ -6790,8 +6884,10 @@
 
     @Override
     protected int computeHorizontalScrollRange() {
-        if (mLayout != null)
-            return mLayout.getWidth();
+        if (mLayout != null) {
+            return mSingleLine && (mGravity & Gravity.HORIZONTAL_GRAVITY_MASK) == Gravity.LEFT ?
+                    (int) mLayout.getLineWidth(0) : mLayout.getWidth();
+        }
 
         return super.computeHorizontalScrollRange();
     }
@@ -6903,6 +6999,9 @@
     }
 
     private boolean canSelectText() {
+        // prepareCursorController() relies on this method.
+        // If you change this condition, make sure prepareCursorController is called anywhere
+        // the value of this condition might be changed.
         if (mText instanceof Spannable && mText.length() != 0 &&
             mMovement != null && mMovement.canSelectArbitrarily()) {
             return true;
@@ -6951,10 +7050,14 @@
     }
 
     /**
-     * Returns a word to add to the dictionary from the context menu,
-     * or null if there is no cursor or no word at the cursor.
+     * Returns the offsets delimiting the 'word' located at position offset.
+     *
+     * @param offset An offset in the text.
+     * @return The offsets for the start and end of the word located at <code>offset</code>.
+     * The two ints offsets are packed in a long, with the starting offset shifted by 32 bits.
+     * Returns a negative value if no valid word was found.
      */
-    private String getWordForDictionary() {
+    private long getWordLimitsAt(int offset) {
         /*
          * Quick return if the input type is one where adding words
          * to the dictionary doesn't make any sense.
@@ -6963,7 +7066,7 @@
         if (klass == InputType.TYPE_CLASS_NUMBER ||
             klass == InputType.TYPE_CLASS_PHONE ||
             klass == InputType.TYPE_CLASS_DATETIME) {
-            return null;
+            return -1;
         }
 
         int variation = mInputType & InputType.TYPE_MASK_VARIATION;
@@ -6972,13 +7075,13 @@
             variation == InputType.TYPE_TEXT_VARIATION_VISIBLE_PASSWORD ||
             variation == InputType.TYPE_TEXT_VARIATION_EMAIL_ADDRESS ||
             variation == InputType.TYPE_TEXT_VARIATION_FILTER) {
-            return null;
+            return -1;
         }
 
-        int end = getSelectionEnd();
+        int end = offset;
 
         if (end < 0) {
-            return null;
+            return -1;
         }
 
         int start = end;
@@ -7012,6 +7115,14 @@
             }
         }
 
+        if (start == end) {
+            return -1;
+        }
+
+        if (end - start > 48) {
+            return -1;
+        }
+
         boolean hasLetter = false;
         for (int i = start; i < end; i++) {
             if (Character.isLetter(mTransformed.charAt(i))) {
@@ -7019,19 +7130,28 @@
                 break;
             }
         }
+
         if (!hasLetter) {
-            return null;
+            return -1;
         }
 
-        if (start == end) {
-            return null;
-        }
+        // Two ints packed in a long
+        return (((long) start) << 32) | end;
+    }
 
-        if (end - start > 48) {
+    /**
+     * Returns a word to add to the dictionary from the context menu,
+     * or null if there is no cursor or no word at the cursor.
+     */
+    private String getWordForDictionary() {
+        long wordLimits = getWordLimitsAt(getSelectionEnd());
+        if (wordLimits < 0) {
             return null;
+        } else {
+             int start = (int) (wordLimits >>> 32);
+             int end = (int) (wordLimits & 0x00000000FFFFFFFFL);
+            return TextUtils.substring(mTransformed, start, end);
         }
-
-        return TextUtils.substring(mTransformed, start, end);
     }
 
     @Override
@@ -7331,6 +7451,15 @@
 
     @Override
     public boolean performLongClick() {
+        // TODO This behavior should be moved to View
+        // TODO handle legacy code that added items to context menu
+        if (canSelectText()) {
+            if (startSelectionMode()) {
+                mEatTouchRelease = true;
+                return true;
+            }
+        }
+
         if (super.performLongClick()) {
             mEatTouchRelease = true;
             return true;
@@ -7339,6 +7468,493 @@
         return false;
     }
 
+    private boolean startSelectionMode() {
+        if (mSelectionModifierCursorController != null) {
+            int offset = ((SelectionModifierCursorController) mSelectionModifierCursorController).
+            getTouchOffset();
+
+            int selectionStart, selectionEnd;
+
+            if (hasSelection()) {
+                selectionStart = getSelectionStart();
+                selectionEnd = getSelectionEnd();
+                if (selectionStart > selectionEnd) {
+                    int tmp = selectionStart;
+                    selectionStart = selectionEnd;
+                    selectionEnd = tmp;
+                }
+                if ((offset >= selectionStart) && (offset <= selectionEnd)) {
+                    // Long press in the current selection.
+                    // Should initiate a drag. Return false, to rely on context menu for now.
+                    return false;
+                }
+            }
+
+            long wordLimits = getWordLimitsAt(offset);
+            if (wordLimits >= 0) {
+                selectionStart = (int) (wordLimits >>> 32);
+                selectionEnd = (int) (wordLimits & 0x00000000FFFFFFFFL);
+            } else {
+                selectionStart = Math.max(offset - 5, 0);
+                selectionEnd = Math.min(offset + 5, mText.length());
+            }
+
+            Selection.setSelection((Spannable) mText, selectionStart, selectionEnd);
+
+            // Has to be done AFTER selection has been changed to correctly position controllers.
+            mSelectionModifierCursorController.show();
+
+            return true;
+        }
+
+        return false;
+    }
+
+    /**
+     * Get the offset character closest to the specified absolute position.
+     *
+     * @param x The horizontal absolute position of a point on screen
+     * @param y The vertical absolute position of a point on screen
+     * @return the  character offset for the character whose position is closest to the specified
+     *  position.
+     *
+     *  @hide
+     */
+    public int getOffset(int x, int y) {
+        x -= getTotalPaddingLeft();
+        y -= getTotalPaddingTop();
+
+        // Clamp the position to inside of the view.
+        if (x < 0) {
+            x = 0;
+        } else if (x >= (getWidth() - getTotalPaddingRight())) {
+            x = getWidth()-getTotalPaddingRight() - 1;
+        }
+        if (y < 0) {
+            y = 0;
+        } else if (y >= (getHeight() - getTotalPaddingBottom())) {
+            y = getHeight()-getTotalPaddingBottom() - 1;
+        }
+
+        x += getScrollX();
+        y += getScrollY();
+
+        Layout layout = getLayout();
+        final int line = layout.getLineForVertical(y);
+        final int offset = layout.getOffsetForHorizontal(line, x);
+        return offset;
+      }
+
+    /**
+     * A CursorController instance can be used to control a cursor in the text.
+     *
+     * It can be passed to an {@link ArrowKeyMovementMethod} which can intercepts events
+     * and send them to this object instead of the cursor.
+     */
+    public interface CursorController {
+        /* Cursor fade-out animation duration, in milliseconds. */
+        static final int FADE_OUT_DURATION = 400;
+
+        /**
+         * Makes the cursor controller visible on screen. Will be drawn by {@link #draw(Canvas)}.
+         * See also {@link #hide()}.
+         */
+        public void show();
+
+        /**
+         * Hide the cursor controller from screen.
+         * See also {@link #show()}.
+         */
+        public void hide();
+
+        /**
+         * Update the controller's position.
+         */
+        public void updatePosition(int offset);
+
+        /**
+         * The controller and the cursor's positions can be link by a fixed offset,
+         * computed when the controller is touched, and then maintained as it moves
+         * @return Horizontal offset between the controller and the cursor.
+         */
+        public float getOffsetX();
+
+        /**
+         * @return Vertical offset between the controller and the cursor.
+         */
+        public float getOffsetY();
+
+        /**
+         * This method is called by {@link #onTouchEvent(MotionEvent)} and gives the controller
+         * a chance to become active and/or visible.
+         * @param event The touch event
+         */
+        public void onTouchEvent(MotionEvent event);
+
+        /**
+         * Draws a visual representation of the controller on the canvas.
+         *
+         * Called at the end of {@link #draw(Canvas)}, in the content coordinates system.
+         * @param canvas The Canvas used by this TextView.
+         */
+        public void draw(Canvas canvas);
+    }
+
+    class InsertionPointCursorController implements CursorController {
+        private static final int DELAY_BEFORE_FADE_OUT = 2100;
+
+        // Whether or not the cursor control is currently visible
+        private boolean mIsVisible = false;
+        // Starting time of the fade timer
+        private long mFadeOutTimerStart;
+        // The cursor controller image
+        private final Drawable mDrawable;
+        // Used to detect a tap (vs drag) on the controller
+        private long mOnDownTimerStart;
+        // Offset between finger hot point on cursor controller and actual cursor
+        private float mOffsetX, mOffsetY;
+
+        InsertionPointCursorController() {
+            Resources res = mContext.getResources();
+            mDrawable = res.getDrawable(com.android.internal.R.drawable.cursor_controller);
+        }
+
+        public void show() {
+            updateDrawablePosition();
+            // Has to be done after updatePosition, so that previous position invalidate
+            // in only done if necessary.
+            mIsVisible = true;
+            if (mSelectionModifierCursorController != null) {
+                mSelectionModifierCursorController.hide();
+            }
+        }
+
+        public void hide() {
+            if (mIsVisible) {
+                long time = System.currentTimeMillis();
+                // Start fading out, only if not already in progress
+                if (time - mFadeOutTimerStart < DELAY_BEFORE_FADE_OUT) {
+                    mFadeOutTimerStart = time - DELAY_BEFORE_FADE_OUT;
+                    postInvalidate(mDrawable);
+                }
+            }
+        }
+
+        public void draw(Canvas canvas) {
+            if (mIsVisible) {
+                int time = (int) (System.currentTimeMillis() - mFadeOutTimerStart);
+                if (time <= DELAY_BEFORE_FADE_OUT) {
+                    postInvalidateDelayed(DELAY_BEFORE_FADE_OUT - time, mDrawable);
+                } else {
+                    time -= DELAY_BEFORE_FADE_OUT;
+                    if (time <= FADE_OUT_DURATION) {
+                        final int alpha = 255 * (FADE_OUT_DURATION - time) / FADE_OUT_DURATION;
+                        mDrawable.setAlpha(alpha);
+                        postInvalidateDelayed(30, mDrawable);
+                    } else {
+                        mDrawable.setAlpha(0);
+                        mIsVisible = false;
+                    }
+                }
+                mDrawable.draw(canvas);
+            }
+        }
+
+        public void updatePosition(int offset) {
+            Selection.setSelection((Spannable) mText, offset);
+            updateDrawablePosition();
+        }
+
+        private void updateDrawablePosition() {
+            if (mIsVisible) {
+                // Clear previous cursor controller before bounds are updated
+                postInvalidate(mDrawable);
+            }
+
+            final int offset = getSelectionStart();
+
+            if (offset < 0) {
+                // Should never happen, safety check.
+                Log.w(LOG_TAG, "Update cursor controller position called with no cursor");
+                mIsVisible = false;
+                return;
+            }
+
+            positionDrawableUnderCursor(offset, mDrawable);
+
+            mFadeOutTimerStart = System.currentTimeMillis();
+            mDrawable.setAlpha(255);
+        }
+
+        public void onTouchEvent(MotionEvent event) {
+            if (isFocused() && isTextEditable() && mIsVisible) {
+                switch (event.getActionMasked()) {
+                    case MotionEvent.ACTION_DOWN : {
+                        final float x = event.getX();
+                        final float y = event.getY();
+
+                        if (fingerIsOnDrawable(x, y, mDrawable)) {
+                            show();
+
+                            if (mMovement instanceof ArrowKeyMovementMethod) {
+                                ((ArrowKeyMovementMethod)mMovement).setCursorController(this);
+                            }
+
+                            if (mParent != null) {
+                                // Prevent possible scrollView parent from scrolling, so that
+                                // we can use auto-scrolling.
+                                mParent.requestDisallowInterceptTouchEvent(true);
+
+                                final Rect bounds = mDrawable.getBounds();
+                                mOffsetX = (bounds.left + bounds.right) / 2.0f - x;
+                                mOffsetY = bounds.top - mCursorControllerVerticalOffset - y;
+
+                                mOnDownTimerStart = event.getEventTime();
+                            }
+                        }
+                        break;
+                    }
+
+                    case MotionEvent.ACTION_UP : {
+                        int time = (int) (event.getEventTime() - mOnDownTimerStart);
+
+                        if (time <= ViewConfiguration.getTapTimeout()) {
+                            // A tap on the controller is not grabbed, move the cursor instead
+                            int offset = getOffset((int) event.getX(), (int) event.getY());
+                            Selection.setSelection((Spannable) mText, offset);
+
+                            // Modified by cancelLongPress and prevents the cursor from changing
+                            mScrolled = false;
+                        }
+                        break;
+                    }
+                }
+            }
+        }
+
+        public float getOffsetX() {
+            return mOffsetX;
+        }
+
+        public float getOffsetY() {
+            return mOffsetY;
+        }
+    }
+
+    class SelectionModifierCursorController implements CursorController {
+        // Whether or not the selection controls are currently visible
+        private boolean mIsVisible = false;
+        // Whether that start or the end of selection controller is dragged
+        private boolean mStartIsDragged = false;
+        // Starting time of the fade timer
+        private long mFadeOutTimerStart;
+        // The cursor controller images
+        private final Drawable mStartDrawable, mEndDrawable;
+        // Offset between finger hot point on active cursor controller and actual cursor
+        private float mOffsetX, mOffsetY;
+        // The offset of that last touch down event. Remembered to start selection there.
+        private int mTouchOffset;
+
+        SelectionModifierCursorController() {
+            Resources res = mContext.getResources();
+            mStartDrawable = res.getDrawable(com.android.internal.R.drawable.selection_start_handle);
+            mEndDrawable = res.getDrawable(com.android.internal.R.drawable.selection_end_handle);
+        }
+
+        public void show() {
+            updateDrawablesPositions();
+            // Has to be done after updatePosition, so that previous position invalidate
+            // in only done if necessary.
+            mIsVisible = true;
+            mFadeOutTimerStart = -1;
+            if (mInsertionPointCursorController != null) {
+                mInsertionPointCursorController.hide();
+            }
+        }
+
+        public void hide() {
+            if (mIsVisible && (mFadeOutTimerStart < 0)) {
+                mFadeOutTimerStart = System.currentTimeMillis();
+                postInvalidate(mStartDrawable);
+                postInvalidate(mEndDrawable);
+            }
+        }
+
+        public void draw(Canvas canvas) {
+            if (mIsVisible) {
+                if (mFadeOutTimerStart >= 0) {
+                    int time = (int) (System.currentTimeMillis() - mFadeOutTimerStart);
+                    if (time <= FADE_OUT_DURATION) {
+                        final int alpha = 255 * (FADE_OUT_DURATION - time) / FADE_OUT_DURATION;
+                        mStartDrawable.setAlpha(alpha);
+                        mEndDrawable.setAlpha(alpha);
+                        postInvalidateDelayed(30, mStartDrawable);
+                        postInvalidateDelayed(30, mEndDrawable);
+                    } else {
+                        mStartDrawable.setAlpha(0);
+                        mEndDrawable.setAlpha(0);
+                        mIsVisible = false;
+                    }
+                }
+                mStartDrawable.draw(canvas);
+                mEndDrawable.draw(canvas);
+            }
+        }
+
+        public void updatePosition(int offset) {
+            int selectionStart = getSelectionStart();
+            int selectionEnd = getSelectionEnd();
+
+            // Handle the case where start and end are swapped, making sure start <= end
+            if (mStartIsDragged) {
+                if (offset <= selectionEnd) {
+                    selectionStart = offset;
+                } else {
+                    selectionStart = selectionEnd;
+                    selectionEnd = offset;
+                    mStartIsDragged = false;
+                }
+            } else {
+                if (offset >= selectionStart) {
+                    selectionEnd = offset;
+                } else {
+                    selectionEnd = selectionStart;
+                    selectionStart = offset;
+                    mStartIsDragged = true;
+                }
+            }
+
+            Selection.setSelection((Spannable) mText, selectionStart, selectionEnd);
+            updateDrawablesPositions();
+        }
+
+        private void updateDrawablesPositions() {
+            if (mIsVisible) {
+                // Clear previous cursor controller before bounds are updated
+                postInvalidate(mStartDrawable);
+                postInvalidate(mEndDrawable);
+            }
+
+            final int selectionStart = getSelectionStart();
+            final int selectionEnd = getSelectionEnd();
+
+            if ((selectionStart < 0) || (selectionEnd < 0)) {
+                // Should never happen, safety check.
+                Log.w(LOG_TAG, "Update selection controller position called with no cursor");
+                mIsVisible = false;
+                return;
+            }
+
+            positionDrawableUnderCursor(selectionStart, mStartDrawable);
+            positionDrawableUnderCursor(selectionEnd, mEndDrawable);
+
+            mStartDrawable.setAlpha(255);
+            mEndDrawable.setAlpha(255);
+        }
+
+        public void onTouchEvent(MotionEvent event) {
+            if (isFocused() && isTextEditable() &&
+                    (event.getActionMasked() == MotionEvent.ACTION_DOWN)) {
+                final int x = (int) event.getX();
+                final int y = (int) event.getY();
+
+                // Remember finger down position, to be able to start selection on that point
+                mTouchOffset = getOffset(x, y);
+
+                if (mIsVisible) {
+                    if (mMovement instanceof ArrowKeyMovementMethod) {
+                        boolean isOnStart = fingerIsOnDrawable(x, y, mStartDrawable);
+                        boolean isOnEnd = fingerIsOnDrawable(x, y, mEndDrawable);
+                        if (isOnStart || isOnEnd) {
+                            if (mParent != null) {
+                                // Prevent possible scrollView parent from scrolling, so that
+                                // we can use auto-scrolling.
+                                mParent.requestDisallowInterceptTouchEvent(true);
+                            }
+
+                            // Start handle will be dragged in case BOTH controller are under finger
+                            mStartIsDragged = isOnStart;
+                            final Rect bounds =
+                                (mStartIsDragged ? mStartDrawable : mEndDrawable).getBounds();
+                            mOffsetX = (bounds.left + bounds.right) / 2.0f - x;
+                            mOffsetY = bounds.top - mCursorControllerVerticalOffset - y;
+
+                            ((ArrowKeyMovementMethod)mMovement).setCursorController(this);
+                        }
+                    }
+                }
+            }
+        }
+
+        public int getTouchOffset() {
+            return mTouchOffset;
+        }
+
+        public float getOffsetX() {
+            return mOffsetX;
+        }
+
+        public float getOffsetY() {
+            return mOffsetY;
+        }
+
+        /**
+         * @return true iff this controller is currently used to move the selection start.
+         */
+        public boolean isSelectionStartDragged() {
+            return mIsVisible && mStartIsDragged;
+        }
+    }
+
+    // Helper methods used by CursorController implementations
+
+    private void positionDrawableUnderCursor(final int offset, Drawable drawable) {
+        final int drawableWidth = drawable.getIntrinsicWidth();
+        final int drawableHeight = drawable.getIntrinsicHeight();
+        final int line = mLayout.getLineForOffset(offset);
+
+        final Rect bounds = sCursorControllerTempRect;
+        bounds.left = (int) (mLayout.getPrimaryHorizontal(offset) - 0.5 - drawableWidth / 2.0);
+        bounds.top = mLayout.getLineTop(line + 1);
+
+        // Move cursor controller a little bit up when editing the last line of text
+        // (or a single line) so that it is visible and easier to grab.
+        if (line == mLayout.getLineCount() - 1) {
+            bounds.top -= Math.max(0, drawableHeight / 2 - getExtendedPaddingBottom());
+        }
+
+        bounds.right = bounds.left + drawableWidth;
+        bounds.bottom = bounds.top + drawableHeight;
+
+        convertFromViewportToContentCoordinates(bounds);
+        drawable.setBounds(bounds);
+        postInvalidate(bounds.left, bounds.top, bounds.right, bounds.bottom);
+    }
+
+    private boolean fingerIsOnDrawable(float x, float y, Drawable drawable) {
+        // Simulate a 'fat finger' to ease grabbing of the controller.
+        // Expands according to controller image size instead of using density.
+        // Assumes controller imager has a sensible size, proportionnal to density.
+        final int drawableWidth = drawable.getIntrinsicWidth();
+        final int drawableHeight = drawable.getIntrinsicHeight();
+        final Rect fingerRect = sCursorControllerTempRect;
+        fingerRect.set((int) (x - drawableWidth / 2.0),
+                       (int) (y - drawableHeight),
+                       (int) (x + drawableWidth / 2.0),
+                       (int) y);
+        return Rect.intersects(drawable.getBounds(), fingerRect);
+    }
+
+    private void postInvalidate(Drawable drawable) {
+        final Rect bounds = drawable.getBounds();
+        postInvalidate(bounds.left, bounds.top, bounds.right, bounds.bottom);
+    }
+
+    private void postInvalidateDelayed(long delay, Drawable drawable) {
+        final Rect bounds = drawable.getBounds();
+        postInvalidateDelayed(delay, bounds.left, bounds.top, bounds.right, bounds.bottom);
+    }
+
     @ViewDebug.ExportedProperty
     private CharSequence            mText;
     private CharSequence            mTransformed;
@@ -7360,13 +7976,21 @@
     private final TextPaint         mTextPaint;
     private boolean                 mUserSetTextScaleX;
     private final Paint             mHighlightPaint;
-    private int                     mHighlightColor = 0xFFBBDDFF;
+    private int                     mHighlightColor = 0xD077A14B;
     private Layout                  mLayout;
 
     private long                    mShowCursor;
     private Blink                   mBlink;
     private boolean                 mCursorVisible = true;
 
+    // Cursor Controllers. Null when disabled.
+    private CursorController        mInsertionPointCursorController;
+    private CursorController        mSelectionModifierCursorController;
+    // Stored once and for all.
+    private int                     mCursorControllerVerticalOffset;
+    // Created once and shared by different CursorController helper methods.
+    private static Rect             sCursorControllerTempRect;
+
     private boolean                 mSelectAllOnFocus = false;
 
     private int                     mGravity = Gravity.TOP | Gravity.LEFT;
diff --git a/core/java/com/android/internal/app/ActionBarImpl.java b/core/java/com/android/internal/app/ActionBarImpl.java
index 6ac68aa..f37021b 100644
--- a/core/java/com/android/internal/app/ActionBarImpl.java
+++ b/core/java/com/android/internal/app/ActionBarImpl.java
@@ -22,6 +22,9 @@
 import com.android.internal.widget.ActionBarView;
 
 import android.app.ActionBar;
+import android.app.Activity;
+import android.app.Fragment;
+import android.app.FragmentTransaction;
 import android.graphics.drawable.Drawable;
 import android.os.Handler;
 import android.view.Menu;
@@ -31,6 +34,9 @@
 import android.widget.SpinnerAdapter;
 import android.widget.ViewAnimator;
 
+import java.lang.ref.WeakReference;
+import java.util.ArrayList;
+
 /**
  * ActionBarImpl is the ActionBar implementation used
  * by devices of all screen sizes. If it detects a compatible decor,
@@ -42,10 +48,21 @@
     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 Activity mActivity;
+
     private ViewAnimator mAnimatorView;
     private ActionBarView mActionView;
     private ActionBarContextView mUpperContextView;
     private LinearLayout mLowerContextView;
+
+    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 ContextMode mContextMode;
     
@@ -54,6 +71,8 @@
     
     private int mContextDisplayMode;
 
+    private boolean mClosingContext;
+
     final Handler mHandler = new Handler();
     final Runnable mCloseContext = new Runnable() {
         public void run() {
@@ -61,10 +80,13 @@
             if (mLowerContextView != null) {
                 mLowerContextView.removeAllViews();
             }
+            mClosingContext = false;
         }
     };
 
-    public ActionBarImpl(View decor) {
+    public ActionBarImpl(Activity activity) {
+        final View decor = activity.getWindow().getDecorView();
+        mActivity = activity;
         mActionView = (ActionBarView) decor.findViewById(com.android.internal.R.id.action_bar);
         mUpperContextView = (ActionBarContextView) decor.findViewById(
                 com.android.internal.R.id.action_context_bar);
@@ -83,32 +105,54 @@
     }
 
     public void setCustomNavigationMode(View view) {
+        cleanupTabs();
         mActionView.setCustomNavigationView(view);
         mActionView.setCallback(null);
     }
 
     public void setDropdownNavigationMode(SpinnerAdapter adapter, NavigationCallback callback) {
+        cleanupTabs();
         mActionView.setCallback(callback);
         mActionView.setNavigationMode(NAVIGATION_MODE_DROPDOWN_LIST);
         mActionView.setDropdownAdapter(adapter);
     }
 
     public void setStandardNavigationMode() {
+        cleanupTabs();
         mActionView.setNavigationMode(NAVIGATION_MODE_STANDARD);
         mActionView.setCallback(null);
     }
 
     public void setStandardNavigationMode(CharSequence title) {
+        cleanupTabs();
         setStandardNavigationMode(title, null);
     }
 
     public void setStandardNavigationMode(CharSequence title, CharSequence subtitle) {
+        cleanupTabs();
         mActionView.setNavigationMode(NAVIGATION_MODE_STANDARD);
         mActionView.setTitle(title);
         mActionView.setSubtitle(subtitle);
         mActionView.setCallback(null);
     }
 
+    private void cleanupTabs() {
+        if (mSelectedTab != null) {
+            selectTab(null);
+        }
+        if (!mTabs.isEmpty()) {
+            if (mTabSwitchMode == TAB_SWITCH_SHOW_HIDE) {
+                final FragmentTransaction trans = mActivity.openFragmentTransaction();
+                final int tabCount = mTabs.size();
+                for (int i = 0; i < tabCount; i++) {
+                    trans.remove(mTabs.get(i).getFragment());
+                }
+                trans.commit();
+            }
+            mTabs.clear();
+        }
+    }
+
     public void setTitle(CharSequence title) {
         mActionView.setTitle(title);
     }
@@ -155,6 +199,14 @@
         if (mContextMode != null) {
             mContextMode.finish();
         }
+
+        // Don't wait for the close context mode animation to finish.
+        if (mClosingContext) {
+            mAnimatorView.clearAnimation();
+            mHandler.removeCallbacks(mCloseContext);
+            mCloseContext.run();
+        }
+
         mContextMode = new ContextMode(callback);
         if (callback.onCreateContextMode(mContextMode, mContextMode.getMenu())) {
             mContextMode.invalidate();
@@ -174,12 +226,120 @@
         }
     }
 
+    private void configureTab(Tab tab, int position) {
+        final TabImpl tabi = (TabImpl) tab;
+        final boolean isFirstTab = mTabs.isEmpty();
+        final FragmentTransaction trans = mActivity.openFragmentTransaction();
+        final Fragment frag = tabi.getFragment();
+
+        tabi.setPosition(position);
+        mTabs.add(position, tabi);
+
+        if (mTabSwitchMode == TAB_SWITCH_SHOW_HIDE) {
+            if (!frag.isAdded()) {
+                trans.add(mTabContainerViewId, frag);
+            }
+        }
+
+        if (isFirstTab) {
+            if (mTabSwitchMode == TAB_SWITCH_SHOW_HIDE) {
+                trans.show(frag);
+            } else if (mTabSwitchMode == TAB_SWITCH_ADD_REMOVE) {
+                trans.add(mTabContainerViewId, frag);
+            }
+            mSelectedTab = tabi;
+        } else {
+            if (mTabSwitchMode == TAB_SWITCH_SHOW_HIDE) {
+                trans.hide(frag);
+            }
+        }
+        trans.commit();
+    }
+
+    @Override
+    public void addTab(Tab tab) {
+        mActionView.addTab(tab);
+        configureTab(tab, mTabs.size());
+    }
+
+    @Override
+    public void insertTab(Tab tab, int position) {
+        mActionView.insertTab(tab, position);
+        configureTab(tab, position);
+    }
+
+    @Override
+    public Tab newTab() {
+        return new TabImpl();
+    }
+
+    @Override
+    public void removeTab(Tab tab) {
+        removeTabAt(tab.getPosition());
+    }
+
+    @Override
+    public void removeTabAt(int position) {
+        mActionView.removeTabAt(position);
+        mTabs.remove(position);
+
+        final int newTabCount = mTabs.size();
+        for (int i = position; i < newTabCount; i++) {
+            mTabs.get(i).setPosition(i);
+        }
+
+        selectTab(mTabs.isEmpty() ? null : mTabs.get(Math.max(0, position - 1)));
+    }
+
+    @Override
+    public void setTabNavigationMode() {
+        mActionView.setNavigationMode(NAVIGATION_MODE_TABS);
+    }
+
+    @Override
+    public void setTabNavigationMode(int containerViewId) {
+        mTabContainerViewId = containerViewId;
+        setTabNavigationMode();
+    }
+
+    @Override
+    public void selectTab(Tab tab) {
+        if (mSelectedTab == tab) {
+            return;
+        }
+
+        mActionView.setTabSelected(tab != null ? tab.getPosition() : Tab.INVALID_POSITION);
+        final FragmentTransaction trans = mActivity.openFragmentTransaction();
+        if (mSelectedTab != null) {
+            if (mTabSwitchMode == TAB_SWITCH_SHOW_HIDE) {
+                trans.hide(mSelectedTab.getFragment());
+            } else if (mTabSwitchMode == TAB_SWITCH_ADD_REMOVE) {
+                trans.remove(mSelectedTab.getFragment());
+            }
+        }
+        if (tab != null) {
+            if (mTabSwitchMode == TAB_SWITCH_SHOW_HIDE) {
+                trans.show(tab.getFragment());
+            } else if (mTabSwitchMode == TAB_SWITCH_ADD_REMOVE) {
+                trans.add(mTabContainerViewId, tab.getFragment());
+            }
+        }
+        mSelectedTab = (TabImpl) tab;
+        trans.commit();
+    }
+
+    @Override
+    public void selectTabAt(int position) {
+        selectTab(mTabs.get(position));
+    }
+
     /**
      * @hide 
      */
     public class ContextMode extends ActionBar.ContextMode {
         private ContextModeCallback mCallback;
         private ActionMenu mMenu;
+        private WeakReference<View> mCustomView;
         
         public ContextMode(ContextModeCallback callback) {
             mCallback = callback;
@@ -197,6 +357,7 @@
             mAnimatorView.setDisplayedChild(NORMAL_VIEW);
 
             // Clear out the context mode views after the animation finishes
+            mClosingContext = true;
             mHandler.postDelayed(mCloseContext, mAnimatorView.getOutAnimation().getDuration());
 
             if (mLowerContextView != null && mLowerContextView.getVisibility() != View.GONE) {
@@ -216,6 +377,7 @@
         @Override
         public void setCustomView(View view) {
             mUpperContextView.setCustomView(view);
+            mCustomView = new WeakReference<View>(view);
         }
 
         @Override
@@ -227,12 +389,81 @@
         public void setTitle(CharSequence title) {
             mUpperContextView.setTitle(title);
         }
+
+        @Override
+        public CharSequence getTitle() {
+            return mUpperContextView.getTitle();
+        }
+
+        @Override
+        public CharSequence getSubtitle() {
+            return mUpperContextView.getSubtitle();
+        }
         
+        @Override
+        public View getCustomView() {
+            return mCustomView != null ? mCustomView.get() : null;
+        }
+
         public void dispatchOnContextItemClicked(MenuItem item) {
             ActionMenuItem actionItem = (ActionMenuItem) item;
             if (!actionItem.invoke()) {
                 mCallback.onContextItemClicked(this, item);
             }
+       }
+    }
+
+    /**
+     * @hide
+     */
+    public class TabImpl extends ActionBar.Tab {
+        private Fragment mFragment;
+        private Drawable mIcon;
+        private CharSequence mText;
+        private int mPosition;
+
+        @Override
+        public Fragment getFragment() {
+            return mFragment;
+        }
+
+        @Override
+        public Drawable getIcon() {
+            return mIcon;
+        }
+
+        @Override
+        public int getPosition() {
+            return mPosition;
+        }
+
+        public void setPosition(int position) {
+            mPosition = position;
+        }
+
+        @Override
+        public CharSequence getText() {
+            return mText;
+        }
+
+        @Override
+        public void setFragment(Fragment fragment) {
+            mFragment = fragment;
+        }
+
+        @Override
+        public void setIcon(Drawable icon) {
+            mIcon = icon;
+        }
+
+        @Override
+        public void setText(CharSequence text) {
+            mText = text;
+        }
+
+        @Override
+        public void select() {
+            selectTab(this);
         }
     }
 }
diff --git a/core/java/com/android/internal/app/AlertController.java b/core/java/com/android/internal/app/AlertController.java
index 107b145..4a0617c 100644
--- a/core/java/com/android/internal/app/AlertController.java
+++ b/core/java/com/android/internal/app/AlertController.java
@@ -435,6 +435,7 @@
                 View titleTemplate = mWindow.findViewById(R.id.title_template);
                 titleTemplate.setVisibility(View.GONE);
                 mIconView.setVisibility(View.GONE);
+                topPanel.setVisibility(View.GONE);
                 hasTitle = false;
             }
         }
diff --git a/core/java/com/android/internal/view/BaseIWindow.java b/core/java/com/android/internal/view/BaseIWindow.java
index b13d656..4da74e6 100644
--- a/core/java/com/android/internal/view/BaseIWindow.java
+++ b/core/java/com/android/internal/view/BaseIWindow.java
@@ -43,59 +43,6 @@
         }
     }
 
-    public void dispatchKey(KeyEvent event) {
-        try {
-            mSession.finishKey(this);
-        } catch (RemoteException ex) {
-        }
-    }
-
-    public boolean onDispatchPointer(MotionEvent event, long eventTime,
-            boolean callWhenDone) {
-        event.recycle();
-        return false;
-    }
-    
-    public void dispatchPointer(MotionEvent event, long eventTime,
-            boolean callWhenDone) {
-        try {
-            if (event == null) {
-                event = mSession.getPendingPointerMove(this);
-                onDispatchPointer(event, eventTime, false);
-            } else if (callWhenDone) {
-                if (!onDispatchPointer(event, eventTime, true)) {
-                    mSession.finishKey(this);
-                }
-            } else {
-                onDispatchPointer(event, eventTime, false);
-            }
-        } catch (RemoteException ex) {
-        }
-    }
-
-    public boolean onDispatchTrackball(MotionEvent event, long eventTime,
-            boolean callWhenDone) {
-        event.recycle();
-        return false;
-    }
-    
-    public void dispatchTrackball(MotionEvent event, long eventTime,
-            boolean callWhenDone) {
-        try {
-            if (event == null) {
-                event = mSession.getPendingTrackballMove(this);
-                onDispatchTrackball(event, eventTime, false);
-            } else if (callWhenDone) {
-                if (!onDispatchTrackball(event, eventTime, true)) {
-                    mSession.finishKey(this);
-                }
-            } else {
-                onDispatchTrackball(event, eventTime, false);
-            }
-        } catch (RemoteException ex) {
-        }
-    }
-
     public void dispatchAppVisibility(boolean visible) {
     }
 
diff --git a/core/java/com/android/internal/view/RootViewSurfaceTaker.java b/core/java/com/android/internal/view/RootViewSurfaceTaker.java
index 7ff8d4c..9c1b558 100644
--- a/core/java/com/android/internal/view/RootViewSurfaceTaker.java
+++ b/core/java/com/android/internal/view/RootViewSurfaceTaker.java
@@ -5,7 +5,7 @@
 
 /** hahahah */
 public interface RootViewSurfaceTaker {
-    SurfaceHolder.Callback willYouTakeTheSurface();
+    SurfaceHolder.Callback2 willYouTakeTheSurface();
     void setSurfaceType(int type);
     void setSurfaceFormat(int format);
     void setSurfaceKeepScreenOn(boolean keepOn);
diff --git a/core/java/com/android/internal/view/menu/MenuBuilder.java b/core/java/com/android/internal/view/menu/MenuBuilder.java
index a962212..94a9f65 100644
--- a/core/java/com/android/internal/view/menu/MenuBuilder.java
+++ b/core/java/com/android/internal/view/menu/MenuBuilder.java
@@ -55,7 +55,7 @@
     private static final String LOGTAG = "MenuBuilder";
     
     /** The number of different menu types */
-    public static final int NUM_TYPES = 4;
+    public static final int NUM_TYPES = 5;
     /** The menu type that represents the icon menu view */
     public static final int TYPE_ICON = 0;
     /** The menu type that represents the expanded menu view */
@@ -66,20 +66,24 @@
      * have an ItemView.
      */
     public static final int TYPE_DIALOG = 2;
-    
     /**
      * The menu type that represents a button in the application's action bar.
      */
     public static final int TYPE_ACTION_BUTTON = 3;
+    /**
+     * The menu type that represents a menu popup.
+     */
+    public static final int TYPE_POPUP = 4;
 
     private static final String VIEWS_TAG = "android:views";
-    
+
     // Order must be the same order as the TYPE_*
     static final int THEME_RES_FOR_TYPE[] = new int[] {
         com.android.internal.R.style.Theme_IconMenu,
         com.android.internal.R.style.Theme_ExpandedMenu,
         0,
         0,
+        0,
     };
     
     // Order must be the same order as the TYPE_*
@@ -88,6 +92,7 @@
         com.android.internal.R.layout.expanded_menu_layout,
         0,
         com.android.internal.R.layout.action_menu_layout,
+        0,
     };
 
     // Order must be the same order as the TYPE_*
@@ -96,6 +101,7 @@
         com.android.internal.R.layout.list_menu_item_layout,
         com.android.internal.R.layout.list_menu_item_layout,
         com.android.internal.R.layout.action_menu_item_layout,
+        com.android.internal.R.layout.list_menu_item_layout,
     };
 
     private static final int[]  sCategoryToOrder = new int[] {
@@ -1251,7 +1257,19 @@
         }
 
         public View getView(int position, View convertView, ViewGroup parent) {
-            return ((MenuItemImpl) getItem(position)).getItemView(mMenuType, parent);
+            if (convertView != null) {
+                MenuView.ItemView itemView = (MenuView.ItemView) convertView;
+                itemView.getItemData().setItemView(mMenuType, null);
+
+                MenuItemImpl item = (MenuItemImpl) getItem(position);
+                itemView.initialize(item, mMenuType);
+                item.setItemView(mMenuType, itemView);
+                return convertView;
+            } else {
+                MenuItemImpl item = (MenuItemImpl) getItem(position);
+                item.setItemView(mMenuType, null);
+                return item.getItemView(mMenuType, parent);
+            }
         }
 
     }
diff --git a/core/java/com/android/internal/view/menu/MenuItemImpl.java b/core/java/com/android/internal/view/menu/MenuItemImpl.java
index 5fe75be..fecbd77 100644
--- a/core/java/com/android/internal/view/menu/MenuItemImpl.java
+++ b/core/java/com/android/internal/view/menu/MenuItemImpl.java
@@ -583,6 +583,10 @@
         return (View) mItemViews[menuType].get();
     }
 
+    void setItemView(int menuType, ItemView view) {
+        mItemViews[menuType] = new WeakReference<ItemView>(view);
+    }
+
     /**
      * Create and initializes a menu item view that implements {@link MenuView.ItemView}.
      * @param menuType The type of menu to get a View for (must be one of
@@ -631,7 +635,10 @@
      * @return Whether the given menu type should show icons for menu items.
      */
     public boolean shouldShowIcon(int menuType) {
-        return menuType == MenuBuilder.TYPE_ICON || mMenu.getOptionalIconsVisible();
+        return menuType == MenuBuilder.TYPE_ICON ||
+                menuType == MenuBuilder.TYPE_ACTION_BUTTON ||
+                menuType == MenuBuilder.TYPE_POPUP ||
+                mMenu.getOptionalIconsVisible();
     }
     
     public boolean isActionButton() {
diff --git a/core/java/com/android/internal/view/menu/MenuPopupHelper.java b/core/java/com/android/internal/view/menu/MenuPopupHelper.java
new file mode 100644
index 0000000..751ecda
--- /dev/null
+++ b/core/java/com/android/internal/view/menu/MenuPopupHelper.java
@@ -0,0 +1,91 @@
+/*
+ * 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 com.android.internal.view.menu;
+
+import com.android.internal.view.menu.MenuBuilder.MenuAdapter;
+
+import android.content.Context;
+import android.util.DisplayMetrics;
+import android.view.View;
+import android.view.View.MeasureSpec;
+import android.widget.AdapterView;
+import android.widget.ListPopupWindow;
+
+/**
+ * @hide
+ */
+public class MenuPopupHelper implements AdapterView.OnItemClickListener {
+    private static final String TAG = "MenuPopupHelper";
+
+    private Context mContext;
+    private ListPopupWindow mPopup;
+    private SubMenuBuilder mSubMenu;
+    private int mPopupMaxWidth;
+
+    public MenuPopupHelper(Context context, SubMenuBuilder subMenu) {
+        mContext = context;
+        mSubMenu = subMenu;
+
+        final DisplayMetrics metrics = context.getResources().getDisplayMetrics();
+        mPopupMaxWidth = metrics.widthPixels / 2;
+    }
+
+    public void show() {
+        // TODO Use a style from the theme here
+        mPopup = new ListPopupWindow(mContext, null, 0,
+                com.android.internal.R.style.Widget_Spinner);
+        mPopup.setOnItemClickListener(this);
+
+        final MenuAdapter adapter = mSubMenu.getMenuAdapter(MenuBuilder.TYPE_POPUP);
+        mPopup.setAdapter(adapter);
+        mPopup.setModal(true);
+
+        final MenuItemImpl itemImpl = (MenuItemImpl) mSubMenu.getItem();
+        final View anchorView = itemImpl.getItemView(MenuBuilder.TYPE_ACTION_BUTTON, null);
+        mPopup.setAnchorView(anchorView);
+
+        mPopup.setContentWidth(Math.min(measureContentWidth(adapter), mPopupMaxWidth));
+        mPopup.show();
+    }
+
+    public void dismiss() {
+        mPopup.dismiss();
+        mPopup = null;
+    }
+
+    public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
+        mSubMenu.performItemAction(mSubMenu.getItem(position), 0);
+        mPopup.dismiss();
+    }
+
+    private int measureContentWidth(MenuAdapter adapter) {
+        // Menus don't tend to be long, so this is more sane than it looks.
+        int width = 0;
+        View itemView = null;
+        final int widthMeasureSpec =
+            MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
+        final int heightMeasureSpec =
+            MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
+        final int count = adapter.getCount();
+        for (int i = 0; i < count; i++) {
+            itemView = adapter.getView(i, itemView, null);
+            itemView.measure(widthMeasureSpec, heightMeasureSpec);
+            width = Math.max(width, itemView.getMeasuredWidth());
+        }
+        return width;
+    }
+}
diff --git a/core/java/com/android/internal/widget/ActionBarContextView.java b/core/java/com/android/internal/widget/ActionBarContextView.java
index 0f895f0..b57b7a8 100644
--- a/core/java/com/android/internal/widget/ActionBarContextView.java
+++ b/core/java/com/android/internal/widget/ActionBarContextView.java
@@ -105,6 +105,14 @@
         initTitle();
     }
 
+    public CharSequence getTitle() {
+        return mTitle;
+    }
+
+    public CharSequence getSubtitle() {
+        return mSubtitle;
+    }
+
     private void initTitle() {
         if (mTitleLayout == null) {
             LayoutInflater inflater = LayoutInflater.from(getContext());
diff --git a/core/java/com/android/internal/widget/ActionBarView.java b/core/java/com/android/internal/widget/ActionBarView.java
index e919f1b..fbff8ae 100644
--- a/core/java/com/android/internal/widget/ActionBarView.java
+++ b/core/java/com/android/internal/widget/ActionBarView.java
@@ -31,8 +31,10 @@
 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.view.Gravity;
 import android.view.LayoutInflater;
 import android.view.Menu;
 import android.view.View;
@@ -85,9 +87,11 @@
     private TextView mTitleView;
     private TextView mSubtitleView;
     private Spinner mSpinner;
+    private LinearLayout mTabLayout;
     private View mCustomNavView;
     
     private boolean mShowMenu;
+    private boolean mUserTitle;
 
     private MenuBuilder mOptionsMenu;
     private ActionMenuView mMenuView;
@@ -128,7 +132,8 @@
 
         ApplicationInfo info = context.getApplicationInfo();
         PackageManager pm = context.getPackageManager();
-        mNavigationMode = a.getInt(R.styleable.ActionBar_navigationMode, ActionBar.NAVIGATION_MODE_STANDARD);
+        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);
@@ -208,7 +213,30 @@
         return mTitle;
     }
 
+    /**
+     * Set the action bar title. This will always replace or override window titles.
+     * @param title Title to set
+     *
+     * @see #setWindowTitle(CharSequence)
+     */
     public void setTitle(CharSequence title) {
+        mUserTitle = true;
+        setTitleImpl(title);
+    }
+
+    /**
+     * Set the window title. A window title will always be replaced or overridden by a user title.
+     * @param title Title to set
+     *
+     * @see #setTitle(CharSequence)
+     */
+    public void setWindowTitle(CharSequence title) {
+        if (!mUserTitle) {
+            setTitleImpl(title);
+        }
+    }
+
+    private void setTitleImpl(CharSequence title) {
         mTitle = title;
         if (mTitleView != null) {
             mTitleView.setText(title);
@@ -271,6 +299,11 @@
                     mCustomNavView = null;
                 }
                 break;
+            case ActionBar.NAVIGATION_MODE_TABS:
+                if (mTabLayout != null) {
+                    removeView(mTabLayout);
+                    mTabLayout = null;
+                }
             }
             
             switch (mode) {
@@ -286,6 +319,10 @@
             case ActionBar.NAVIGATION_MODE_CUSTOM:
                 addView(mCustomNavView);
                 break;
+            case ActionBar.NAVIGATION_MODE_TABS:
+                mTabLayout = new LinearLayout(getContext());
+                addView(mTabLayout);
+                break;
             }
             mNavigationMode = mode;
             requestLayout();
@@ -308,6 +345,35 @@
         return mDisplayOptions;
     }
 
+    private TabView createTabView(ActionBar.Tab tab) {
+        final TabView tabView = new TabView(getContext(), tab);
+        tabView.setFocusable(true);
+        tabView.setOnClickListener(new TabClickListener());
+        return tabView;
+    }
+
+    public void addTab(ActionBar.Tab tab) {
+        final boolean isFirst = mTabLayout.getChildCount() == 0;
+        final TabView tabView = createTabView(tab);
+        mTabLayout.addView(tabView);
+        if (isFirst) {
+            tabView.setSelected(true);
+        }
+    }
+
+    public void insertTab(ActionBar.Tab tab, int position) {
+        final boolean isFirst = mTabLayout.getChildCount() == 0;
+        final TabView tabView = createTabView(tab);
+        mTabLayout.addView(tabView, position);
+        if (isFirst) {
+            tabView.setSelected(true);
+        }
+    }
+
+    public void removeTabAt(int position) {
+        mTabLayout.removeViewAt(position);
+    }
+
     @Override
     protected LayoutParams generateDefaultLayoutParams() {
         // Used by custom nav views if they don't supply layout params. Everything else
@@ -356,7 +422,7 @@
             
         case ActionBar.NAVIGATION_MODE_TABS:
             throw new UnsupportedOperationException(
-                    "Tab navigation isn't supported yet!");
+                    "Inflating tab navigation isn't supported yet!");
             
         case ActionBar.NAVIGATION_MODE_CUSTOM:
             if (mCustomNavView != null) {
@@ -381,6 +447,14 @@
         addView(mTitleLayout);
     }
 
+    public void setTabSelected(int position) {
+        final int tabCount = mTabLayout.getChildCount();
+        for (int i = 0; i < tabCount; i++) {
+            final View child = mTabLayout.getChildAt(i);
+            child.setSelected(i == position);
+        }
+    }
+
     @Override
     protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
         int widthMode = MeasureSpec.getMode(widthMeasureSpec);
@@ -442,6 +516,13 @@
                         MeasureSpec.makeMeasureSpec(customNavHeight, customNavHeightMode));
             }
             break;
+        case ActionBar.NAVIGATION_MODE_TABS:
+            if (mTabLayout != null) {
+                mTabLayout.measure(
+                        MeasureSpec.makeMeasureSpec(availableWidth, MeasureSpec.AT_MOST),
+                        MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY));
+            }
+            break;
         }
 
         setMeasuredDimension(contentWidth, mContentHeight);
@@ -486,6 +567,10 @@
                 x += positionChild(mCustomNavView, x, y, contentHeight) + mSpacing;
             }
             break;
+        case ActionBar.NAVIGATION_MODE_TABS:
+            if (mTabLayout != null) {
+                x += positionChild(mTabLayout, x, y, contentHeight) + mSpacing;
+            }
         }
 
         x = r - l - getPaddingRight();
@@ -515,4 +600,59 @@
 
         return childWidth;
     }
+
+    private static class TabView extends LinearLayout {
+        private ActionBar.Tab mTab;
+
+        public TabView(Context context, ActionBar.Tab tab) {
+            super(context);
+            mTab = tab;
+
+            // TODO Style tabs based on the theme
+
+            final Drawable icon = tab.getIcon();
+            final CharSequence text = tab.getText();
+
+            if (icon != null) {
+                ImageView iconView = new ImageView(context);
+                iconView.setImageDrawable(icon);
+                LayoutParams lp = new LayoutParams(LayoutParams.WRAP_CONTENT,
+                        LayoutParams.WRAP_CONTENT);
+                lp.gravity = Gravity.CENTER_VERTICAL;
+                iconView.setLayoutParams(lp);
+                addView(iconView);
+            }
+
+            if (text != null) {
+                TextView textView = new TextView(context);
+                textView.setText(text);
+                textView.setSingleLine();
+                textView.setEllipsize(TruncateAt.END);
+                LayoutParams lp = new LayoutParams(LayoutParams.WRAP_CONTENT,
+                        LayoutParams.WRAP_CONTENT);
+                lp.gravity = Gravity.CENTER_VERTICAL;
+                textView.setLayoutParams(lp);
+                addView(textView);
+            }
+
+            setLayoutParams(new LayoutParams(LayoutParams.WRAP_CONTENT,
+                    LayoutParams.MATCH_PARENT, 1));
+        }
+
+        public ActionBar.Tab getTab() {
+            return mTab;
+        }
+    }
+
+    private class TabClickListener implements OnClickListener {
+        public void onClick(View view) {
+            TabView tabView = (TabView) view;
+            tabView.getTab().select();
+            final int tabCount = mTabLayout.getChildCount();
+            for (int i = 0; i < tabCount; i++) {
+                final View child = mTabLayout.getChildAt(i);
+                child.setSelected(child == view);
+            }
+        }
+    }
 }
diff --git a/core/jni/ActivityManager.cpp b/core/jni/ActivityManager.cpp
index 8950dfb..0bd14fa 100644
--- a/core/jni/ActivityManager.cpp
+++ b/core/jni/ActivityManager.cpp
@@ -39,7 +39,7 @@
         data.writeString16(uri);
         status_t ret = am->transact(OPEN_CONTENT_URI_TRANSACTION, data, &reply);
         if (ret == NO_ERROR) {
-            int32_t exceptionCode = reply.readInt32();
+            int32_t exceptionCode = reply.readExceptionCode();
             if (!exceptionCode) {
                 // Success is indicated here by a nonzero int followed by the fd;
                 // failure by a zero int with no data following.
diff --git a/core/jni/Android.mk b/core/jni/Android.mk
index 722dacb..d61d56e 100644
--- a/core/jni/Android.mk
+++ b/core/jni/Android.mk
@@ -105,6 +105,7 @@
 	android/graphics/Rasterizer.cpp \
 	android/graphics/Region.cpp \
 	android/graphics/Shader.cpp \
+	android/graphics/TextLayout.cpp \
 	android/graphics/Typeface.cpp \
 	android/graphics/Xfermode.cpp \
 	android/graphics/YuvToJpegEncoder.cpp \
@@ -187,7 +188,6 @@
 	libssl \
 	libicuuc \
 	libicui18n \
-	libicudata \
 	libmedia \
 	libwpa_client \
 	libjpeg
diff --git a/core/jni/android/graphics/Canvas.cpp b/core/jni/android/graphics/Canvas.cpp
index 2e49c64..558f5ff 100644
--- a/core/jni/android/graphics/Canvas.cpp
+++ b/core/jni/android/graphics/Canvas.cpp
@@ -30,6 +30,8 @@
 #include "SkBoundaryPatch.h"
 #include "SkMeshUtils.h"
 
+#include "TextLayout.h"
+
 #include "unicode/ubidi.h"
 #include "unicode/ushape.h"
 
@@ -57,24 +59,6 @@
 class SkCanvasGlue {
 public:
 
-    enum {
-      kDirection_LTR = 0,
-      kDirection_RTL = 1
-    };
-
-    enum {
-      kDirection_Mask = 0x1
-    };
-
-    enum {
-      kBidi_LTR = 0,
-      kBidi_RTL = 1,
-      kBidi_Default_LTR = 2,
-      kBidi_Default_RTL = 3,
-      kBidi_Force_LTR = 4,
-      kBidi_Force_RTL = 5
-    };
-
     static void finalizer(JNIEnv* env, jobject clazz, SkCanvas* canvas) {
         canvas->unref();
     }
@@ -767,192 +751,12 @@
                              indices, indexCount, *paint);
     }
 
-    /**
-     * Character-based Arabic shaping.
-     *
-     * We'll use harfbuzz and glyph-based shaping instead once we're set up for it.
-     *
-     * @context the text context
-     * @start the start of the text to render
-     * @count the length of the text to render, start + count  must be <= contextCount
-     * @contextCount the length of the context
-     * @shaped where to put the shaped text, must have capacity for count uchars
-     * @return the length of the shaped text, or -1 if error
-     */
-    static int shapeRtlText(const jchar* context, jsize start, jsize count, jsize contextCount,
-                            jchar* shaped, UErrorCode &status) {
-        jchar buffer[contextCount];
-
-        // Use fixed length since we need to keep start and count valid
-        u_shapeArabic(context, contextCount, buffer, contextCount,
-                       U_SHAPE_LENGTH_FIXED_SPACES_NEAR |
-                       U_SHAPE_TEXT_DIRECTION_LOGICAL | U_SHAPE_LETTERS_SHAPE |
-                       U_SHAPE_X_LAMALEF_SUB_ALTERNATE, &status);
-
-        if (U_SUCCESS(status)) {
-            // trim out 0xffff following ligatures, if any
-            int end = 0;
-            for (int i = start, e = start + count; i < e; ++i) {
-                if (buffer[i] != 0xffff) {
-                    buffer[end++] = buffer[i];
-                }
-            }
-            count = end;
-            // LOG(LOG_INFO, "CSRTL", "start %d count %d ccount %d\n", start, count, contextCount);
-            ubidi_writeReverse(buffer, count, shaped, count, UBIDI_DO_MIRRORING | UBIDI_OUTPUT_REVERSE
-                               | UBIDI_KEEP_BASE_COMBINING, &status);
-            if (U_SUCCESS(status)) {
-                return count;
-            }
-        }
-
-        return -1;
-    }
-
-    /**
-     * Basic character-based layout supporting rtl and arabic shaping.
-     * Runs bidi on the text and generates a reordered, shaped line in buffer, returning
-     * the length.
-     * @text the text
-     * @len the length of the text in uchars
-     * @dir receives the resolved paragraph direction
-     * @buffer the buffer to receive the reordered, shaped line.  Must have capacity of
-     * at least len jchars.
-     * @flags line bidi flags
-     * @return the length of the reordered, shaped line, or -1 if error
-     */
-    static jint layoutLine(const jchar* text, jint len, jint flags, int &dir, jchar* buffer,
-            UErrorCode &status) {
-        static int RTL_OPTS = UBIDI_DO_MIRRORING | UBIDI_KEEP_BASE_COMBINING |
-                UBIDI_REMOVE_BIDI_CONTROLS | UBIDI_OUTPUT_REVERSE;
-
-        UBiDiLevel bidiReq = 0;
-        switch (flags) {
-          case kBidi_LTR: bidiReq = 0; break; // no ICU constant, canonical LTR level
-          case kBidi_RTL: bidiReq = 1; break; // no ICU constant, canonical RTL level
-          case kBidi_Default_LTR: bidiReq = UBIDI_DEFAULT_LTR; break;
-          case kBidi_Default_RTL: bidiReq = UBIDI_DEFAULT_RTL; break;
-          case kBidi_Force_LTR: memcpy(buffer, text, len * sizeof(jchar)); return len;
-          case kBidi_Force_RTL: return shapeRtlText(text, 0, len, len, buffer, status);
-        }
-
-        int32_t result = -1;
-
-        UBiDi* bidi = ubidi_open();
-        if (bidi) {
-            ubidi_setPara(bidi, text, len, bidiReq, NULL, &status);
-            if (U_SUCCESS(status)) {
-                dir = ubidi_getParaLevel(bidi) & 0x1; // 0 if ltr, 1 if rtl
-
-                int rc = ubidi_countRuns(bidi, &status);
-                if (U_SUCCESS(status)) {
-                    // LOG(LOG_INFO, "LAYOUT", "para bidiReq=%d dir=%d rc=%d\n", bidiReq, dir, rc);
-
-                    int32_t slen = 0;
-                    for (int i = 0; i < rc; ++i) {
-                        int32_t start;
-                        int32_t length;
-                        UBiDiDirection runDir = ubidi_getVisualRun(bidi, i, &start, &length);
-                        // LOG(LOG_INFO, "LAYOUT", "  [%2d] runDir=%d start=%3d len=%3d\n", i, runDir, start, length);
-                        if (runDir == UBIDI_RTL) {
-                            slen += shapeRtlText(text + start, 0, length, length, buffer + slen, status);
-                        } else {
-                            memcpy(buffer + slen, text + start, length * sizeof(jchar));
-                            slen += length;
-                        }
-                    }
-                    if (U_SUCCESS(status)) {
-                        result = slen;
-                    }
-                }
-            }
-            ubidi_close(bidi);
-        }
-
-        return result;
-    }
-
-    // Returns true if we might need layout.  If bidiFlags force LTR, assume no layout, if
-    // bidiFlags indicate there probably is RTL, assume we do, otherwise scan the text
-    // looking for a character >= the first RTL character in unicode and assume we do if
-    // we find one.
-    static bool needsLayout(const jchar* text, jint len, jint bidiFlags) {
-        if (bidiFlags == kBidi_Force_LTR) {
-            return false;
-        }
-        if ((bidiFlags == kBidi_RTL) || (bidiFlags == kBidi_Default_RTL) ||
-                bidiFlags == kBidi_Force_RTL) {
-            return true;
-        }
-        for (int i = 0; i < len; ++i) {
-            if (text[i] >= 0x0590) {
-                return true;
-            }
-        }
-        return false;
-    }
-
-    // Draws a paragraph of text on a single line, running bidi and shaping
-    static void drawText(JNIEnv* env, SkCanvas* canvas, const jchar* text, jsize len,
-                           jfloat x, jfloat y, int bidiFlags, SkPaint* paint) {
-
-        SkScalar x_ = SkFloatToScalar(x);
-        SkScalar y_ = SkFloatToScalar(y);
-
-        SkPaint::Align horiz = paint->getTextAlign();
-
-        const jchar *workText = text;
-        jchar *buffer = NULL;
-        int dir = kDirection_LTR;
-        if (needsLayout(text, len, bidiFlags)) {
-            buffer =(jchar *) malloc(len * sizeof(jchar));
-            if (!buffer) {
-                return;
-            }
-            UErrorCode status = U_ZERO_ERROR;
-            len = layoutLine(text, len, bidiFlags, dir, buffer, status); // might change len, dir
-            if (!U_SUCCESS(status)) {
-                LOG(LOG_WARN, "LAYOUT", "drawText error %d\n", status);
-                free(buffer);
-                return; // can't render
-            }
-
-            workText = buffer; // use the shaped text
-        }
-
-        bool trimLeft = false;
-        bool trimRight = false;
-
-        switch (horiz) {
-        case SkPaint::kLeft_Align: trimLeft = dir & kDirection_Mask; break;
-        case SkPaint::kCenter_Align: trimLeft = trimRight = true; break;
-        case SkPaint::kRight_Align: trimRight = !(dir & kDirection_Mask);
-        default: break;
-        }
-        const jchar* workLimit = workText + len;
-
-        if (trimLeft) {
-            while (workText < workLimit && *workText == ' ') {
-                ++workText;
-            }
-        }
-        if (trimRight) {
-            while (workLimit > workText && *(workLimit - 1) == ' ') {
-                --workLimit;
-            }
-        }
-        int32_t workBytes = (workLimit - workText) << 1;
-
-        canvas->drawText(workText, workBytes, x_, y_, *paint);
-
-        free(buffer);
-    }
 
     static void drawText___CIIFFIPaint(JNIEnv* env, jobject, SkCanvas* canvas,
                                       jcharArray text, int index, int count,
                                       jfloat x, jfloat y, int flags, SkPaint* paint) {
         jchar* textArray = env->GetCharArrayElements(text, NULL);
-        drawText(env, canvas, textArray + index, count, x, y, flags, paint);
+        TextLayout::drawText(paint, textArray + index, count, flags, x, y, canvas);
         env->ReleaseCharArrayElements(text, textArray, JNI_ABORT);
     }
 
@@ -961,41 +765,18 @@
                                           int start, int end,
                                           jfloat x, jfloat y, int flags, SkPaint* paint) {
         const jchar* textArray = env->GetStringChars(text, NULL);
-        drawText(env, canvas, textArray + start, end - start, x, y, flags, paint);
+        TextLayout::drawText(paint, textArray + start, end - start, flags, x, y, canvas);
         env->ReleaseStringChars(text, textArray);
     }
 
-    // Draws a unidirectional run of text.
-    static void drawTextRun(JNIEnv* env, SkCanvas* canvas, const jchar* chars,
-                              jint start, jint count, jint contextCount,
-                              jfloat x, jfloat y, int dirFlags, SkPaint* paint) {
-
-        SkScalar x_ = SkFloatToScalar(x);
-        SkScalar y_ = SkFloatToScalar(y);
-
-        uint8_t rtl = dirFlags & 0x1;
-        if (rtl) {
-            SkAutoSTMalloc<80, jchar> buffer(contextCount);
-            UErrorCode status = U_ZERO_ERROR;
-            count = shapeRtlText(chars, start, count, contextCount, buffer.get(), status);
-            if (U_SUCCESS(status)) {
-                canvas->drawText(buffer.get(), count << 1, x_, y_, *paint);
-            } else {
-                LOG(LOG_WARN, "LAYOUT", "drawTextRun error %d\n", status);
-            }
-        } else {
-            canvas->drawText(chars + start, count << 1, x_, y_, *paint);
-        }
-    }
-
     static void drawTextRun___CIIIIFFIPaint(
         JNIEnv* env, jobject, SkCanvas* canvas, jcharArray text, int index,
         int count, int contextIndex, int contextCount,
         jfloat x, jfloat y, int dirFlags, SkPaint* paint) {
 
         jchar* chars = env->GetCharArrayElements(text, NULL);
-        drawTextRun(env, canvas, chars + contextIndex, index - contextIndex,
-                      count, contextCount, x, y, dirFlags, paint);
+        TextLayout::drawTextRun(paint, chars + contextIndex, index - contextIndex,
+                                count, contextCount, dirFlags, x, y, canvas);
         env->ReleaseCharArrayElements(text, chars, JNI_ABORT);
     }
 
@@ -1007,8 +788,8 @@
         jint count = end - start;
         jint contextCount = contextEnd - contextStart;
         const jchar* chars = env->GetStringChars(text, NULL);
-        drawTextRun(env, canvas, chars + contextStart, start - contextStart,
-                      count, contextCount, x, y, dirFlags, paint);
+        TextLayout::drawTextRun(paint, chars + contextStart, start - contextStart,
+                                count, contextCount, dirFlags, x, y, canvas);
         env->ReleaseStringChars(text, chars);
     }
 
@@ -1059,31 +840,13 @@
         delete[] posPtr;
     }
 
-    static void drawTextOnPath(JNIEnv *env, SkCanvas* canvas, const jchar* text, int count,
-            int bidiFlags, SkPath* path, jfloat hOffset, jfloat vOffset, SkPaint* paint) {
-
-        if (!needsLayout(text, count, bidiFlags)) {
-            canvas->drawTextOnPathHV(text, count << 1, *path,
-                SkFloatToScalar(hOffset), SkFloatToScalar(vOffset), *paint);
-            return;
-        }
-
-        SkAutoSTMalloc<80, jchar> buffer(count);
-        int dir = kDirection_LTR;
-        UErrorCode status = U_ZERO_ERROR;
-        count = layoutLine(text, count, bidiFlags, dir, buffer.get(), status);
-        if (U_SUCCESS(status)) {
-            canvas->drawTextOnPathHV(buffer.get(), count << 1, *path,
-                SkFloatToScalar(hOffset), SkFloatToScalar(vOffset), *paint);
-        }
-    }
-
     static void drawTextOnPath___CIIPathFFPaint(JNIEnv* env, jobject,
             SkCanvas* canvas, jcharArray text, int index, int count,
             SkPath* path, jfloat hOffset, jfloat vOffset, jint bidiFlags, SkPaint* paint) {
 
         jchar* textArray = env->GetCharArrayElements(text, NULL);
-        drawTextOnPath(env, canvas, textArray, count, bidiFlags, path, hOffset, vOffset, paint);
+        TextLayout::drawTextOnPath(paint, textArray, count, bidiFlags, hOffset, vOffset,
+                                   path, canvas);
         env->ReleaseCharArrayElements(text, textArray, 0);
     }
 
@@ -1092,7 +855,8 @@
             jfloat hOffset, jfloat vOffset, jint bidiFlags, SkPaint* paint) {
         const jchar* text_ = env->GetStringChars(text, NULL);
         int count = env->GetStringLength(text);
-        drawTextOnPath(env, canvas, text_, count, bidiFlags, path, hOffset, vOffset, paint);
+        TextLayout::drawTextOnPath(paint, text_, count, bidiFlags, hOffset, vOffset,
+                                   path, canvas);
         env->ReleaseStringChars(text, text_);
     }
 
diff --git a/core/jni/android/graphics/Paint.cpp b/core/jni/android/graphics/Paint.cpp
index ca9c9de..e4d4850 100644
--- a/core/jni/android/graphics/Paint.cpp
+++ b/core/jni/android/graphics/Paint.cpp
@@ -32,6 +32,7 @@
 #include "SkTypeface.h"
 #include "SkXfermode.h"
 #include "unicode/ushape.h"
+#include "TextLayout.h"
 
 // temporary for debugging
 #include <utils/Log.h>
@@ -403,56 +404,14 @@
         return count;
     }
 
-    static jfloat doTextRunAdvances(JNIEnv *env, SkPaint *paint, const jchar *text, jint start, jint count, jint contextCount, jint flags,
+    static jfloat doTextRunAdvances(JNIEnv *env, SkPaint *paint, const jchar *text,
+                                    jint start, jint count, jint contextCount, jint flags,
                                     jfloatArray advances, jint advancesIndex) {
         jfloat advancesArray[count];
-        jchar buffer[contextCount];
+        jfloat totalAdvance;
 
-        SkScalar* scalarArray = (SkScalar *)advancesArray;
-        jfloat totalAdvance = 0;
-
-        // this is where we'd call harfbuzz
-        // for now we just use ushape.c
-
-        int widths;
-        if (flags & 0x1) { // rtl, call arabic shaping in case
-            UErrorCode status = U_ZERO_ERROR;
-            // Use fixed length since we need to keep start and count valid
-            u_shapeArabic(text, contextCount, buffer, contextCount,
-                          U_SHAPE_LENGTH_FIXED_SPACES_NEAR |
-                          U_SHAPE_TEXT_DIRECTION_LOGICAL | U_SHAPE_LETTERS_SHAPE |
-                          U_SHAPE_X_LAMALEF_SUB_ALTERNATE, &status);
-            // we shouldn't fail unless there's an out of memory condition,
-            // in which case we're hosed anyway
-            for (int i = start, e = i + count; i < e; ++i) {
-              if (buffer[i] == 0xffff) {
-                buffer[i] = 0x200b; // zero-width-space for skia
-              }
-            }
-            widths = paint->getTextWidths(buffer + start, count << 1, scalarArray);
-        } else {
-            widths = paint->getTextWidths(text + start, count << 1, scalarArray);
-        }
-
-        if (widths < count) {
-            // Skia operates on code points, not code units, so surrogate pairs return only
-            // one value. Expand the result so we have one value per UTF-16 code unit.
-
-            // Note, skia's getTextWidth gets confused if it encounters a surrogate pair,
-            // leaving the remaining widths zero.  Not nice.
-            const jchar *chars = text + start;
-            for (int i = 0, p = 0; i < widths; ++i) {
-                totalAdvance += advancesArray[p++] = SkScalarToFloat(scalarArray[i]);
-                if (p < count && chars[p] >= 0xdc00 && chars[p] < 0xe000 &&
-                        chars[p-1] >= 0xd800 && chars[p-1] < 0xdc00) {
-                    advancesArray[p++] = 0;
-                }
-            }
-        } else {
-            for (int i = 0; i < count; i++) {
-                totalAdvance += advancesArray[i] = SkScalarToFloat(scalarArray[i]);
-            }
-        }
+        TextLayout::getTextRunAdvances(paint, text, start, count, contextCount, flags,
+                                       advancesArray, totalAdvance);
 
         if (advances != NULL) {
             env->SetFloatArrayRegion(advances, advancesIndex, count, advancesArray);
@@ -580,19 +539,25 @@
         return result;
     }
 
-    static void getTextPath___CIIFFPath(JNIEnv* env, jobject clazz, SkPaint* paint, jcharArray text, int index, int count, jfloat x, jfloat y, SkPath* path) {
-        const jchar* textArray = env->GetCharArrayElements(text, NULL);
-        paint->getTextPath(textArray + index, count << 1, SkFloatToScalar(x), SkFloatToScalar(y), path);
-        env->ReleaseCharArrayElements(text, const_cast<jchar*>(textArray),
-                                      JNI_ABORT);
+    static void getTextPath(JNIEnv* env, SkPaint* paint, const jchar* text, jint count,
+                            jint bidiFlags, jfloat x, jfloat y, SkPath *path) {
+        TextLayout::getTextPath(paint, text, count, bidiFlags, x, y, path);
     }
- 
-    static void getTextPath__StringIIFFPath(JNIEnv* env, jobject clazz, SkPaint* paint, jstring text, int start, int end, jfloat x, jfloat y, SkPath* path) {
+
+    static void getTextPath___C(JNIEnv* env, jobject clazz, SkPaint* paint, jint bidiFlags,
+            jcharArray text, int index, int count, jfloat x, jfloat y, SkPath* path) {
+        const jchar* textArray = env->GetCharArrayElements(text, NULL);
+        getTextPath(env, paint, textArray + index, count, bidiFlags, x, y, path);
+        env->ReleaseCharArrayElements(text, const_cast<jchar*>(textArray), JNI_ABORT);
+    }
+
+    static void getTextPath__String(JNIEnv* env, jobject clazz, SkPaint* paint, jint bidiFlags,
+            jstring text, int start, int end, jfloat x, jfloat y, SkPath* path) {
         const jchar* textArray = env->GetStringChars(text, NULL);
-        paint->getTextPath(textArray + start, (end - start) << 1, SkFloatToScalar(x), SkFloatToScalar(y), path);
+        getTextPath(env, paint, textArray + start, end - start, bidiFlags, x, y, path);
         env->ReleaseStringChars(text, textArray);
     }
- 
+
     static void setShadowLayer(JNIEnv* env, jobject jpaint, jfloat radius,
                                jfloat dx, jfloat dy, int color) {
         NPE_CHECK_RETURN_VOID(env, jpaint);
@@ -767,8 +732,8 @@
     {"native_getTextRunCursor", "(I[CIIIII)I", (void*) SkPaintGlue::getTextRunCursor___C},
     {"native_getTextRunCursor", "(ILjava/lang/String;IIIII)I",
         (void*) SkPaintGlue::getTextRunCursor__String},
-    {"native_getTextPath","(I[CIIFFI)V", (void*) SkPaintGlue::getTextPath___CIIFFPath},
-    {"native_getTextPath","(ILjava/lang/String;IIFFI)V", (void*) SkPaintGlue::getTextPath__StringIIFFPath},
+    {"native_getTextPath","(II[CIIFFI)V", (void*) SkPaintGlue::getTextPath___C},
+    {"native_getTextPath","(IILjava/lang/String;IIFFI)V", (void*) SkPaintGlue::getTextPath__String},
     {"nativeGetStringBounds", "(ILjava/lang/String;IILandroid/graphics/Rect;)V",
                                         (void*) SkPaintGlue::getStringBounds },
     {"nativeGetCharArrayBounds", "(I[CIILandroid/graphics/Rect;)V",
diff --git a/core/jni/android/graphics/TextLayout.cpp b/core/jni/android/graphics/TextLayout.cpp
new file mode 100644
index 0000000..e2536ee
--- /dev/null
+++ b/core/jni/android/graphics/TextLayout.cpp
@@ -0,0 +1,324 @@
+/*
+ * 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.
+ */
+
+#include "TextLayout.h"
+
+#include <android_runtime/AndroidRuntime.h>
+
+#include "SkTemplates.h"
+#include "unicode/ubidi.h"
+#include "unicode/ushape.h"
+#include <utils/Log.h>
+
+
+namespace android {
+// Returns true if we might need layout.  If bidiFlags force LTR, assume no layout, if
+// bidiFlags indicate there probably is RTL, assume we do, otherwise scan the text
+// looking for a character >= the first RTL character in unicode and assume we do if
+// we find one.
+bool TextLayout::needsLayout(const jchar* text, jint len, jint bidiFlags) {
+    if (bidiFlags == kBidi_Force_LTR) {
+        return false;
+    }
+    if ((bidiFlags == kBidi_RTL) || (bidiFlags == kBidi_Default_RTL) ||
+            bidiFlags == kBidi_Force_RTL) {
+        return true;
+    }
+    for (int i = 0; i < len; ++i) {
+        if (text[i] >= 0x0590) {
+            return true;
+        }
+    }
+    return false;
+}
+
+/**
+ * Character-based Arabic shaping.
+ *
+ * We'll use harfbuzz and glyph-based shaping instead once we're set up for it.
+ *
+ * @context the text context
+ * @start the start of the text to render
+ * @count the length of the text to render, start + count  must be <= contextCount
+ * @contextCount the length of the context
+ * @shaped where to put the shaped text, must have capacity for count uchars
+ * @return the length of the shaped text, or -1 if error
+ */
+int TextLayout::shapeRtlText(const jchar* context, jsize start, jsize count, jsize contextCount,
+                        jchar* shaped, UErrorCode &status) {
+    jchar buffer[contextCount];
+
+    // Use fixed length since we need to keep start and count valid
+    u_shapeArabic(context, contextCount, buffer, contextCount,
+                   U_SHAPE_LENGTH_FIXED_SPACES_NEAR |
+                   U_SHAPE_TEXT_DIRECTION_LOGICAL | U_SHAPE_LETTERS_SHAPE |
+                   U_SHAPE_X_LAMALEF_SUB_ALTERNATE, &status);
+
+    if (U_SUCCESS(status)) {
+        // trim out 0xffff following ligatures, if any
+        int end = 0;
+        for (int i = start, e = start + count; i < e; ++i) {
+            if (buffer[i] != 0xffff) {
+                buffer[end++] = buffer[i];
+            }
+        }
+        count = end;
+        // LOG(LOG_INFO, "CSRTL", "start %d count %d ccount %d\n", start, count, contextCount);
+        ubidi_writeReverse(buffer, count, shaped, count, UBIDI_DO_MIRRORING | UBIDI_OUTPUT_REVERSE
+                           | UBIDI_KEEP_BASE_COMBINING, &status);
+        if (U_SUCCESS(status)) {
+            return count;
+        }
+    }
+
+    return -1;
+}
+
+/**
+ * Basic character-based layout supporting rtl and arabic shaping.
+ * Runs bidi on the text and generates a reordered, shaped line in buffer, returning
+ * the length.
+ * @text the text
+ * @len the length of the text in uchars
+ * @dir receives the resolved paragraph direction
+ * @buffer the buffer to receive the reordered, shaped line.  Must have capacity of
+ * at least len jchars.
+ * @flags line bidi flags
+ * @return the length of the reordered, shaped line, or -1 if error
+ */
+jint TextLayout::layoutLine(const jchar* text, jint len, jint flags, int &dir, jchar* buffer,
+        UErrorCode &status) {
+    static const int RTL_OPTS = UBIDI_DO_MIRRORING | UBIDI_KEEP_BASE_COMBINING |
+            UBIDI_REMOVE_BIDI_CONTROLS | UBIDI_OUTPUT_REVERSE;
+
+    UBiDiLevel bidiReq = 0;
+    switch (flags) {
+    case kBidi_LTR: bidiReq = 0; break; // no ICU constant, canonical LTR level
+    case kBidi_RTL: bidiReq = 1; break; // no ICU constant, canonical RTL level
+    case kBidi_Default_LTR: bidiReq = UBIDI_DEFAULT_LTR; break;
+    case kBidi_Default_RTL: bidiReq = UBIDI_DEFAULT_RTL; break;
+    case kBidi_Force_LTR: memcpy(buffer, text, len * sizeof(jchar)); return len;
+    case kBidi_Force_RTL: return shapeRtlText(text, 0, len, len, buffer, status);
+    }
+
+    int32_t result = -1;
+
+    UBiDi* bidi = ubidi_open();
+    if (bidi) {
+        ubidi_setPara(bidi, text, len, bidiReq, NULL, &status);
+        if (U_SUCCESS(status)) {
+            dir = ubidi_getParaLevel(bidi) & 0x1; // 0 if ltr, 1 if rtl
+
+            int rc = ubidi_countRuns(bidi, &status);
+            if (U_SUCCESS(status)) {
+                // LOG(LOG_INFO, "LAYOUT", "para bidiReq=%d dir=%d rc=%d\n", bidiReq, dir, rc);
+
+                int32_t slen = 0;
+                for (int i = 0; i < rc; ++i) {
+                    int32_t start;
+                    int32_t length;
+                    UBiDiDirection runDir = ubidi_getVisualRun(bidi, i, &start, &length);
+
+                    if (runDir == UBIDI_RTL) {
+                        slen += shapeRtlText(text + start, 0, length, length, buffer + slen, status);
+                    } else {
+                        memcpy(buffer + slen, text + start, length * sizeof(jchar));
+                        slen += length;
+                    }
+                }
+                if (U_SUCCESS(status)) {
+                    result = slen;
+                }
+            }
+        }
+        ubidi_close(bidi);
+    }
+
+    return result;
+}
+
+// Draws or gets the path of a paragraph of text on a single line, running bidi and shaping.
+// This will draw if canvas is not null, otherwise path must be non-null and it will create
+// a path representing the text that would have been drawn.
+void TextLayout::handleText(SkPaint *paint, const jchar* text, jsize len,
+                            jint bidiFlags, jfloat x, jfloat y,SkCanvas *canvas, SkPath *path) {
+
+    const jchar *workText = text;
+    jchar *buffer = NULL;
+    int dir = kDirection_LTR;
+    if (needsLayout(text, len, bidiFlags)) {
+        buffer =(jchar *) malloc(len * sizeof(jchar));
+        if (!buffer) {
+            return;
+        }
+        UErrorCode status = U_ZERO_ERROR;
+        len = layoutLine(text, len, bidiFlags, dir, buffer, status); // might change len, dir
+        if (!U_SUCCESS(status)) {
+            LOG(LOG_WARN, "LAYOUT", "drawText error %d\n", status);
+            free(buffer);
+            return; // can't render
+        }
+
+        workText = buffer; // use the shaped text
+    }
+
+    bool trimLeft = false;
+    bool trimRight = false;
+
+    SkPaint::Align horiz = paint->getTextAlign();
+    switch (horiz) {
+    case SkPaint::kLeft_Align: trimLeft = dir & kDirection_Mask; break;
+    case SkPaint::kCenter_Align: trimLeft = trimRight = true; break;
+    case SkPaint::kRight_Align: trimRight = !(dir & kDirection_Mask);
+    default: break;
+    }
+    const jchar* workLimit = workText + len;
+
+    if (trimLeft) {
+        while (workText < workLimit && *workText == ' ') {
+            ++workText;
+        }
+    }
+    if (trimRight) {
+        while (workLimit > workText && *(workLimit - 1) == ' ') {
+            --workLimit;
+        }
+    }
+
+    int32_t workBytes = (workLimit - workText) << 1;
+    SkScalar x_ = SkFloatToScalar(x);
+    SkScalar y_ = SkFloatToScalar(y);
+    if (canvas) {
+        canvas->drawText(workText, workBytes, x_, y_, *paint);
+    } else {
+        paint->getTextPath(workText, workBytes, x_, y_, path);
+    }
+
+    free(buffer);
+}
+
+void TextLayout::drawTextRun(SkPaint* paint, const jchar* chars,
+                             jint start, jint count, jint contextCount,
+                             int dirFlags, jfloat x, jfloat y, SkCanvas* canvas) {
+
+     SkScalar x_ = SkFloatToScalar(x);
+     SkScalar y_ = SkFloatToScalar(y);
+
+     uint8_t rtl = dirFlags & 0x1;
+     if (rtl) {
+         SkAutoSTMalloc<80, jchar> buffer(contextCount);
+         UErrorCode status = U_ZERO_ERROR;
+         count = shapeRtlText(chars, start, count, contextCount, buffer.get(), status);
+         if (U_SUCCESS(status)) {
+             canvas->drawText(buffer.get(), count << 1, x_, y_, *paint);
+         } else {
+             LOG(LOG_WARN, "LAYOUT", "drawTextRun error %d\n", status);
+         }
+     } else {
+         canvas->drawText(chars + start, count << 1, x_, y_, *paint);
+     }
+ }
+
+void TextLayout::getTextRunAdvances(SkPaint *paint, const jchar *chars, jint start,
+                                    jint count, jint contextCount, jint dirFlags,
+                                    jfloat *resultAdvances, jfloat &resultTotalAdvance) {
+    jchar buffer[contextCount];
+
+    SkScalar* scalarArray = (SkScalar *)resultAdvances;
+    resultTotalAdvance = 0;
+
+    // this is where we'd call harfbuzz
+    // for now we just use ushape.c
+
+    int widths;
+    const jchar* text;
+    if (dirFlags & 0x1) { // rtl, call arabic shaping in case
+        UErrorCode status = U_ZERO_ERROR;
+        // Use fixed length since we need to keep start and count valid
+        u_shapeArabic(chars, contextCount, buffer, contextCount,
+                      U_SHAPE_LENGTH_FIXED_SPACES_NEAR |
+                      U_SHAPE_TEXT_DIRECTION_LOGICAL | U_SHAPE_LETTERS_SHAPE |
+                      U_SHAPE_X_LAMALEF_SUB_ALTERNATE, &status);
+        // we shouldn't fail unless there's an out of memory condition,
+        // in which case we're hosed anyway
+        for (int i = start, e = i + count; i < e; ++i) {
+          if (buffer[i] == 0xffff) {
+            buffer[i] = 0x200b; // zero-width-space for skia
+          }
+        }
+        text = buffer + start;
+        widths = paint->getTextWidths(text, count << 1, scalarArray);
+    } else {
+        text = chars + start;
+        widths = paint->getTextWidths(text, count << 1, scalarArray);
+    }
+
+    if (widths < count) {
+        // Skia operates on code points, not code units, so surrogate pairs return only
+        // one value. Expand the result so we have one value per UTF-16 code unit.
+
+        // Note, skia's getTextWidth gets confused if it encounters a surrogate pair,
+        // leaving the remaining widths zero.  Not nice.
+        for (int i = 0, p = 0; i < widths; ++i) {
+            resultTotalAdvance += resultAdvances[p++] = SkScalarToFloat(scalarArray[i]);
+            if (p < count && text[p] >= 0xdc00 && text[p] < 0xe000 &&
+                    text[p-1] >= 0xd800 && text[p-1] < 0xdc00) {
+                resultAdvances[p++] = 0;
+            }
+        }
+    } else {
+        for (int i = 0; i < count; i++) {
+            resultTotalAdvance += resultAdvances[i] = SkScalarToFloat(scalarArray[i]);
+        }
+    }
+}
+
+
+// Draws a paragraph of text on a single line, running bidi and shaping
+void TextLayout::drawText(SkPaint* paint, const jchar* text, jsize len,
+                          int bidiFlags, jfloat x, jfloat y, SkCanvas* canvas) {
+
+    handleText(paint, text, len, bidiFlags, x, y, canvas, NULL);
+}
+
+void TextLayout::getTextPath(SkPaint *paint, const jchar *text, jsize len,
+                             jint bidiFlags, jfloat x, jfloat y, SkPath *path) {
+    handleText(paint, text, len, bidiFlags, x, y, NULL, path);
+}
+
+
+void TextLayout::drawTextOnPath(SkPaint* paint, const jchar* text, int count,
+                                int bidiFlags, jfloat hOffset, jfloat vOffset,
+                                SkPath* path, SkCanvas* canvas) {
+
+    SkScalar h_ = SkFloatToScalar(hOffset);
+    SkScalar v_ = SkFloatToScalar(vOffset);
+
+    if (!needsLayout(text, count, bidiFlags)) {
+        canvas->drawTextOnPathHV(text, count << 1, *path, h_, v_, *paint);
+        return;
+    }
+
+    SkAutoSTMalloc<80, jchar> buffer(count);
+    int dir = kDirection_LTR;
+    UErrorCode status = U_ZERO_ERROR;
+    count = layoutLine(text, count, bidiFlags, dir, buffer.get(), status);
+    if (U_SUCCESS(status)) {
+        canvas->drawTextOnPathHV(buffer.get(), count << 1, *path, h_, v_, *paint);
+    }
+}
+
+}
diff --git a/core/jni/android/graphics/TextLayout.h b/core/jni/android/graphics/TextLayout.h
new file mode 100644
index 0000000..c0d9f75
--- /dev/null
+++ b/core/jni/android/graphics/TextLayout.h
@@ -0,0 +1,77 @@
+/*
+ * 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.
+ */
+
+#include "jni.h"
+
+#include "SkCanvas.h"
+#include "SkPaint.h"
+#include "unicode/utypes.h"
+
+namespace android {
+
+class TextLayout {
+public:
+
+    enum {
+        kDirection_LTR = 0,
+        kDirection_RTL = 1,
+
+        kDirection_Mask = 0x1
+    };
+
+    enum {
+        kBidi_LTR = 0,
+        kBidi_RTL = 1,
+        kBidi_Default_LTR = 2,
+        kBidi_Default_RTL = 3,
+        kBidi_Force_LTR = 4,
+        kBidi_Force_RTL = 5,
+
+        kBidi_Mask = 0x7
+    };
+
+    /*
+     * Draws a unidirectional run of text.
+     */
+    static void drawTextRun(SkPaint* paint, const jchar* chars,
+                            jint start, jint count, jint contextCount,
+                            int dirFlags, jfloat x, jfloat y, SkCanvas* canvas);
+
+    static void getTextRunAdvances(SkPaint *paint, const jchar *chars, jint start,
+                                   jint count, jint contextCount, jint dirFlags,
+                                   jfloat *resultAdvances, jfloat &resultTotalAdvance);
+
+    static void drawText(SkPaint* paint, const jchar* text, jsize len,
+                         jint bidiFlags, jfloat x, jfloat y, SkCanvas* canvas);
+
+    static void getTextPath(SkPaint *paint, const jchar *text, jsize len,
+                            jint bidiFlags, jfloat x, jfloat y, SkPath *path);
+
+    static void drawTextOnPath(SkPaint* paint, const jchar* text, jsize len,
+                               int bidiFlags, jfloat hOffset, jfloat vOffset,
+                               SkPath* path, SkCanvas* canvas);
+
+private:
+    static bool needsLayout(const jchar* text, jint len, jint bidiFlags);
+    static int shapeRtlText(const jchar* context, jsize start, jsize count, jsize contextCount,
+                            jchar* shaped, UErrorCode &status);
+    static jint layoutLine(const jchar* text, jint len, jint flags, int &dir, jchar* buffer,
+                           UErrorCode &status);
+    static void handleText(SkPaint *paint, const jchar* text, jsize len,
+                           int bidiFlags, jfloat x, jfloat y,SkCanvas *canvas, SkPath *path);
+};
+
+}
diff --git a/core/jni/android_app_NativeActivity.cpp b/core/jni/android_app_NativeActivity.cpp
index af61b80..acbf854 100644
--- a/core/jni/android_app_NativeActivity.cpp
+++ b/core/jni/android_app_NativeActivity.cpp
@@ -19,9 +19,11 @@
 
 #include <poll.h>
 #include <dlfcn.h>
+#include <fcntl.h>
 
 #include <android_runtime/AndroidRuntime.h>
-#include <android/native_activity.h>
+#include <android_runtime/android_view_Surface.h>
+#include <android_runtime/android_app_NativeActivity.h>
 #include <surfaceflinger/Surface.h>
 #include <ui/egl/android_natives.h>
 #include <ui/InputTransport.h>
@@ -31,7 +33,9 @@
 #include "android_os_MessageQueue.h"
 #include "android_view_InputChannel.h"
 #include "android_view_KeyEvent.h"
-#include "android_view_Surface.h"
+
+//#define LOG_TRACE(...)
+#define LOG_TRACE(...) LOG(LOG_DEBUG, LOG_TAG, __VA_ARGS__)
 
 namespace android
 {
@@ -42,58 +46,239 @@
     jmethodID dispatchUnhandledKeyEvent;
     jmethodID setWindowFlags;
     jmethodID setWindowFormat;
+    jmethodID showIme;
+    jmethodID hideIme;
 } gNativeActivityClassInfo;
 
 // ------------------------------------------------------------------------
 
-/*
- * Specialized input queue that allows unhandled key events to be dispatched
- * back to the native activity's Java framework code.
- */
-struct MyInputQueue : AInputQueue {
-    explicit MyInputQueue(const android::sp<android::InputChannel>& channel, int workWrite)
-        : AInputQueue(channel), mWorkWrite(workWrite) {
-    }
-    
-    virtual void doDefaultKey(android::KeyEvent* keyEvent) {
-        mLock.lock();
-        LOGI("Default key: pending=%d write=%d\n", mPendingKeys.size(), mWorkWrite);
-        if (mPendingKeys.size() <= 0 && mWorkWrite >= 0) {
-            int8_t cmd = 1;
-            write(mWorkWrite, &cmd, sizeof(cmd));
-        }
-        mPendingKeys.add(keyEvent);
-        mLock.unlock();
-    }
-    
-    KeyEvent* getNextEvent() {
-        KeyEvent* event = NULL;
-        
-        mLock.lock();
-        if (mPendingKeys.size() > 0) {
-            event = mPendingKeys[0];
-            mPendingKeys.removeAt(0);
-        }
-        mLock.unlock();
-        
-        return event;
-    }
-    
-    int mWorkWrite;
-    
-    Mutex mLock;
-    Vector<KeyEvent*> mPendingKeys;
+struct ActivityWork {
+    int32_t cmd;
+    int32_t arg1;
+    int32_t arg2;
 };
 
+enum {
+    CMD_DEF_KEY = 1,
+    CMD_SET_WINDOW_FORMAT,
+    CMD_SET_WINDOW_FLAGS,
+    CMD_SHOW_SOFT_INPUT,
+    CMD_HIDE_SOFT_INPUT,
+};
+
+static void write_work(int fd, int32_t cmd, int32_t arg1=0, int32_t arg2=0) {
+    ActivityWork work;
+    work.cmd = cmd;
+    work.arg1 = arg1;
+    work.arg2 = arg2;
+    
+    LOG_TRACE("write_work: cmd=%d", cmd);
+
+restart:
+    int res = write(fd, &work, sizeof(work));
+    if (res < 0 && errno == EINTR) {
+        goto restart;
+    }
+    
+    if (res == sizeof(work)) return;
+    
+    if (res < 0) LOGW("Failed writing to work fd: %s", strerror(errno));
+    else LOGW("Truncated writing to work fd: %d", res);
+}
+
+static bool read_work(int fd, ActivityWork* outWork) {
+    int res = read(fd, outWork, sizeof(ActivityWork));
+    // no need to worry about EINTR, poll loop will just come back again.
+    if (res == sizeof(ActivityWork)) return true;
+    
+    if (res < 0) LOGW("Failed reading work fd: %s", strerror(errno));
+    else LOGW("Truncated reading work fd: %d", res);
+    return false;
+}
+
+// ------------------------------------------------------------------------
+
+} // namespace android
+
+using namespace android;
+
+AInputQueue::AInputQueue(const sp<InputChannel>& channel, int workWrite) :
+        mWorkWrite(workWrite), mConsumer(channel) {
+    int msgpipe[2];
+    if (pipe(msgpipe)) {
+        LOGW("could not create pipe: %s", strerror(errno));
+        mDispatchKeyRead = mDispatchKeyWrite = -1;
+    } else {
+        mDispatchKeyRead = msgpipe[0];
+        mDispatchKeyWrite = msgpipe[1];
+        int result = fcntl(mDispatchKeyRead, F_SETFL, O_NONBLOCK);
+        SLOGW_IF(result != 0, "Could not make AInputQueue read pipe "
+                "non-blocking: %s", strerror(errno));
+        result = fcntl(mDispatchKeyWrite, F_SETFL, O_NONBLOCK);
+        SLOGW_IF(result != 0, "Could not make AInputQueue write pipe "
+                "non-blocking: %s", strerror(errno));
+    }
+}
+
+AInputQueue::~AInputQueue() {
+    close(mDispatchKeyRead);
+    close(mDispatchKeyWrite);
+}
+
+void AInputQueue::attachLooper(ALooper* looper, ALooper_callbackFunc* callback, void* data) {
+    mPollLoop = static_cast<android::PollLoop*>(looper);
+    mPollLoop->setLooperCallback(mConsumer.getChannel()->getReceivePipeFd(),
+            POLLIN, callback, data);
+    mPollLoop->setLooperCallback(mDispatchKeyRead,
+            POLLIN, callback, data);
+}
+
+void AInputQueue::detachLooper() {
+    mPollLoop->removeCallback(mConsumer.getChannel()->getReceivePipeFd());
+    mPollLoop->removeCallback(mDispatchKeyRead);
+}
+
+int32_t AInputQueue::hasEvents() {
+    struct pollfd pfd[2];
+
+    pfd[0].fd = mConsumer.getChannel()->getReceivePipeFd();
+    pfd[0].events = POLLIN;
+    pfd[0].revents = 0;
+    pfd[1].fd = mDispatchKeyRead;
+    pfd[0].events = POLLIN;
+    pfd[0].revents = 0;
+    
+    int nfd = poll(pfd, 2, 0);
+    if (nfd <= 0) return 0;
+    return (pfd[0].revents == POLLIN || pfd[1].revents == POLLIN) ? 1 : -1;
+}
+
+int32_t AInputQueue::getEvent(AInputEvent** outEvent) {
+    *outEvent = NULL;
+
+    char byteread;
+    ssize_t nRead = read(mDispatchKeyRead, &byteread, 1);
+    if (nRead == 1) {
+        mLock.lock();
+        if (mDispatchingKeys.size() > 0) {
+            KeyEvent* kevent = mDispatchingKeys[0];
+            *outEvent = kevent;
+            mDispatchingKeys.removeAt(0);
+            mDeliveringKeys.add(kevent);
+        }
+        mLock.unlock();
+        if (*outEvent != NULL) {
+            return 0;
+        }
+    }
+    
+    int32_t res = mConsumer.receiveDispatchSignal();
+    if (res != android::OK) {
+        LOGE("channel '%s' ~ Failed to receive dispatch signal.  status=%d",
+                mConsumer.getChannel()->getName().string(), res);
+        return -1;
+    }
+
+    InputEvent* myEvent = NULL;
+    res = mConsumer.consume(&mInputEventFactory, &myEvent);
+    if (res != android::OK) {
+        LOGW("channel '%s' ~ Failed to consume input event.  status=%d",
+                mConsumer.getChannel()->getName().string(), res);
+        mConsumer.sendFinishedSignal();
+        return -1;
+    }
+
+    *outEvent = myEvent;
+    return 0;
+}
+
+void AInputQueue::finishEvent(AInputEvent* event, bool handled) {
+    bool needFinished = true;
+
+    if (!handled && ((InputEvent*)event)->getType() == INPUT_EVENT_TYPE_KEY
+            && ((KeyEvent*)event)->hasDefaultAction()) {
+        // The app didn't handle this, but it may have a default action
+        // associated with it.  We need to hand this back to Java to be
+        // executed.
+        doDefaultKey((KeyEvent*)event);
+        needFinished = false;
+    }
+
+    const size_t N = mDeliveringKeys.size();
+    for (size_t i=0; i<N; i++) {
+        if (mDeliveringKeys[i] == event) {
+            delete event;
+            mDeliveringKeys.removeAt(i);
+            needFinished = false;
+            break;
+        }
+    }
+    
+    if (needFinished) {
+        int32_t res = mConsumer.sendFinishedSignal();
+        if (res != android::OK) {
+            LOGW("Failed to send finished signal on channel '%s'.  status=%d",
+                    mConsumer.getChannel()->getName().string(), res);
+        }
+    }
+}
+
+void AInputQueue::dispatchEvent(android::KeyEvent* event) {
+    mLock.lock();
+    LOG_TRACE("dispatchEvent: dispatching=%d write=%d\n", mDispatchingKeys.size(),
+            mDispatchKeyWrite);
+    mDispatchingKeys.add(event);
+    mLock.unlock();
+    
+restart:
+    char dummy = 0;
+    int res = write(mDispatchKeyWrite, &dummy, sizeof(dummy));
+    if (res < 0 && errno == EINTR) {
+        goto restart;
+    }
+
+    if (res == sizeof(dummy)) return;
+
+    if (res < 0) LOGW("Failed writing to dispatch fd: %s", strerror(errno));
+    else LOGW("Truncated writing to dispatch fd: %d", res);
+}
+
+KeyEvent* AInputQueue::consumeUnhandledEvent() {
+    KeyEvent* event = NULL;
+
+    mLock.lock();
+    if (mPendingKeys.size() > 0) {
+        event = mPendingKeys[0];
+        mPendingKeys.removeAt(0);
+    }
+    mLock.unlock();
+
+    LOG_TRACE("consumeUnhandledEvent: KeyEvent=%p", event);
+
+    return event;
+}
+
+void AInputQueue::doDefaultKey(KeyEvent* keyEvent) {
+    mLock.lock();
+    LOG_TRACE("Default key: pending=%d write=%d\n", mPendingKeys.size(), mWorkWrite);
+    if (mPendingKeys.size() <= 0 && mWorkWrite >= 0) {
+        write_work(mWorkWrite, CMD_DEF_KEY);
+    }
+    mPendingKeys.add(keyEvent);
+    mLock.unlock();
+}
+
+namespace android {
+
 // ------------------------------------------------------------------------
 
 /*
  * Native state for interacting with the NativeActivity class.
  */
-struct NativeCode {
+struct NativeCode : public ANativeActivity {
     NativeCode(void* _dlhandle, ANativeActivity_createFunc* _createFunc) {
-        memset(&activity, sizeof(activity), 0);
-        memset(&callbacks, sizeof(callbacks), 0);
+        memset((ANativeActivity*)this, 0, sizeof(ANativeActivity));
+        memset(&callbacks, 0, sizeof(callbacks));
         dlhandle = _dlhandle;
         createActivityFunc = _createFunc;
         nativeWindow = NULL;
@@ -103,8 +288,11 @@
     }
     
     ~NativeCode() {
-        if (activity.env != NULL && activity.clazz != NULL) {
-            activity.env->DeleteGlobalRef(activity.clazz);
+        if (callbacks.onDestroy != NULL) {
+            callbacks.onDestroy(this);
+        }
+        if (env != NULL && clazz != NULL) {
+            env->DeleteGlobalRef(clazz);
         }
         if (pollLoop != NULL && mainWorkRead >= 0) {
             pollLoop->removeCallback(mainWorkRead);
@@ -114,9 +302,6 @@
         }
         setSurface(NULL);
         setInputChannel(NULL);
-        if (callbacks.onDestroy != NULL) {
-            callbacks.onDestroy(&activity);
-        }
         if (mainWorkRead >= 0) close(mainWorkRead);
         if (mainWorkWrite >= 0) close(mainWorkWrite);
         if (dlhandle != NULL) {
@@ -129,7 +314,7 @@
     
     void setSurface(jobject _surface) {
         if (_surface != NULL) {
-            nativeWindow = android_Surface_getNativeWindow(activity.env, _surface);
+            nativeWindow = android_Surface_getNativeWindow(env, _surface);
         } else {
             nativeWindow = NULL;
         }
@@ -138,16 +323,16 @@
     status_t setInputChannel(jobject _channel) {
         if (inputChannel != NULL) {
             delete nativeInputQueue;
-            activity.env->DeleteGlobalRef(inputChannel);
+            env->DeleteGlobalRef(inputChannel);
         }
         inputChannel = NULL;
         nativeInputQueue = NULL;
         if (_channel != NULL) {
-            inputChannel = activity.env->NewGlobalRef(_channel);
+            inputChannel = env->NewGlobalRef(_channel);
             sp<InputChannel> ic =
-                    android_view_InputChannel_getInputChannel(activity.env, _channel);
+                    android_view_InputChannel_getInputChannel(env, _channel);
             if (ic != NULL) {
-                nativeInputQueue = new MyInputQueue(ic, mainWorkWrite);
+                nativeInputQueue = new AInputQueue(ic, mainWorkWrite);
                 if (nativeInputQueue->getConsumer().initialize() != android::OK) {
                     delete nativeInputQueue;
                     nativeInputQueue = NULL;
@@ -160,7 +345,6 @@
         return OK;
     }
     
-    ANativeActivity activity;
     ANativeActivityCallbacks callbacks;
     
     void* dlhandle;
@@ -170,8 +354,11 @@
     String8 externalDataPath;
     
     sp<ANativeWindow> nativeWindow;
+    int32_t lastWindowWidth;
+    int32_t lastWindowHeight;
+
     jobject inputChannel;
-    struct MyInputQueue* nativeInputQueue;
+    struct AInputQueue* nativeInputQueue;
     
     // These are used to wake up the main thread to process work.
     int mainWorkRead;
@@ -179,6 +366,30 @@
     sp<PollLoop> pollLoop;
 };
 
+void android_NativeActivity_setWindowFormat(
+        ANativeActivity* activity, int32_t format) {
+    NativeCode* code = static_cast<NativeCode*>(activity);
+    write_work(code->mainWorkWrite, CMD_SET_WINDOW_FORMAT, format);
+}
+
+void android_NativeActivity_setWindowFlags(
+        ANativeActivity* activity, int32_t values, int32_t mask) {
+    NativeCode* code = static_cast<NativeCode*>(activity);
+    write_work(code->mainWorkWrite, CMD_SET_WINDOW_FLAGS, values, mask);
+}
+
+void android_NativeActivity_showSoftInput(
+        ANativeActivity* activity, int32_t flags) {
+    NativeCode* code = static_cast<NativeCode*>(activity);
+    write_work(code->mainWorkWrite, CMD_SHOW_SOFT_INPUT, flags);
+}
+
+void android_NativeActivity_hideSoftInput(
+        ANativeActivity* activity, int32_t flags) {
+    NativeCode* code = static_cast<NativeCode*>(activity);
+    write_work(code->mainWorkWrite, CMD_HIDE_SOFT_INPUT, flags);
+}
+
 // ------------------------------------------------------------------------
 
 /*
@@ -186,19 +397,51 @@
  */
 static bool mainWorkCallback(int fd, int events, void* data) {
     NativeCode* code = (NativeCode*)data;
-    if ((events & POLLIN) != 0) {
-        KeyEvent* keyEvent;
-        while ((keyEvent=code->nativeInputQueue->getNextEvent()) != NULL) {
-            jobject inputEventObj = android_view_KeyEvent_fromNative(
-                    code->activity.env, keyEvent);
-            code->activity.env->CallVoidMethod(code->activity.clazz,
-                    gNativeActivityClassInfo.dispatchUnhandledKeyEvent, inputEventObj);
-            int32_t res = code->nativeInputQueue->getConsumer().sendFinishedSignal();
-            if (res != OK) {
-                LOGW("Failed to send finished signal on channel '%s'.  status=%d",
-                        code->nativeInputQueue->getConsumer().getChannel()->getName().string(), res);
+    if ((events & POLLIN) == 0) {
+        return true;
+    }
+    
+    ActivityWork work;
+    if (!read_work(code->mainWorkRead, &work)) {
+        return true;
+    }
+
+    LOG_TRACE("mainWorkCallback: cmd=%d", work.cmd);
+
+    switch (work.cmd) {
+        case CMD_DEF_KEY: {
+            KeyEvent* keyEvent;
+            while ((keyEvent=code->nativeInputQueue->consumeUnhandledEvent()) != NULL) {
+                jobject inputEventObj = android_view_KeyEvent_fromNative(
+                        code->env, keyEvent);
+                code->env->CallVoidMethod(code->clazz,
+                        gNativeActivityClassInfo.dispatchUnhandledKeyEvent, inputEventObj);
+                int32_t res = code->nativeInputQueue->getConsumer().sendFinishedSignal();
+                if (res != OK) {
+                    LOGW("Failed to send finished signal on channel '%s'.  status=%d",
+                            code->nativeInputQueue->getConsumer().getChannel()->getName().string(), res);
+                }
             }
-        }
+        } break;
+        case CMD_SET_WINDOW_FORMAT: {
+            code->env->CallVoidMethod(code->clazz,
+                    gNativeActivityClassInfo.setWindowFormat, work.arg1);
+        } break;
+        case CMD_SET_WINDOW_FLAGS: {
+            code->env->CallVoidMethod(code->clazz,
+                    gNativeActivityClassInfo.setWindowFlags, work.arg1, work.arg2);
+        } break;
+        case CMD_SHOW_SOFT_INPUT: {
+            code->env->CallVoidMethod(code->clazz,
+                    gNativeActivityClassInfo.showIme, work.arg1);
+        } break;
+        case CMD_HIDE_SOFT_INPUT: {
+            code->env->CallVoidMethod(code->clazz,
+                    gNativeActivityClassInfo.hideIme, work.arg1);
+        } break;
+        default:
+            LOGW("Unknown work command: %d", work.cmd);
+            break;
     }
     
     return true;
@@ -210,6 +453,8 @@
 loadNativeCode_native(JNIEnv* env, jobject clazz, jstring path, jobject messageQueue,
         jstring internalDataDir, jstring externalDataDir, int sdkVersion)
 {
+    LOG_TRACE("loadNativeCode_native");
+
     const char* pathStr = env->GetStringUTFChars(path, NULL);
     NativeCode* code = NULL;
     
@@ -241,30 +486,36 @@
         }
         code->mainWorkRead = msgpipe[0];
         code->mainWorkWrite = msgpipe[1];
+        int result = fcntl(code->mainWorkRead, F_SETFL, O_NONBLOCK);
+        SLOGW_IF(result != 0, "Could not make main work read pipe "
+                "non-blocking: %s", strerror(errno));
+        result = fcntl(code->mainWorkWrite, F_SETFL, O_NONBLOCK);
+        SLOGW_IF(result != 0, "Could not make main work write pipe "
+                "non-blocking: %s", strerror(errno));
         code->pollLoop->setCallback(code->mainWorkRead, POLLIN, mainWorkCallback, code);
         
-        code->activity.callbacks = &code->callbacks;
-        if (env->GetJavaVM(&code->activity.vm) < 0) {
+        code->ANativeActivity::callbacks = &code->callbacks;
+        if (env->GetJavaVM(&code->vm) < 0) {
             LOGW("NativeActivity GetJavaVM failed");
             delete code;
             return 0;
         }
-        code->activity.env = env;
-        code->activity.clazz = env->NewGlobalRef(clazz);
+        code->env = env;
+        code->clazz = env->NewGlobalRef(clazz);
         
         const char* dirStr = env->GetStringUTFChars(internalDataDir, NULL);
         code->internalDataPath = dirStr;
-        code->activity.internalDataPath = code->internalDataPath.string();
+        code->internalDataPath = code->internalDataPath.string();
         env->ReleaseStringUTFChars(path, dirStr);
     
         dirStr = env->GetStringUTFChars(externalDataDir, NULL);
         code->externalDataPath = dirStr;
-        code->activity.externalDataPath = code->externalDataPath.string();
+        code->externalDataPath = code->externalDataPath.string();
         env->ReleaseStringUTFChars(path, dirStr);
     
-        code->activity.sdkVersion = sdkVersion;
+        code->sdkVersion = sdkVersion;
         
-        code->createActivityFunc(&code->activity, NULL, 0);
+        code->createActivityFunc(code, NULL, 0);
     }
     
     return (jint)code;
@@ -273,6 +524,7 @@
 static void
 unloadNativeCode_native(JNIEnv* env, jobject clazz, jint handle)
 {
+    LOG_TRACE("unloadNativeCode_native");
     if (handle != 0) {
         NativeCode* code = (NativeCode*)handle;
         delete code;
@@ -282,10 +534,11 @@
 static void
 onStart_native(JNIEnv* env, jobject clazz, jint handle)
 {
+    LOG_TRACE("onStart_native");
     if (handle != 0) {
         NativeCode* code = (NativeCode*)handle;
         if (code->callbacks.onStart != NULL) {
-            code->callbacks.onStart(&code->activity);
+            code->callbacks.onStart(code);
         }
     }
 }
@@ -293,10 +546,11 @@
 static void
 onResume_native(JNIEnv* env, jobject clazz, jint handle)
 {
+    LOG_TRACE("onResume_native");
     if (handle != 0) {
         NativeCode* code = (NativeCode*)handle;
         if (code->callbacks.onResume != NULL) {
-            code->callbacks.onResume(&code->activity);
+            code->callbacks.onResume(code);
         }
     }
 }
@@ -304,11 +558,12 @@
 static void
 onSaveInstanceState_native(JNIEnv* env, jobject clazz, jint handle)
 {
+    LOG_TRACE("onSaveInstanceState_native");
     if (handle != 0) {
         NativeCode* code = (NativeCode*)handle;
         if (code->callbacks.onSaveInstanceState != NULL) {
             size_t len = 0;
-            code->callbacks.onSaveInstanceState(&code->activity, &len);
+            code->callbacks.onSaveInstanceState(code, &len);
         }
     }
 }
@@ -316,10 +571,11 @@
 static void
 onPause_native(JNIEnv* env, jobject clazz, jint handle)
 {
+    LOG_TRACE("onPause_native");
     if (handle != 0) {
         NativeCode* code = (NativeCode*)handle;
         if (code->callbacks.onPause != NULL) {
-            code->callbacks.onPause(&code->activity);
+            code->callbacks.onPause(code);
         }
     }
 }
@@ -327,10 +583,11 @@
 static void
 onStop_native(JNIEnv* env, jobject clazz, jint handle)
 {
+    LOG_TRACE("onStop_native");
     if (handle != 0) {
         NativeCode* code = (NativeCode*)handle;
         if (code->callbacks.onStop != NULL) {
-            code->callbacks.onStop(&code->activity);
+            code->callbacks.onStop(code);
         }
     }
 }
@@ -338,10 +595,11 @@
 static void
 onLowMemory_native(JNIEnv* env, jobject clazz, jint handle)
 {
+    LOG_TRACE("onLowMemory_native");
     if (handle != 0) {
         NativeCode* code = (NativeCode*)handle;
         if (code->callbacks.onLowMemory != NULL) {
-            code->callbacks.onLowMemory(&code->activity);
+            code->callbacks.onLowMemory(code);
         }
     }
 }
@@ -349,10 +607,11 @@
 static void
 onWindowFocusChanged_native(JNIEnv* env, jobject clazz, jint handle, jboolean focused)
 {
+    LOG_TRACE("onWindowFocusChanged_native");
     if (handle != 0) {
         NativeCode* code = (NativeCode*)handle;
         if (code->callbacks.onWindowFocusChanged != NULL) {
-            code->callbacks.onWindowFocusChanged(&code->activity, focused ? 1 : 0);
+            code->callbacks.onWindowFocusChanged(code, focused ? 1 : 0);
         }
     }
 }
@@ -360,33 +619,72 @@
 static void
 onSurfaceCreated_native(JNIEnv* env, jobject clazz, jint handle, jobject surface)
 {
+    LOG_TRACE("onSurfaceCreated_native");
     if (handle != 0) {
         NativeCode* code = (NativeCode*)handle;
         code->setSurface(surface);
         if (code->nativeWindow != NULL && code->callbacks.onNativeWindowCreated != NULL) {
-            code->callbacks.onNativeWindowCreated(&code->activity,
+            code->callbacks.onNativeWindowCreated(code,
                     code->nativeWindow.get());
         }
     }
 }
 
+static int32_t getWindowProp(ANativeWindow* window, int what) {
+    int value;
+    int res = window->query(window, what, &value);
+    return res < 0 ? res : value;
+}
+
 static void
 onSurfaceChanged_native(JNIEnv* env, jobject clazz, jint handle, jobject surface,
         jint format, jint width, jint height)
 {
+    LOG_TRACE("onSurfaceChanged_native");
     if (handle != 0) {
         NativeCode* code = (NativeCode*)handle;
         sp<ANativeWindow> oldNativeWindow = code->nativeWindow;
         code->setSurface(surface);
         if (oldNativeWindow != code->nativeWindow) {
             if (oldNativeWindow != NULL && code->callbacks.onNativeWindowDestroyed != NULL) {
-                code->callbacks.onNativeWindowDestroyed(&code->activity,
+                code->callbacks.onNativeWindowDestroyed(code,
                         oldNativeWindow.get());
             }
-            if (code->nativeWindow != NULL && code->callbacks.onNativeWindowCreated != NULL) {
-                code->callbacks.onNativeWindowCreated(&code->activity,
-                        code->nativeWindow.get());
+            if (code->nativeWindow != NULL) {
+                if (code->callbacks.onNativeWindowCreated != NULL) {
+                    code->callbacks.onNativeWindowCreated(code,
+                            code->nativeWindow.get());
+                }
+                code->lastWindowWidth = getWindowProp(code->nativeWindow.get(),
+                        NATIVE_WINDOW_WIDTH);
+                code->lastWindowHeight = getWindowProp(code->nativeWindow.get(),
+                        NATIVE_WINDOW_HEIGHT);
             }
+        } else {
+            // Maybe it resized?
+            int32_t newWidth = getWindowProp(code->nativeWindow.get(),
+                    NATIVE_WINDOW_WIDTH);
+            int32_t newHeight = getWindowProp(code->nativeWindow.get(),
+                    NATIVE_WINDOW_HEIGHT);
+            if (newWidth != code->lastWindowWidth
+                    || newHeight != code->lastWindowHeight) {
+                if (code->callbacks.onNativeWindowResized != NULL) {
+                    code->callbacks.onNativeWindowResized(code,
+                            code->nativeWindow.get());
+                }
+            }
+        }
+    }
+}
+
+static void
+onSurfaceRedrawNeeded_native(JNIEnv* env, jobject clazz, jint handle)
+{
+    LOG_TRACE("onSurfaceRedrawNeeded_native");
+    if (handle != 0) {
+        NativeCode* code = (NativeCode*)handle;
+        if (code->nativeWindow != NULL && code->callbacks.onNativeWindowRedrawNeeded != NULL) {
+            code->callbacks.onNativeWindowRedrawNeeded(code, code->nativeWindow.get());
         }
     }
 }
@@ -394,10 +692,11 @@
 static void
 onSurfaceDestroyed_native(JNIEnv* env, jobject clazz, jint handle, jobject surface)
 {
+    LOG_TRACE("onSurfaceDestroyed_native");
     if (handle != 0) {
         NativeCode* code = (NativeCode*)handle;
         if (code->nativeWindow != NULL && code->callbacks.onNativeWindowDestroyed != NULL) {
-            code->callbacks.onNativeWindowDestroyed(&code->activity,
+            code->callbacks.onNativeWindowDestroyed(code,
                     code->nativeWindow.get());
         }
         code->setSurface(NULL);
@@ -407,6 +706,7 @@
 static void
 onInputChannelCreated_native(JNIEnv* env, jobject clazz, jint handle, jobject channel)
 {
+    LOG_TRACE("onInputChannelCreated_native");
     if (handle != 0) {
         NativeCode* code = (NativeCode*)handle;
         status_t err = code->setInputChannel(channel);
@@ -416,7 +716,7 @@
             return;
         }
         if (code->callbacks.onInputQueueCreated != NULL) {
-            code->callbacks.onInputQueueCreated(&code->activity,
+            code->callbacks.onInputQueueCreated(code,
                     code->nativeInputQueue);
         }
     }
@@ -425,17 +725,50 @@
 static void
 onInputChannelDestroyed_native(JNIEnv* env, jobject clazz, jint handle, jobject channel)
 {
+    LOG_TRACE("onInputChannelDestroyed_native");
     if (handle != 0) {
         NativeCode* code = (NativeCode*)handle;
         if (code->nativeInputQueue != NULL
                 && code->callbacks.onInputQueueDestroyed != NULL) {
-            code->callbacks.onInputQueueDestroyed(&code->activity,
+            code->callbacks.onInputQueueDestroyed(code,
                     code->nativeInputQueue);
         }
         code->setInputChannel(NULL);
     }
 }
 
+static void
+onContentRectChanged_native(JNIEnv* env, jobject clazz, jint handle,
+        jint x, jint y, jint w, jint h)
+{
+    LOG_TRACE("onContentRectChanged_native");
+    if (handle != 0) {
+        NativeCode* code = (NativeCode*)handle;
+        if (code->callbacks.onContentRectChanged != NULL) {
+            ARect rect;
+            rect.left = x;
+            rect.top = y;
+            rect.right = x+w;
+            rect.bottom = y+h;
+            code->callbacks.onContentRectChanged(code, &rect);
+        }
+    }
+}
+
+static void
+dispatchKeyEvent_native(JNIEnv* env, jobject clazz, jint handle, jobject eventObj)
+{
+    LOG_TRACE("dispatchKeyEvent_native");
+    if (handle != 0) {
+        NativeCode* code = (NativeCode*)handle;
+        if (code->nativeInputQueue != NULL) {
+            KeyEvent* event = new KeyEvent();
+            android_view_KeyEvent_toNative(env, eventObj, INPUT_EVENT_NATURE_KEY, event);
+            code->nativeInputQueue->dispatchEvent(event);
+        }
+    }
+}
+
 static const JNINativeMethod g_methods[] = {
     { "loadNativeCode", "(Ljava/lang/String;Landroid/os/MessageQueue;Ljava/lang/String;Ljava/lang/String;I)I",
             (void*)loadNativeCode_native },
@@ -449,9 +782,12 @@
     { "onWindowFocusChangedNative", "(IZ)V", (void*)onWindowFocusChanged_native },
     { "onSurfaceCreatedNative", "(ILandroid/view/Surface;)V", (void*)onSurfaceCreated_native },
     { "onSurfaceChangedNative", "(ILandroid/view/Surface;III)V", (void*)onSurfaceChanged_native },
+    { "onSurfaceRedrawNeededNative", "(ILandroid/view/Surface;)V", (void*)onSurfaceRedrawNeeded_native },
     { "onSurfaceDestroyedNative", "(I)V", (void*)onSurfaceDestroyed_native },
     { "onInputChannelCreatedNative", "(ILandroid/view/InputChannel;)V", (void*)onInputChannelCreated_native },
     { "onInputChannelDestroyedNative", "(ILandroid/view/InputChannel;)V", (void*)onInputChannelDestroyed_native },
+    { "onContentRectChangedNative", "(IIIII)V", (void*)onContentRectChanged_native },
+    { "dispatchKeyEventNative", "(ILandroid/view/KeyEvent;)V", (void*)dispatchKeyEvent_native },
 };
 
 static const char* const kNativeActivityPathName = "android/app/NativeActivity";
@@ -481,6 +817,12 @@
     GET_METHOD_ID(gNativeActivityClassInfo.setWindowFormat,
             gNativeActivityClassInfo.clazz,
             "setWindowFormat", "(I)V");
+    GET_METHOD_ID(gNativeActivityClassInfo.showIme,
+            gNativeActivityClassInfo.clazz,
+            "showIme", "(I)V");
+    GET_METHOD_ID(gNativeActivityClassInfo.hideIme,
+            gNativeActivityClassInfo.clazz,
+            "hideIme", "(I)V");
 
     return AndroidRuntime::registerNativeMethods(
         env, kNativeActivityPathName,
diff --git a/core/jni/android_database_SQLiteDatabase.cpp b/core/jni/android_database_SQLiteDatabase.cpp
index 5a92193..290b532 100644
--- a/core/jni/android_database_SQLiteDatabase.cpp
+++ b/core/jni/android_database_SQLiteDatabase.cpp
@@ -62,6 +62,7 @@
 };
 
 static jfieldID offset_db_handle;
+static jmethodID method_custom_function_callback;
 
 static char *createStr(const char *path, short extra) {
     int len = strlen(path) + extra;
@@ -458,6 +459,62 @@
     }
 }
 
+static void custom_function_callback(sqlite3_context * context, int argc, sqlite3_value ** argv) {
+    JNIEnv* env = AndroidRuntime::getJNIEnv();
+    if (!env) {
+        LOGE("custom_function_callback cannot call into Java on this thread");
+        return;
+    }
+
+    // pack up the arguments into a string array
+    jobjectArray strArray = env->NewObjectArray(argc, env->FindClass("java/lang/String"), NULL);
+    if (!strArray) {
+        jniThrowException(env, "java/lang/OutOfMemoryError", NULL);
+        return;
+    }
+    for (int i = 0; i < argc; i++) {
+        char* arg = (char *)sqlite3_value_text(argv[i]);
+        jobject obj = env->NewStringUTF(arg);
+        if (!obj) {
+            jniThrowException(env, "java/lang/OutOfMemoryError", NULL);
+            return;
+        }
+        env->SetObjectArrayElement(strArray, i, obj);
+        env->DeleteLocalRef(obj);
+    }
+
+    // get global ref to CustomFunction object from our user data
+    jobject function = (jobject)sqlite3_user_data(context);
+    env->CallVoidMethod(function, method_custom_function_callback, strArray);
+}
+
+static jint native_addCustomFunction(JNIEnv* env, jobject object,
+        jstring name, jint numArgs, jobject function)
+{
+    sqlite3 * handle = (sqlite3 *)env->GetIntField(object, offset_db_handle);
+    char const *nameStr = env->GetStringUTFChars(name, NULL);
+    jobject ref = env->NewGlobalRef(function);
+    LOGD("native_addCustomFunction %s ref: %d", nameStr, ref);
+    int err = sqlite3_create_function(handle, nameStr, numArgs, SQLITE_UTF8,
+            (void *)ref, custom_function_callback, NULL, NULL);
+    env->ReleaseStringUTFChars(name, nameStr);
+
+    if (err == SQLITE_OK)
+        return (int)ref;
+    else {
+        LOGE("sqlite3_create_function returned %d", err);
+        env->DeleteGlobalRef(ref);
+        throw_sqlite3_exception(env, handle);
+        return 0;
+     }
+}
+
+static void native_releaseCustomFunction(JNIEnv* env, jobject object, jint ref)
+{
+    LOGD("native_releaseCustomFunction %d", ref);
+    env->DeleteGlobalRef((jobject)ref);
+}
+
 static JNINativeMethod sMethods[] =
 {
     /* name, signature, funcPtr */
@@ -472,6 +529,10 @@
     {"native_getDbLookaside", "()I", (void *)native_getDbLookaside},
     {"releaseMemory", "()I", (void *)native_releaseMemory},
     {"native_finalize", "(I)V", (void *)native_finalize},
+    {"native_addCustomFunction",
+                    "(Ljava/lang/String;ILandroid/database/sqlite/SQLiteDatabase$CustomFunction;)I",
+                    (void *)native_addCustomFunction},
+    {"native_releaseCustomFunction", "(I)V", (void *)native_releaseCustomFunction},
 };
 
 int register_android_database_SQLiteDatabase(JNIEnv *env)
@@ -490,6 +551,17 @@
         return -1;
     }
 
+    clazz = env->FindClass("android/database/sqlite/SQLiteDatabase$CustomFunction");
+    if (clazz == NULL) {
+        LOGE("Can't find android/database/sqlite/SQLiteDatabase$CustomFunction\n");
+        return -1;
+    }
+    method_custom_function_callback = env->GetMethodID(clazz, "callback", "([Ljava/lang/String;)V");
+    if (method_custom_function_callback == NULL) {
+        LOGE("Can't find method SQLiteDatabase.CustomFunction.callback\n");
+        return -1;
+    }
+
     return AndroidRuntime::registerNativeMethods(env, "android/database/sqlite/SQLiteDatabase",
             sMethods, NELEM(sMethods));
 }
diff --git a/core/jni/android_net_NetUtils.cpp b/core/jni/android_net_NetUtils.cpp
index feb0dad..3cde9d6 100644
--- a/core/jni/android_net_NetUtils.cpp
+++ b/core/jni/android_net_NetUtils.cpp
@@ -222,10 +222,10 @@
 
     { "enableInterface", "(Ljava/lang/String;)I",  (void *)android_net_utils_enableInterface },
     { "disableInterface", "(Ljava/lang/String;)I",  (void *)android_net_utils_disableInterface },
-    { "addHostRoute", "(Ljava/lang/String;I)I",  (void *)android_net_utils_addHostRoute },
+    { "addHostRouteNative", "(Ljava/lang/String;I)I",  (void *)android_net_utils_addHostRoute },
     { "removeHostRoutes", "(Ljava/lang/String;)I",  (void *)android_net_utils_removeHostRoutes },
-    { "setDefaultRoute", "(Ljava/lang/String;I)I",  (void *)android_net_utils_setDefaultRoute },
-    { "getDefaultRoute", "(Ljava/lang/String;)I",  (void *)android_net_utils_getDefaultRoute },
+    { "setDefaultRouteNative", "(Ljava/lang/String;I)I",  (void *)android_net_utils_setDefaultRoute },
+    { "getDefaultRouteNative", "(Ljava/lang/String;)I",  (void *)android_net_utils_getDefaultRoute },
     { "removeDefaultRoute", "(Ljava/lang/String;)I",  (void *)android_net_utils_removeDefaultRoute },
     { "resetConnections", "(Ljava/lang/String;)I",  (void *)android_net_utils_resetConnections },
     { "runDhcp", "(Ljava/lang/String;Landroid/net/DhcpInfo;)Z",  (void *)android_net_utils_runDhcp },
diff --git a/core/jni/android_os_Debug.cpp b/core/jni/android_os_Debug.cpp
index 3ee404a..4a877d2 100644
--- a/core/jni/android_os_Debug.cpp
+++ b/core/jni/android_os_Debug.cpp
@@ -14,6 +14,7 @@
  * limitations under the License.
  */
 
+#define LOG_TAG "android.os.Debug"
 #include "JNIHelp.h"
 #include "jni.h"
 #include "utils/misc.h"
@@ -24,6 +25,8 @@
 #include <unistd.h>
 #include <time.h>
 #include <sys/time.h>
+#include <errno.h>
+#include <assert.h>
 
 #ifdef HAVE_MALLOC_H
 #include <malloc.h>
@@ -274,6 +277,176 @@
 jint android_os_Debug_getProxyObjectCount(JNIEnv* env, jobject clazz);
 jint android_os_Debug_getDeathObjectCount(JNIEnv* env, jobject clazz);
 
+
+#ifdef HAVE_ANDROID_OS
+/* pulled out of bionic */
+extern "C" void get_malloc_leak_info(uint8_t** info, size_t* overallSize,
+    size_t* infoSize, size_t* totalMemory, size_t* backtraceSize);
+extern "C" void free_malloc_leak_info(uint8_t* info);
+#define SIZE_FLAG_ZYGOTE_CHILD  (1<<31)
+#define BACKTRACE_SIZE          32
+
+/*
+ * This is a qsort() callback.
+ *
+ * See dumpNativeHeap() for comments about the data format and sort order.
+ */
+static int compareHeapRecords(const void* vrec1, const void* vrec2)
+{
+    const size_t* rec1 = (const size_t*) vrec1;
+    const size_t* rec2 = (const size_t*) vrec2;
+    size_t size1 = *rec1;
+    size_t size2 = *rec2;
+
+    if (size1 < size2) {
+        return 1;
+    } else if (size1 > size2) {
+        return -1;
+    }
+
+    intptr_t* bt1 = (intptr_t*)(rec1 + 2);
+    intptr_t* bt2 = (intptr_t*)(rec2 + 2);
+    for (size_t idx = 0; idx < BACKTRACE_SIZE; idx++) {
+        intptr_t addr1 = bt1[idx];
+        intptr_t addr2 = bt2[idx];
+        if (addr1 == addr2) {
+            if (addr1 == 0)
+                break;
+            continue;
+        }
+        if (addr1 < addr2) {
+            return -1;
+        } else if (addr1 > addr2) {
+            return 1;
+        }
+    }
+
+    return 0;
+}
+
+/*
+ * The get_malloc_leak_info() call returns an array of structs that
+ * look like this:
+ *
+ *   size_t size
+ *   size_t allocations
+ *   intptr_t backtrace[32]
+ *
+ * "size" is the size of the allocation, "backtrace" is a fixed-size
+ * array of function pointers, and "allocations" is the number of
+ * allocations with the exact same size and backtrace.
+ *
+ * The entries are sorted by descending total size (i.e. size*allocations)
+ * then allocation count.  For best results with "diff" we'd like to sort
+ * primarily by individual size then stack trace.  Since the entries are
+ * fixed-size, and we're allowed (by the current implementation) to mangle
+ * them, we can do this in place.
+ */
+static void dumpNativeHeap(FILE* fp)
+{
+    uint8_t* info = NULL;
+    size_t overallSize, infoSize, totalMemory, backtraceSize;
+
+    get_malloc_leak_info(&info, &overallSize, &infoSize, &totalMemory,
+        &backtraceSize);
+    if (info == NULL) {
+        fprintf(fp, "Native heap dump not available. To enable, run these"
+                    " commands (requires root):\n");
+        fprintf(fp, "$ adb shell setprop libc.debug.malloc 1\n");
+        fprintf(fp, "$ adb shell stop\n");
+        fprintf(fp, "$ adb shell start\n");
+        return;
+    }
+    assert(infoSize != 0);
+    assert(overallSize % infoSize == 0);
+
+    fprintf(fp, "Android Native Heap Dump v1.0\n\n");
+
+    size_t recordCount = overallSize / infoSize;
+    fprintf(fp, "Total memory: %zu\n", totalMemory);
+    fprintf(fp, "Allocation records: %zd\n", recordCount);
+    if (backtraceSize != BACKTRACE_SIZE) {
+        fprintf(fp, "WARNING: mismatched backtrace sizes (%d vs. %d)\n",
+            backtraceSize, BACKTRACE_SIZE);
+    }
+    fprintf(fp, "\n");
+
+    /* re-sort the entries */
+    qsort(info, recordCount, infoSize, compareHeapRecords);
+
+    /* dump the entries to the file */
+    const uint8_t* ptr = info;
+    for (size_t idx = 0; idx < recordCount; idx++) {
+        size_t size = *(size_t*) ptr;
+        size_t allocations = *(size_t*) (ptr + sizeof(size_t));
+        intptr_t* backtrace = (intptr_t*) (ptr + sizeof(size_t) * 2);
+
+        fprintf(fp, "z %d  sz %8zu  num %4zu  bt",
+                (size & SIZE_FLAG_ZYGOTE_CHILD) != 0,
+                size & ~SIZE_FLAG_ZYGOTE_CHILD,
+                allocations);
+        for (size_t bt = 0; bt < backtraceSize; bt++) {
+            if (backtrace[bt] == 0) {
+                break;
+            } else {
+                fprintf(fp, " %08x", backtrace[bt]);
+            }
+        }
+        fprintf(fp, "\n");
+
+        ptr += infoSize;
+    }
+
+    fprintf(fp, "END\n");
+    free_malloc_leak_info(info);
+}
+#endif /*HAVE_ANDROID_OS*/
+
+/*
+ * Dump the native heap, writing human-readable output to the specified
+ * file descriptor.
+ */
+static void android_os_Debug_dumpNativeHeap(JNIEnv* env, jobject clazz,
+    jobject fileDescriptor)
+{
+    if (fileDescriptor == NULL) {
+        jniThrowNullPointerException(env, NULL);
+        return;
+    }
+    int origFd = jniGetFDFromFileDescriptor(env, fileDescriptor);
+    if (origFd < 0) {
+        jniThrowRuntimeException(env, "Invalid file descriptor");
+        return;
+    }
+
+    /* dup() the descriptor so we don't close the original with fclose() */
+    int fd = dup(origFd);
+    if (fd < 0) {
+        LOGW("dup(%d) failed: %s\n", origFd, strerror(errno));
+        jniThrowRuntimeException(env, "dup() failed");
+        return;
+    }
+
+    FILE* fp = fdopen(fd, "w");
+    if (fp == NULL) {
+        LOGW("fdopen(%d) failed: %s\n", fd, strerror(errno));
+        close(fd);
+        jniThrowRuntimeException(env, "fdopen() failed");
+        return;
+    }
+
+#ifdef HAVE_ANDROID_OS
+    LOGD("Native heap dump starting...\n");
+    dumpNativeHeap(fp);
+    LOGD("Native heap dump complete.\n");
+#else
+    fprintf(fp, "Native heap dump not available on this platform\n");
+#endif
+
+    fclose(fp);
+}
+
+
 /*
  * JNI registration.
  */
@@ -289,6 +462,8 @@
             (void*) android_os_Debug_getDirtyPages },
     { "getMemoryInfo",          "(ILandroid/os/Debug$MemoryInfo;)V",
             (void*) android_os_Debug_getDirtyPagesPid },
+    { "dumpNativeHeap",         "(Ljava/io/FileDescriptor;)V",
+            (void*) android_os_Debug_dumpNativeHeap },
     { "getBinderSentTransactions", "()I",
             (void*) android_os_Debug_getBinderSentTransactions },
     { "getBinderReceivedTransactions", "()I",
@@ -320,4 +495,4 @@
     return jniRegisterNativeMethods(env, "android/os/Debug", gMethods, NELEM(gMethods));
 }
 
-};
+}; // namespace android
diff --git a/core/jni/android_os_MessageQueue.cpp b/core/jni/android_os_MessageQueue.cpp
index 961f806..847b5a5 100644
--- a/core/jni/android_os_MessageQueue.cpp
+++ b/core/jni/android_os_MessageQueue.cpp
@@ -53,7 +53,7 @@
 NativeMessageQueue::NativeMessageQueue() {
     mPollLoop = PollLoop::getForThread();
     if (mPollLoop == NULL) {
-        mPollLoop = new PollLoop();
+        mPollLoop = new PollLoop(false);
         PollLoop::setForThread(mPollLoop);
     }
 }
@@ -62,7 +62,7 @@
 }
 
 bool NativeMessageQueue::pollOnce(int timeoutMillis) {
-    return mPollLoop->pollOnce(timeoutMillis);
+    return mPollLoop->pollOnce(timeoutMillis) != PollLoop::POLL_TIMEOUT;
 }
 
 void NativeMessageQueue::wake() {
diff --git a/core/jni/android_server_BluetoothEventLoop.cpp b/core/jni/android_server_BluetoothEventLoop.cpp
index 3c88158..efaff12 100644
--- a/core/jni/android_server_BluetoothEventLoop.cpp
+++ b/core/jni/android_server_BluetoothEventLoop.cpp
@@ -231,6 +231,20 @@
             return JNI_FALSE;
         }
         dbus_bus_add_match(nat->conn,
+                "type='signal',interface='"BLUEZ_DBUS_BASE_IFC".Input'",
+                &err);
+        if (dbus_error_is_set(&err)) {
+            LOG_AND_FREE_DBUS_ERROR(&err);
+            return JNI_FALSE;
+        }
+        dbus_bus_add_match(nat->conn,
+                "type='signal',interface='"BLUEZ_DBUS_BASE_IFC".Network'",
+                &err);
+        if (dbus_error_is_set(&err)) {
+            LOG_AND_FREE_DBUS_ERROR(&err);
+            return JNI_FALSE;
+        }
+        dbus_bus_add_match(nat->conn,
                 "type='signal',interface='org.bluez.AudioSink'",
                 &err);
         if (dbus_error_is_set(&err)) {
diff --git a/core/jni/android_view_GLES20Canvas.cpp b/core/jni/android_view_GLES20Canvas.cpp
index 47f5bfc..dbf482e 100644
--- a/core/jni/android_view_GLES20Canvas.cpp
+++ b/core/jni/android_view_GLES20Canvas.cpp
@@ -178,65 +178,32 @@
 // ----------------------------------------------------------------------------
 
 static void android_view_GLES20Canvas_drawBitmap(JNIEnv* env, jobject canvas,
-        OpenGLRenderer* renderer, SkBitmap* bitmap, float left, float top,
-        SkPaint* paint, jint bitmapDensity, jint canvasDensity,jint screenDensity) {
-    if (canvasDensity == bitmapDensity || canvasDensity == 0 || bitmapDensity == 0) {
-        renderer->drawBitmap(bitmap, left, top, paint);
-    } else {
-        renderer->save(0);
-        const float scale = canvasDensity / float(bitmapDensity);
-        renderer->translate(left, top);
-        renderer->scale(scale, scale);
-        renderer->drawBitmap(bitmap, left, top, paint);
-        renderer->restore();
-    }
+        OpenGLRenderer* renderer, SkBitmap* bitmap, float left, float top, SkPaint* paint) {
+    renderer->drawBitmap(bitmap, left, top, paint);
 }
 
 static void android_view_GLES20Canvas_drawBitmapRect(JNIEnv* env, jobject canvas,
         OpenGLRenderer* renderer, SkBitmap* bitmap,
         float srcLeft, float srcTop, float srcRight, float srcBottom,
-        float dstLeft, float dstTop, float dstRight, float dstBottom,
-        SkPaint* paint, jint bitmapDensity, jint canvasDensity, jint screenDensity) {
-    if (canvasDensity == bitmapDensity || canvasDensity == 0 || bitmapDensity == 0) {
-        renderer->drawBitmap(bitmap, srcLeft, srcTop, srcRight, srcBottom,
-                dstLeft, dstTop, dstRight, dstBottom, paint);
-    } else {
-        // TODO: implement
-    }
+        float dstLeft, float dstTop, float dstRight, float dstBottom, SkPaint* paint) {
+    renderer->drawBitmap(bitmap, srcLeft, srcTop, srcRight, srcBottom,
+            dstLeft, dstTop, dstRight, dstBottom, paint);
 }
 
 static void android_view_GLES20Canvas_drawBitmapMatrix(JNIEnv* env, jobject canvas,
-        OpenGLRenderer* renderer, SkBitmap* bitmap, SkMatrix* matrix, SkPaint* paint,
-        jint bitmapDensity, jint canvasDensity,jint screenDensity) {
-    if (canvasDensity == bitmapDensity || canvasDensity == 0 || bitmapDensity == 0) {
-        renderer->drawBitmap(bitmap, matrix, paint);
-    } else {
-        // TODO: implement
-    }
+        OpenGLRenderer* renderer, SkBitmap* bitmap, SkMatrix* matrix, SkPaint* paint) {
+    renderer->drawBitmap(bitmap, matrix, paint);
 }
 
 static void android_view_GLES20Canvas_drawPatch(JNIEnv* env, jobject canvas,
         OpenGLRenderer* renderer, SkBitmap* bitmap, jbyteArray chunks,
-        float left, float top, float right, float bottom, SkPaint* paint,
-        jint bitmapDensity, jint canvasDensity,jint screenDensity) {
+        float left, float top, float right, float bottom, SkPaint* paint) {
 
     jbyte* storage = env->GetByteArrayElements(chunks, NULL);
     Res_png_9patch* patch = reinterpret_cast<Res_png_9patch*>(storage);
     Res_png_9patch::deserialize(patch);
 
-    if (canvasDensity == bitmapDensity || canvasDensity == 0 || bitmapDensity == 0) {
-        renderer->drawPatch(bitmap, patch, left, top, right, bottom, paint);
-    } else {
-        renderer->save(0);
-        const float scale = canvasDensity / float(bitmapDensity);
-        renderer->translate(left, top);
-        renderer->scale(scale, scale);
-        left = top = 0.0f;
-        right = (right - left) / scale;
-        bottom = (bottom - top) / scale;
-        renderer->drawPatch(bitmap, patch, left, top, right, bottom, paint);
-        renderer->restore();
-    }
+    renderer->drawPatch(bitmap, patch, left, top, right, bottom, paint);
 
     // TODO: make sure that 0 is correct for the flags
     env->ReleaseByteArrayElements(chunks, storage, 0);
@@ -254,43 +221,62 @@
 }
 
 // ----------------------------------------------------------------------------
+// Shaders
+// ----------------------------------------------------------------------------
+
+static void android_view_GLES20Canvas_resetShader(JNIEnv* env, jobject canvas,
+        OpenGLRenderer* renderer) {
+    renderer->resetShader();
+}
+
+static void android_view_GLES20Canvas_setupBitmapShader(JNIEnv* env, jobject canvas,
+        OpenGLRenderer* renderer, SkShader* shader, SkBitmap* bitmap,
+        SkShader::TileMode tileX, SkShader::TileMode tileY, SkMatrix* matrix) {
+    renderer->setupBitmapShader(bitmap, tileX, tileY, matrix,
+            (shader->getFlags() & SkShader::kOpaqueAlpha_Flag) == 0);
+}
+
+// ----------------------------------------------------------------------------
 // JNI Glue
 // ----------------------------------------------------------------------------
 
 const char* const kClassPathName = "android/view/GLES20Canvas";
 
 static JNINativeMethod gMethods[] = {
-    {   "nCreateRenderer",    "()I",                (void*) android_view_GLES20Canvas_createRenderer },
-    {   "nDestroyRenderer",   "(I)V",               (void*) android_view_GLES20Canvas_destroyRenderer },
-    {   "nSetViewport",       "(III)V",             (void*) android_view_GLES20Canvas_setViewport },
-    {   "nPrepare",           "(I)V",               (void*) android_view_GLES20Canvas_prepare },
+    {   "nCreateRenderer",    "()I",             (void*) android_view_GLES20Canvas_createRenderer },
+    {   "nDestroyRenderer",   "(I)V",            (void*) android_view_GLES20Canvas_destroyRenderer },
+    {   "nSetViewport",       "(III)V",          (void*) android_view_GLES20Canvas_setViewport },
+    {   "nPrepare",           "(I)V",            (void*) android_view_GLES20Canvas_prepare },
 
-    {   "nSave",              "(II)I",              (void*) android_view_GLES20Canvas_save },
-    {   "nRestore",           "(I)V",               (void*) android_view_GLES20Canvas_restore },
-    {   "nRestoreToCount",    "(II)V",              (void*) android_view_GLES20Canvas_restoreToCount },
-    {   "nGetSaveCount",      "(I)I",               (void*) android_view_GLES20Canvas_getSaveCount },
+    {   "nSave",              "(II)I",           (void*) android_view_GLES20Canvas_save },
+    {   "nRestore",           "(I)V",            (void*) android_view_GLES20Canvas_restore },
+    {   "nRestoreToCount",    "(II)V",           (void*) android_view_GLES20Canvas_restoreToCount },
+    {   "nGetSaveCount",      "(I)I",            (void*) android_view_GLES20Canvas_getSaveCount },
 
-    {   "nSaveLayer",         "(IFFFFII)I",         (void*) android_view_GLES20Canvas_saveLayer },
-    {   "nSaveLayerAlpha",    "(IFFFFII)I",         (void*) android_view_GLES20Canvas_saveLayerAlpha },
+    {   "nSaveLayer",         "(IFFFFII)I",      (void*) android_view_GLES20Canvas_saveLayer },
+    {   "nSaveLayerAlpha",    "(IFFFFII)I",      (void*) android_view_GLES20Canvas_saveLayerAlpha },
 
-    {   "nQuickReject",       "(IFFFFI)Z",          (void*) android_view_GLES20Canvas_quickReject },
-    {   "nClipRect",          "(IFFFF)Z",           (void*) android_view_GLES20Canvas_clipRectF },
-    {   "nClipRect",          "(IIIII)Z",           (void*) android_view_GLES20Canvas_clipRect },
+    {   "nQuickReject",       "(IFFFFI)Z",       (void*) android_view_GLES20Canvas_quickReject },
+    {   "nClipRect",          "(IFFFF)Z",        (void*) android_view_GLES20Canvas_clipRectF },
+    {   "nClipRect",          "(IIIII)Z",        (void*) android_view_GLES20Canvas_clipRect },
 
-    {   "nTranslate",         "(IFF)V",             (void*) android_view_GLES20Canvas_translate },
-    {   "nRotate",            "(IF)V",              (void*) android_view_GLES20Canvas_rotate },
-    {   "nScale",             "(IFF)V",             (void*) android_view_GLES20Canvas_scale },
+    {   "nTranslate",         "(IFF)V",          (void*) android_view_GLES20Canvas_translate },
+    {   "nRotate",            "(IF)V",           (void*) android_view_GLES20Canvas_rotate },
+    {   "nScale",             "(IFF)V",          (void*) android_view_GLES20Canvas_scale },
 
-    {   "nSetMatrix",         "(II)V",              (void*) android_view_GLES20Canvas_setMatrix },
-    {   "nGetMatrix",         "(II)V",              (void*) android_view_GLES20Canvas_getMatrix },
-    {   "nConcatMatrix",      "(II)V",              (void*) android_view_GLES20Canvas_concatMatrix },
+    {   "nSetMatrix",         "(II)V",           (void*) android_view_GLES20Canvas_setMatrix },
+    {   "nGetMatrix",         "(II)V",           (void*) android_view_GLES20Canvas_getMatrix },
+    {   "nConcatMatrix",      "(II)V",           (void*) android_view_GLES20Canvas_concatMatrix },
 
-    {   "nDrawBitmap",        "(IIFFIIII)V",        (void*) android_view_GLES20Canvas_drawBitmap },
-    {   "nDrawBitmap",        "(IIFFFFFFFFIIII)V",  (void*) android_view_GLES20Canvas_drawBitmapRect },
-    {   "nDrawBitmap",        "(IIIIIII)V",         (void*) android_view_GLES20Canvas_drawBitmapMatrix },
-    {   "nDrawPatch",         "(II[BFFFFIIII)V",    (void*) android_view_GLES20Canvas_drawPatch },
-    {   "nDrawColor",         "(III)V",             (void*) android_view_GLES20Canvas_drawColor },
-    {   "nDrawRect",          "(IFFFFI)V",          (void*) android_view_GLES20Canvas_drawRect },
+    {   "nDrawBitmap",        "(IIFFI)V",        (void*) android_view_GLES20Canvas_drawBitmap },
+    {   "nDrawBitmap",        "(IIFFFFFFFFI)V",  (void*) android_view_GLES20Canvas_drawBitmapRect },
+    {   "nDrawBitmap",        "(IIII)V",         (void*) android_view_GLES20Canvas_drawBitmapMatrix },
+    {   "nDrawPatch",         "(II[BFFFFI)V",    (void*) android_view_GLES20Canvas_drawPatch },
+    {   "nDrawColor",         "(III)V",          (void*) android_view_GLES20Canvas_drawColor },
+    {   "nDrawRect",          "(IFFFFI)V",       (void*) android_view_GLES20Canvas_drawRect },
+
+    {   "nResetShader",       "(I)V",            (void*) android_view_GLES20Canvas_resetShader },
+    {   "nSetupBitmapShader", "(IIIIII)V",       (void*) android_view_GLES20Canvas_setupBitmapShader },
 
     {   "nGetClipBounds",     "(ILandroid/graphics/Rect;)Z",
             (void*) android_view_GLES20Canvas_getClipBounds },
diff --git a/core/jni/android_view_Surface.cpp b/core/jni/android_view_Surface.cpp
index a82abc93..7305032 100644
--- a/core/jni/android_view_Surface.cpp
+++ b/core/jni/android_view_Surface.cpp
@@ -33,7 +33,7 @@
 
 #include "jni.h"
 #include <android_runtime/AndroidRuntime.h>
-#include "android_view_Surface.h"
+#include <android_runtime/android_view_Surface.h>
 #include <utils/misc.h>
 
 
diff --git a/core/jni/com_google_android_gles_jni_EGLImpl.cpp b/core/jni/com_google_android_gles_jni_EGLImpl.cpp
index 866c038..941ed63 100644
--- a/core/jni/com_google_android_gles_jni_EGLImpl.cpp
+++ b/core/jni/com_google_android_gles_jni_EGLImpl.cpp
@@ -16,6 +16,7 @@
 */
 
 #include <android_runtime/AndroidRuntime.h>
+#include <android_runtime/android_view_Surface.h>
 #include <utils/misc.h>
 
 #include <EGL/egl.h>
@@ -25,8 +26,6 @@
 #include <SkBitmap.h>
 #include <SkPixelRef.h>
 
-#include "android_view_Surface.h"
-
 namespace android {
 
 static jclass gDisplay_class;
diff --git a/core/res/res/drawable-hdpi/cursor_controller.png b/core/res/res/drawable-hdpi/cursor_controller.png
new file mode 100644
index 0000000..720aded
--- /dev/null
+++ b/core/res/res/drawable-hdpi/cursor_controller.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/selection_end_handle.png b/core/res/res/drawable-hdpi/selection_end_handle.png
new file mode 100644
index 0000000..624ab58
--- /dev/null
+++ b/core/res/res/drawable-hdpi/selection_end_handle.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/selection_start_handle.png b/core/res/res/drawable-hdpi/selection_start_handle.png
new file mode 100644
index 0000000..7d6f24c
--- /dev/null
+++ b/core/res/res/drawable-hdpi/selection_start_handle.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_phone_call_bluetooth.png b/core/res/res/drawable-hdpi/stat_sys_phone_call_bluetooth.png
deleted file mode 100644
index 2d13237..0000000
--- a/core/res/res/drawable-hdpi/stat_sys_phone_call_bluetooth.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_phone_call_ringing.png b/core/res/res/drawable-hdpi/stat_sys_phone_call_ringing.png
deleted file mode 100644
index 950713b..0000000
--- a/core/res/res/drawable-hdpi/stat_sys_phone_call_ringing.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_vp_phone_call_bluetooth.png b/core/res/res/drawable-hdpi/stat_sys_vp_phone_call_bluetooth.png
deleted file mode 100644
index 2d13237..0000000
--- a/core/res/res/drawable-hdpi/stat_sys_vp_phone_call_bluetooth.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-mdpi/cursor_controller.png b/core/res/res/drawable-mdpi/cursor_controller.png
new file mode 100644
index 0000000..1a8a459
--- /dev/null
+++ b/core/res/res/drawable-mdpi/cursor_controller.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/selection_end_handle.png b/core/res/res/drawable-mdpi/selection_end_handle.png
new file mode 100644
index 0000000..7e075eb
--- /dev/null
+++ b/core/res/res/drawable-mdpi/selection_end_handle.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/selection_start_handle.png b/core/res/res/drawable-mdpi/selection_start_handle.png
new file mode 100644
index 0000000..d8022f7
--- /dev/null
+++ b/core/res/res/drawable-mdpi/selection_start_handle.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/stat_sys_phone_call_bluetooth.png b/core/res/res/drawable-mdpi/stat_sys_phone_call_bluetooth.png
deleted file mode 100644
index 7abfd19..0000000
--- a/core/res/res/drawable-mdpi/stat_sys_phone_call_bluetooth.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-mdpi/stat_sys_phone_call_ringing.png b/core/res/res/drawable-mdpi/stat_sys_phone_call_ringing.png
deleted file mode 100644
index c44d062..0000000
--- a/core/res/res/drawable-mdpi/stat_sys_phone_call_ringing.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-mdpi/stat_sys_vp_phone_call_bluetooth.png b/core/res/res/drawable-mdpi/stat_sys_vp_phone_call_bluetooth.png
deleted file mode 100644
index 7abfd19..0000000
--- a/core/res/res/drawable-mdpi/stat_sys_vp_phone_call_bluetooth.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xlarge/default_wallpaper.jpg b/core/res/res/drawable-xlarge/default_wallpaper.jpg
new file mode 100644
index 0000000..0302f00
--- /dev/null
+++ b/core/res/res/drawable-xlarge/default_wallpaper.jpg
Binary files differ
diff --git a/core/res/res/layout/list_content.xml b/core/res/res/layout/list_content.xml
index 6f9f1e0..1414032 100644
--- a/core/res/res/layout/list_content.xml
+++ b/core/res/res/layout/list_content.xml
@@ -1,8 +1,6 @@
 <?xml version="1.0" encoding="utf-8"?>
 <!--
-/* //device/apps/common/assets/res/layout/list_content.xml
-**
-** Copyright 2006, The Android Open Source Project
+/* Copyright 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. 
@@ -17,8 +15,42 @@
 ** limitations under the License.
 */
 -->
-<ListView xmlns:android="http://schemas.android.com/apk/res/android" android:id="@android:id/list"
-    android:layout_width="match_parent" 
-    android:layout_height="match_parent"
-    android:drawSelectorOnTop="false"
-    />
+<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent">
+    
+    <LinearLayout android:id="@+id/progressContainer"
+            android:orientation="vertical"
+            android:layout_width="match_parent" 
+            android:layout_height="match_parent"
+            android:visibility="gone"
+            android:gravity="center">
+        
+        <ProgressBar style="?android:attr/progressBarStyleLarge"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content" />
+        <TextView android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:textAppearance="?android:attr/textAppearanceSmall"
+                android:text="@string/loading"
+                android:paddingTop="4dip"
+                android:singleLine="true" />
+            
+    </LinearLayout>
+        
+    <FrameLayout android:id="@+id/listContainer"
+            android:layout_width="match_parent" 
+            android:layout_height="match_parent">
+            
+        <ListView android:id="@android:id/list"
+                android:layout_width="match_parent" 
+                android:layout_height="match_parent"
+                android:drawSelectorOnTop="false" />
+        <TextView android:id="@+android:id/internalEmpty"
+                android:layout_width="match_parent"
+                android:layout_height="match_parent"
+                android:gravity="center"
+                android:textAppearance="?android:attr/textAppearanceLarge" />
+    </FrameLayout>
+        
+</FrameLayout>
diff --git a/core/res/res/layout/list_content_rich.xml b/core/res/res/layout/list_content_rich.xml
deleted file mode 100644
index 1414032..0000000
--- a/core/res/res/layout/list_content_rich.xml
+++ /dev/null
@@ -1,56 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/* Copyright 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.
-*/
--->
-<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
-        android:layout_width="match_parent"
-        android:layout_height="match_parent">
-    
-    <LinearLayout android:id="@+id/progressContainer"
-            android:orientation="vertical"
-            android:layout_width="match_parent" 
-            android:layout_height="match_parent"
-            android:visibility="gone"
-            android:gravity="center">
-        
-        <ProgressBar style="?android:attr/progressBarStyleLarge"
-                android:layout_width="wrap_content"
-                android:layout_height="wrap_content" />
-        <TextView android:layout_width="wrap_content"
-                android:layout_height="wrap_content"
-                android:textAppearance="?android:attr/textAppearanceSmall"
-                android:text="@string/loading"
-                android:paddingTop="4dip"
-                android:singleLine="true" />
-            
-    </LinearLayout>
-        
-    <FrameLayout android:id="@+id/listContainer"
-            android:layout_width="match_parent" 
-            android:layout_height="match_parent">
-            
-        <ListView android:id="@android:id/list"
-                android:layout_width="match_parent" 
-                android:layout_height="match_parent"
-                android:drawSelectorOnTop="false" />
-        <TextView android:id="@+android:id/internalEmpty"
-                android:layout_width="match_parent"
-                android:layout_height="match_parent"
-                android:gravity="center"
-                android:textAppearance="?android:attr/textAppearanceLarge" />
-    </FrameLayout>
-        
-</FrameLayout>
diff --git a/core/res/res/layout/list_content_simple.xml b/core/res/res/layout/list_content_simple.xml
new file mode 100644
index 0000000..6f9f1e0
--- /dev/null
+++ b/core/res/res/layout/list_content_simple.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/* //device/apps/common/assets/res/layout/list_content.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License"); 
+** you may not use this file except in compliance with the License. 
+** You may obtain a copy of the License at 
+**
+**     http://www.apache.org/licenses/LICENSE-2.0 
+**
+** Unless required by applicable law or agreed to in writing, software 
+** distributed under the License is distributed on an "AS IS" BASIS, 
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+** See the License for the specific language governing permissions and 
+** limitations under the License.
+*/
+-->
+<ListView xmlns:android="http://schemas.android.com/apk/res/android" android:id="@android:id/list"
+    android:layout_width="match_parent" 
+    android:layout_height="match_parent"
+    android:drawSelectorOnTop="false"
+    />
diff --git a/core/res/res/values-xlarge/config.xml b/core/res/res/values-xlarge/config.xml
new file mode 100644
index 0000000..2640662
--- /dev/null
+++ b/core/res/res/values-xlarge/config.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+** Copyright 2009, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License"); 
+** you may not use this file except in compliance with the License. 
+** You may obtain a copy of the License at 
+**
+**     http://www.apache.org/licenses/LICENSE-2.0 
+**
+** Unless required by applicable law or agreed to in writing, software 
+** distributed under the License is distributed on an "AS IS" BASIS, 
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+** See the License for the specific language governing permissions and 
+** limitations under the License.
+*/
+-->
+
+<!-- These resources are around just to allow their values to be customized
+     for different hardware and product builds. -->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <!-- Component to be used as the status bar service.  Must implement the IStatusBar
+         interface.  This name is in the ComponentName flattened format (package/class)  -->
+    <string name="config_statusBarComponent">com.android.systemui/com.android.systemui.statusbar.tablet.TabletStatusBarService</string>
+</resources>
+
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index b3f280b..67072b6 100755
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -942,6 +942,21 @@
         <enum name="KEYCODE_PAGE_DOWN" value="93" />
         <enum name="KEYCODE_PICTSYMBOLS" value="94" />
         <enum name="KEYCODE_SWITCH_CHARSET" value="95" />
+        <enum name="KEYCODE_BUTTON_A" value="96" />
+        <enum name="KEYCODE_BUTTON_B" value="97" />
+        <enum name="KEYCODE_BUTTON_C" value="98" />
+        <enum name="KEYCODE_BUTTON_X" value="99" />
+        <enum name="KEYCODE_BUTTON_Y" value="100" />
+        <enum name="KEYCODE_BUTTON_Z" value="101" />
+        <enum name="KEYCODE_BUTTON_L1" value="102" />
+        <enum name="KEYCODE_BUTTON_R1" value="103" />
+        <enum name="KEYCODE_BUTTON_L2" value="104" />
+        <enum name="KEYCODE_BUTTON_R2" value="105" />
+        <enum name="KEYCODE_BUTTON_THUMBL" value="106" />
+        <enum name="KEYCODE_BUTTON_THUMBR" value="107" />
+        <enum name="KEYCODE_BUTTON_START" value="108" />
+        <enum name="KEYCODE_BUTTON_SELECT" value="109" />
+        <enum name="KEYCODE_BUTTON_MODE" value="110" />
     </attr>
 
     <!-- ***************************************************************** -->
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 689f73a..ec0d83c 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -22,7 +22,7 @@
 <resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <!-- Component to be used as the status bar service.  Must implement the IStatusBar
          interface.  This name is in the ComponentName flattened format (package/class)  -->
-    <string name="config_statusBarComponent">com.android.systemui/com.android.systemui.statusbar.StatusBarService</string>
+    <string name="config_statusBarComponent">com.android.systemui/com.android.systemui.statusbar.PhoneStatusBarService</string>
 
     <!-- Do not translate. Defines the slots for the right-hand side icons.  That is to say, the
          icons in the status bar that are not notifications. -->
diff --git a/core/res/res/values/dimens.xml b/core/res/res/values/dimens.xml
index 61e7b88..679e642 100644
--- a/core/res/res/values/dimens.xml
+++ b/core/res/res/values/dimens.xml
@@ -19,9 +19,9 @@
 -->
 <resources>
     <!-- The width that is used when creating thumbnails of applications. -->
-    <dimen name="thumbnail_width">84dp</dimen>
+    <dimen name="thumbnail_width">0dp</dimen>
     <!-- The height that is used when creating thumbnails of applications. -->
-    <dimen name="thumbnail_height">63dp</dimen>
+    <dimen name="thumbnail_height">0dp</dimen>
     <!-- The standard size (both width and height) of an application icon that
          will be displayed in the app launcher and elsewhere. -->
     <dimen name="app_icon_size">48dip</dimen>
@@ -45,4 +45,6 @@
     <dimen name="password_keyboard_key_height">56dip</dimen>
     <!-- Default correction for the space key in the password keyboard -->
     <dimen name="password_keyboard_spacebar_vertical_correction">4dip</dimen>
+    <!-- Distance between the text base line and virtual finger position used to position cursor -->
+    <dimen name="cursor_controller_vertical_offset">12dp</dimen>
 </resources>
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index b9e5e84..d0be554 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -869,8 +869,11 @@
   <public type="drawable" name="stat_sys_download" id="0x01080081" />
   <public type="drawable" name="stat_sys_download_done" id="0x01080082" />
   <public type="drawable" name="stat_sys_headset" id="0x01080083" />
+  <!-- @deprecated Replaced by a private asset in the phone app. -->
   <public type="drawable" name="stat_sys_phone_call" id="0x01080084" />
+  <!-- @deprecated Replaced by a private asset in the phone app. -->
   <public type="drawable" name="stat_sys_phone_call_forward" id="0x01080085" />
+  <!-- @deprecated Replaced by a private asset in the phone app. -->
   <public type="drawable" name="stat_sys_phone_call_on_hold" id="0x01080086" />
   <public type="drawable" name="stat_sys_speakerphone" id="0x01080087" />
   <public type="drawable" name="stat_sys_upload" id="0x01080088" />
@@ -1132,7 +1135,9 @@
   <public type="style" name="Widget.ProgressBar.Large.Inverse" id="0x0103005c" />
   <public type="style" name="Widget.ProgressBar.Small.Inverse" id="0x0103005d" />
 
+  <!-- @deprecated Replaced by a private asset in the phone app. -->
   <public type="drawable" name="stat_sys_vp_phone_call" id="0x010800a7" />
+  <!-- @deprecated Replaced by a private asset in the phone app. -->
   <public type="drawable" name="stat_sys_vp_phone_call_on_hold" id="0x010800a8" />
 
   <public type="anim" name="anticipate_interpolator" id="0x010a0007" />
@@ -1246,6 +1251,7 @@
   <public type="attr" name="logo" id="0x010102be" />
   <public type="attr" name="xlargeScreens" id="0x010102bf" />
   <public type="attr" name="heavyWeight" id="0x010102c0" />
+  <public type="attr" name="immersive" id="0x010102c1" />
   <public-padding type="attr" name="kraken_resource_pad" end="0x01010300" />
 
   <public-padding type="id" name="kraken_resource_pad" end="0x01020040" />
@@ -1309,4 +1315,11 @@
   <public type="style" name="Widget.Spinner.DropDown" />
   <public type="style" name="Widget.ActionButton" />
 
+  <!-- Standard content view for a {@link android.app.ListFragment}.
+       If you are implementing a subclass of ListFragment with your
+       own customized content, you can include this layout in that
+       content to still retain all of the standard functionality of
+       the base class. -->
+  <public type="layout" name="list_content" />
+  
 </resources>
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 289ec32..7a80884 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -1605,7 +1605,7 @@
 
     <!-- Do not translate.  WebView User Agent string -->
     <string name="web_user_agent" translatable="false">Mozilla/5.0 (Linux; U; <xliff:g id="x">Android %s</xliff:g>)
-        AppleWebKit/534.2 (KHTML, like Gecko) Version/4.0 <xliff:g id="mobile">%s</xliff:g>Safari/534.2</string>
+        AppleWebKit/534.3 (KHTML, like Gecko) Version/4.0 <xliff:g id="mobile">%s</xliff:g>Safari/534.3</string>
 
     <!-- Title for a JavaScript dialog. "The page at <url of current page> says:" -->
     <string name="js_dialog_title">The page at \'<xliff:g id="title">%s</xliff:g>\' says:</string>
diff --git a/core/res/res/values/styles.xml b/core/res/res/values/styles.xml
index 449b56c..3c09a89 100644
--- a/core/res/res/values/styles.xml
+++ b/core/res/res/values/styles.xml
@@ -626,7 +626,7 @@
 
     <style name="TextAppearance">
         <item name="android:textColor">?textColorPrimary</item>
-        <item name="android:textColorHighlight">#FFFF9200</item>
+        <item name="android:textColorHighlight">#D077A14B</item>
         <item name="android:textColorHint">?textColorHint</item>
         <item name="android:textColorLink">#5C5CFF</item>
         <item name="android:textSize">16sp</item>
diff --git a/core/tests/coretests/src/android/database/sqlite/SQLiteDatabaseTest.java b/core/tests/coretests/src/android/database/sqlite/SQLiteDatabaseTest.java
index 8006b73..91ef0b7 100644
--- a/core/tests/coretests/src/android/database/sqlite/SQLiteDatabaseTest.java
+++ b/core/tests/coretests/src/android/database/sqlite/SQLiteDatabaseTest.java
@@ -199,7 +199,7 @@
 
     private boolean inXact = false;
     private int numXacts;
-    private static final int TIME_TO_RUN_WAL_TEST_FOR = 15; // num sec this test shoudl run
+    private static final int TIME_TO_RUN_WAL_TEST_FOR = 15; // num sec this test should run
     private int[][] counts = new int[2][2];
 
     private synchronized boolean inXact() {
@@ -279,11 +279,24 @@
         }
     }
 
+    private static class ClassToTestSqlCompilationAndCaching extends SQLiteProgram {
+        private ClassToTestSqlCompilationAndCaching(SQLiteDatabase db, String sql) {
+            super(db, sql);
+        }
+        private static ClassToTestSqlCompilationAndCaching create(SQLiteDatabase db, String sql) {
+            db.lock();
+            try {
+                return new ClassToTestSqlCompilationAndCaching(db, sql);
+            } finally {
+                db.unlock();
+            }
+        }
+    }
+
     @SmallTest
     public void testLruCachingOfSqliteCompiledSqlObjs() {
         mDatabase.disableWriteAheadLogging();
         mDatabase.execSQL("CREATE TABLE test (i int, j int);");
-        mDatabase.execSQL("insert into test values(1,1);");
         // set cache size
         int N = SQLiteDatabase.MAX_SQL_CACHE_SIZE;
         mDatabase.setMaxSqlCacheSize(N);
@@ -292,22 +305,24 @@
         // insertion of (N+1)th entry, make sure 0th entry is closed
         ArrayList<Integer> stmtObjs = new ArrayList<Integer>();
         ArrayList<String> sqlStrings = new ArrayList<String>();
-        SQLiteStatement stmt0 = null;
+        int stmt0 = 0;
         for (int i = 0; i < N+1; i++) {
-            String s = "select * from test where i = " + i + " and j = ?";
+            String s = "insert into test values(" + i + ",?);";
             sqlStrings.add(s);
-            SQLiteStatement c = mDatabase.compileStatement(s);
-            c.bindLong(1, 1);
-            stmtObjs.add(i, c.getSqlStatementId());
+            ClassToTestSqlCompilationAndCaching c =
+                    ClassToTestSqlCompilationAndCaching.create(mDatabase, s);
+            int n = c.getSqlStatementId();
+            stmtObjs.add(i, n);
             if (i == 0) {
-                // save thie SQLiteStatement obj. we want to make sure it is thrown out of
-                // the cache and its handle is 0'ed.
-                stmt0 = c;
+                // save the statementId of this obj. we want to make sure it is thrown out of
+                // the cache at the end of this test.
+                stmt0 = n;
             }
             c.close();
         }
-        // is 0'th entry out of the cache?
-        assertEquals(0, stmt0.getSqlStatementId());
+        // is 0'th entry out of the cache? it should be in the list of statementIds
+        // corresponding to the pre-compiled sql statements to be finalized.
+        assertTrue(mDatabase.getQueuedUpStmtList().contains(stmt0));
         for (int i = 1; i < N+1; i++) {
             SQLiteCompiledSql compSql = mDatabase.getCompiledStatementForSql(sqlStrings.get(i));
             assertNotNull(compSql);
@@ -321,11 +336,7 @@
                 "num1 INTEGER, num2 INTEGER, image BLOB);");
         final String statement = "DELETE FROM test WHERE _id=?;";
         SQLiteStatement statementDoNotClose = mDatabase.compileStatement(statement);
-        // SQl statement is compiled only at find bind or execute call
-        assertTrue(statementDoNotClose.getSqlStatementId() == 0);
         statementDoNotClose.bindLong(1, 1);
-        assertTrue(statementDoNotClose.getSqlStatementId() > 0);
-        int nStatement = statementDoNotClose.getSqlStatementId();
         /* do not close statementDoNotClose object.
          * That should leave it in SQLiteDatabase.mPrograms.
          * mDatabase.close() in tearDown() should release it.
@@ -334,30 +345,31 @@
 
     /**
      * test to make sure the statement finalizations are not done right away but
-     * piggybacked onto the next sql statement execution on the same database.
+     * piggy-backed onto the next sql statement execution on the same database.
      */
     @SmallTest
     public void testStatementClose() {
         mDatabase.execSQL("CREATE TABLE test (i int, j int);");
         // fill up statement cache in mDatabase\
-        int N = 26;
+        int N = SQLiteDatabase.MAX_SQL_CACHE_SIZE;
         mDatabase.setMaxSqlCacheSize(N);
         SQLiteStatement stmt;
         int stmt0Id = 0;
         for (int i = 0; i < N; i ++) {
-            stmt = mDatabase.compileStatement("insert into test values(" + i + ", ?);");
-            stmt.bindLong(1, 1);
+            ClassToTestSqlCompilationAndCaching c =
+                    ClassToTestSqlCompilationAndCaching.create(mDatabase,
+                            "insert into test values(" + i + ", ?);");
             // keep track of 0th entry
             if (i == 0) {
-                stmt0Id = stmt.getSqlStatementId();
+                stmt0Id = c.getSqlStatementId();
             }
-            stmt.executeInsert();
-            stmt.close();
+            c.close();
         }
 
         // add one more to the cache - and the above 'stmt0Id' should fall out of cache
-        SQLiteStatement stmt1 = mDatabase.compileStatement("select * from test where i = ?;");
-        stmt1.bindLong(1, 1);
+        ClassToTestSqlCompilationAndCaching stmt1 =
+                ClassToTestSqlCompilationAndCaching.create(mDatabase,
+                        "insert into test values(100, ?);");
         stmt1.close();
 
         // the above close() should have queuedUp the statement for finalization
@@ -372,7 +384,7 @@
 
     /**
      * same as above - except that the statement to be finalized is from Thread # 1.
-     * and it is eventually finalized in Thread # 2 when it executes a sql statement.
+     * and it is eventually finalized in Thread # 2 when it executes a SQL statement.
      * @throws InterruptedException
      */
     @LargeTest
@@ -381,18 +393,18 @@
         // fill up statement cache in mDatabase in a thread
         Thread t1 = new Thread() {
             @Override public void run() {
-                int N = 26;
+                int N = SQLiteDatabase.MAX_SQL_CACHE_SIZE;
                 mDatabase.setMaxSqlCacheSize(N);
                 SQLiteStatement stmt;
                 for (int i = 0; i < N; i ++) {
-                    stmt = mDatabase.compileStatement("insert into test values(" + i + ", ?);");
-                    stmt.bindLong(1,1);
+                    ClassToTestSqlCompilationAndCaching c =
+                        ClassToTestSqlCompilationAndCaching.create(mDatabase,
+                                "insert into test values(" + i + ", ?);");
                     // keep track of 0th entry
                     if (i == 0) {
-                        setStmt0Id(stmt.getSqlStatementId());
+                        stmt0Id = c.getSqlStatementId();
                     }
-                    stmt.executeInsert();
-                    stmt.close();
+                    c.close();
                 }
             }
         };
@@ -404,9 +416,9 @@
         // just for the heck of it, do it in a separate thread
         Thread t2 = new Thread() {
             @Override public void run() {
-                SQLiteStatement stmt1 = mDatabase.compileStatement(
-                        "select * from test where i = ?;");
-                stmt1.bindLong(1, 1);
+                ClassToTestSqlCompilationAndCaching stmt1 =
+                        ClassToTestSqlCompilationAndCaching.create(mDatabase,
+                                "insert into test values(100, ?);");
                 stmt1.close();
             }
         };
@@ -452,18 +464,18 @@
         // fill up statement cache in mDatabase in a thread
         Thread t1 = new Thread() {
             @Override public void run() {
-                int N = 26;
+                int N = SQLiteDatabase.MAX_SQL_CACHE_SIZE;
                 mDatabase.setMaxSqlCacheSize(N);
                 SQLiteStatement stmt;
                 for (int i = 0; i < N; i ++) {
-                    stmt = mDatabase.compileStatement("insert into test values(" + i + ", ?);");
-                    stmt.bindLong(1, 1);
+                    ClassToTestSqlCompilationAndCaching c =
+                            ClassToTestSqlCompilationAndCaching.create(mDatabase,
+                                    "insert into test values(" + i + ", ?);");
                     // keep track of 0th entry
                     if (i == 0) {
-                        setStmt0Id(stmt.getSqlStatementId());
+                        stmt0Id = c.getSqlStatementId();
                     }
-                    stmt.executeInsert();
-                    stmt.close();
+                    c.close();
                 }
             }
         };
@@ -475,8 +487,9 @@
         // just for the heck of it, do it in a separate thread
         Thread t2 = new Thread() {
             @Override public void run() {
-                SQLiteStatement stmt1 = mDatabase.compileStatement(
-                        "select * from test where i = ?;");
+                ClassToTestSqlCompilationAndCaching stmt1 =
+                        ClassToTestSqlCompilationAndCaching.create(mDatabase,
+                                "insert into test values(100, ?);");
                 stmt1.bindLong(1, 1);
                 stmt1.close();
             }
diff --git a/core/tests/coretests/src/android/database/sqlite/SQLiteStatementTest.java b/core/tests/coretests/src/android/database/sqlite/SQLiteStatementTest.java
index eb27551..217545f 100644
--- a/core/tests/coretests/src/android/database/sqlite/SQLiteStatementTest.java
+++ b/core/tests/coretests/src/android/database/sqlite/SQLiteStatementTest.java
@@ -158,14 +158,16 @@
         assertEquals(0, stmt.getSqlStatementId());
         int colValue = new Random().nextInt();
         stmt.bindLong(1, colValue);
-        // verify that the sql statement is now compiled
-        int n = stmt.nStatement;
-        assertTrue(n > 0);
-        assertEquals(n, stmt.getSqlStatementId());
+        // verify that the sql statement is still not compiled
+        assertEquals(0, stmt.getSqlStatementId());
         // should still be using the mDatabase connection - verify
         assertEquals(mDatabase.mNativeHandle, stmt.nHandle);
+        assertEquals(mDatabase, stmt.mDatabase);
         stmt.bindString(2, "blah" + colValue);
-        assertEquals(n, stmt.nStatement);
+        // verify that the sql statement is still not compiled
+        assertEquals(0, stmt.getSqlStatementId());
+        assertEquals(mDatabase.mNativeHandle, stmt.nHandle);
+        assertEquals(mDatabase, stmt.mDatabase);
         stmt.executeInsert();
         // now that the statement is executed, pre-compiled statement should be released
         assertEquals(0, stmt.nStatement);
@@ -187,97 +189,25 @@
         assertEquals(mDatabase.mNativeHandle, stmt.nHandle);
         assertEquals(mDatabase, stmt.mDatabase);
         stmt.bindString(1, "blah" + colValue);
-        // verify that the sql statement is now compiled
-        n = stmt.nStatement;
-        assertTrue(n > 0);
-        assertEquals(n, stmt.getSqlStatementId());
-        SQLiteDatabase dbUsed = mDatabase;
-        if (wal) {
-            // if wal is set, should be using a pooled connection handle
-            dbUsed = mDatabase.mConnectionPool.getConnectionList().get(0);
-            assertTrue(mDatabase.mNativeHandle != dbUsed.mNativeHandle);
-        }
-        assertEquals(dbUsed.mNativeHandle, stmt.nHandle);
-        assertEquals(dbUsed, stmt.mDatabase);
+        // verify that the sql statement is still not compiled
+        assertEquals(0, stmt.nStatement);
+        assertEquals(0, stmt.getSqlStatementId());
+        assertEquals(mDatabase.mNativeHandle, stmt.nHandle);
+        assertEquals(mDatabase, stmt.mDatabase);
         // execute the statement
         Long l = stmt.simpleQueryForLong();
         assertEquals(colValue, l.intValue());
         // now that the statement is executed, pre-compiled statement should be released
         assertEquals(0, stmt.nStatement);
         assertEquals(0, stmt.getSqlStatementId());
-        // but the database handle should still remain attached to the statement
-        assertEquals(dbUsed.mNativeHandle, stmt.nHandle);
-        assertEquals(dbUsed, stmt.mDatabase);
+        assertEquals(mDatabase.mNativeHandle, stmt.nHandle);
+        assertEquals(mDatabase, stmt.mDatabase);
         stmt.close();
         // pre-compiled SQL statement should still remain released from this object
         assertEquals(0, stmt.nStatement);
         assertEquals(0, stmt.getSqlStatementId());
         // but the database handle should still remain attached to the statement
-        assertEquals(dbUsed, stmt.mDatabase);
-    }
-
-    /**
-     * test to make sure SqliteStatement.nStatement is populated only during bind and execute calls.
-     */
-    public void testGetSqlStatementId() {
-        mDatabase.execSQL("CREATE TABLE test (_id INTEGER PRIMARY KEY, text1 TEXT, text2 TEXT, " +
-                "num1 INTEGER, num2 INTEGER, image BLOB);");
-        final String statement = "DELETE FROM test WHERE _id=?;";
-        SQLiteStatement statementOne = mDatabase.compileStatement(statement);
-        // sql statement is NOT compiled until the bind or execute call.
-        statementOne.bindLong(1, 1);
-        SQLiteStatement statementTwo = mDatabase.compileStatement(statement);
-        statementTwo.bindLong(1, 1);
-        // since the same compiled statement is being accessed at the same time by 2 different
-        // objects, they each get their own statement id
-        assertTrue(statementOne.getSqlStatementId() != statementTwo.getSqlStatementId());
-        statementOne.close();
-        statementTwo.close();
-
-        // two SQLiteStatements referring to the same SQL statement should refer to the same
-        // pre-compiled SQl statement id if the SQLiteStatement objects are NOT in use at the same
-        // time
-        statementOne = mDatabase.compileStatement(statement);
-        statementOne.bindLong(1, 1);
-        // now that the SQL statement is compiled, get its pre-compiled SQL statement id
-        int n = statementOne.getSqlStatementId();
-        statementOne.close();
-        statementTwo = mDatabase.compileStatement(statement);
-        statementTwo.bindLong(1, 2); // use different value for bindarg, just for the heck of it
-        assertEquals(n, statementTwo.getSqlStatementId());
-        statementTwo.close();
-
-        // now try to compile 2 different statements and they should have different uniquerIds.
-        SQLiteStatement statement1 = mDatabase.compileStatement("DELETE FROM test WHERE _id > ?;");
-        statement1.bindLong(1, 1);
-        SQLiteStatement statement2 = mDatabase.compileStatement("DELETE FROM test WHERE _id < ?;");
-        statement2.bindLong(1, 11);
-        assertTrue(statement1.getSqlStatementId() != statement2.getSqlStatementId());
-        statement1.close();
-        statement2.close();
-    }
-
-    public void testOnAllReferencesReleased() {
-        mDatabase.execSQL("CREATE TABLE test (_id INTEGER PRIMARY KEY, text1 TEXT, text2 TEXT, " +
-                "num1 INTEGER, num2 INTEGER, image BLOB);");
-        final String statement = "DELETE FROM test WHERE _id=?;";
-        SQLiteStatement statementOne = mDatabase.compileStatement(statement);
-        statementOne.bindLong(1, 1);
-        assertTrue(statementOne.getSqlStatementId() > 0);
-        statementOne.releaseReference();
-        assertEquals(0, statementOne.getSqlStatementId());
-        statementOne.close();
-    }
-
-    public void testOnAllReferencesReleasedFromContainer() {
-        mDatabase.execSQL("CREATE TABLE test (_id INTEGER PRIMARY KEY, text1 TEXT, text2 TEXT, " +
-                "num1 INTEGER, num2 INTEGER, image BLOB);");
-        final String statement = "DELETE FROM test WHERE _id=?;";
-        SQLiteStatement statementOne = mDatabase.compileStatement(statement);
-        statementOne.bindLong(1, 1);
-        assertTrue(statementOne.getSqlStatementId() > 0);
-        statementOne.releaseReferenceFromContainer();
-        assertEquals(0, statementOne.getSqlStatementId());
-        statementOne.close();
+        assertEquals(mDatabase.mNativeHandle, stmt.nHandle);
+        assertEquals(mDatabase, stmt.mDatabase);
     }
 }
diff --git a/docs/html/community/index.jd b/docs/html/community/index.jd
index 3e69de4..23203c1 100644
--- a/docs/html/community/index.jd
+++ b/docs/html/community/index.jd
@@ -4,10 +4,10 @@
 
 	<div id="mainBodyFluid">
 <h1>Community</h1>
-<p>Welcome to the Android developers community! We're glad you're here and invite you to participate in these discussions. Before posting, please read the <a href="http://source.android.com/discuss/android-discussion-groups-charter">Groups Charter</a> that covers the community guidelines.</p>
+<p>Welcome to the Android developers community! We're glad you're here and invite you to participate in these discussions. Before posting, please read the <a href="http://source.android.com/community/groups-charter.html">Groups Charter</a> that covers the community guidelines.</p>
 
 <p class="note"><strong>Note:</strong> If you are seeking discussion about Android source code (not application development),
-then please refer to the <a href="http://source.android.com/discuss">Open Source Project Mailing lists</a>.</p>
+then please refer to the <a href="http://source.android.com/community">Open Source Project Mailing lists</a>.</p>
 
 <p style="margin-bottom:.5em"><strong>Contents</strong></p>
 <ol class="toc">
@@ -31,7 +31,7 @@
 As you write your post, please do the following:
 <ol>
 <li><b>Read
-the <a href="http://sites.google.com/a/android.com/opensource/discuss/android-discussion-groups-charter">mailing list charter</a></b> that covers the community guidelines. 
+the <a href="http://source.android.com/community/groups-charter.html">mailing list charter</a></b> that covers the community guidelines. 
 </li>
 <li><b>Select the most appropriate mailing list for your question</b>. There are several different lists for 
 developers, described below.</li>
diff --git a/docs/html/guide/topics/resources/available-resources.jd b/docs/html/guide/topics/resources/available-resources.jd
index 09c55a5..19babee 100644
--- a/docs/html/guide/topics/resources/available-resources.jd
+++ b/docs/html/guide/topics/resources/available-resources.jd
@@ -18,23 +18,6 @@
 
 <p>Here's a brief summary of each resource type:</p>
 
-<div class="sidebox-wrapper">
-<div class="sidebox">
-<h2>{@code R.id} Is Not a Resource</h2>
-
-<p>You will often use an {@code R.id} integer to handle {@link android.view.View} objects in
-your UI. Although the {@code id} is a subclass of the {@code R} class, it is not considered a
-"resource" because it is not a reference to an externalized application resource. The {@code id}
-is simply a unique identifier that allows you to handle elements in your UI by instantiating
-objects with {@link android.app.Activity#findViewById(int) findViewById()}.</p>
-
-<p>For information about using {@code R.id} with your UI, see <a
-href="{@docRoot}guide/topics/ui/declaring-layout.html#attributes">Declaring Layout</a>.</p>
-
-</div>
-</div>
-
-
 <dl>
   <dt><a href="{@docRoot}guide/topics/resources/animation-resource.html">Animation Resources</a></dt>
     <dd>Define pre-determined animations.<br/>
diff --git a/docs/html/guide/topics/resources/drawable-resource.jd b/docs/html/guide/topics/resources/drawable-resource.jd
index d8de16a..1e4cca7 100644
--- a/docs/html/guide/topics/resources/drawable-resource.jd
+++ b/docs/html/guide/topics/resources/drawable-resource.jd
@@ -18,32 +18,50 @@
 <dl>
   <dt><a href="#Bitmap">Bitmap File</a><dt>
     <dd>A bitmap graphic file ({@code .png}, {@code .jpg}, or {@code .gif}).
-      A {@link android.graphics.drawable.BitmapDrawable}.</dd>
+      Creates a {@link android.graphics.drawable.BitmapDrawable}.</dd>
   <dt><a href="#NinePatch">Nine-Patch File</a></dt>
     <dd>A PNG file with stretchable regions to allow image resizing based on content ({@code
-.9.png}). A {@link android.graphics.drawable.NinePatchDrawable}.</dd>
-<!--  <dt><a href="#BitmapAlias">Bitmap Alias</a><dt>
-    <dd>An alias for a drawable.</dd>  -->
+.9.png}). Creates a {@link android.graphics.drawable.NinePatchDrawable}.</dd>
+  <dt><a href="#LayerList">Layer List</a></dt>
+    <dd>A Drawable that manages an array of other Drawables. These are drawn in array order, so the
+element with the largest index is be drawn on top. Creates a {@link
+android.graphics.drawable.LayerDrawable}.</dd>
   <dt><a href="#StateList">State List</a></dt>
     <dd>An XML file that references different bitmap graphics
     for different states (for example, to use a different image when a button is pressed).
-    A {@link android.graphics.drawable.StateListDrawable}.</dd>
-  <dt><a href="#Color">Color</a></dt>
-    <dd>A resource defined in XML that specifies a rectangle of color, with
-    optionally rounded corners. A {@link android.graphics.drawable.PaintDrawable}.</dd>
-  <dt><a href="#Shape">Shape</a></dt>
+    Creates a {@link android.graphics.drawable.StateListDrawable}.</dd>
+  <dt><a href="#LevelList">Level List</a></dt>
+    <dd>An XML file that defines a Drawable that manages a number of alternate Drawables, each
+assigned a maximum numerical value. Creates a {@link
+android.graphics.drawable.LevelListDrawable}.</dd>
+  <dt><a href="#Transition">Transition Drawable</a></dt>
+    <dd>An XML file that defines a Drawable that can cross-fade between two drawable resources.
+Creates a {@link android.graphics.drawable.TransitionDrawable}.</dd>
+  <dt><a href="#Clip">Clip Drawable</a></dt>
+    <dd>An XML file that defines a drawable that clips another Drawable based on this Drawable's
+current level value. Creates a {@link android.graphics.drawable.ClipDrawable}.</dd>
+  <dt><a href="#Scale">Scale Drawable</a></dt>
+    <dd>An XML file that defines a drawable that changes the size of another Drawable based on its
+current level value.  Creates a {@link android.graphics.drawable.ScaleDrawable}</dd>
+  <dt><a href="#Shape">Shape Drawable</a></dt>
     <dd>An XML file that defines a geometric shape, including colors and gradients.
-    A {@link android.graphics.drawable.ShapeDrawable}.</dd>
+    Creates a {@link android.graphics.drawable.ShapeDrawable}.</dd>
 </dl>
 
-<p>Documentation for the {@link android.graphics.drawable.AnimationDrawable} resource
-is in the <a href="animation-resource.html">Animation Resource</a> document.</p>
+<p>Also see the <a href="animation-resource.html">Animation Resource</a> document for how to
+create an {@link android.graphics.drawable.AnimationDrawable}.</p>
 
-<h2 id="Bitmap">Bitmap File</h2>
 
-<p>A basic bitmap image. Android supports basic bitmap files in a few different formats:
+
+
+<h2 id="Bitmap">Bitmap</h2>
+
+<p>A bitmap image. Android supports bitmap files in a three formats:
 {@code .png} (preferred), {@code .jpg} (acceptable), {@code .gif} (discouraged).</p>
 
+<p>You can reference a bitmap file directly, using the filename as the resource ID, or create an
+alias resource ID in XML.</p>
+
 <p class="note"><strong>Note:</strong> Bitmap files may be automatically optimized with lossless
 image compression by the <a href="{@docRoot}guide/developing/tools/aapt.html">aapt</a> tool. For
 example, a true-color PNG that does not require more than 256 colors may be converted to an 8-bit
@@ -52,11 +70,18 @@
 you plan on reading an image as a bit stream in order to convert it to a bitmap, put your images in
 the <code>res/raw/</code> folder instead, where they will not be optimized.</p>
 
+
+<h3 id="BitmapFile">Bitmap File</h3>
+
+<p>A bitmap file is a {@code .png}, {@code .jpg}, or {@code .gif} file. Android creates a {@link
+android.graphics.drawable.Drawable}
+resource for any of these files when you save them in the {@code res/drawable/} directory.</p>
+
 <dl class="xml">
 
 <dt>file location:</dt>
 <dd><code>res/drawable/<em>filename</em>.png</code> ({@code .png}, {@code .jpg}, or {@code .gif})<br/>
-The filename will be used as the resource ID.</dd>
+The filename is used as the resource ID.</dd>
 
 <dt>compiled resource datatype:</dt>
 <dd>Resource pointer to a {@link android.graphics.drawable.BitmapDrawable}.</dd>
@@ -68,15 +93,16 @@
 </dd>
 
 <dt>example:</dt>
-<dd>With an image saved at <code>res/drawable/myimage.png</code>, this layout XML will apply
+
+<dd>With an image saved at <code>res/drawable/myimage.png</code>, this layout XML applies
 the image to a View:
 <pre>
 &lt;ImageView
     android:layout_height="wrap_content"
     android:layout_width="wrap_content"
-    <strong>android:src="@drawable/myimage"</strong> />
+    android:src="@drawable/myimage" />
 </pre>
-<p>This application code will retrieve the image as a {@link
+<p>The following application code retrieves the image as a {@link
 android.graphics.drawable.Drawable}:</p>
 <pre>
 Resources res = {@link android.content.Context#getResources()};
@@ -97,50 +123,218 @@
 
 
 
+<h3 id="XmlBitmap">XML Bitmap</h3>
+
+<p>An XML bitmap is a resource defined in XML that points to a bitmap file. The effect is an alias for a
+raw bitmap file. The XML can specify additional properties for the bitmap such as dithering and tiling.</p>
+
+<p class="note"><strong>Note:</strong> You can use a {@code &lt;bitmap&gt;} element as a child of
+an {@code &lt;item&gt;} element. For
+example, when creating a <a href="#StateList">state list</a> or <a href="#LayerList">layer list</a>,
+you can exclude the {@code android:drawable}
+attribute from an {@code &lt;item&gt;} element and nest a {@code &lt;bitmap&gt;} inside it
+that defines the drawable item.</p>
+
+<dl class="xml">
+
+<dt>file location:</dt>
+<dd><code>res/drawable/<em>filename</em>.xml</code><br/>
+The filename is used as the resource ID.</dd>
+
+<dt>compiled resource datatype:</dt>
+<dd>Resource pointer to a {@link android.graphics.drawable.BitmapDrawable}.</dd>
+
+<dt>resource reference:</dt>
+<dd>
+In Java: <code>R.drawable.<em>filename</em></code></li><br/>
+In XML: <code>@[<em>package</em>:]drawable/<em>filename</em></code>
+</dd>
+
+<dt>syntax:</dt>
+<dd>
+<pre class="stx">
+&lt;?xml version="1.0" encoding="utf-8"?&gt;
+&lt;<a href="#bitmap-element">bitmap</a>
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:src="@[package:]drawable/<em>drawable_resource</em>"
+    android:antialias=["true" | "false"]
+    android:dither=["true" | "false"]
+    android:filter=["true" | "false"]
+    android:gravity=["top" | "bottom" | "left" | "right" | "center_vertical" |
+                      "fill_vertical" | "center_horizontal" | "fill_horizontal" |
+                      "center" | "fill" | "clip_vertical" | "clip_horizontal"]
+    android:tileMode=["disabled" | "clamp" | "repeat" | "mirror"] /&gt;
+</pre>
+</dd>
+
+
+<dt>elements:</dt>
+<dd>
+<dl class="tag-list">
+
+  <dt id="bitmap-element"><code>&lt;bitmap&gt;</code></dt>
+    <dd>Defines the bitmap source and its properties.
+      <p class="caps">attributes:</p>
+      <dl class="atn-list">
+        <dt><code>xmlns:android</code></dt>
+          <dd><em>String</em>. Defines the XML namespace, which must be
+          <code>"http://schemas.android.com/apk/res/android"</code>. This is required only if the
+<code>&lt;bitmap&gt;</code> is the root element&mdash;it is not needed when the
+<code>&lt;bitmap&gt;</code> is nested inside an <code>&lt;item&gt;</code>.</dd>
+        <dt><code>android:src</code></dt>
+          <dd><em>Drawable resource</em>. <strong>Required</strong>. Reference to a drawable
+resource.</dd>
+        <dt><code>android:antialias</code></dt>
+          <dd><em>Boolean</em>. Enables or disables antialiasing.</dd>
+        <dt><code>android:dither</code></dt>
+          <dd><em>Boolean</em>. Enables or disables dithering of the bitmap if the bitmap does not
+have the same pixel configuration as the screen (for instance: a ARGB 8888 bitmap with an RGB 565
+screen).</dd>
+        <dt><code>android:filter</code></dt>
+          <dd><em>Boolean</em>. Enables or disables bitmap filtering. Filtering is used when the
+bitmap is shrunk or stretched to smooth its apperance.</dd>
+        <dt><code>android:gravity</code></dt>
+          <dd><em>Keyword</em>. Defines the gravity for the bitmap. The gravity indicates where to
+position the drawable in its container if the bitmap is smaller than the container.
+            <p>Must be one or more (separated by '|') of the following constant values:</p>
+<table>
+<tr><th>Value</th><th>Description</th></tr>
+<tr><td><code>top</code></td>
+<td>Put the object at the top of its container, not changing its size.</td></tr>
+<tr><td><code>bottom</code></td>
+<td>Put the object at the bottom of its container, not changing its size. </td></tr>
+<tr><td><code>left</code></td>
+<td>Put the object at the left edge of its container, not changing its size. </td></tr>
+<tr><td><code>right</code></td>
+<td>Put the object at the right edge of its container, not changing its size. </td></tr>
+<tr><td><code>center_vertical</code></td>
+<td>Place object in the vertical center of its container, not changing its size. </td></tr>
+<tr><td><code>fill_vertical</code></td>
+<td>Grow the vertical size of the object if needed so it completely fills its container. </td></tr>
+<tr><td><code>center_horizontal</code></td>
+<td>Place object in the horizontal center of its container, not changing its size. </td></tr>
+<tr><td><code>fill_horizontal</code></td>
+<td>Grow the horizontal size of the object if needed so it completely fills its container.
+</td></tr>
+<tr><td><code>center</code></td>
+<td>Place the object in the center of its container in both the vertical and horizontal axis, not
+changing its size. </td></tr>
+<tr><td><code>fill</code></td>
+<td>Grow the horizontal and vertical size of the object if needed so it completely fills its
+container. This is the default.</td></tr>
+<tr><td><code>clip_vertical</code></td>
+<td>Additional option that can be set to have the top and/or bottom edges of the child clipped to
+its container's bounds. The clip is based on the vertical gravity: a top gravity clips the
+bottom edge, a bottom gravity clips the top edge, and neither clips both edges.
+</td></tr>
+<tr><td><code>clip_horizontal</code></td>
+<td>Additional option that can be set to have the left and/or right edges of the child clipped to
+its container's bounds. The clip is based on the horizontal gravity: a left gravity clips
+the right edge, a right gravity clips the left edge, and neither clips both edges.
+</td></tr>
+</table>
+          </dd>
+        <dt><code>android:tileMode</code></dt>
+          <dd><em>Keyword</em>. Defines the tile mode. When the tile mode is enabled, the bitmap is
+repeated. Gravity is ignored when the tile mode is enabled.
+            <p>Must be one of the following constant values:</p>
+<table>
+<tr><th>Value</th><th>Description</th></tr>
+<tr><td><code>disabled</code></td>
+<td>Do not tile the bitmap. This is the default value.</td></tr>
+<tr><td><code>clamp</code></td>
+<td>Replicates the edge color if the shader draws outside of its original bounds</td></tr>
+<tr><td><code>repeat</code></td>
+<td>Repeats the shader's image horizontally and vertically.</td></tr>
+<tr><td><code>mirror</code></td>
+<td>Repeats the shader's image horizontally and vertically, alternating mirror images so that
+adjacent images always seam.</td></tr>
+</table>
+
+          </dd>
+      </dl>
+    </dd>
+
+</dl>
+</dd> <!-- end  elements and attributes -->
+
+<dt>example:</dt>
+<dd>
+<pre>
+&lt;?xml version="1.0" encoding="utf-8"?&gt;
+&lt;bitmap xmlns:android="http://schemas.android.com/apk/res/android"
+    android:src="@drawable/icon"
+    android:tileMode="repeat" /&gt;
+</pre>
+
+</dd>
+
+<dt>see also:</dt>
+<dd>
+<ul>
+  <li>{@link android.graphics.drawable.BitmapDrawable}</li>
+  <li><a href="{@docRoot}guide/topics/resources/providing-resources.html#AliasResources">Creating
+alias resources</a>
+</ul>
+</dd>
+
+</dl>
 
 
 
-<h2 id="NinePatch">Nine-Patch File</h2>
+
+
+
+<h2 id="NinePatch">Nine-Patch</h2>
 
 <p>A {@link android.graphics.NinePatch} is a PNG image in which you can define stretchable regions
-that Android will scale when content within the View exceeds the normal image bounds. You will
+that Android scales when content within the View exceeds the normal image bounds. You
 typically assign this type of image as the background of a View that has at least one dimension set
 to {@code "wrap_content"}, and when the View grows to accomodate the content, the Nine-Patch image
-will also be scaled to match the size of the View. An example use of a Nine-Patch image is the
+is also scaled to match the size of the View. An example use of a Nine-Patch image is the
 background used by Android's standard {@link android.widget.Button} widget, which must stretch to
 accommodate the text (or image) inside the button.</p>
 
-<p>For a complete discussion about how to define a Nine-Patch file with stretchable regions,
+<p>Same as with a normal <a href="#Bitmap">bitmap</a>, you can reference a Nine-Patch file directly
+or from a resource defined by XML.</p>
+
+<p>For a complete discussion about how to create a Nine-Patch file with stretchable regions,
 see the <a href="{@docRoot}guide/topics/graphics/2d-graphics.html#nine-patch">2D Graphics</a>
 document.</p>
 
+
+<h3 id="NinePatchFile">Nine-Patch File</h3>
+
 <dl class="xml">
 
 <dt>file location:</dt>
 <dd><code>res/drawable/<em>filename</em>.9.png</code><br/>
-The filename will be used as the resource ID.</dd>
+The filename is used as the resource ID.</dd>
 
 <dt>compiled resource datatype:</dt>
 <dd>Resource pointer to a {@link android.graphics.drawable.NinePatchDrawable}.</dd>
 
 <dt>resource reference:</dt>
+
 <dd>
 In Java: <code>R.drawable.<em>filename</em></code><br/>
 In XML: <code>@[<em>package</em>:]drawable/<em>filename</em></code>
 </dd>
 
 <dt>example:</dt>
-<dd>With an image saved at <code>res/drawable/myninepatch.9.png</code>, this layout XML will
-apply the Nine-Patch to a View:
+
+<dd>With an image saved at <code>res/drawable/myninepatch.9.png</code>, this layout XML
+applies the Nine-Patch to a View:
 <pre>
 &lt;Button
     android:layout_height="wrap_content"
     android:layout_width="wrap_content"
-    <strong>android:background="@drawable/myninepatch"</strong> />
+    android:background="@drawable/myninepatch" />
 </pre>
 </dd>
 
 <dt>see also:</dt>
+
 <dd>
 <ul>
   <li><a href="{@docRoot}guide/topics/graphics/2d-graphics.html#nine-patch">2D Graphics</a></li>
@@ -153,6 +347,238 @@
 
 
 
+<h3 id="NinePatchXml">XML Nine-Patch</h3>
+
+<p>An XML Nine-Patch is a resource defined in XML that points to a Nine-Patch file. The XML can
+specify dithering for the image.</p>
+
+<dl class="xml">
+
+<dt>file location:</dt>
+<dd><code>res/drawable/<em>filename</em>.xml</code><br/>
+The filename is used as the resource ID.</dd>
+
+<dt>compiled resource datatype:</dt>
+<dd>Resource pointer to a {@link android.graphics.drawable.NinePatchDrawable}.</dd>
+
+<dt>resource reference:</dt>
+
+<dd>
+In Java: <code>R.drawable.<em>filename</em></code><br/>
+In XML: <code>@[<em>package</em>:]drawable/<em>filename</em></code>
+</dd>
+
+
+<dt>syntax:</dt>
+
+<dd>
+<pre class="stx">
+&lt;?xml version="1.0" encoding="utf-8"?&gt;
+&lt;<a href="#bitmap-element">nine-patch</a>
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:src="@[package:]drawable/<em>drawable_resource</em>"
+    android:dither=["true" | "false"] /&gt;
+</pre>
+</dd>
+
+
+<dt>elements:</dt>
+
+<dd>
+<dl class="tag-list">
+
+  <dt id="layerlist-element"><code>&lt;bitmap&gt;</code></dt>
+    <dd>Defines the bitmap source and its properties.
+      <p class="caps">attributes:</p>
+      <dl class="atn-list">
+        <dt><code>xmlns:android</code></dt>
+          <dd><em>String</em>. <strong>Required.</strong> Defines the XML namespace, which must be
+          <code>"http://schemas.android.com/apk/res/android"</code>.
+        <dt><code>android:src</code></dt>
+          <dd><em>Drawable resource</em>. <strong>Required</strong>. Reference to a Nine-Patch
+file.</dd>
+        <dt><code>android:dither</code></dt>
+          <dd><em>Boolean</em>. Enables or disables dithering of the bitmap if the bitmap does not
+have the same pixel configuration as the screen (for instance: a ARGB 8888 bitmap with an RGB 565
+screen).</dd>
+      </dl>
+    </dd>
+</dl>
+</dd>
+
+
+<dt>example:</dt>
+
+<dd>
+<pre class="stx">
+&lt;?xml version="1.0" encoding="utf-8"?&gt;
+&lt;nine-patch xmlns:android="http://schemas.android.com/apk/res/android"
+    android:src="@drawable/myninepatch"
+    android:dither="false" /&gt;
+</pre>
+</dd>
+</dl>
+
+
+
+
+
+
+<h2 id="LayerList">Layer List</h2>
+
+<p>A {@link android.graphics.drawable.LayerDrawable} is a drawable object
+that manages an array of other drawables. Each drawable in the list is drawn in the order of the 
+list&mdash;the last drawable in the list is drawn on top.</p>
+
+<p>Each drawable is represented by an {@code &lt;item&gt;} element inside a single {@code
+&lt;layer-list&gt;} element.</p>
+
+<dl class="xml">
+
+<dt>file location:</dt>
+<dd><code>res/drawable/<em>filename</em>.xml</code><br/>
+The filename is used as the resource ID.</dd>
+
+<dt>compiled resource datatype:</dt>
+<dd>Resource pointer to a {@link android.graphics.drawable.LayerDrawable}.</dd>
+
+<dt>resource reference:</dt>
+
+<dd>
+In Java: <code>R.drawable.<em>filename</em></code><br/>
+In XML: <code>@[<em>package</em>:]drawable/<em>filename</em></code>
+</dd>
+
+<dt>syntax:</dt>
+
+<dd>
+<pre class="stx">
+&lt;?xml version="1.0" encoding="utf-8"?>
+&lt;<a href="#layerlist-element">layer-list</a>
+    xmlns:android="http://schemas.android.com/apk/res/android" &gt;
+    &lt;<a href="#layerlist-item-element">item</a>
+        android:drawable="@[package:]drawable/<em>drawable_resource</em>"
+        android:id="@[+][<em>package</em>:]id/<i>resource_name</i>"
+        android:top="<em>dimension</em>"
+        android:right="<em>dimension</em>"
+        android:bottom="<em>dimension</em>"
+        android:left="<em>dimension</em>" /&gt;
+&lt;/selector>
+</pre>
+</dd>
+
+<dt>elements:</dt>
+
+<dd>
+<dl class="tag-list">
+
+  <dt id="layerlist-element"><code>&lt;layer-list&gt;</code></dt>
+    <dd><strong>Required.</strong> This must be the root element. Contains one or more {@code
+&lt;item>} elements.
+      <p class="caps">attributes:</p>
+      <dl class="atn-list">
+        <dt><code>xmlns:android</code></dt>
+          <dd><em>String</em>. <strong>Required.</strong> Defines the XML namespace, which must be
+          <code>"http://schemas.android.com/apk/res/android"</code>.
+      </dl>
+    </dd>
+  <dt id="layerlist-item-element"><code>&lt;item&gt;</code></dt>
+    <dd>Defines a drawable to place in the layer drawable, in a position defined by its attributes.
+Must be a child of a <code>&lt;selector&gt;</code> element. Accepts child {@code &lt;bitmap&gt;}
+elements.
+      <p class="caps">attributes:</p>
+      <dl class="atn-list">
+        <dt><code>android:drawable</code></dt>
+          <dd><em>Drawable resource</em>. <strong>Required</strong>. Reference to a drawable
+resource.</dd>
+        <dt><code>android:id</code></dt>
+          <dd><em>Resource ID</em>. A unique resource ID for this drawable. To create a new resource
+ID for this item, use the form:
+<code>"@+id/<em>name</em>"</code>. The plus symbol indicates that this should be created as a new
+ID. You can use this identifier to
+retrieve and modify the drawable with {@link android.view.View#findViewById(int)
+View.findViewById()} or {@link android.app.Activity#findViewById(int) Activity.findViewById()}.</dd>
+        <dt><code>android:top</code></dt>
+          <dd><em>Integer</em>. The top offset in pixels.</dd>
+        <dt><code>android:right</code></dt>
+          <dd><em>Integer</em>. The right offset in pixels.</dd>
+        <dt><code>android:bottom</code></dt>
+          <dd><em>Integer</em>. The bottom offset in pixels.</dd>
+        <dt><code>android:left</code></dt>
+          <dd><em>Integer</em>. The left offset in pixels.</dd>
+      </dl>
+      <p>All drawable items are scaled to fit the size of the containing View, by default. Thus,
+placing your images in a layer list at different positions might increase the size of the View and
+some images scale as appropriate. To avoid
+scaling items in the list, use a {@code &lt;bitmap&gt;} element inside the {@code
+&lt;item&gt;} element to specify the drawable and define the gravity to something that does not
+scale, such as {@code "center"}. For example, the following {@code &lt;item&gt;} defines an item
+that scales to fit its container View:</p>
+<pre>
+&lt;item android:drawable="@drawable/image" /&gt;
+</pre>
+
+<p>To avoid scaling, the following example uses a {@code &lt;bitmap&gt;} element with centered
+gravity:</p>
+<pre>
+&lt;item&gt;
+  &lt;bitmap android:src="<b>@drawable/image</b>"
+          android:gravity="center" /&gt;
+&lt;/item&gt;
+</pre>
+    </dd>
+
+</dl>
+</dd> <!-- end  elements and attributes -->
+
+<dt>example:</dt>
+
+<dd>XML file saved at <code>res/drawable/layers.xml</code>:
+<pre>
+&lt;?xml version="1.0" encoding="utf-8"?&gt;
+&lt;layer-list xmlns:android="http://schemas.android.com/apk/res/android"&gt;
+    &lt;item&gt;
+      &lt;bitmap android:src="@drawable/android_red"
+        android:gravity="center" /&gt;
+    &lt;/item&gt;
+    &lt;item android:top="10dp" android:left="10dp"&gt;
+      &lt;bitmap android:src="@drawable/android_green"
+        android:gravity="center" /&gt;
+    &lt;/item&gt;
+    &lt;item android:top="20dp" android:left="20dp"&gt;
+      &lt;bitmap android:src="@drawable/android_blue"
+        android:gravity="center" /&gt;
+    &lt;/item&gt;
+&lt;/layer-list&gt;
+</pre>
+<p>Notice that this example uses a nested {@code &lt;bitmap&gt;} element to define the drawable
+resource for each item with a "center" gravity. This ensures that none of the images are scaled to
+fit the size of the container, due to resizing caused by the offset images.</p>
+
+<p>This layout XML applies the drawable to a View:</p>
+<pre>
+&lt;ImageView
+    android:layout_height="wrap_content"
+    android:layout_width="wrap_content"
+    android:src="@drawable/layers" /&gt;
+</pre>
+
+<p>The result is a stack of increasingly offset images:</p>
+<img src="{@docRoot}images/resources/layers.png" alt="" />
+</dd> <!-- end example -->
+
+<dt>see also:</dt>
+<dd>
+<ul>
+  <li>{@link android.graphics.drawable.LayerDrawable}</li>
+</ul>
+</dd>
+
+</dl>
+
+
+
+
 
 
 
@@ -163,33 +589,36 @@
 that uses a several different images to represent the same graphic, depending on the state of
 the object. For example, a {@link
 android.widget.Button} widget can exist in one of several different states (pressed, focused,
-or niether) and, using a state list drawable, you can provide a different button image for each
+or niether) and, using a state list drawable, you can provide a different background image for each
 state.</p>
 
 <p>You can describe the state list in an XML file. Each graphic is represented by an {@code
 &lt;item>} element inside a single {@code &lt;selector>} element. Each {@code &lt;item>}
 uses various attributes to describe the state in which it should be used as the graphic for the
 drawable.</p>
+
 <p>During each state change, the state list is traversed top to bottom and the first item that
-matches the current state will be used&mdash;the selection is <em>not</em> based on the "best
+matches the current state is used&mdash;the selection is <em>not</em> based on the "best
 match," but simply the first item that meets the minimum criteria of the state.</p>
 
 <dl class="xml">
 
 <dt>file location:</dt>
 <dd><code>res/drawable/<em>filename</em>.xml</code><br/>
-The filename will be used as the resource ID.</dd>
+The filename is used as the resource ID.</dd>
 
 <dt>compiled resource datatype:</dt>
 <dd>Resource pointer to a {@link android.graphics.drawable.StateListDrawable}.</dd>
 
 <dt>resource reference:</dt>
+
 <dd>
 In Java: <code>R.drawable.<em>filename</em></code><br/>
 In XML: <code>@[<em>package</em>:]drawable/<em>filename</em></code>
 </dd>
 
 <dt>syntax:</dt>
+
 <dd>
 <pre class="stx">
 &lt;?xml version="1.0" encoding="utf-8"?>
@@ -212,6 +641,7 @@
 </dd>
 
 <dt>elements:</dt>
+
 <dd>
 <dl class="tag-list">
 
@@ -224,8 +654,8 @@
           <dd><em>String</em>. <strong>Required.</strong> Defines the XML namespace, which must be
           <code>"http://schemas.android.com/apk/res/android"</code>.
         <dt><code>android:constantSize</code></dt>
-          <dd><em>Boolean</em>. "true" if the drawable's reported internal size will remain constant as the state
-changes (the size will be the maximum of all of the states); "false" if the size will vary based on
+          <dd><em>Boolean</em>. "true" if the drawable's reported internal size remains constant as the state
+changes (the size is the maximum of all of the states); "false" if the size varies based on
 the current state. Default is false.</dd>
         <dt><code>android:dither</code></dt>
           <dd><em>Boolean</em>. "true" to enable dithering of the bitmap if the bitmap does not have the same pixel
@@ -270,9 +700,9 @@
 application is in the foreground), "false" if this item should be used when the application
 window does not have focus (for example, if the notification shade is pulled down or a dialog appears).</dd>
       </dl>
-      <p class="note"><strong>Note:</strong>Remember that the first item in the state list that
-matches the current state of the object will be applied. So if the first item in the list contains
-none of the state attributes above, then it will be applied every time, which is why your
+      <p class="note"><strong>Note:</strong> Remember that Android applies the first item in the state list that
+matches the current state of the object. So, if the first item in the list contains
+none of the state attributes above, then it is applied every time, which is why your
 default value should always be last (as demonstrated in the following example).</p>
     </dd>
 
@@ -280,6 +710,7 @@
 </dd> <!-- end  elements and attributes -->
 
 <dt>example:</dt>
+
 <dd>XML file saved at <code>res/drawable/button.xml</code>:
 <pre>
 &lt;?xml version="1.0" encoding="utf-8"?>
@@ -292,12 +723,12 @@
 &lt;/selector>
 </pre>
 
-<p>This layout XML will apply the drawable to a View:</p>
+<p>This layout XML applies the drawable to a View:</p>
 <pre>
 &lt;ImageView
     android:layout_height="wrap_content"
     android:layout_width="wrap_content"
-    <strong>android:src="@drawable/button"</strong> />
+    android:src="@drawable/button" />
 </pre>
 </dd> <!-- end example -->
 
@@ -317,106 +748,513 @@
 
 
 
+<h2 id="LevelList">Level List</h2>
 
-
-
-
-
-
-<h2 id="Color">Color</h2>
-
-<p>This is a color defined in XML that's used as a drawable to fill a rectangular space,
-with optionally rounded corners. This kind of drawable behaves like a color fill.</p>
-
-<p class="note"><strong>Note:</strong> A color drawable is a simple resource that is referenced
-using the value provided in the {@code name} attribute (not the name of the XML file). As
-such, you can combine a color drawable resources with other simple resources in the one XML file,
-under one {@code &lt;resources>} element.</p>
-
+<p>A Drawable that manages a number of alternate Drawables, each assigned a maximum numerical
+value. Setting the level value of the drawable with {@link
+android.graphics.drawable.Drawable#setLevel(int) setLevel()} loads the drawable resource in the
+level list that has a {@code android:maxLevel} value greater than or equal to the value
+passed to the method.</p>
 
 <dl class="xml">
 
 <dt>file location:</dt>
-<dd><code>res/drawable/<em>filename</em>.png</code><br/>
-The filename is arbitrary. The element's {@code name} will be used as the resource ID.</dd>
+<dd><code>res/drawable/<em>filename</em>.xml</code><br/>
+The filename is used as the resource ID.</dd>
 
 <dt>compiled resource datatype:</dt>
-<dd>Resource pointer to a {@link android.graphics.drawable.PaintDrawable}.</dd>
+<dd>Resource pointer to a {@link android.graphics.drawable.LevelListDrawable}.</dd>
 
 <dt>resource reference:</dt>
+
 <dd>
-In Java: <code>R.drawable.<em>color_name</em></code><br/>
-In XML: <code>@[<em>package</em>:]drawable/<em>color_name</em></code>
+In Java: <code>R.drawable.<em>filename</em></code><br/>
+In XML: <code>@[<em>package</em>:]drawable/<em>filename</em></code>
 </dd>
 
 <dt>syntax:</dt>
+
 <dd>
 <pre class="stx">
-&lt;?xml version="1.0" encoding="utf-8"?&gt;
-&lt;<a href="#color-resources-element">resources</a>>
-    &lt;<a href="#drawable-element">drawable</a>
-        name="<em>color_name</em>"
-        &gt;<em>color</em>&lt;/drawable&gt;
-&lt;/resources&gt;
+&lt;?xml version="1.0" encoding="utf-8"?>
+&lt;<a href="#levellist-element">level-list</a>
+    xmlns:android="http://schemas.android.com/apk/res/android" &gt;
+    &lt;<a href="#levellist-item-element">item</a>
+        android:drawable="@drawable/<i>drawable_resource</i>"
+        android:maxLevel="<i>integer</i>"
+        android:minLevel="<i>integer</i>" /&gt;
+&lt;/level-list&gt;
 </pre>
 </dd>
 
 <dt>elements:</dt>
+
 <dd>
 <dl class="tag-list">
 
-  <dt id="color-resources-element"><code>&lt;resources&gt;</code></dt>
-    <dd><strong>Required.</strong> This must be the root node.
-      <p>No attributes.</p>
-    </dd>
-  <dt id="drawable-element"><code>&lt;drawable&gt;</code></dt>
-    <dd>A color to use as a drawable rectangle. The value can be
-    any valid hexadecimal color value or a <a href="more-resources.html#Color">color
-    resource</a>. A color value always begins with a pound (#) character, followed
-    by the Alpha-Red-Green-Blue information in one of the following formats:
-    #<em>RGB</em>, #<em>RRGGBB</em>, #<em>ARGB</em>, or #<em>AARRGGBB</em>.
+  <dt id="levellist-element"><code>&lt;level-list&gt;</code></dt>
+  <dd>This must be the root element. Contains one or more {@code &lt;item&gt;} elements.
+    <p class="caps">attributes:</p>
+    <dl class="atn-list">
+      <dt><code>xmlns:android</code></dt>
+        <dd><em>String</em>. <strong>Required.</strong> Defines the XML namespace, which must be
+        <code>"http://schemas.android.com/apk/res/android"</code>.
+    </dl>
+  </dd>
+
+  <dt id="levellist-item-element"><code>&lt;item&gt;</code></dt>
+  <dd>Defines a drawable to use at a certain level.
+    <p class="caps">attributes:</p>
+    <dl class="atn-list">
+      <dt><code>android:drawable</code></dt>
+        <dd><em>Drawable resource</em>. <strong>Required</strong>. Reference to a drawable
+resource to be inset.</dd>
+      <dt><code>android:maxLevel</code></dt>
+        <dd><em>Integer</em>. The maximum level allowed for this item.</dd>
+      <dt><code>android:minLevel</code></dt>
+        <dd><em>Integer</em>. The minimum level allowed for this item.</dd>
+    </dl>
+  </dd>
+</dl>
+
+</dd>
+
+<dt>example:</dt>
+
+<dd>
+
+<pre>
+&lt;?xml version="1.0" encoding="utf-8"?>
+&lt;level-list xmlns:android="http://schemas.android.com/apk/res/android" &gt;
+    &lt;item
+        android:drawable="@drawable/status_off"
+        android:maxLevel="0" /&gt;
+    &lt;item
+        android:drawable="@drawable/status_on"
+        android:maxLevel="1" /&gt;
+&lt;/level-list&gt;
+</pre>
+<p>Once this is applied to a {@link android.view.View}, the level can be changed with {@link
+android.graphics.drawable.Drawable#setLevel(int) setLevel()} or {@link
+android.widget.ImageView#setImageLevel(int) setImageLevel()}.</p>
+
+</dd>
+
+<dt>see also:</dt>
+
+<dd>
+<ul>
+  <li>{@link android.graphics.drawable.LevelListDrawable}</li>
+</ul>
+</dd>
+
+</dl>
+
+
+
+
+
+
+<h2 id="Transition">Transition Drawable</h2>
+
+<p>A {@link android.graphics.drawable.TransitionDrawable} is a drawable object
+that can cross-fade between the two drawable resources.</p>
+
+<p>Each drawable is represented by an {@code &lt;item&gt;} element inside a single {@code
+&lt;transition&gt;} element. No more than two items are supported. To transition forward, call
+{@link android.graphics.drawable.TransitionDrawable#startTransition(int) startTransition()}. To
+transition backward, call {@link android.graphics.drawable.TransitionDrawable#reverseTransition(int)
+reverseTransition()}.</p>
+
+<dl class="xml">
+
+<dt>file location:</dt>
+<dd><code>res/drawable/<em>filename</em>.xml</code><br/>
+The filename is used as the resource ID.</dd>
+
+<dt>compiled resource datatype:</dt>
+<dd>Resource pointer to a {@link android.graphics.drawable.TransitionDrawable}.</dd>
+
+<dt>resource reference:</dt>
+
+<dd>
+In Java: <code>R.drawable.<em>filename</em></code><br/>
+In XML: <code>@[<em>package</em>:]drawable/<em>filename</em></code>
+</dd>
+
+<dt>syntax:</dt>
+
+<dd>
+<pre class="stx">
+&lt;?xml version="1.0" encoding="utf-8"?>
+&lt;<a href="#transition-element">layer-list</a>
+xmlns:android="http://schemas.android.com/apk/res/android" &gt;
+    &lt;<a href="#transition-item-element">item</a>
+        android:drawable="@[package:]drawable/<em>drawable_resource</em>"
+        android:id="@[+][<em>package</em>:]id/<i>resource_name</i>"
+        android:top="<em>dimension</em>"
+        android:right="<em>dimension</em>"
+        android:bottom="<em>dimension</em>"
+        android:left="<em>dimension</em>" /&gt;
+&lt;/selector>
+</pre>
+</dd>
+
+<dt>elements:</dt>
+
+<dd>
+<dl class="tag-list">
+
+  <dt id="transition-element"><code>&lt;transition&gt;</code></dt>
+    <dd><strong>Required.</strong> This must be the root element. Contains one or more {@code
+&lt;item>} elements.
       <p class="caps">attributes:</p>
       <dl class="atn-list">
-        <dt><code>name</code></dt>
-        <dd><em>String</em>. <strong>Required</strong>.
-        A name for the color. This name will be used as the resource ID.</dd>
+        <dt><code>xmlns:android</code></dt>
+          <dd><em>String</em>. <strong>Required.</strong> Defines the XML namespace, which must be
+          <code>"http://schemas.android.com/apk/res/android"</code>.
       </dl>
-
+    </dd>
+  <dt id="transition-item-element"><code>&lt;item&gt;</code></dt>
+    <dd>Defines a drawable to place in the layer drawable, in a position defined by its attributes.
+Must be a child of a <code>&lt;selector&gt;</code> element. Accepts child {@code &lt;bitmap&gt;}
+elements.
+      <p class="caps">attributes:</p>
+      <dl class="atn-list">
+        <dt><code>android:drawable</code></dt>
+          <dd><em>Drawable resource</em>. <strong>Required</strong>. Reference to a drawable
+resource.</dd>
+        <dt><code>android:id</code></dt>
+          <dd><em>Resource ID</em>. A unique resource ID for this drawable. To create a new resource
+ID for this item, use the form:
+<code>"@+id/<em>name</em>"</code>. The plus symbol indicates that this should be created as a new
+ID. You can use this identifier to
+retrieve and modify the drawable with {@link android.view.View#findViewById(int)
+View.findViewById()} or {@link android.app.Activity#findViewById(int) Activity.findViewById()}.</dd>
+        <dt><code>android:top</code></dt>
+          <dd><em>Integer</em>. The top offset in pixels.</dd>
+        <dt><code>android:right</code></dt>
+          <dd><em>Integer</em>. The right offset in pixels.</dd>
+        <dt><code>android:bottom</code></dt>
+          <dd><em>Integer</em>. The bottom offset in pixels.</dd>
+        <dt><code>android:left</code></dt>
+          <dd><em>Integer</em>. The left offset in pixels.</dd>
+      </dl>
     </dd>
 
 </dl>
 </dd> <!-- end  elements and attributes -->
 
 <dt>example:</dt>
-<dd>XML file saved at <code>res/drawable/colors.xml</code>:
-<pre>
-&lt;?xml version="1.0" encoding="utf-8"?>
-&lt;resources>
-    &lt;drawable name="solid_red">#f00&lt;/drawable>
-    &lt;drawable name="solid_blue">#0000ff&lt;/drawable>
-&lt;/resources>
-</pre>
-    <p>This layout XML will apply a color drawable to a View:</p>
-<pre>
-&lt;TextView
-    android:layout_width="fill_parent"
-    android:layout_height="wrap_content"
-    <strong>android:background="@drawable/solid_blue"</strong> />
-</pre>
-    <p>This application code will get a color drawable and apply it to a View:</p>
-<pre>
-Resources res =  {@link android.content.Context#getResources()};
-Drawable redDrawable = res.{@link android.content.res.Resources#getDrawable(int) getDrawable}(R.drawable.solid_red);
 
-TextView tv = (TextView) findViewByID(R.id.text);
-tv.setBackground(redDrawable);
+<dd>XML file saved at <code>res/drawable/transition.xml</code>:
+<pre>
+&lt;?xml version="1.0" encoding="utf-8"?&gt;
+&lt;transition xmlns:android="http://schemas.android.com/apk/res/android"&gt;
+    &lt;item android:drawable="@drawable/on" /&gt;
+    &lt;item android:drawable="@drawable/off" /&gt;
+&lt;/layer-list&gt;
 </pre>
+
+<p>This layout XML applies the drawable to a View:</p>
+<pre>
+&lt;ImageButton
+    android:id="@+id/button"
+    android:layout_height="wrap_content"
+    android:layout_width="wrap_content"
+    android:src="@drawable/transition" /&gt;
+</pre>
+
+<p>And the following code performs a 500ms transition from the first item to the second:</p>
+<pre>
+ImageButton button = (ImageButton) findViewById(R.id.button);
+TransitionDrawable drawable = (TransitionDrawable) button.getDrawable();
+drawable.startTransition(500);
+</pre>
+
 </dd> <!-- end example -->
 
 <dt>see also:</dt>
+
 <dd>
 <ul>
-  <li>{@link android.graphics.drawable.PaintDrawable}</li>
+  <li>{@link android.graphics.drawable.TransitionDrawable}</li>
+</ul>
+</dd>
+
+</dl>
+
+
+
+
+
+
+
+
+<h2 id="Inset">Inset Drawable</h2>
+
+<p>A drawable defined in XML that insets another drawable by a specified distance. This is used when
+a View needs a background that is smaller than the View's actual bounds.</p>
+
+<dl class="xml">
+
+<dt>file location:</dt>
+<dd><code>res/drawable/<em>filename</em>.xml</code><br/>
+The filename is used as the resource ID.</dd>
+
+<dt>compiled resource datatype:</dt>
+<dd>Resource pointer to a {@link android.graphics.drawable.InsetDrawable}.</dd>
+
+<dt>resource reference:</dt>
+
+<dd>
+In Java: <code>R.drawable.<em>filename</em></code><br/>
+In XML: <code>@[<em>package</em>:]drawable/<em>filename</em></code>
+</dd>
+
+<dt>syntax:</dt>
+
+<dd>
+<pre class="stx">
+&lt;?xml version="1.0" encoding="utf-8"?>
+&lt;<a href="#inset-element">inset</a>
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:drawable="@drawable/<i>drawable_resource</i>"
+    android:insetTop="<i>dimension</i>"
+    android:insetRight="<i>dimension</i>"
+    android:insetBottom="<i>dimension</i>"
+    android:insetLeft="<i>dimension</i>" /&gt;
+</pre>
+</dd>
+
+<dt>elements:</dt>
+
+<dd>
+<dl class="tag-list">
+
+  <dt id="inset-element"><code>&lt;inset&gt;</code></dt>
+  <dd>Defines the inset drawable. This must be the root element.
+    <p class="caps">attributes:</p>
+    <dl class="atn-list">
+      <dt><code>xmlns:android</code></dt>
+        <dd><em>String</em>. <strong>Required.</strong> Defines the XML namespace, which must be
+        <code>"http://schemas.android.com/apk/res/android"</code>.
+      <dt><code>android:drawable</code></dt>
+        <dd><em>Drawable resource</em>. <strong>Required</strong>. Reference to a drawable
+resource to be inset.</dd>
+      <dt><code>android:insetTop</code></dt>
+        <dd><em>Dimension</em>. The top inset, as a dimension value or <a
+href="more-resources.html#Dimension">dimension resource</a></dd>
+      <dt><code>android:insetRight</code></dt>
+        <dd><em>Dimension</em>. The right inset, as a dimension value or <a
+href="more-resources.html#Dimension">dimension resource</a></dd>
+      <dt><code>android:insetBottom</code></dt>
+        <dd><em>Dimension</em>. The bottom inset, as a dimension value or <a
+href="more-resources.html#Dimension">dimension resource</a></dd>
+      <dt><code>android:insetLeft</code></dt>
+        <dd><em>Dimension</em>. The left inset, as a dimension value or <a
+href="more-resources.html#Dimension">dimension resource</a></dd>
+    </dl>
+  </dd>
+</dl>
+
+</dd>
+
+<dt>example:</dt>
+
+<dd>
+<pre>
+&lt;?xml version="1.0" encoding="utf-8"?>
+&lt;inset xmlns:android="http://schemas.android.com/apk/res/android"
+    android:drawable="@drawable/background"
+    android:insetTop="10dp"
+    android:insetLeft="10dp" /&gt;
+</pre>
+</dd>
+
+<dt>see also:</dt>
+
+<dd>
+<ul>
+  <li>{@link android.graphics.drawable.InsetDrawable}</li>
+</ul>
+</dd>
+
+</dl>
+
+
+
+
+
+
+
+
+<h2 id="Clip">Clip Drawable</h2>
+
+<p>A drawable defined in XML that clips another drawable based on this Drawable's current level. You
+can control how much the child drawable gets clipped in width and height based on the level, as well
+as a gravity to control where it is placed in its overall container. Most often used to implement
+things like progress bars.</p>
+
+<dl class="xml">
+
+<dt>file location:</dt>
+<dd><code>res/drawable/<em>filename</em>.xml</code><br/>
+The filename is used as the resource ID.</dd>
+
+<dt>compiled resource datatype:</dt>
+<dd>Resource pointer to a {@link android.graphics.drawable.ClipDrawable}.</dd>
+
+<dt>resource reference:</dt>
+
+<dd>
+In Java: <code>R.drawable.<em>filename</em></code><br/>
+In XML: <code>@[<em>package</em>:]drawable/<em>filename</em></code>
+</dd>
+
+<dt>syntax:</dt>
+
+<dd>
+<pre class="stx">
+&lt;?xml version="1.0" encoding="utf-8"?>
+&lt;<a href="#clip-element">clip</a>
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:drawable="@drawable/<i>drawable_resource</i>"
+    android:clipOrientation=["horizontal" | "vertical"]
+    android:gravity=["top" | "bottom" | "left" | "right" | "center_vertical" |
+                     "fill_vertical" | "center_horizontal" | "fill_horizontal" |
+                     "center" | "fill" | "clip_vertical" | "clip_horizontal"] /&gt;
+</pre>
+</dd>
+
+<dt>elements:</dt>
+
+<dd>
+<dl class="tag-list">
+
+  <dt id="clip-element"><code>&lt;clip&gt;</code></dt>
+  <dd>Defines the clip drawable. This must be the root element.
+    <p class="caps">attributes:</p>
+    <dl class="atn-list">
+      <dt><code>xmlns:android</code></dt>
+        <dd><em>String</em>. <strong>Required.</strong> Defines the XML namespace, which must be
+        <code>"http://schemas.android.com/apk/res/android"</code>.
+      <dt><code>android:drawable</code></dt>
+        <dd><em>Drawable resource</em>. <strong>Required</strong>. Reference to a drawable
+resource to be clipped.</dd>
+      <dt><code>android:clipOrientation</code></dt>
+        <dd><em>Keyword</em>. The orientation for the clip.
+          <p>Must be one of the following constant values:</p>
+<table>
+<tr><th>Value</th><th>Description</th></tr>
+<tr><td><code>horizontal</code></td>
+<td>Clip the drawable horizontally.</td></tr>
+<tr><td><code>vertical</code></td>
+<td>Clip the drawable vertically.</td></tr>
+</table>
+        </dd>
+      <dt><code>android:gravity</code></dt>
+        <dd><em>Keyword</em>. Specifies where to clip within the drawable.
+          <p>Must be one or more (separated by '|') of the following constant values:</p>
+<table>
+<tr><th>Value</th><th>Description</th></tr>
+<tr><td><code>top</code></td>
+<td>Put the object at the top of its container, not changing its size. When {@code
+clipOrientation} is {@code "vertical"}, clipping occurs at the bottom of the drawable.</td></tr>
+<tr><td><code>bottom</code></td>
+<td>Put the object at the bottom of its container, not changing its size. When {@code
+clipOrientation} is {@code "vertical"}, clipping occurs at the top of the drawable.</td></tr>
+<tr><td><code>left</code></td>
+<td>Put the object at the left edge of its container, not changing its size. This is the
+default. When {@code clipOrientation} is {@code "horizontal"}, clipping occurs at the right side of
+the drawable. This is the default.</td></tr>
+<tr><td><code>right</code></td>
+<td>Put the object at the right edge of its container, not changing its size. When {@code
+clipOrientation} is {@code "horizontal"}, clipping occurs at the left side of
+the drawable.</td></tr>
+<tr><td><code>center_vertical</code></td>
+<td>Place object in the vertical center of its container, not changing its size. Clipping behaves
+the same as when gravity is {@code "center"}.</td></tr>
+<tr><td><code>fill_vertical</code></td>
+<td>Grow the vertical size of the object if needed so it completely fills its container. When {@code
+clipOrientation} is {@code "vertical"}, no clipping occurs because the drawable fills the
+vertical space (unless the drawable level is 0, in which case it's not visible).</td></tr>
+<tr><td><code>center_horizontal</code></td>
+<td>Place object in the horizontal center of its container, not changing its size.
+Clipping behaves the same as when gravity is {@code "center"}.</td></tr>
+<tr><td><code>fill_horizontal</code></td>
+<td>Grow the horizontal size of the object if needed so it completely fills its container. When
+{@code clipOrientation} is {@code "horizontal"}, no clipping occurs because the drawable fills the
+horizontal space (unless the drawable level is 0, in which case it's not visible).
+</td></tr>
+<tr><td><code>center</code></td>
+<td>Place the object in the center of its container in both the vertical and horizontal axis, not
+changing its size. When {@code
+clipOrientation} is {@code "horizontal"}, clipping occurs on the left and right. When {@code
+clipOrientation} is {@code "vertical"}, clipping occurs on the top and bottom.</td></tr>
+<tr><td><code>fill</code></td>
+<td>Grow the horizontal and vertical size of the object if needed so it completely fills its
+container. No clipping occurs because the drawable fills the
+horizontal and vertical space (unless the drawable level is 0, in which case it's not
+visible).</td></tr>
+<tr><td><code>clip_vertical</code></td>
+<td>Additional option that can be set to have the top and/or bottom edges of the child clipped to
+its container's bounds. The clip is based on the vertical gravity: a top gravity clips the
+bottom edge, a bottom gravity clips the top edge, and neither clips both edges.
+</td></tr>
+<tr><td><code>clip_horizontal</code></td>
+<td>Additional option that can be set to have the left and/or right edges of the child clipped to
+its container's bounds. The clip is based on the horizontal gravity: a left gravity clips
+the right edge, a right gravity clips the left edge, and neither clips both edges.
+</td></tr>
+</table></dd>
+    </dl>
+  </dd>
+</dl>
+
+</dd> <!-- end  elements and attributes -->
+
+<dt>example:</dt>
+
+<dd>XML file saved at <code>res/drawable/clip.xml</code>:
+<pre>
+&lt;?xml version="1.0" encoding="utf-8"?>
+&lt;shape xmlns:android="http://schemas.android.com/apk/res/android"
+    android:drawable="@drawable/android"
+    android:clipOrientation="horizontal"
+    android:gravity="left" /&gt;
+&lt;/shape>
+</pre>
+    <p>The following layout XML applies the clip drawable to a View:</p>
+<pre>
+&lt;ImageView
+    android:id="@+id/image"
+    android:background="@drawable/clip"
+    android:layout_height="wrap_content"
+    android:layout_width="wrap_content" />
+</pre>
+
+    <p>The following code gets the drawable and increases the amount of clipping in order to
+progressively reveal the image:</p>
+<pre>
+ImageView imageview = (ImageView) findViewById(R.id.image);
+ClipDrawable drawable = (ClipDrawable) imageview.getDrawable();
+drawable.setLevel(drawable.getLevel() + 1000);
+</pre>
+
+<p>Increasing the level reduces the amount of clipping and slowly reveals the image. Here it is
+at a level of 7000:</p>
+<img src="{@docRoot}images/resources/clip.png" alt="" />
+
+<p class="note"><strong>Note:</strong> The default level is 0, which is fully clipped so the image
+is not visible. When the level is 10,000, the image is not clipped and completely visible.</p>
+</dd> <!-- end example -->
+
+<dt>see also:</dt>
+
+<dd>
+<ul>
+  <li>{@link android.graphics.drawable.ClipDrawable}</li>
 </ul>
 </dd>
 
@@ -430,10 +1268,139 @@
 
 
 
+<h2 id="Scale">Scale Drawable</h2>
+
+<p>A drawable defined in XML that changes the size of another drawable based on its current
+level.</p>
+
+<dl class="xml">
+
+<dt>file location:</dt>
+<dd><code>res/drawable/<em>filename</em>.xml</code><br/>
+The filename is used as the resource ID.</dd>
+
+<dt>compiled resource datatype:</dt>
+<dd>Resource pointer to a {@link android.graphics.drawable.ScaleDrawable}.</dd>
+
+<dt>resource reference:</dt>
+
+<dd>
+In Java: <code>R.drawable.<em>filename</em></code><br/>
+In XML: <code>@[<em>package</em>:]drawable/<em>filename</em></code>
+</dd>
+
+<dt>syntax:</dt>
+
+<dd>
+<pre class="stx">
+&lt;?xml version="1.0" encoding="utf-8"?>
+&lt;<a href="#scale-element">scale</a>
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:drawable="@drawable/<i>drawable_resource</i>"
+    android:scaleGravity=["top" | "bottom" | "left" | "right" | "center_vertical" |
+                          "fill_vertical" | "center_horizontal" | "fill_horizontal" |
+                          "center" | "fill" | "clip_vertical" | "clip_horizontal"]
+    android:scaleHeight="<i>percentage</i>"
+    android:scaleWidth="<i>percentage</i>" /&gt;
+</pre>
+</dd>
+
+<dt>elements:</dt>
+
+<dd>
+<dl class="tag-list">
+
+  <dt id="scale-element"><code>&lt;scale&gt;</code></dt>
+  <dd>Defines the scale drawable. This must be the root element.
+    <p class="caps">attributes:</p>
+    <dl class="atn-list">
+      <dt><code>xmlns:android</code></dt>
+        <dd><em>String</em>. <strong>Required.</strong> Defines the XML namespace, which must be
+        <code>"http://schemas.android.com/apk/res/android"</code>.
+      <dt><code>android:drawable</code></dt>
+        <dd><em>Drawable resource</em>. <strong>Required</strong>. Reference to a drawable
+resource.</dd>
+      <dt><code>android:scaleGravity</code></dt>
+        <dd><em>Keyword</em>. Specifies the gravity position after scaling.
+          <p>Must be one or more (separated by '|') of the following constant values:</p>
+<table>
+<tr><th>Value</th><th>Description</th></tr>
+<tr><td><code>top</code></td>
+<td>Put the object at the top of its container, not changing its size.</td></tr>
+<tr><td><code>bottom</code></td>
+<td>Put the object at the bottom of its container, not changing its size. </td></tr>
+<tr><td><code>left</code></td>
+<td>Put the object at the left edge of its container, not changing its size. This is the
+default.</td></tr>
+<tr><td><code>right</code></td>
+<td>Put the object at the right edge of its container, not changing its size. </td></tr>
+<tr><td><code>center_vertical</code></td>
+<td>Place object in the vertical center of its container, not changing its size. </td></tr>
+<tr><td><code>fill_vertical</code></td>
+<td>Grow the vertical size of the object if needed so it completely fills its container. </td></tr>
+<tr><td><code>center_horizontal</code></td>
+<td>Place object in the horizontal center of its container, not changing its size. </td></tr>
+<tr><td><code>fill_horizontal</code></td>
+<td>Grow the horizontal size of the object if needed so it completely fills its container.
+</td></tr>
+<tr><td><code>center</code></td>
+<td>Place the object in the center of its container in both the vertical and horizontal axis, not
+changing its size. </td></tr>
+<tr><td><code>fill</code></td>
+<td>Grow the horizontal and vertical size of the object if needed so it completely fills its
+container. </td></tr>
+<tr><td><code>clip_vertical</code></td>
+<td>Additional option that can be set to have the top and/or bottom edges of the child clipped to
+its container's bounds. The clip is based on the vertical gravity: a top gravity clips the
+bottom edge, a bottom gravity clips the top edge, and neither clips both edges.
+</td></tr>
+<tr><td><code>clip_horizontal</code></td>
+<td>Additional option that can be set to have the left and/or right edges of the child clipped to
+its container's bounds. The clip is based on the horizontal gravity: a left gravity clips
+the right edge, a right gravity clips the left edge, and neither clips both edges.
+</td></tr>
+</table></dd>
+      <dt><code>android:scaleHeight</code></dt>
+        <dd><em>Percentage</em>. The scale height, expressed as a percentage of the drawable's
+bound. The value's format is XX%. For instance: 100%, 12.5%, etc.</dd>
+      <dt><code>android:scaleWidth</code></dt>
+        <dd><em>Percentage</em>. The scale width, expressed as a percentage of the drawable's
+bound. The value's format is XX%. For instance: 100%, 12.5%, etc.</dd>
+    </dl>
+  </dd>
+</dl>
+
+</dd>
+
+<dt>example:</dt>
+
+<dd>
+<pre class="stx">
+&lt;?xml version="1.0" encoding="utf-8"?>
+&lt;scale xmlns:android="http://schemas.android.com/apk/res/android"
+    android:drawable="@drawable/logo"
+    android:scaleGravity="center_vertical|center_horizontal"
+    android:scaleHeight="80%"
+    android:scaleWidth="80%" /&gt;
+</pre>
+</dd>
+
+<dt>see also:</dt>
+<dd>
+<ul>
+  <li>{@link android.graphics.drawable.ScaleDrawable}</li>
+</ul>
+</dd>
+
+</dl>
 
 
 
-<h2 id="Shape">Shape</h2>
+
+
+
+
+<h2 id="Shape">Shape Drawable</h2>
 
 <p>This is a generic shape defined in XML.</p>
 
@@ -441,23 +1408,32 @@
 
 <dt>file location:</dt>
 <dd><code>res/drawable/<em>filename</em>.xml</code><br/>
-The filename will be used as the resource ID.</dd>
+The filename is used as the resource ID.</dd>
 
 <dt>compiled resource datatype:</dt>
 <dd>Resource pointer to a {@link android.graphics.drawable.ShapeDrawable}.</dd>
 
 <dt>resource reference:</dt>
+
 <dd>
 In Java: <code>R.drawable.<em>filename</em></code><br/>
 In XML: <code>@[<em>package</em>:]drawable/<em>filename</em></code>
 </dd>
 
 <dt>syntax:</dt>
+
 <dd>
 <pre class="stx">
 &lt;?xml version="1.0" encoding="utf-8"?>
-&lt;<a href="#shape-element">shape</a> xmlns:android="http://schemas.android.com/apk/res/android"
+&lt;<a href="#shape-element">shape</a>
+    xmlns:android="http://schemas.android.com/apk/res/android"
     android:shape=["rectangle" | "oval" | "line" | "ring"] >
+    &lt;<a href="#corners-element">corners</a>
+        android:radius="<em>integer</em>"
+        android:topLeftRadius="<em>integer</em>"
+        android:topRightRadius="<em>integer</em>"
+        android:bottomLeftRadius="<em>integer</em>"
+        android:bottomRightRadius="<em>integer</em>" /&gt;
     &lt;<a href="#gradient-element">gradient</a>
         android:angle="<em>integer</em>"
         android:centerX="<em>integer</em>"
@@ -467,37 +1443,40 @@
         android:gradientRadius="<em>integer</em>"
         android:startColor="<em>color</em>"
         android:type=["linear" | "radial" | "sweep"]
-        android:usesLevel=["true" | "false"] />
-    &lt;<a href="#solid-element">solid</a>
-        android:color="<em>color</em>" />
-    &lt;<a href="#stroke-element">stroke</a>
-        android:width="<em>integer</em>"
-        android:color="<em>color</em>"
-        android:dashWidth="<em>integer</em>"
-        android:dashGap="<em>integer</em>" />
+        android:usesLevel=["true" | "false"] /&gt;
     &lt;<a href="#padding-element">padding</a>
         android:left="<em>integer</em>"
         android:top="<em>integer</em>"
         android:right="<em>integer</em>"
-        android:bottom="<em>integer</em>" />
-    &lt;<a href="#corners-element">corners</a>
-        android:radius="<em>integer</em>"
-        android:topLeftRadius="<em>integer</em>"
-        android:topRightRadius="<em>integer</em>"
-        android:bottomLeftRadius="<em>integer</em>"
-        android:bottomRightRadius="<em>integer</em>" />
+        android:bottom="<em>integer</em>" /&gt;
+    &lt;<a href="#size-element">size</a>
+        android:width="<em>integer</em>"
+        android:color="<em>color</em>"
+        android:dashWidth="<em>integer</em>"
+        android:dashGap="<em>integer</em>" /&gt;
+    &lt;<a href="#solid-element">solid</a>
+        android:color="<em>color</em>" /&gt;
+    &lt;<a href="#stroke-element">stroke</a>
+        android:width="<em>integer</em>"
+        android:color="<em>color</em>"
+        android:dashWidth="<em>integer</em>"
+        android:dashGap="<em>integer</em>" /&gt;
 &lt;/shape>
 </pre>
 </dd>
 
 <dt>elements:</dt>
+
 <dd>
 <dl class="tag-list">
 
   <dt id="shape-element"><code>&lt;shape&gt;</code></dt>
-    <dd><strong>Required.</strong> This must be the root element.
+    <dd>The shape drawable. This must be the root element.
       <p class="caps">attributes:</p>
       <dl class="atn-list">
+        <dt><code>xmlns:android</code></dt>
+          <dd><em>String</em>. <strong>Required.</strong> Defines the XML namespace, which must be
+          <code>"http://schemas.android.com/apk/res/android"</code>.
         <dt><code>android:shape</code></dt>
         <dd><em>Keyword</em>. Defines the type of shape. Valid values are:
           <table>
@@ -525,7 +1504,7 @@
         <dd><em>Float</em>. The radius for the inner
 part of the ring, expressed as a ratio of the ring's width. For instance, if {@code
 android:innerRadiusRatio="5"}, then the inner radius equals the ring's width divided by 5. This
-value will be overridden by {@code android:innerRadius}. Default value is 9.</dd>
+value is overridden by {@code android:innerRadius}. Default value is 9.</dd>
         <dt><code>android:thickness</code></dt>
         <dd><em>Dimension</em>. The thickness of the
 ring, as a dimension value or <a
@@ -533,13 +1512,40 @@
         <dt><code>android:thicknessRatio</code></dt>
         <dd><em>Float</em>. The thickness of the ring,
 expressed as a ratio of the ring's width. For instance, if {@code android:thicknessRatio="2"}, then
-the thickness equals the ring's width divided by 2. This value will be overridden by {@code
+the thickness equals the ring's width divided by 2. This value is overridden by {@code
 android:innerRadius}. Default value is 3.</dd>
         <dt><code>android:useLevel</code></dt>
         <dd><em>Boolean</em>. "true" if this is used as
 a {@link android.graphics.drawable.LevelListDrawable}. This should normally be "false"
           or your shape may not appear.</dd>
       </dl>
+  <dt id="corners-element"><code>&lt;corners&gt;</code></dt>
+    <dd>Creates rounded corners for the shape. Applies only when the shape is a rectangle.
+      <p class="caps">attributes:</p>
+      <dl class="atn-list">
+        <dt><code>android:radius</code></dt>
+        <dd><em>Dimension</em>. The radius for all corners, as a dimension value or <a
+href="more-resources.html#Dimension">dimension resource</a>. This is overridden for each
+corner by the following attributes.</dd>
+        <dt><code>android:topLeftRadius</code></dt>
+        <dd><em>Dimension</em>. The radius for the top-left corner, as a dimension value or <a
+href="more-resources.html#Dimension">dimension resource</a>.</dd>
+        <dt><code>android:topRightRadius</code></dt>
+        <dd><em>Dimension</em>. The radius for the top-right corner, as a dimension value or <a
+href="more-resources.html#Dimension">dimension resource</a>.</dd>
+        <dt><code>android:bottomLeftRadius</code></dt>
+        <dd><em>Dimension</em>. The radius for the bottom-left corner, as a dimension value or <a
+href="more-resources.html#Dimension">dimension resource</a>.</dd>
+        <dt><code>android:bottomRightRadius</code></dt>
+        <dd><em>Dimension</em>. The radius for the bottom-right corner, as a dimension value or <a
+href="more-resources.html#Dimension">dimension resource</a>.</dd>
+      </dl>
+      <p class="note"><strong>Note:</strong> Every corner must (initially) be provided a corner
+radius greater than 1, or else no corners are rounded. If you want specific corners
+to <em>not</em> be rounded, a work-around is to use {@code android:radius} to set a default corner
+radius greater than 1, but then override each and every corner with the values you really
+want, providing zero ("0dp") where you don't want rounded corners.</p>
+    </dd>
   <dt id="gradient-element"><code>&lt;gradient&gt;</code></dt>
     <dd>Specifies a gradient color for the shape.
       <p class="caps">attributes:</p>
@@ -582,6 +1588,42 @@
 android.graphics.drawable.LevelListDrawable}.</dd>
       </dl>
     </dd>
+  <dt id="padding-element"><code>&lt;padding&gt;</code></dt>
+    <dd>Padding to apply to the containing View element (this pads the position of the View
+content, not the shape).
+      <p class="caps">attributes:</p>
+      <dl class="atn-list">
+        <dt><code>android:left</code></dt>
+        <dd><em>Dimension</em>. Left padding, as a dimension value or <a
+href="more-resources.html#Dimension">dimension resource</a>.</dd>
+        <dt><code>android:top</code></dt>
+        <dd><em>Dimension</em>. Top padding, as a dimension value or <a
+href="more-resources.html#Dimension">dimension resource</a>.</dd>
+        <dt><code>android:right</code></dt>
+        <dd><em>Dimension</em>. Right padding, as a dimension value or <a
+href="more-resources.html#Dimension">dimension resource</a>.</dd>
+        <dt><code>android:bottom</code></dt>
+        <dd><em>Dimension</em>. Bottom padding, as a dimension value or <a
+href="more-resources.html#Dimension">dimension resource</a>.</dd>
+      </dl>
+    </dd>
+  <dt id="solid-element"><code>&lt;size&gt;</code></dt>
+    <dd>The size of the shape.
+      <p class="caps">attributes:</p>
+      <dl class="atn-list">
+        <dt><code>android:height</code></dt>
+        <dd><em>Dimension</em>. The height of the shape, as a dimension value or <a
+href="more-resources.html#Dimension">dimension resource</a>.</dd>
+        <dt><code>android:width</code></dt>
+        <dd><em>Dimension</em>. The width of the shape, as a dimension value or <a
+href="more-resources.html#Dimension">dimension resource</a>.</dd>
+      </dl>
+      <p class="note"><strong>Note:</strong> The shape scales to the size of the container
+View proportionate to the dimensions defined here, by default. When you use the shape in an {@link
+android.widget.ImageView}, you can restrict scaling by setting the <a
+href="{@docRoot}reference/android/widget/ImageView.html#attr_android:scaleType">{@code
+android:scaleType}</a> to {@code "center"}.</p>
+    </dd>
   <dt id="solid-element"><code>&lt;solid&gt;</code></dt>
     <dd>A solid color to fill the shape.
       <p class="caps">attributes:</p>
@@ -611,57 +1653,12 @@
 android:dashGap} is set.</dd>
       </dl>
     </dd>
-  <dt id="padding-element"><code>&lt;padding&gt;</code></dt>
-    <dd>Padding to apply to the containing View element (this pads the position of the View
-content, not the shape).
-      <p class="caps">attributes:</p>
-      <dl class="atn-list">
-        <dt><code>android:left</code></dt>
-        <dd><em>Dimension</em>. Left padding, as a dimension value or <a
-href="more-resources.html#Dimension">dimension resource</a>.</dd>
-        <dt><code>android:top</code></dt>
-        <dd><em>Dimension</em>. Top padding, as a dimension value or <a
-href="more-resources.html#Dimension">dimension resource</a>.</dd>
-        <dt><code>android:right</code></dt>
-        <dd><em>Dimension</em>. Right padding, as a dimension value or <a
-href="more-resources.html#Dimension">dimension resource</a>.</dd>
-        <dt><code>android:bottom</code></dt>
-        <dd><em>Dimension</em>. Bottom padding, as a dimension value or <a
-href="more-resources.html#Dimension">dimension resource</a>.</dd>
-      </dl>
-    </dd>
-  <dt id="corners-element"><code>&lt;corners&gt;</code></dt>
-    <dd>Creates rounded corners for the shape. Applies only when the shape is a rectangle.
-      <p class="caps">attributes:</p>
-      <dl class="atn-list">
-        <dt><code>android:radius</code></dt>
-        <dd><em>Dimension</em>. The radius for all corners, as a dimension value or <a
-href="more-resources.html#Dimension">dimension resource</a>. This will be overridden for each
-corner by the following attributes.</dd>
-        <dt><code>android:topLeftRadius</code></dt>
-        <dd><em>Dimension</em>. The radius for the top-left corner, as a dimension value or <a
-href="more-resources.html#Dimension">dimension resource</a>.</dd>
-        <dt><code>android:topRightRadius</code></dt>
-        <dd><em>Dimension</em>. The radius for the top-right corner, as a dimension value or <a
-href="more-resources.html#Dimension">dimension resource</a>.</dd>
-        <dt><code>android:bottomLeftRadius</code></dt>
-        <dd><em>Dimension</em>. The radius for the bottom-left corner, as a dimension value or <a
-href="more-resources.html#Dimension">dimension resource</a>.</dd>
-        <dt><code>android:bottomRightRadius</code></dt>
-        <dd><em>Dimension</em>. The radius for the bottom-right corner, as a dimension value or <a
-href="more-resources.html#Dimension">dimension resource</a>.</dd>
-      </dl>
-      <p class="note"><strong>Note:</strong> Every corner must (initially) be provided a corner
-radius greater than zero, or else no corners will be rounded. If you want specific corners
-to <em>not</em> be rounded, a work-around is to use {@code android:radius} to set a default corner
-radius greater than zero, but then override each and every corner with the values you really
-want, providing zero ("0dp") where you don't want rounded corners.</p>
-    </dd>
 
 </dl>
 </dd> <!-- end  elements and attributes -->
 
 <dt>example:</dt>
+
 <dd>XML file saved at <code>res/drawable/gradient_box.xml</code>:
 <pre>
 &lt;?xml version="1.0" encoding="utf-8"?>
@@ -678,14 +1675,16 @@
     &lt;corners android:radius="8dp" />
 &lt;/shape>
 </pre>
-    <p>This layout XML will apply the shape drawable to a View:</p>
+
+    <p>This layout XML applies the shape drawable to a View:</p>
 <pre>
 &lt;TextView
     android:background="@drawable/gradient_box"
     android:layout_height="wrap_content"
     android:layout_width="wrap_content" />
 </pre>
-    <p>This application code will get the shape drawable and apply it to a View:</p>
+
+    <p>This application code gets the shape drawable and applies it to a View:</p>
 <pre>
 Resources res = {@link android.content.Context#getResources()};
 Drawable shape = res. {@link android.content.res.Resources#getDrawable(int) getDrawable}(R.drawable.gradient_box);
@@ -695,6 +1694,14 @@
 </pre>
 </dd> <!-- end example -->
 
+<dt>see also:</dt>
+
+<dd>
+<ul>
+  <li>{@link android.graphics.drawable.ShapeDrawable}</li>
+</ul>
+</dd>
+
 </dl>
 
 
diff --git a/docs/html/guide/topics/resources/layout-resource.jd b/docs/html/guide/topics/resources/layout-resource.jd
index 0688a18..111851c 100644
--- a/docs/html/guide/topics/resources/layout-resource.jd
+++ b/docs/html/guide/topics/resources/layout-resource.jd
@@ -35,12 +35,12 @@
 <pre class="stx">
 &lt;?xml version="1.0" encoding="utf-8"?>
 &lt;<a href="#viewgroup-element"><em>ViewGroup</em></a> xmlns:android="http://schemas.android.com/apk/res/android"
-    android:id="@+id/<em>name</em>"
+    android:id="@[+][<em>package</em>:]id/<em>resource_name</em>"
     android:layout_height=["<em>dimension</em>" | "fill_parent" | "wrap_content"]
     android:layout_width=["<em>dimension</em>" | "fill_parent" | "wrap_content"]
     [<em>ViewGroup-specific attributes</em>] &gt;
     &lt;<a href="#view-element"><em>View</em></a>
-        android:id="@+id/<em>name</em>"
+        android:id="@[+][<em>package</em>:]id/<em>resource_name</em>"
         android:layout_height=["<em>dimension</em>" | "fill_parent" | "wrap_content"]
         android:layout_width=["<em>dimension</em>" | "fill_parent" | "wrap_content"]
         [<em>View-specific attributes</em>] &gt;
@@ -49,10 +49,12 @@
     &lt;<a href="#viewgroup-element"><em>ViewGroup</em></a> &gt;
         &lt;<a href="#view-element"><em>View</em></a> /&gt;
     &lt;/<em>ViewGroup</em>&gt;
+    &lt;<a href="#include-element">include</a> layout="@layout/<i>layout_resource</i>"/&gt;
 &lt;/<em>ViewGroup</em>&gt;
 </pre>
 <p class="note"><strong>Note:</strong> The root element can be either a
-{@link android.view.ViewGroup} or a {@link android.view.View}, but there must be only
+{@link android.view.ViewGroup}, a {@link android.view.View}, or a <a
+href="#merge-element">{@code &lt;merge&gt;}</a> element, but there must be only
 one root element and it must contain the {@code xmlns:android} attribute with the {@code android}
 namespace as shown.</p>
 </dd>
@@ -74,10 +76,9 @@
       <p class="caps">attributes:</p>
       <dl class="atn-list">
         <dt><code>android:id</code></dt>
-        <dd><em>Resource name</em>. A unique resource name for the element, which you can
-use to obtain a reference to the {@link android.view.ViewGroup} from your application.
-          The value takes the form: <code>"@+id/<em>name</em>"</code>. See more about the
-          <a href="#idvalue">value for {@code android:id}</a> below.
+        <dd><em>Resource ID</em>. A unique resource name for the element, which you can
+use to obtain a reference to the {@link android.view.ViewGroup} from your application. See more
+about the <a href="#idvalue">value for {@code android:id}</a> below.
         </dd>
         <dt><code>android:layout_height</code></dt>
         <dd><em>Dimension or keyword</em>. <strong>Required</strong>. The height for the group, as a
@@ -107,10 +108,9 @@
       <p class="caps">attributes:</p>
       <dl class="atn-list">
         <dt><code>android:id</code></dt>
-        <dd><em>Resource name</em>. A unique resource name for the element, which you can use to
-          obtain a reference to the {@link android.view.View} from your application.
-          The value takes the form: <code>"@+id/<em>name</em>"</code>. See more about the
-          <a href="#idvalue">value for {@code android:id}</a> below.
+        <dd><em>Resource ID</em>. A unique resource name for the element, which you can use to
+          obtain a reference to the {@link android.view.View} from your application. See more about
+the <a href="#idvalue">value for {@code android:id}</a> below.
         </dd>
         <dt><code>android:layout_height</code></dt>
         <dd><em>Dimension or keyword</em>. <strong>Required</strong>. The height for the element, as
@@ -137,20 +137,71 @@
     which gives it's parent initial focus on the screen. You can have only one of these
     elements per file.</dd>
 
+  <dt id="include-element"><code>&lt;include&gt;</code></dt>
+    <dd>Includes a layout file into this layout.
+      <p class="caps">attributes:</p>
+      <dl class="atn-list">
+        <dt><code>layout</code></dt>
+        <dd><em>Layout resource</em>. <strong>Required</strong>. Reference to a layout
+resource.</dd>
+        <dt><code>android:id</code></dt>
+        <dd><em>Resource ID</em>. Overrides the ID given to the root view in the included layout.
+        </dd>
+        <dt><code>android:layout_height</code></dt>
+        <dd><em>Dimension or keyword</em>. Overrides the height given to the root view in the
+included layout.
+        </dd>
+        <dt><code>android:layout_width</code></dt>
+        <dd><em>Dimension or keyword</em>. Overrides the width given to the root view in the
+included layout.
+        </dd>
+      </dl>
+      <p>You can include any other layout attributes in the <code>&lt;include&gt;</code> that are
+supported by the root element in the included layout and they will override those defined in the
+root element.</p>
+
+    <p>Another way to include a layout is to use {@link android.view.ViewStub}. It is a lightweight
+View that consumes no layout space until you explicitly inflate it, at which point, it includes a
+layout file defined by its {@code android:layout} attribute. For more information about using {@link
+android.view.ViewStub}, read <a href="{@docRoot}resources/articles/layout-tricks-stubs.html">Layout
+Tricks: ViewStubs</a>.</p>
+    </dd>
+
+  <dt id="merge-element"><code>&lt;merge&gt;</code></dt>
+    <dd>An alternative root element that is not drawn in the layout hierarchy. Using this as the
+root element is useful when you know that this layout will be placed into a layout
+that already contains the appropriate parent View to contain the children of the
+<code>&lt;merge&gt;</code> element. This is particularly useful when you plan to include this layout
+in another layout file using <a href="#include-element"><code>&lt;include&gt;</code></a> and
+this layout doesn't require a different {@link android.view.ViewGroup} container. For more
+information about merging layouts, read <a
+href="{@docRoot}resources/articles/layout-tricks-merging.html">Layout
+Tricks: Merging</a>.</dd>
+
   </dl>
 
+
+
 <h4 id="idvalue">Value for <code>android:id</code></h4>
 
-<p>For the ID value, you should use this syntax form: <code>"@+id/<em>name</em>"</code>. The plus symbol,
-{@code +}, indicates that this is a new resource ID and the aapt tool will create
-a new resource number to the {@code R.java} class, if it doesn't already exist. For example:</p>
+<p>For the ID value, you should usually use this syntax form: <code>"@+id/<em>name</em>"</code>. The
+plus symbol, {@code +}, indicates that this is a new resource ID and the <code>aapt</code> tool will
+create a new resource integer in the {@code R.java} class, if it doesn't already exist. For
+example:</p>
 <pre>
 &lt;TextView android:id="@+id/nameTextbox"/>
 </pre>
-<p>You can then refer to it this way in Java:</p>
+<p>The <code>nameTextbox</code> name is now a resource ID attached to this element. You can then
+refer to the {@link android.widget.TextView} to which the ID is associated in Java:</p>
 <pre>
 findViewById(R.id.nameTextbox);
 </pre>
+<p>This code returns the {@link android.widget.TextView} object.</p>
+
+<p>However, if you have already defined an <a
+href="{@docRoot}guide/topics/resources/drawable-resource.html#Id">ID resource</a> (and it is not
+already used), then you can apply that ID to a {@link android.view.View} element by excluding the
+plus symbol in the <code>android:id</code> value.</p>
 
 <h4 id="layoutvalues">Value for <code>android:layout_height</code> and
 <code>android:layout_width</code>:</h4>
diff --git a/docs/html/guide/topics/resources/menu-resource.jd b/docs/html/guide/topics/resources/menu-resource.jd
index badc403..cde72bd 100644
--- a/docs/html/guide/topics/resources/menu-resource.jd
+++ b/docs/html/guide/topics/resources/menu-resource.jd
@@ -35,7 +35,7 @@
 <pre>
 &lt;?xml version="1.0" encoding="utf-8"?>
 &lt;<a href="#menu-element">menu</a> xmlns:android="http://schemas.android.com/apk/res/android">
-    &lt;<a href="#item-element">item</a> android:id="@+id/<em>id_name</em>"
+    &lt;<a href="#item-element">item</a> android:id="@[+][<em>package</em>:]id/<em>resource_name</em>"
           android:menuCategory=["container" | "system" | "secondary" | "alternative"]
           android:orderInCategory="<em>integer</em>"
           android:title="<em>string</em>"
@@ -46,7 +46,7 @@
           android:checkable=["true" | "false"]
           android:visible=["visible" | "invisible" | "gone"]
           android:enabled=["enabled" | "disabled"] /&gt;
-    &lt;<a href="#group-element">group</a> android:id="<em>resource ID</em>"
+    &lt;<a href="#group-element">group</a> android:id="@[+][<em>package</em>:]id/<em>resource name</em>"
            android:menuCategory=["container" | "system" | "secondary" | "alternative"]
            android:orderInCategory="<em>integer</em>"
            android:checkableBehavior=["none" | "all" | "single"]
@@ -84,8 +84,8 @@
       <p class="caps">attributes:</p>
       <dl class="atn-list">
         <dt><code>android:id</code></dt>
-        <dd><em>Resource name</em>. A unique resource name. The value takes the form:
-<code>"@+id/<em>name</em>"</code>.</dd>
+        <dd><em>Resource ID</em>. A unique resource ID. To create a new resource ID for this item, use the form:
+<code>"@+id/<em>name</em>"</code>. The plus symbol indicates that this should be created as a new ID.</dd>
         <dt><code>android:menuCategory</code></dt>
           <dd><em>Keyword</em>. Value corresponding to {@link android.view.Menu} {@code CATEGORY_*}
           constants, which define the group's priority. Valid values:
@@ -124,8 +124,8 @@
       <p class="caps">attributes:</p>
       <dl class="atn-list">
         <dt><code>android:id</code></dt>
-        <dd><em>Resource name</em>. A unique resource name. The value takes the form:
-<code>"@+id/<em>name</em>"</code>.</dd>
+        <dd><em>Resource ID</em>. A unique resource ID. To create a new resource ID for this item, use the form:
+<code>"@+id/<em>name</em>"</code>. The plus symbol indicates that this should be created as a new ID.</dd>
         <dt><code>android:menuCategory</code></dt>
           <dd><em>Keyword</em>. Value corresponding to {@link android.view.Menu} {@code CATEGORY_*}
           constants, which define the item's priority. Valid values:
diff --git a/docs/html/guide/topics/resources/more-resources.jd b/docs/html/guide/topics/resources/more-resources.jd
index 0e2b30be..22abbb2 100644
--- a/docs/html/guide/topics/resources/more-resources.jd
+++ b/docs/html/guide/topics/resources/more-resources.jd
@@ -12,6 +12,9 @@
     <dd>XML resource that carries a color value (a hexadecimal color).</dd>
   <dt><a href="#Dimension">Dimension</a></dt>
     <dd>XML resource that carries a dimension value (with a unit of measure).</dd>
+  <dt><a href="#Id">ID</a></dt>
+    <dd>XML resource that provides a unique identifier for application resources and
+components.</dd>
   <dt><a href="#Integer">Integer</a></dt>
     <dd>XML resource that carries an integer value.</dd>
   <dt><a href="#IntegerArray">Integer Array</a></dt>
@@ -111,8 +114,8 @@
 <h2 id="Color">Color</h2>
 
 <p>A color value defined in XML.
-The color is specified with an RGB value and alpha channel. A color resource can be used
-any place that expects a hexadecimal color value.</p>
+The color is specified with an RGB value and alpha channel. You can use color resource
+any place that accepts a hexadecimal color value.</p>
 
 <p>The value always begins with a pound (#) character and then followed by the
 Alpha-Red-Green-Blue information in one of the following formats:</p>
@@ -318,6 +321,118 @@
 
 
 
+<h2 id="Id">ID</h2>
+
+<p>A unique resource ID defined in XML. Using the name you provide in the {@code &lt;item&gt;}
+element, the Android developer tools create a unique integer in your project's {@code
+R.java} class, which you can use as an
+identifier for an application resources (for example, a {@link android.view.View} in your UI layout)
+or a unique integer for use in your application code (for example, as an ID for a dialog or a
+result code).</p>
+
+<p class="note"><strong>Note:</strong> An ID is a simple resource that is referenced
+using the value provided in the {@code name} attribute (not the name of the XML file). As
+such, you can combine ID resources with other simple resources in the one XML file,
+under one {@code &lt;resources&gt;} element. Also, remember that an ID resources does not reference
+an actual resource item; it is simply a unique ID that you can attach to other resources or use
+as a unique integer in your application.</p>
+
+<dl class="xml">
+
+<dt>file location:</dt>
+<dd><code>res/values/<em>filename.xml</em></code><br/>
+The filename is arbitrary.</dd>
+
+<dt>resource reference:</dt>
+<dd>
+In Java: <code>R.id.<em>name</em></code><br/>
+In XML: <code>@[<em>package</em>:]id/<em>name</em></code>
+</dd>
+
+<dt>syntax:</dt>
+<dd>
+<pre class="stx">
+&lt;?xml version="1.0" encoding="utf-8"?>
+&lt;<a href="#id-resources-element">resources</a>&gt;
+    &lt;<a href="#id-item-element">item</a>
+        type="id"
+        name="<em>id_name</em>" /&gt;
+&lt;/resources&gt;
+</pre>
+</dd>
+
+<dt>elements:</dt>
+<dd>
+<dl class="tag-list">
+
+  <dt id="integer-resources-element"><code>&lt;resources&gt;</code></dt>
+    <dd><strong>Required.</strong> This must be the root node.
+      <p>No attributes.</p>
+    </dd>
+  <dt id="integer-element"><code>&lt;integer&gt;</code></dt>
+    <dd>Defines a unique ID. Takes no value, only attributes.
+      <p class="caps">attributes:</p>
+      <dl class="atn-list">
+        <dt><code>type</code></dt>
+        <dd>Must be "id".</dd>
+        <dt><code>name</code></dt>
+        <dd><em>String</em>. A unique name for the ID.</dd>
+      </dl>
+    </dd>
+
+</dl>
+</dd> <!-- end  elements and attributes -->
+
+<dt>example:</dt>
+<dd>
+  <p>XML file saved at <code>res/values/ids.xml</code>:</p>
+<pre>
+&lt;?xml version="1.0" encoding="utf-8"?>
+&lt;resources>
+    &lt;item type="id" name="button_ok" /&gt;
+    &lt;item type="id" name="dialog_exit" /&gt;
+&lt;/resources>
+</pre>
+
+    <p>Then, this layout snippet uses the "button_ok" ID for a Button widget:</p>
+<pre>
+&lt;Button android:id="<b>@id/button_ok</b>"
+    style="@style/button_style" /&gt;
+</pre>
+
+    <p>Notice that the {@code android:id} value does not include the plus sign in the ID reference,
+because the ID already exists, as defined in the {@code ids.xml} example above. (When you specify an
+ID to an XML resource using the plus sign&mdash;in the format {@code
+android:id="@+id/name"}&mdash;it means that the "name" ID does not exist and should be created.)</p>
+
+  <p>As another example, the following code snippet uses the "dialog_exit" ID as a unique identifier
+for a dialog:</p>
+<pre>
+{@link android.app.Activity#showDialog(int) showDialog}(<b>R.id.dialog_exit</b>);
+</pre>
+  <p>In the same application, the "dialog_exit" ID is compared when creating a dialog:</p>
+<pre>
+protected Dialog {@link android.app.Activity#onCreateDialog(int)}(int id) {
+    Dialog dialog;
+    switch(id) {
+    case <b>R.id.dialog_exit</b>:
+        ...
+        break;
+    default:
+        dialog = null;
+    }
+    return dialog;
+}
+</pre>
+</dd> <!-- end example -->
+
+
+</dl>
+
+
+
+
+
 <h2 id="Integer">Integer</h2>
 
 <p>An integer defined in XML.</p>
@@ -347,7 +462,7 @@
 &lt;<a href="#integer-resources-element">resources</a>>
     &lt;<a href="#integer-element">integer</a>
         name="<em>integer_name</em>"
-        &gt;<em>integer</em>&lt;/dimen&gt;
+        &gt;<em>integer</em>&lt;/integer&gt;
 &lt;/resources&gt;
 </pre>
 </dd>
@@ -379,8 +494,8 @@
 <pre>
 &lt;?xml version="1.0" encoding="utf-8"?>
 &lt;resources>
-    &lt;integer name="max_speed">75&lt;/dimen>
-    &lt;integer name="min_speed">5&lt;/dimen>
+    &lt;integer name="max_speed">75&lt;/integer>
+    &lt;integer name="min_speed">5&lt;/integer>
 &lt;/resources>
 </pre>
     <p>This application code retrieves an integer:</p>
diff --git a/docs/html/images/resources/clip.png b/docs/html/images/resources/clip.png
new file mode 100644
index 0000000..9196b3f
--- /dev/null
+++ b/docs/html/images/resources/clip.png
Binary files differ
diff --git a/docs/html/images/resources/layers.png b/docs/html/images/resources/layers.png
new file mode 100644
index 0000000..f7e6929
--- /dev/null
+++ b/docs/html/images/resources/layers.png
Binary files differ
diff --git a/docs/html/intl/ja/community/index.jd b/docs/html/intl/ja/community/index.jd
index 659aee7..490b23f 100644
--- a/docs/html/intl/ja/community/index.jd
+++ b/docs/html/intl/ja/community/index.jd
@@ -4,9 +4,9 @@
 
 	<div id="mainBodyFluid">
 			<h1>コミュニティ</h1>
-			<p>Android デベロッパー コミュニティへようこそ。コミュニティでのディスカッションにぜひ参加してください。投稿する前に、コミュニティ ガイドラインが記載されている<a href="http://source.android.com/discuss/android-discussion-groups-charter">グループの趣意</a>をお読みください。</p>
+			<p>Android デベロッパー コミュニティへようこそ。コミュニティでのディスカッションにぜひ参加してください。投稿する前に、コミュニティ ガイドラインが記載されている<a href="http://source.android.com/community/groups-charter.html">グループの趣意</a>をお読みください。</p>
 
-<p class="note"><strong>注:</strong> Android ソース コード(アプリケーション開発ではなく)に関するディスカッションは、<a href="http://source.android.com/discuss">オープンソース プロジェクトのメーリング リスト</a>(英語)を参照してください。</p>
+<p class="note"><strong>注:</strong> Android ソース コード(アプリケーション開発ではなく)に関するディスカッションは、<a href="http://source.android.com/community">オープンソース プロジェクトのメーリング リスト</a>(英語)を参照してください。</p>
 
 <p style="margin-bottom:.5em"><strong>目次</strong></p>
 <ol class="toc">
@@ -28,7 +28,7 @@
 
 <p>質問への答えが見つからない場合、コミュニティで質問することをおすすめします。投稿する際は、次の手順に従ってください。
 <ol>
-<li>コミュニティ ガイドラインが記載されている<b><a href="http://sites.google.com/a/android.com/opensource/discuss/android-discussion-groups-charter">Android メーリングリストの趣意</a></b>をお読みください。 
+<li>コミュニティ ガイドラインが記載されている<b><a href="http://source.android.com/community/groups-charter.html">Android メーリングリストの趣意</a></b>をお読みください。 
 </li>
 <li><b>質問に最適なメーリング リストを選択してください</b>。後述するように、デベロッパー向けのメーリング リストは何種類かに分かれています。</li>
 <li>
diff --git a/docs/html/intl/ja/resources/community-groups.jd b/docs/html/intl/ja/resources/community-groups.jd
index c99b1f8..ecedde1 100644
--- a/docs/html/intl/ja/resources/community-groups.jd
+++ b/docs/html/intl/ja/resources/community-groups.jd
@@ -4,9 +4,9 @@
 
 	<div id="mainBodyFluid">
 			<h1>コミュニティ</h1>
-			<p>Android デベロッパー コミュニティへようこそ。コミュニティでのディスカッションにぜひ参加してください。投稿する前に、コミュニティ ガイドラインが記載されている<a href="http://source.android.com/discuss/android-discussion-groups-charter">グループの趣意</a>をお読みください。</p>
+			<p>Android デベロッパー コミュニティへようこそ。コミュニティでのディスカッションにぜひ参加してください。投稿する前に、コミュニティ ガイドラインが記載されている<a href="http://source.android.com/community/groups-charter.html">グループの趣意</a>をお読みください。</p>
 
-<p class="note"><strong>注:</strong> Android ソース コード(アプリケーション開発ではなく)に関するディスカッションは、<a href="http://source.android.com/discuss">オープンソース プロジェクトのメーリング リスト</a>(英語)を参照してください。</p>
+<p class="note"><strong>注:</strong> Android ソース コード(アプリケーション開発ではなく)に関するディスカッションは、<a href="http://source.android.com/community">オープンソース プロジェクトのメーリング リスト</a>(英語)を参照してください。</p>
 
 <p style="margin-bottom:.5em"><strong>目次</strong></p>
 <ol class="toc">
@@ -28,7 +28,7 @@
 
 <p>質問への答えが見つからない場合、コミュニティで質問することをおすすめします。投稿する際は、次の手順に従ってください。
 <ol>
-<li>コミュニティ ガイドラインが記載されている<b><a href="http://sites.google.com/a/android.com/opensource/discuss/android-discussion-groups-charter">Android メーリングリストの趣意</a></b>をお読みください。 
+<li>コミュニティ ガイドラインが記載されている<b><a href="http://source.android.com/community/groups-charter.html">Android メーリングリストの趣意</a></b>をお読みください。 
 </li>
 <li><b>質問に最適なメーリング リストを選択してください</b>。後述するように、デベロッパー向けのメーリング リストは何種類かに分かれています。</li>
 <li>
diff --git a/docs/html/resources/articles/painless-threading.jd b/docs/html/resources/articles/painless-threading.jd
index 921f4df..17cec35 100644
--- a/docs/html/resources/articles/painless-threading.jd
+++ b/docs/html/resources/articles/painless-threading.jd
@@ -108,7 +108,7 @@
   new DownloadImageTask().execute("http://example.com/image.png");
 }
 
-private class DownloadImageTask extends AsyncTask&lt;string, void,="" bitmap=""&gt; {
+private class DownloadImageTask extends AsyncTask&lt;String, Void, Bitmap&gt; {
      protected Bitmap doInBackground(String... urls) {
          return loadImageFromNetwork(urls[0]);
      }
diff --git a/docs/html/resources/community-groups.jd b/docs/html/resources/community-groups.jd
index 72bdf7a..6d59648 100644
--- a/docs/html/resources/community-groups.jd
+++ b/docs/html/resources/community-groups.jd
@@ -22,7 +22,7 @@
 
 <p>Welcome to the Android developers community! We're glad you're here and invite you to participate in discussions with other Android application developers on topics that interest you.</p>
 
-<p>The lists on this page are primarily for discussion about Android application development. If you are seeking discussion about Android source code (not application development), then please refer to the <a href="http://source.android.com/discuss">Open Source Project Mailing lists</a>.</p>
+<p>The lists on this page are primarily for discussion about Android application development. If you are seeking discussion about Android source code (not application development), then please refer to the <a href="http://source.android.com/community">Open Source Project Mailing lists</a>.</p>
 
 <h2 id="StackOverflow">Stack Overflow</h2>
 
@@ -56,7 +56,7 @@
 As you write your post, please do the following:
 <ol>
 <li><strong>Read
-the <a href="http://source.android.com/discuss/android-discussion-groups-charter">mailing list charter</a></strong> that covers the community guidelines.
+the <a href="http://source.android.com/community/groups-charter.html">mailing list charter</a></strong> that covers the community guidelines.
 </li>
 <li><strong>Select the most appropriate mailing list for your question</strong>. There are several different lists for
 developers, described below.</li>
diff --git a/docs/html/sdk/android-1.5.jd b/docs/html/sdk/android-1.5.jd
index 1d6e0ad..0c16b60 100644
--- a/docs/html/sdk/android-1.5.jd
+++ b/docs/html/sdk/android-1.5.jd
@@ -139,7 +139,7 @@
 
 <div class="toggleable closed">
   <a href="#" onclick="return toggleDiv(this)">
-        <img src="{@docRoot}assets/images/triangle-opened.png" class="toggle-img" height="9px" width="9px" />
+        <img src="{@docRoot}assets/images/triangle-closed.png" class="toggle-img" height="9px" width="9px" />
         Android 1.5, Revision 3</a> <em>(July 2009)</em></a>
   <div class="toggleme">
 <dl>
diff --git a/docs/html/sdk/android-1.6.jd b/docs/html/sdk/android-1.6.jd
index c2651b6..c4e08ff 100644
--- a/docs/html/sdk/android-1.6.jd
+++ b/docs/html/sdk/android-1.6.jd
@@ -138,7 +138,7 @@
 
 <div class="toggleable closed">
   <a href="#" onclick="return toggleDiv(this)">
-        <img src="{@docRoot}assets/images/triangle-opened.png" class="toggle-img" height="9px" width="9px" />
+        <img src="{@docRoot}assets/images/triangle-closed.png" class="toggle-img" height="9px" width="9px" />
         Android 1.6, Revision 2</a> <em>(December 2009)</em></a>
   <div class="toggleme">
 <dl>
diff --git a/docs/html/sdk/android-2.1.jd b/docs/html/sdk/android-2.1.jd
index 7490bae..cd48a72 100644
--- a/docs/html/sdk/android-2.1.jd
+++ b/docs/html/sdk/android-2.1.jd
@@ -139,7 +139,7 @@
 
 <div class="toggleable closed">
   <a href="#" onclick="return toggleDiv(this)">
-        <img src="{@docRoot}assets/images/triangle-opened.png" class="toggle-img" height="9px" width="9px" />
+        <img src="{@docRoot}assets/images/triangle-closed.png" class="toggle-img" height="9px" width="9px" />
         Android 2.1, Revision 1</a> <em>(January 2010)</em></a>
   <div class="toggleme">
 <dl>
diff --git a/docs/html/sdk/android-2.2.jd b/docs/html/sdk/android-2.2.jd
index f82edf9..495fd80 100644
--- a/docs/html/sdk/android-2.2.jd
+++ b/docs/html/sdk/android-2.2.jd
@@ -2,7 +2,6 @@
 sdk.platform.version=2.2
 sdk.platform.apiLevel=8
 sdk.platform.majorMinor=minor
-sdk.platform.deployableDate=May 2010
 
 @jd:body
 
@@ -118,6 +117,30 @@
 <div class="toggleable opened">
   <a href="#" onclick="return toggleDiv(this)">
         <img src="{@docRoot}assets/images/triangle-opened.png" class="toggle-img" height="9px" width="9px" />
+        Android {@sdkPlatformVersion}, Revision 2</a> <em>(July 2010)</em></a>
+  <div class="toggleme">
+<dl>
+<dt>Dependencies:</dt>
+<dd>
+<p>Requires SDK Tools r6 or higher.</p>
+</dd>
+
+<dt>System Image:</dt>
+<dd>
+<ul>
+<li>Adds default Search Widget.</li>
+<li>Includes proper provisioning for the platform's Backup Manager. For more information about how to use the Backup Manager, see <a href="{@docRoot}guide/topics/data/backup.html">Data Backup</a>.</li>
+<li>Updates the Android 2.2 system image to FRF91.</li>
+</ul>
+</dd>
+
+</dl>
+ </div>
+</div>
+
+<div class="toggleable closed">
+  <a href="#" onclick="return toggleDiv(this)">
+        <img src="{@docRoot}assets/images/triangle-closed.png" class="toggle-img" height="9px" width="9px" />
         Android {@sdkPlatformVersion}, Revision 1</a> <em>(May 2010)</em></a>
   <div class="toggleme">
 <dl>
@@ -135,7 +158,6 @@
  </div>
 </div>
 
-
 <h2 id="api-level">API Level</h2>
 
 <p>The Android {@sdkPlatformVersion} platform delivers an updated version of
@@ -444,4 +466,4 @@
 <p>For more information about how to develop an application that displays
 and functions properly on all Android-powered devices, see <a
 href="{@docRoot}guide/practices/screens_support.html">Supporting Multiple
-Screens</a>.</p>
\ No newline at end of file
+Screens</a>.</p>
diff --git a/docs/html/sdk/download.jd b/docs/html/sdk/download.jd
new file mode 100644
index 0000000..81b4ff6
--- /dev/null
+++ b/docs/html/sdk/download.jd
@@ -0,0 +1,4 @@
+sdk.redirect=true
+
+@jd:body
+
diff --git a/docs/html/sdk/eclipse-adt.jd b/docs/html/sdk/eclipse-adt.jd
index f5558ab..bd7eeed 100644
--- a/docs/html/sdk/eclipse-adt.jd
+++ b/docs/html/sdk/eclipse-adt.jd
@@ -48,6 +48,9 @@
 how to update ADT to the latest version or how to uninstall it, if necessary.
 </p>
 
+<p class="caution"><strong>Caution:</strong> There are known issues with the ADT plugin running with
+Eclipse 3.6. Please stay on 3.5 until further notice.</p>
+
 <h2 id="notes">Revisions</h2>
 
 <p>The sections below provide notes about successive releases of
@@ -295,7 +298,7 @@
 
 <p>Additionally, before you can configure or use ADT, you must install the
 Android SDK starter package, as described in <a
-href="installing.html#Installing">Downloading the SDK Starter Pacskage</a>.
+href="installing.html#Installing">Downloading the SDK Starter Package</a>.
 Specifically, you need to install a compatible version of the Android SDK Tools
 and at least one development platform. To simplify ADT setup, we recommend
 installing the Android SDK prior to installing ADT. </p>
diff --git a/docs/html/sdk/ndk/index.jd b/docs/html/sdk/ndk/index.jd
index 69cc73d..9e88d94 100644
--- a/docs/html/sdk/ndk/index.jd
+++ b/docs/html/sdk/ndk/index.jd
@@ -1,16 +1,16 @@
 ndk=true
 
-ndk.win_download=android-ndk-r4-windows.zip
-ndk.win_bytes=45778965
-ndk.win_checksum=1eded98a7f5cd5e71f8ac74565f73f11
+ndk.win_download=android-ndk-r4b-windows.zip
+ndk.win_bytes=45792835
+ndk.win_checksum=e397145e155a639be53ee4b6db8ad511
 
-ndk.mac_download=android-ndk-r4-darwin-x86.zip
-ndk.mac_bytes=50572163
-ndk.mac_checksum=b7d5f149fecf951c05a79b045f00419f
+ndk.mac_download=android-ndk-r4b-darwin-x86.zip
+ndk.mac_bytes=50586041
+ndk.mac_checksum=41dbd54335fb828ee408eab17103a1b0
 
-ndk.linux_download=android-ndk-r4-linux-x86.zip
-ndk.linux_bytes=49450682
-ndk.linux_checksum=0892b0637d45d145e045cc68e163dee3
+ndk.linux_download=android-ndk-r4b-linux-x86.zip
+ndk.linux_bytes=49464776
+ndk.linux_checksum=2deabcb125c219b34140975b710f00ec
 
 page.title=Android NDK
 @jd:body
@@ -62,8 +62,15 @@
 <div class="toggleable open">
   <a href="#" onclick="return toggleDiv(this)">
         <img src="{@docRoot}assets/images/triangle-opened.png" class="toggle-img" height="9px" width="9px" />
-Android NDK, Revision 4</a> <em>(May 2010)</em>
+Android NDK, Revision 4b</a> <em>(June 2010)</em>
   <div class="toggleme">
+<dl>
+<dt>NDK r4b notes:</dt>
+<dd><p>Includes fixes for several issues in the NDK build and debugging scripts
+&mdash; if you are using NDK r4, we recommend downloading the NDK r4b build. For
+detailed information the changes in this release, read the CHANGES.TXT document
+included in the downloaded NDK package.</p></dd>
+</dl>
 
 <dl>
 <dt>General notes:</dt>
@@ -114,7 +121,7 @@
 
 <div class="toggleable closed">
   <a href="#" onclick="return toggleDiv(this)">
-        <img src="{@docRoot}assets/images/triangle-opened.png" class="toggle-img" height="9px" width="9px" />
+        <img src="{@docRoot}assets/images/triangle-closed.png" class="toggle-img" height="9px" width="9px" />
 Android NDK, Revision 3</a> <em>(March 2010)</em>
   <div class="toggleme">
 
diff --git a/docs/html/sdk/requirements.jd b/docs/html/sdk/requirements.jd
index cb9cdf3..d710b8e 100644
--- a/docs/html/sdk/requirements.jd
+++ b/docs/html/sdk/requirements.jd
@@ -23,6 +23,9 @@
 <h4 style="margin-top:.25em"><em>Eclipse IDE</em></h4>
     <ul>
       <li>Eclipse 3.4 (Ganymede) or 3.5 (Galileo)
+         <p class="caution"><strong>Caution:</strong> There are known issues with the ADT plugin
+running with Eclipse 3.6. Please stay on 3.5 until further notice.</p>
+      </li>
       <li>Eclipse <a href="http://www.eclipse.org/jdt">JDT</a> plugin (included
 in most Eclipse IDE packages) </li>
       <li>If you need to install or update Eclipse, you can download it from <a
diff --git a/docs/html/sdk/sdk_toc.cs b/docs/html/sdk/sdk_toc.cs
index a80981ce..404e938 100644
--- a/docs/html/sdk/sdk_toc.cs
+++ b/docs/html/sdk/sdk_toc.cs
@@ -75,7 +75,8 @@
       </li>
     </ul>
     <ul>
-      <li><a href="<?cs var:toroot ?>sdk/tools-notes.html">SDK Tools, r6</a> <span class="new">new!</span></li>
+      <li><a href="<?cs var:toroot ?>sdk/tools-notes.html">SDK Tools, r6</a>
+      </li>
       <li><a href="<?cs var:toroot ?>sdk/win-usb.html">USB Driver for
       Windows, r3</a>
       </li>
@@ -101,7 +102,6 @@
       <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>
     </ul>
   </li>
@@ -116,7 +116,7 @@
       <span style="display:none" class="zh-TW"></span>
     </h2>
     <ul>
-      <li><a href="<?cs var:toroot ?>sdk/ndk/index.html">Android NDK, r4</a>
+      <li><a href="<?cs var:toroot ?>sdk/ndk/index.html">Android NDK, r4b</a>
       <span class="new">new!</span></li>
     </ul>
   </li>
diff --git a/graphics/java/android/graphics/BitmapFactory.java b/graphics/java/android/graphics/BitmapFactory.java
index 5394530..320fc4d 100644
--- a/graphics/java/android/graphics/BitmapFactory.java
+++ b/graphics/java/android/graphics/BitmapFactory.java
@@ -69,8 +69,11 @@
          * the decoder will try to pick the best matching config based on the
          * system's screen depth, and characteristics of the original image such
          * as if it has per-pixel alpha (requiring a config that also does).
+         * 
+         * The configuration is set to {@link android.graphics.Bitmap.Config#ARGB_8888}
+         * by default.
          */
-        public Bitmap.Config inPreferredConfig;
+        public Bitmap.Config inPreferredConfig = Bitmap.Config.ARGB_8888;
 
         /**
          * If dither is true, the decoder will attempt to dither the decoded
diff --git a/graphics/java/android/graphics/BitmapShader.java b/graphics/java/android/graphics/BitmapShader.java
index 612b0ab..37b40e7 100644
--- a/graphics/java/android/graphics/BitmapShader.java
+++ b/graphics/java/android/graphics/BitmapShader.java
@@ -16,10 +16,25 @@
 
 package android.graphics;
 
+/**
+ * Shader used to draw a bitmap as a texture. The bitmap can be repeated or
+ * mirrored by setting the tiling mode.
+ */
 public class BitmapShader extends Shader {
-
-    // we hold on just for the GC, since our native counterpart is using it
-    private Bitmap mBitmap;
+    /**
+     * We hold on just for the GC, since our native counterpart is using it.
+     * 
+     * @hide 
+     */
+    public Bitmap mBitmap;
+    /**
+     * @hide 
+     */
+    public int mTileX;
+    /**
+     * @hide 
+     */
+    public int mTileY;
 
     /**
      * Call this to create a new shader that will draw with a bitmap.
@@ -30,12 +45,11 @@
      */
     public BitmapShader(Bitmap bitmap, TileMode tileX, TileMode tileY) {
         mBitmap = bitmap;
-        native_instance = nativeCreate(bitmap.ni(),
-                                       tileX.nativeInt, tileY.nativeInt);
+        mTileX = tileX.nativeInt;
+        mTileY = tileY.nativeInt;
+        native_instance = nativeCreate(bitmap.ni(), mTileX, mTileY);
     }
 
-    private static native int nativeCreate(int native_bitmap,
-                                           int shaderTileModeX,
-                                           int shaderTileModeY);    
+    private static native int nativeCreate(int native_bitmap, int shaderTileModeX,
+            int shaderTileModeY);    
 }
-
diff --git a/graphics/java/android/graphics/Canvas.java b/graphics/java/android/graphics/Canvas.java
index a4df80c..77a1930 100644
--- a/graphics/java/android/graphics/Canvas.java
+++ b/graphics/java/android/graphics/Canvas.java
@@ -126,6 +126,7 @@
      * 
      * @deprecated This constructor is not supported and should not be invoked.
      */
+    @Deprecated
     public Canvas(GL gl) {
         mNativeCanvas = initGL();
         mGL = gl;
@@ -151,6 +152,7 @@
      * 
      * @deprecated This method is not supported and should not be invoked.
      */
+    @Deprecated
     public GL getGL() {
         return mGL;
     }
@@ -162,6 +164,7 @@
      * 
      * @deprecated This method is not supported and should not be invoked.
      */
+    @Deprecated
     public static void freeGlCaches() {
         freeCaches();
     }
@@ -198,6 +201,7 @@
      * 
      * @deprecated This method is not supported and should not be invoked.
      */
+    @Deprecated
     public void setViewport(int width, int height) {
         if (mGL != null) {
             nativeSetViewport(mNativeCanvas, width, height);
@@ -415,8 +419,8 @@
      *
      * @param sx The amount to scale in X
      * @param sy The amount to scale in Y
-     * @param px The x-coord for the pivot point (unchanged by the rotation)
-     * @param py The y-coord for the pivot point (unchanged by the rotation)
+     * @param px The x-coord for the pivot point (unchanged by the scale)
+     * @param py The y-coord for the pivot point (unchanged by the scale)
      */
     public final void scale(float sx, float sy, float px, float py) {
         translate(px, py);
@@ -1585,6 +1589,7 @@
         restore();
     }
     
+    @Override
     protected void finalize() throws Throwable {
         super.finalize();
         // If the constructor threw an exception before setting mNativeCanvas, the native finalizer
diff --git a/graphics/java/android/graphics/ImageFormat.java b/graphics/java/android/graphics/ImageFormat.java
index f126374..3f9f961 100644
--- a/graphics/java/android/graphics/ImageFormat.java
+++ b/graphics/java/android/graphics/ImageFormat.java
@@ -16,61 +16,84 @@
 
 package android.graphics;
 
-public class ImageFormat
-{
-    /* these constants are chosen to be binary compatible with
-     * their previous location in PixelFormat.java */
-    
-    public static final int UNKNOWN = 0;
+public class ImageFormat {
+	/*
+	 * these constants are chosen to be binary compatible with their previous
+	 * location in PixelFormat.java
+	 */
 
-    /** RGB format used for pictures encoded as RGB_565   
-     *  see {@link android.hardware.Camera.Parameters#setPictureFormat(int)}.
-     */
-    public static final int RGB_565 = 4;
+	public static final int UNKNOWN = 0;
 
-    /**
-     * YCbCr formats, used for video. These are not necessarily supported
-     * by the hardware.
-     */
-    public static final int NV16 = 0x10;
+	/**
+	 * RGB format used for pictures encoded as RGB_565 see
+	 * {@link android.hardware.Camera.Parameters#setPictureFormat(int)}.
+	 */
+	public static final int RGB_565 = 4;
 
-    
-    /** YCrCb format used for images, which uses the NV21 encoding format.   
-     *  This is the default format for camera preview images, when not
-     *  otherwise set with 
-     *  {@link android.hardware.Camera.Parameters#setPreviewFormat(int)}.
-     */
-    public static final int NV21 = 0x11;
+	/**
+	 * Planar 4:2:0 YCrCb format. This format assumes an horizontal stride of 16
+	 * pixels for all planes and an implicit vertical stride of the image
+	 * height's next multiple of two.
+	 *   y_size = stride * ALIGN(height, 2)
+	 *   c_size = ALIGN(stride/2, 16) * height
+	 *   size = y_size + c_size * 2
+	 *   cr_offset = y_size
+	 *   cb_offset = y_size + c_size
+	 * 
+	 * Whether this format is supported by the camera hardware can be determined
+	 * by
+	 * {@link android.hardware.Camera.Parameters#getSupportedPreviewFormats()}.
+	 */
+	public static final int YV12 = 0x32315659;
 
+	/**
+	 * YCbCr format, used for video. Whether this format is supported by the
+	 * camera hardware can be determined by
+	 * {@link android.hardware.Camera.Parameters#getSupportedPreviewFormats()}.
+	 */
+	public static final int NV16 = 0x10;
 
-    /** YCbCr format used for images, which uses YUYV (YUY2) encoding format.
-     *  This is an alternative format for camera preview images. Whether this
-     *  format is supported by the camera hardware can be determined by
-     *  {@link android.hardware.Camera.Parameters#getSupportedPreviewFormats()}.
-     */
-    public static final int YUY2 = 0x14;
+	/**
+	 * YCrCb format used for images, which uses the NV21 encoding format. This
+	 * is the default format for camera preview images, when not otherwise set
+	 * with {@link android.hardware.Camera.Parameters#setPreviewFormat(int)}.
+	 */
+	public static final int NV21 = 0x11;
 
-    
-    /**
-     * Encoded formats.  These are not necessarily supported by the hardware.
-     */
-    public static final int JPEG = 0x100;
+	/**
+	 * YCbCr format used for images, which uses YUYV (YUY2) encoding format.
+	 * This is an alternative format for camera preview images. Whether this
+	 * format is supported by the camera hardware can be determined by
+	 * {@link android.hardware.Camera.Parameters#getSupportedPreviewFormats()}.
+	 */
+	public static final int YUY2 = 0x14;
 
+	/**
+	 * Encoded formats. These are not necessarily supported by the hardware.
+	 */
+	public static final int JPEG = 0x100;
 
-    /**
-     * Use this function to retrieve the number of bits per pixel of
-     * an ImageFormat.
-     * @param format
-     * @return the number of bits per pixel of the given format or -1 if the
-     * format doesn't exist or is not supported.
-     */
-    public static int getBitsPerPixel(int format) {
-        switch (format) {
-            case RGB_565:   return 16;
-            case NV16:      return 16;
-            case NV21:      return 12;
-            case YUY2:      return 16;
-        }
-        return -1;
-    }
+	/**
+	 * Use this function to retrieve the number of bits per pixel of an
+	 * ImageFormat.
+	 * 
+	 * @param format
+	 * @return the number of bits per pixel of the given format or -1 if the
+	 *         format doesn't exist or is not supported.
+	 */
+	public static int getBitsPerPixel(int format) {
+		switch (format) {
+		case RGB_565:
+			return 16;
+		case NV16:
+			return 16;
+		case YUY2:
+			return 16;
+		case YV12:
+			return 12;
+		case NV21:
+			return 12;
+		}
+		return -1;
+	}
 }
diff --git a/graphics/java/android/graphics/Paint.java b/graphics/java/android/graphics/Paint.java
index 88ff0e6..9b4d3a8 100644
--- a/graphics/java/android/graphics/Paint.java
+++ b/graphics/java/android/graphics/Paint.java
@@ -1718,7 +1718,8 @@
         if ((index | count) < 0 || index + count > text.length) {
             throw new ArrayIndexOutOfBoundsException();
         }
-        native_getTextPath(mNativePaint, text, index, count, x, y, path.ni());
+        native_getTextPath(mNativePaint, mBidiFlags, text, index, count, x, y, 
+                path.ni());
     }
 
     /**
@@ -1739,7 +1740,8 @@
         if ((start | end | (end - start) | (text.length() - end)) < 0) {
             throw new IndexOutOfBoundsException();
         }
-        native_getTextPath(mNativePaint, text, start, end, x, y, path.ni());
+        native_getTextPath(mNativePaint, mBidiFlags, text, start, end, x, y, 
+                path.ni());
     }
     
     /**
@@ -1836,9 +1838,9 @@
     private native int native_getTextRunCursor(int native_object, String text,
             int contextStart, int contextEnd, int flags, int offset, int cursorOpt);
 
-    private static native void native_getTextPath(int native_object,
+    private static native void native_getTextPath(int native_object, int bidiFlags,
                 char[] text, int index, int count, float x, float y, int path);
-    private static native void native_getTextPath(int native_object,
+    private static native void native_getTextPath(int native_object, int bidiFlags,
                 String text, int start, int end, float x, float y, int path);
     private static native void nativeGetStringBounds(int nativePaint,
                                 String text, int start, int end, Rect bounds);
diff --git a/graphics/java/android/graphics/Rect.java b/graphics/java/android/graphics/Rect.java
index 98ffb8b..7830224 100644
--- a/graphics/java/android/graphics/Rect.java
+++ b/graphics/java/android/graphics/Rect.java
@@ -75,6 +75,7 @@
         bottom = r.bottom;
     }
 
+    @Override
     public boolean equals(Object obj) {
         Rect r = (Rect) obj;
         if (r != null) {
@@ -84,6 +85,7 @@
         return false;
     }
 
+    @Override
     public String toString() {
         StringBuilder sb = new StringBuilder(32);
         sb.append("Rect("); sb.append(left); sb.append(", ");
@@ -351,7 +353,7 @@
      * rectangle, return true and set this rectangle to that intersection,
      * otherwise return false and do not change this rectangle. No check is
      * performed to see if either rectangle is empty. Note: To just test for
-     * intersection, use intersects()
+     * intersection, use {@link #intersects(Rect, Rect)}.
      *
      * @param left The left side of the rectangle being intersected with this
      *             rectangle
@@ -445,7 +447,7 @@
     /**
      * Returns true iff the two specified rectangles intersect. In no event are
      * either of the rectangles modified. To record the intersection,
-     * use intersect() or setIntersect().
+     * use {@link #intersect(Rect)} or {@link #setIntersect(Rect, Rect)}.
      *
      * @param a The first rectangle being tested for intersection
      * @param b The second rectangle being tested for intersection
diff --git a/graphics/java/android/graphics/Shader.java b/graphics/java/android/graphics/Shader.java
index ae0304e..03eb55b 100644
--- a/graphics/java/android/graphics/Shader.java
+++ b/graphics/java/android/graphics/Shader.java
@@ -23,9 +23,19 @@
  * drawn with that paint will get its color(s) from the shader.
  */
 public class Shader {
+    /**
+     * Local matrix native instance.
+     * 
+     * @hide
+     */
+    public int mLocalMatrix;
 
-    // this is set by subclasses, but don't make it public
-    /* package */ int native_instance;
+    /**
+     * This is set by subclasses, but don't make it public.
+     * 
+     * @hide 
+     */
+    public int native_instance;
 
     public enum TileMode {
         /**
@@ -64,11 +74,12 @@
      * @param localM The shader's new local matrix, or null to specify identity
      */
     public void setLocalMatrix(Matrix localM) {
-        nativeSetLocalMatrix(native_instance,
-                             localM != null ? localM.native_instance : 0);
+        mLocalMatrix = localM != null ? localM.native_instance : 0;
+        nativeSetLocalMatrix(native_instance, mLocalMatrix);
     }
 
     protected void finalize() throws Throwable {
+        super.finalize();
         nativeDestructor(native_instance);
     }
 
diff --git a/graphics/java/android/graphics/drawable/AnimationDrawable.java b/graphics/java/android/graphics/drawable/AnimationDrawable.java
index fdc4c92..e275ba8 100644
--- a/graphics/java/android/graphics/drawable/AnimationDrawable.java
+++ b/graphics/java/android/graphics/drawable/AnimationDrawable.java
@@ -64,6 +64,8 @@
  * // Start the animation (looped playback by default).
  * frameAnimation.start()
  * </pre>
+ * <p>For more information, see the guide to <a
+ * href="{@docRoot}guide/topics/resources/animation-resource.html">Animation Resources</a>.</p>
  *
  * @attr ref android.R.styleable#AnimationDrawable_visible
  * @attr ref android.R.styleable#AnimationDrawable_variablePadding
diff --git a/graphics/java/android/graphics/drawable/BitmapDrawable.java b/graphics/java/android/graphics/drawable/BitmapDrawable.java
index 29e14d2..32111e8 100644
--- a/graphics/java/android/graphics/drawable/BitmapDrawable.java
+++ b/graphics/java/android/graphics/drawable/BitmapDrawable.java
@@ -40,7 +40,9 @@
  * A Drawable that wraps a bitmap and can be tiled, stretched, or aligned. You can create a
  * BitmapDrawable from a file path, an input stream, through XML inflation, or from
  * a {@link android.graphics.Bitmap} object.
- * <p>It can be defined in an XML file with the <code>&lt;bitmap></code> element.</p>
+ * <p>It can be defined in an XML file with the <code>&lt;bitmap></code> element.  For more
+ * information, see the guide to <a
+ * href="{@docRoot}guide/topics/resources/drawable-resource.html">Drawable Resources</a>.</p>
  * <p>
  * Also see the {@link android.graphics.Bitmap} class, which handles the management and 
  * transformation of raw bitmap graphics, and should be used when drawing to a 
diff --git a/graphics/java/android/graphics/drawable/ClipDrawable.java b/graphics/java/android/graphics/drawable/ClipDrawable.java
index c387a9b..a772871 100644
--- a/graphics/java/android/graphics/drawable/ClipDrawable.java
+++ b/graphics/java/android/graphics/drawable/ClipDrawable.java
@@ -32,9 +32,14 @@
  * level value.  You can control how much the child Drawable gets clipped in width
  * and height based on the level, as well as a gravity to control where it is
  * placed in its overall container.  Most often used to implement things like
- * progress bars.
+ * progress bars, by increasing the drawable's level with {@link
+ * android.graphics.drawable.Drawable#setLevel(int) setLevel()}.
+ * <p class="note"><strong>Note:</strong> The drawable is clipped completely and not visible when
+ * the level is 0 and fully revealed when the level is 10,000.</p>
  *
- * <p>It can be defined in an XML file with the <code>&lt;clip></code> element.</p>
+ * <p>It can be defined in an XML file with the <code>&lt;clip></code> element.  For more
+ * information, see the guide to <a
+ * href="{@docRoot}guide/topics/resources/drawable-resource.html">Drawable Resources</a>.</p>
  *
  * @attr ref android.R.styleable#ClipDrawable_clipOrientation
  * @attr ref android.R.styleable#ClipDrawable_gravity
diff --git a/graphics/java/android/graphics/drawable/Drawable.java b/graphics/java/android/graphics/drawable/Drawable.java
index 4c1d243..7b2d9d7 100644
--- a/graphics/java/android/graphics/drawable/Drawable.java
+++ b/graphics/java/android/graphics/drawable/Drawable.java
@@ -102,8 +102,8 @@
  *     whose overall size is modified based on the current level.
  * </ul>
  * <p>For information and examples of creating drawable resources (XML or bitmap files that
- * can be loaded in code), see <a href="{@docRoot}guide/topics/resources/resources-i18n.html">Resources
- * and Internationalization</a>.
+ * can be loaded in code), see <a
+ * href="{@docRoot}guide/topics/resources/drawable-resource.html">Drawable Resources</a>.
  */
 public abstract class Drawable {
     private static final Rect ZERO_BOUNDS_RECT = new Rect();
@@ -720,8 +720,7 @@
     /**
      * Create a drawable from an XML document. For more information on how to
      * create resources in XML, see
-     * <a href="{@docRoot}guide/topics/resources/resources-i18n.html">Resources and
-     * Internationalization</a>.
+     * <a href="{@docRoot}guide/topics/resources/drawable-resource.html">Drawable Resources</a>.
      */
     public static Drawable createFromXml(Resources r, XmlPullParser parser)
             throws XmlPullParserException, IOException {
diff --git a/graphics/java/android/graphics/drawable/GradientDrawable.java b/graphics/java/android/graphics/drawable/GradientDrawable.java
index 63d1446..33ecbea 100644
--- a/graphics/java/android/graphics/drawable/GradientDrawable.java
+++ b/graphics/java/android/graphics/drawable/GradientDrawable.java
@@ -42,7 +42,9 @@
 /**
  * A Drawable with a color gradient for buttons, backgrounds, etc. 
  *
- * <p>It can be defined in an XML file with the <code>&lt;shape></code> element.</p>
+ * <p>It can be defined in an XML file with the <code>&lt;shape></code> element. For more
+ * information, see the guide to <a
+ * href="{@docRoot}guide/topics/resources/drawable-resource.html">Drawable Resources</a>.</p>
  *
  * @attr ref android.R.styleable#GradientDrawable_visible
  * @attr ref android.R.styleable#GradientDrawable_shape
diff --git a/graphics/java/android/graphics/drawable/InsetDrawable.java b/graphics/java/android/graphics/drawable/InsetDrawable.java
index 4fa9d44..a9c983e 100644
--- a/graphics/java/android/graphics/drawable/InsetDrawable.java
+++ b/graphics/java/android/graphics/drawable/InsetDrawable.java
@@ -32,7 +32,9 @@
  * This is used when a View needs a background that is smaller than
  * the View's actual bounds.
  *
- * <p>It can be defined in an XML file with the <code>&lt;inset></code> element.</p>
+ * <p>It can be defined in an XML file with the <code>&lt;inset></code> element. For more
+ * information, see the guide to <a
+ * href="{@docRoot}guide/topics/resources/drawable-resource.html">Drawable Resources</a>.</p>
  *
  * @attr ref android.R.styleable#InsetDrawable_visible
  * @attr ref android.R.styleable#InsetDrawable_drawable
diff --git a/graphics/java/android/graphics/drawable/LayerDrawable.java b/graphics/java/android/graphics/drawable/LayerDrawable.java
index b727d47..501cca9 100644
--- a/graphics/java/android/graphics/drawable/LayerDrawable.java
+++ b/graphics/java/android/graphics/drawable/LayerDrawable.java
@@ -32,8 +32,9 @@
  * order, so the element with the largest index will be drawn on top.
  * <p>
  * It can be defined in an XML file with the <code>&lt;layer-list></code> element.
- * Each Drawable in the layer is defined in a nested <code>&lt;item></code>.
- * </p>
+ * Each Drawable in the layer is defined in a nested <code>&lt;item></code>. For more
+ * information, see the guide to <a
+ * href="{@docRoot}guide/topics/resources/drawable-resource.html">Drawable Resources</a>.</p>
  *
  * @attr ref android.R.styleable#LayerDrawableItem_left
  * @attr ref android.R.styleable#LayerDrawableItem_top
diff --git a/graphics/java/android/graphics/drawable/LevelListDrawable.java b/graphics/java/android/graphics/drawable/LevelListDrawable.java
index ae8f224..21be983 100644
--- a/graphics/java/android/graphics/drawable/LevelListDrawable.java
+++ b/graphics/java/android/graphics/drawable/LevelListDrawable.java
@@ -47,7 +47,10 @@
  * <p>With this XML saved into the res/drawable/ folder of the project, it can be referenced as
  * the drawable for an {@link android.widget.ImageView}. The default image is the first in the list.
  * It can then be changed to one of the other levels with
- * {@link android.widget.ImageView#setImageLevel(int)}.</p>
+ * {@link android.widget.ImageView#setImageLevel(int)}. For more
+ * information, see the guide to <a
+ * href="{@docRoot}guide/topics/resources/drawable-resource.html">Drawable Resources</a>.</p>
+ *
  * @attr ref android.R.styleable#LevelListDrawableItem_minLevel
  * @attr ref android.R.styleable#LevelListDrawableItem_maxLevel
  * @attr ref android.R.styleable#LevelListDrawableItem_drawable
diff --git a/graphics/java/android/graphics/drawable/RotateDrawable.java b/graphics/java/android/graphics/drawable/RotateDrawable.java
index 2083e05..9c47dab 100644
--- a/graphics/java/android/graphics/drawable/RotateDrawable.java
+++ b/graphics/java/android/graphics/drawable/RotateDrawable.java
@@ -35,7 +35,9 @@
  * value. The start and end angles of rotation can be controlled to map any
  * circular arc to the level values range.</p>
  *
- * <p>It can be defined in an XML file with the <code>&lt;rotate></code> element.</p>
+ * <p>It can be defined in an XML file with the <code>&lt;rotate></code> element. For more
+ * information, see the guide to <a
+ * href="{@docRoot}guide/topics/resources/animation-resource.html">Animation Resources</a>.</p>
  *
  * @attr ref android.R.styleable#RotateDrawable_visible
  * @attr ref android.R.styleable#RotateDrawable_fromDegrees
diff --git a/graphics/java/android/graphics/drawable/ScaleDrawable.java b/graphics/java/android/graphics/drawable/ScaleDrawable.java
index 275e36f..b623d80 100644
--- a/graphics/java/android/graphics/drawable/ScaleDrawable.java
+++ b/graphics/java/android/graphics/drawable/ScaleDrawable.java
@@ -34,7 +34,9 @@
  * placed in its overall container.  Most often used to implement things like
  * progress bars.
  *
- * <p>It can be defined in an XML file with the <code>&lt;scale></code> element.</p>
+ * <p>It can be defined in an XML file with the <code>&lt;scale></code> element. For more
+ * information, see the guide to <a
+ * href="{@docRoot}guide/topics/resources/drawable-resource.html">Drawable Resources</a>.</p>
  *
  * @attr ref android.R.styleable#ScaleDrawable_scaleWidth
  * @attr ref android.R.styleable#ScaleDrawable_scaleHeight
diff --git a/graphics/java/android/graphics/drawable/ShapeDrawable.java b/graphics/java/android/graphics/drawable/ShapeDrawable.java
index c699a82..be1892e 100644
--- a/graphics/java/android/graphics/drawable/ShapeDrawable.java
+++ b/graphics/java/android/graphics/drawable/ShapeDrawable.java
@@ -34,6 +34,10 @@
  * the ShapeDrawable will default to a 
  * {@link android.graphics.drawable.shapes.RectShape}.
  *
+ * <p>It can be defined in an XML file with the <code>&lt;shape></code> element. For more
+ * information, see the guide to <a
+ * href="{@docRoot}guide/topics/resources/drawable-resource.html">Drawable Resources</a>.</p>
+ *
  * @attr ref android.R.styleable#ShapeDrawablePadding_left
  * @attr ref android.R.styleable#ShapeDrawablePadding_top
  * @attr ref android.R.styleable#ShapeDrawablePadding_right
diff --git a/graphics/java/android/graphics/drawable/StateListDrawable.java b/graphics/java/android/graphics/drawable/StateListDrawable.java
index b94df84..239be40 100644
--- a/graphics/java/android/graphics/drawable/StateListDrawable.java
+++ b/graphics/java/android/graphics/drawable/StateListDrawable.java
@@ -31,7 +31,9 @@
  * ID value.
  * <p/>
  * <p>It can be defined in an XML file with the <code>&lt;selector></code> element.
- * Each state Drawable is defined in a nested <code>&lt;item></code> element.</p>
+ * Each state Drawable is defined in a nested <code>&lt;item></code> element. For more
+ * information, see the guide to <a
+ * href="{@docRoot}guide/topics/resources/drawable-resource.html">Drawable Resources</a>.</p>
  *
  * @attr ref android.R.styleable#StateListDrawable_visible
  * @attr ref android.R.styleable#StateListDrawable_variablePadding
diff --git a/graphics/java/android/graphics/drawable/TransitionDrawable.java b/graphics/java/android/graphics/drawable/TransitionDrawable.java
index 97b45d8..4470356 100644
--- a/graphics/java/android/graphics/drawable/TransitionDrawable.java
+++ b/graphics/java/android/graphics/drawable/TransitionDrawable.java
@@ -26,8 +26,10 @@
  * display just the first layer, call {@link #resetTransition()}.
  * <p>
  * It can be defined in an XML file with the <code>&lt;transition></code> element.
- * Each Drawable in the transition is defined in a nested <code>&lt;item></code>.
- * </p>
+ * Each Drawable in the transition is defined in a nested <code>&lt;item></code>. For more
+ * information, see the guide to <a
+ * href="{@docRoot}guide/topics/resources/drawable-resource.html">Drawable Resources</a>.</p>
+ *
  * @attr ref android.R.styleable#LayerDrawableItem_left
  * @attr ref android.R.styleable#LayerDrawableItem_top
  * @attr ref android.R.styleable#LayerDrawableItem_right
@@ -212,7 +214,7 @@
      * Enables or disables the cross fade of the drawables. When cross fade
      * is disabled, the first drawable is always drawn opaque. With cross
      * fade enabled, the first drawable is drawn with the opposite alpha of
-     * the second drawable.
+     * the second drawable. Cross fade is disabled by default.
      *
      * @param enabled True to enable cross fading, false otherwise.
      */
diff --git a/graphics/java/android/renderscript/Allocation.java b/graphics/java/android/renderscript/Allocation.java
index ddb2abf..87735b5 100644
--- a/graphics/java/android/renderscript/Allocation.java
+++ b/graphics/java/android/renderscript/Allocation.java
@@ -40,6 +40,21 @@
         mType = t;
     }
 
+    Allocation(int id, RenderScript rs) {
+        super(rs);
+        mID = id;
+    }
+
+    @Override
+    void updateFromNative() {
+        mRS.validate();
+        int typeID = mRS.nAllocationGetType(mID);
+        if(typeID != 0) {
+            mType = new Type(typeID, mRS);
+            mType.updateFromNative();
+        }
+    }
+
     public Type getType() {
         return mType;
     }
diff --git a/graphics/java/android/renderscript/BaseObj.java b/graphics/java/android/renderscript/BaseObj.java
index 002fc78..28675dc 100644
--- a/graphics/java/android/renderscript/BaseObj.java
+++ b/graphics/java/android/renderscript/BaseObj.java
@@ -81,5 +81,10 @@
         mRS.nObjDestroy(mID);
     }
 
+    // If an object came from an a3d file, java fields need to be
+    // created with objects from the native layer
+    void updateFromNative() {
+    }
+
 }
 
diff --git a/graphics/java/android/renderscript/Element.java b/graphics/java/android/renderscript/Element.java
index 308d663..5d2a059 100644
--- a/graphics/java/android/renderscript/Element.java
+++ b/graphics/java/android/renderscript/Element.java
@@ -17,6 +17,7 @@
 package android.renderscript;
 
 import java.lang.reflect.Field;
+import android.util.Log;
 
 /**
  * @hide
@@ -308,6 +309,45 @@
         mID = rs.nElementCreate(dt.mID, dk.mID, norm, size);
     }
 
+    Element(RenderScript rs, int id) {
+        super(rs);
+        mID = id;
+    }
+
+    @Override
+    void updateFromNative() {
+
+        // we will pack mType; mKind; mNormalized; mVectorSize; NumSubElements
+        int[] dataBuffer = new int[5];
+        mRS.nElementGetNativeData(mID, dataBuffer);
+        for (DataType dt: DataType.values()) {
+            if(dt.mID == dataBuffer[0]){
+                mType = dt;
+            }
+        }
+        for (DataKind dk: DataKind.values()) {
+            if(dk.mID == dataBuffer[1]){
+                mKind = dk;
+            }
+        }
+
+        mNormalized = dataBuffer[2] == 1 ? true : false;
+        mVectorSize = dataBuffer[3];
+        int numSubElements = dataBuffer[4];
+        if(numSubElements > 0) {
+            mElements = new Element[numSubElements];
+            mElementNames = new String[numSubElements];
+
+            int[] subElementIds = new int[numSubElements];
+            mRS.nElementGetSubElements(mID, subElementIds, mElementNames);
+            for(int i = 0; i < numSubElements; i ++) {
+                mElements[i] = new Element(mRS, subElementIds[i]);
+                mElements[i].updateFromNative();
+            }
+        }
+
+    }
+
     public void destroy() throws IllegalStateException {
         super.destroy();
     }
diff --git a/graphics/java/android/renderscript/FileA3D.java b/graphics/java/android/renderscript/FileA3D.java
index 3b3711b..302a5f4 100644
--- a/graphics/java/android/renderscript/FileA3D.java
+++ b/graphics/java/android/renderscript/FileA3D.java
@@ -56,7 +56,7 @@
     }
 
     // Read only class with index entries
-    public class IndexEntry {
+    public static class IndexEntry {
         RenderScript mRS;
         int mIndex;
         int mID;
@@ -73,34 +73,40 @@
         }
 
         public BaseObj getObject() {
-            if(mLoadedObj != null) {
-                return mLoadedObj;
+            mRS.validate();
+            BaseObj obj = internalCreate(mRS, this);
+            return obj;
+        }
+
+        static synchronized BaseObj internalCreate(RenderScript rs, IndexEntry entry) {
+            if(entry.mLoadedObj != null) {
+                return entry.mLoadedObj;
             }
 
-            if(mClassID == ClassID.UNKNOWN) {
+            if(entry.mClassID == ClassID.UNKNOWN) {
                 return null;
             }
 
-            int objectID = mRS.nFileA3DGetEntryByIndex(mID, mIndex);
+            int objectID = rs.nFileA3DGetEntryByIndex(entry.mID, entry.mIndex);
             if(objectID == 0) {
                 return null;
             }
 
-            switch (mClassID) {
+            switch (entry.mClassID) {
             case MESH:
-                mLoadedObj = new Mesh(objectID, mRS);
+                entry.mLoadedObj = new Mesh(objectID, rs);
                 break;
             case TYPE:
-                mLoadedObj = new Type(objectID, mRS);
+                entry.mLoadedObj = new Type(objectID, rs);
                 break;
             case ELEMENT:
-                mLoadedObj = null;
+                entry.mLoadedObj = null;
                 break;
             case ALLOCATION:
-                mLoadedObj = null;
+                entry.mLoadedObj = null;
                 break;
             case PROGRAM_VERTEX:
-                mLoadedObj = new ProgramVertex(objectID, mRS);
+                entry.mLoadedObj = new ProgramVertex(objectID, rs);
                 break;
             case PROGRAM_RASTER:
                 break;
@@ -122,7 +128,9 @@
                 break;
             }
 
-            return mLoadedObj;
+            entry.mLoadedObj.updateFromNative();
+
+            return entry.mLoadedObj;
         }
 
         IndexEntry(RenderScript rs, int index, int id, String name, ClassID classID) {
diff --git a/graphics/java/android/renderscript/Mesh.java b/graphics/java/android/renderscript/Mesh.java
index 5a53878..4bee97a 100644
--- a/graphics/java/android/renderscript/Mesh.java
+++ b/graphics/java/android/renderscript/Mesh.java
@@ -59,6 +59,38 @@
         return mPrimitives[slot];
     }
 
+    @Override
+    void updateFromNative() {
+        int vtxCount = mRS.nMeshGetVertexBufferCount(mID);
+        int idxCount = mRS.nMeshGetIndexCount(mID);
+
+        int[] vtxIDs = new int[vtxCount];
+        int[] idxIDs = new int[idxCount];
+        int[] primitives = new int[idxCount];
+
+        mRS.nMeshGetVertices(mID, vtxIDs, vtxCount);
+        mRS.nMeshGetIndices(mID, idxIDs, primitives, vtxCount);
+
+        mVertexBuffers = new Allocation[vtxCount];
+        mIndexBuffers = new Allocation[idxCount];
+        mPrimitives = new Primitive[idxCount];
+
+        for(int i = 0; i < vtxCount; i ++) {
+            if(vtxIDs[i] != 0) {
+                mVertexBuffers[i] = new Allocation(vtxIDs[i], mRS);
+                mVertexBuffers[i].updateFromNative();
+            }
+        }
+
+        for(int i = 0; i < idxCount; i ++) {
+            if(idxIDs[i] != 0) {
+                mIndexBuffers[i] = new Allocation(idxIDs[i], mRS);
+                mIndexBuffers[i].updateFromNative();
+            }
+            mPrimitives[i] = Primitive.values()[primitives[i]];
+        }
+    }
+
     public static class Builder {
         RenderScript mRS;
 
diff --git a/graphics/java/android/renderscript/Program.java b/graphics/java/android/renderscript/Program.java
index 1614ec5..b16dac1 100644
--- a/graphics/java/android/renderscript/Program.java
+++ b/graphics/java/android/renderscript/Program.java
@@ -91,8 +91,9 @@
             mTextureCount = 0;
         }
 
-        public void setShader(String s) {
+        public BaseProgramBuilder setShader(String s) {
             mShader = s;
+            return this;
         }
 
         public void addInput(Element e) throws IllegalStateException {
@@ -120,12 +121,13 @@
             return mConstantCount++;
         }
 
-        public void setTextureCount(int count) throws IllegalArgumentException {
+        public BaseProgramBuilder setTextureCount(int count) throws IllegalArgumentException {
             // Should check for consistant and non-conflicting names...
             if(count >= MAX_CONSTANT) {
                 throw new IllegalArgumentException("Max texture count exceeded.");
             }
             mTextureCount = count;
+            return this;
         }
 
         protected void initProgram(Program p) {
diff --git a/graphics/java/android/renderscript/ProgramFragment.java b/graphics/java/android/renderscript/ProgramFragment.java
index 5e04f0c..d06d768 100644
--- a/graphics/java/android/renderscript/ProgramFragment.java
+++ b/graphics/java/android/renderscript/ProgramFragment.java
@@ -106,16 +106,18 @@
             mPointSpriteEnable = false;
         }
 
-        public void setTexture(EnvMode env, Format fmt, int slot)
+        public Builder setTexture(EnvMode env, Format fmt, int slot)
             throws IllegalArgumentException {
             if((slot < 0) || (slot >= MAX_TEXTURE)) {
                 throw new IllegalArgumentException("MAX_TEXTURE exceeded.");
             }
             mSlots[slot] = new Slot(env, fmt);
+            return this;
         }
 
-        public void setPointSpriteTexCoordinateReplacement(boolean enable) {
+        public Builder setPointSpriteTexCoordinateReplacement(boolean enable) {
             mPointSpriteEnable = enable;
+            return this;
         }
 
         public ProgramFragment create() {
diff --git a/graphics/java/android/renderscript/ProgramRaster.java b/graphics/java/android/renderscript/ProgramRaster.java
index 56f9bf4..6fc9fff 100644
--- a/graphics/java/android/renderscript/ProgramRaster.java
+++ b/graphics/java/android/renderscript/ProgramRaster.java
@@ -26,23 +26,34 @@
  *
  **/
 public class ProgramRaster extends BaseObj {
+
+    public enum CullMode {
+        BACK (0),
+        FRONT (1),
+        NONE (2);
+
+        int mID;
+        CullMode(int id) {
+            mID = id;
+        }
+    }
+
     boolean mPointSmooth;
     boolean mLineSmooth;
     boolean mPointSprite;
-    float mPointSize;
     float mLineWidth;
-    Element mIn;
-    Element mOut;
+    CullMode mCullMode;
 
     ProgramRaster(int id, RenderScript rs) {
         super(rs);
         mID = id;
 
-        mPointSize = 1.0f;
         mLineWidth = 1.0f;
         mPointSmooth = false;
         mLineSmooth = false;
         mPointSprite = false;
+
+        mCullMode = CullMode.BACK;
     }
 
     public void setLineWidth(float w) {
@@ -51,51 +62,43 @@
         mRS.nProgramRasterSetLineWidth(mID, w);
     }
 
-    public void setPointSize(float s) {
+    public void setCullMode(CullMode m) {
         mRS.validate();
-        mPointSize = s;
-        mRS.nProgramRasterSetPointSize(mID, s);
+        mCullMode = m;
+        mRS.nProgramRasterSetCullMode(mID, m.mID);
     }
 
-    void internalInit() {
-        int inID = 0;
-        int outID = 0;
-        if (mIn != null) {
-            inID = mIn.mID;
-        }
-        if (mOut != null) {
-            outID = mOut.mID;
-        }
-        mID = mRS.nProgramRasterCreate(inID, outID, mPointSmooth, mLineSmooth, mPointSprite);
-    }
-
-
     public static class Builder {
         RenderScript mRS;
-        ProgramRaster mPR;
+        boolean mPointSprite;
+        boolean mPointSmooth;
+        boolean mLineSmooth;
 
-        public Builder(RenderScript rs, Element in, Element out) {
+        public Builder(RenderScript rs) {
             mRS = rs;
-            mPR = new ProgramRaster(0, rs);
+            mPointSmooth = false;
+            mLineSmooth = false;
+            mPointSprite = false;
         }
 
-        public void setPointSpriteEnable(boolean enable) {
-            mPR.mPointSprite = enable;
+        public Builder setPointSpriteEnable(boolean enable) {
+            mPointSprite = enable;
+            return this;
         }
 
-        public void setPointSmoothEnable(boolean enable) {
-            mPR.mPointSmooth = enable;
+        public Builder setPointSmoothEnable(boolean enable) {
+            mPointSmooth = enable;
+            return this;
         }
 
-        public void setLineSmoothEnable(boolean enable) {
-            mPR.mLineSmooth = enable;
+        public Builder setLineSmoothEnable(boolean enable) {
+            mLineSmooth = enable;
+            return this;
         }
 
-
         static synchronized ProgramRaster internalCreate(RenderScript rs, Builder b) {
-            b.mPR.internalInit();
-            ProgramRaster pr = b.mPR;
-            b.mPR = new ProgramRaster(0, b.mRS);
+            int id = rs.nProgramRasterCreate(b.mPointSmooth, b.mLineSmooth, b.mPointSprite);
+            ProgramRaster pr = new ProgramRaster(id, rs);
             return pr;
         }
 
@@ -111,3 +114,4 @@
 
 
 
+
diff --git a/graphics/java/android/renderscript/ProgramStore.java b/graphics/java/android/renderscript/ProgramStore.java
index f558117..a92cbb6 100644
--- a/graphics/java/android/renderscript/ProgramStore.java
+++ b/graphics/java/android/renderscript/ProgramStore.java
@@ -114,28 +114,33 @@
 
         }
 
-        public void setDepthFunc(DepthFunc func) {
+        public Builder setDepthFunc(DepthFunc func) {
             mDepthFunc = func;
+            return this;
         }
 
-        public void setDepthMask(boolean enable) {
+        public Builder setDepthMask(boolean enable) {
             mDepthMask = enable;
+            return this;
         }
 
-        public void setColorMask(boolean r, boolean g, boolean b, boolean a) {
+        public Builder setColorMask(boolean r, boolean g, boolean b, boolean a) {
             mColorMaskR = r;
             mColorMaskG = g;
             mColorMaskB = b;
             mColorMaskA = a;
+            return this;
         }
 
-        public void setBlendFunc(BlendSrcFunc src, BlendDstFunc dst) {
+        public Builder setBlendFunc(BlendSrcFunc src, BlendDstFunc dst) {
             mBlendSrc = src;
             mBlendDst = dst;
+            return this;
         }
 
-        public void setDitherEnable(boolean enable) {
+        public Builder setDitherEnable(boolean enable) {
             mDither = enable;
+            return this;
         }
 
         static synchronized ProgramStore internalCreate(RenderScript rs, Builder b) {
diff --git a/graphics/java/android/renderscript/ProgramVertex.java b/graphics/java/android/renderscript/ProgramVertex.java
index 1b155d7..ec377e2 100644
--- a/graphics/java/android/renderscript/ProgramVertex.java
+++ b/graphics/java/android/renderscript/ProgramVertex.java
@@ -47,8 +47,9 @@
             mRS = rs;
         }
 
-        public void setTextureMatrixEnable(boolean enable) {
+        public Builder setTextureMatrixEnable(boolean enable) {
             mTextureMatrixEnable = enable;
+            return this;
         }
 
         public ProgramVertex create() {
diff --git a/graphics/java/android/renderscript/RenderScript.java b/graphics/java/android/renderscript/RenderScript.java
index fcc6cbb..1135a75 100644
--- a/graphics/java/android/renderscript/RenderScript.java
+++ b/graphics/java/android/renderscript/RenderScript.java
@@ -90,12 +90,15 @@
 
     native int  nElementCreate(int type, int kind, boolean norm, int vecSize);
     native int  nElementCreate2(int[] elements, String[] names);
+    native void nElementGetNativeData(int id, int[] elementData);
+    native void nElementGetSubElements(int id, int[] IDs, String[] names);
 
     native void nTypeBegin(int elementID);
     native void nTypeAdd(int dim, int val);
     native int  nTypeCreate();
     native void nTypeFinalDestroy(Type t);
     native void nTypeSetupFields(Type t, int[] types, int[] bits, Field[] IDs);
+    native void nTypeGetNativeData(int id, int[] typeData);
 
     native int  nAllocationCreateTyped(int type);
     native int  nAllocationCreateFromBitmap(int dstFmt, boolean genMips, Bitmap bmp);
@@ -117,6 +120,7 @@
     native void nAllocationRead(int id, float[] d);
     native void nAllocationSubDataFromObject(int id, Type t, int offset, Object o);
     native void nAllocationSubReadFromObject(int id, Type t, int offset, Object o);
+    native int  nAllocationGetType(int id);
 
     native int  nFileA3DCreateFromAssetStream(int assetStream);
     native int  nFileA3DGetNumIndexEntries(int fileA3D);
@@ -165,9 +169,9 @@
     native void nProgramStoreDither(boolean enable);
     native int  nProgramStoreCreate();
 
-    native int  nProgramRasterCreate(int in, int out, boolean pointSmooth, boolean lineSmooth, boolean pointSprite);
+    native int  nProgramRasterCreate(boolean pointSmooth, boolean lineSmooth, boolean pointSprite);
     native void nProgramRasterSetLineWidth(int pr, float v);
-    native void nProgramRasterSetPointSize(int pr, float v);
+    native void nProgramRasterSetCullMode(int pr, int mode);
 
     native void nProgramBindConstants(int pv, int slot, int mID);
     native void nProgramBindTexture(int vpf, int slot, int a);
@@ -189,6 +193,10 @@
     native int  nMeshCreate(int vtxCount, int indexCount);
     native void nMeshBindVertex(int id, int alloc, int slot);
     native void nMeshBindIndex(int id, int alloc, int prim, int slot);
+    native int  nMeshGetVertexBufferCount(int id);
+    native int  nMeshGetIndexCount(int id);
+    native void nMeshGetVertices(int id, int[] vtxIds, int vtxIdCount);
+    native void nMeshGetIndices(int id, int[] idxIds, int[] primitives, int vtxIdCount);
 
     native void nAnimationBegin(int attribCount, int keyframeCount);
     native void nAnimationAdd(float time, float[] attribs);
@@ -358,3 +366,4 @@
 }
 
 
+
diff --git a/graphics/java/android/renderscript/Type.java b/graphics/java/android/renderscript/Type.java
index 14422b2..8e45f2b 100644
--- a/graphics/java/android/renderscript/Type.java
+++ b/graphics/java/android/renderscript/Type.java
@@ -16,7 +16,9 @@
 
 package android.renderscript;
 
+
 import java.lang.reflect.Field;
+import android.util.Log;
 
 /**
  * @hide
@@ -108,6 +110,27 @@
         super.finalize();
     }
 
+    @Override
+    void updateFromNative() {
+        // We have 6 integer to obtain mDimX; mDimY; mDimZ;
+        // mDimLOD; mDimFaces; mElement;
+        int[] dataBuffer = new int[6];
+        mRS.nTypeGetNativeData(mID, dataBuffer);
+
+        mDimX = dataBuffer[0];
+        mDimY = dataBuffer[1];
+        mDimZ = dataBuffer[2];
+        mDimLOD = dataBuffer[3] == 1 ? true : false;
+        mDimFaces = dataBuffer[4] == 1 ? true : false;
+
+        int elementID = dataBuffer[5];
+        if(elementID != 0) {
+            mElement = new Element(mRS, elementID);
+            mElement.updateFromNative();
+        }
+        calcElementCount();
+    }
+
     public static Type createFromClass(RenderScript rs, Class c, int size, String scriptName) {
         android.util.Log.e("RenderScript", "Calling depricated createFromClass");
         return null;
diff --git a/graphics/jni/android_renderscript_RenderScript.cpp b/graphics/jni/android_renderscript_RenderScript.cpp
index cbc24c4..888c76a 100644
--- a/graphics/jni/android_renderscript_RenderScript.cpp
+++ b/graphics/jni/android_renderscript_RenderScript.cpp
@@ -297,6 +297,46 @@
     return (jint)id;
 }
 
+static void
+nElementGetNativeData(JNIEnv *_env, jobject _this, jint id, jintArray _elementData)
+{
+    int dataSize = _env->GetArrayLength(_elementData);
+    RsContext con = (RsContext)(_env->GetIntField(_this, gContextId));
+    LOG_API("nElementGetNativeData, con(%p)", con);
+
+    // we will pack mType; mKind; mNormalized; mVectorSize; NumSubElements
+    assert(dataSize == 5);
+
+    uint32_t elementData[5];
+    rsElementGetNativeData(con, (RsElement)id, elementData, dataSize);
+
+    for(jint i = 0; i < dataSize; i ++) {
+        _env->SetIntArrayRegion(_elementData, i, 1, (const jint*)&elementData[i]);
+    }
+}
+
+
+static void
+nElementGetSubElements(JNIEnv *_env, jobject _this, jint id, jintArray _IDs, jobjectArray _names)
+{
+    int dataSize = _env->GetArrayLength(_IDs);
+    RsContext con = (RsContext)(_env->GetIntField(_this, gContextId));
+    LOG_API("nElementGetSubElements, con(%p)", con);
+
+    uint32_t *ids = (uint32_t *)malloc((uint32_t)dataSize * sizeof(uint32_t));
+    const char **names = (const char **)malloc((uint32_t)dataSize * sizeof(const char *));
+
+    rsElementGetSubElements(con, (RsElement)id, ids, names, (uint32_t)dataSize);
+
+    for(jint i = 0; i < dataSize; i ++) {
+        _env->SetObjectArrayElement(_names, i, _env->NewStringUTF(names[i]));
+        _env->SetIntArrayRegion(_IDs, i, 1, (const jint*)&ids[i]);
+    }
+
+    free(ids);
+    free(names);
+}
+
 // -----------------------------------
 
 static void
@@ -323,6 +363,26 @@
     return (jint)rsTypeCreate(con);
 }
 
+static void
+nTypeGetNativeData(JNIEnv *_env, jobject _this, jint id, jintArray _typeData)
+{
+    // We are packing 6 items: mDimX; mDimY; mDimZ;
+    // mDimLOD; mDimFaces; mElement; into typeData
+    int elementCount = _env->GetArrayLength(_typeData);
+
+    assert(elementCount == 6);
+
+    RsContext con = (RsContext)(_env->GetIntField(_this, gContextId));
+    LOG_API("nTypeCreate, con(%p)", con);
+
+    uint32_t typeData[6];
+    rsTypeGetNativeData(con, (RsType)id, typeData, 6);
+
+    for(jint i = 0; i < elementCount; i ++) {
+        _env->SetIntArrayRegion(_typeData, i, 1, (const jint*)&typeData[i]);
+    }
+}
+
 static void * SF_LoadInt(JNIEnv *_env, jobject _obj, jfieldID _field, void *buffer)
 {
     ((int32_t *)buffer)[0] = _env->GetIntField(_obj, _field);
@@ -708,6 +768,14 @@
     free(bufAlloc);
 }
 
+static jint
+nAllocationGetType(JNIEnv *_env, jobject _this, jint a)
+{
+    RsContext con = (RsContext)(_env->GetIntField(_this, gContextId));
+    LOG_API("nAllocationGetType, con(%p), a(%p)", con, (RsAllocation)a);
+    return (jint) rsAllocationGetType(con, (RsAllocation)a);
+}
+
 // -----------------------------------
 
 static int
@@ -725,12 +793,10 @@
 static int
 nFileA3DGetNumIndexEntries(JNIEnv *_env, jobject _this, jint fileA3D)
 {
-    LOGV("______nFileA3D %u", (uint32_t) fileA3D);
     RsContext con = (RsContext)(_env->GetIntField(_this, gContextId));
 
     int32_t numEntries = 0;
     rsFileA3DGetNumIndexEntries(con, &numEntries, (RsFile)fileA3D);
-    LOGV("______nFileA3D NumEntries %u", (uint32_t) numEntries);
     return numEntries;
 }
 
@@ -1203,21 +1269,12 @@
 // ---------------------------------------------------------------------------
 
 static jint
-nProgramRasterCreate(JNIEnv *_env, jobject _this, jint in, jint out,
-                     jboolean pointSmooth, jboolean lineSmooth, jboolean pointSprite)
+nProgramRasterCreate(JNIEnv *_env, jobject _this, jboolean pointSmooth, jboolean lineSmooth, jboolean pointSprite)
 {
     RsContext con = (RsContext)(_env->GetIntField(_this, gContextId));
-    LOG_API("nProgramRasterCreate, con(%p), in(%p), out(%p), pointSmooth(%i), lineSmooth(%i), pointSprite(%i)",
-            con, (RsElement)in, (RsElement)out, pointSmooth, lineSmooth, pointSprite);
-    return (jint)rsProgramRasterCreate(con, (RsElement)in, (RsElement)out, pointSmooth, lineSmooth, pointSprite);
-}
-
-static void
-nProgramRasterSetPointSize(JNIEnv *_env, jobject _this, jint vpr, jfloat v)
-{
-    RsContext con = (RsContext)(_env->GetIntField(_this, gContextId));
-    LOG_API("nProgramRasterSetPointSize, con(%p), vpf(%p), value(%f)", con, (RsProgramRaster)vpr, v);
-    rsProgramRasterSetPointSize(con, (RsProgramFragment)vpr, v);
+    LOG_API("nProgramRasterCreate, con(%p), pointSmooth(%i), lineSmooth(%i), pointSprite(%i)",
+            con, pointSmooth, lineSmooth, pointSprite);
+    return (jint)rsProgramRasterCreate(con, pointSmooth, lineSmooth, pointSprite);
 }
 
 static void
@@ -1225,7 +1282,15 @@
 {
     RsContext con = (RsContext)(_env->GetIntField(_this, gContextId));
     LOG_API("nProgramRasterSetLineWidth, con(%p), vpf(%p), value(%f)", con, (RsProgramRaster)vpr, v);
-    rsProgramRasterSetLineWidth(con, (RsProgramFragment)vpr, v);
+    rsProgramRasterSetLineWidth(con, (RsProgramRaster)vpr, v);
+}
+
+static void
+nProgramRasterSetCullMode(JNIEnv *_env, jobject _this, jint vpr, jint v)
+{
+    RsContext con = (RsContext)(_env->GetIntField(_this, gContextId));
+    LOG_API("nProgramRasterSetCullMode, con(%p), vpf(%p), value(%i)", con, (RsProgramRaster)vpr, v);
+    rsProgramRasterSetCullMode(con, (RsProgramRaster)vpr, (RsCullMode)v);
 }
 
 
@@ -1360,19 +1425,75 @@
 }
 
 static void
-nMeshBindVertex(JNIEnv *_env, jobject _this, jint s, jint alloc, jint slot)
+nMeshBindVertex(JNIEnv *_env, jobject _this, jint mesh, jint alloc, jint slot)
 {
     RsContext con = (RsContext)(_env->GetIntField(_this, gContextId));
-    LOG_API("nMeshBindVertex, con(%p), Mesh(%p), Alloc(%p), slot(%i)", con, (RsMesh)s, (RsAllocation)alloc, slot);
-    rsMeshBindVertex(con, (RsMesh)s, (RsAllocation)alloc, slot);
+    LOG_API("nMeshBindVertex, con(%p), Mesh(%p), Alloc(%p), slot(%i)", con, (RsMesh)mesh, (RsAllocation)alloc, slot);
+    rsMeshBindVertex(con, (RsMesh)mesh, (RsAllocation)alloc, slot);
 }
 
 static void
-nMeshBindIndex(JNIEnv *_env, jobject _this, jint s, jint alloc, jint primID, jint slot)
+nMeshBindIndex(JNIEnv *_env, jobject _this, jint mesh, jint alloc, jint primID, jint slot)
 {
     RsContext con = (RsContext)(_env->GetIntField(_this, gContextId));
-    LOG_API("nMeshBindIndex, con(%p), Mesh(%p), Alloc(%p)", con, (RsMesh)s, (RsAllocation)alloc);
-    rsMeshBindIndex(con, (RsMesh)s, (RsAllocation)alloc, primID, slot);
+    LOG_API("nMeshBindIndex, con(%p), Mesh(%p), Alloc(%p)", con, (RsMesh)mesh, (RsAllocation)alloc);
+    rsMeshBindIndex(con, (RsMesh)mesh, (RsAllocation)alloc, primID, slot);
+}
+
+static jint
+nMeshGetVertexBufferCount(JNIEnv *_env, jobject _this, jint mesh)
+{
+    RsContext con = (RsContext)(_env->GetIntField(_this, gContextId));
+    LOG_API("nMeshGetVertexBufferCount, con(%p), Mesh(%p)", con, (RsMesh)mesh);
+    jint vtxCount = 0;
+    rsMeshGetVertexBufferCount(con, (RsMesh)mesh, &vtxCount);
+    return vtxCount;
+}
+
+static jint
+nMeshGetIndexCount(JNIEnv *_env, jobject _this, jint mesh)
+{
+    RsContext con = (RsContext)(_env->GetIntField(_this, gContextId));
+    LOG_API("nMeshGetIndexCount, con(%p), Mesh(%p)", con, (RsMesh)mesh);
+    jint idxCount = 0;
+    rsMeshGetIndexCount(con, (RsMesh)mesh, &idxCount);
+    return idxCount;
+}
+
+static void
+nMeshGetVertices(JNIEnv *_env, jobject _this, jint mesh, jintArray _ids, int numVtxIDs)
+{
+    RsContext con = (RsContext)(_env->GetIntField(_this, gContextId));
+    LOG_API("nMeshGetVertices, con(%p), Mesh(%p)", con, (RsMesh)mesh);
+
+    RsAllocation *allocs = (RsAllocation*)malloc((uint32_t)numVtxIDs * sizeof(RsAllocation));
+    rsMeshGetVertices(con, (RsMesh)mesh, allocs, (uint32_t)numVtxIDs);
+
+    for(jint i = 0; i < numVtxIDs; i ++) {
+        _env->SetIntArrayRegion(_ids, i, 1, (const jint*)&allocs[i]);
+    }
+
+    free(allocs);
+}
+
+static void
+nMeshGetIndices(JNIEnv *_env, jobject _this, jint mesh, jintArray _idxIds, jintArray _primitives, int numIndices)
+{
+    RsContext con = (RsContext)(_env->GetIntField(_this, gContextId));
+    LOG_API("nMeshGetVertices, con(%p), Mesh(%p)", con, (RsMesh)mesh);
+
+    RsAllocation *allocs = (RsAllocation*)malloc((uint32_t)numIndices * sizeof(RsAllocation));
+    uint32_t *prims= (uint32_t*)malloc((uint32_t)numIndices * sizeof(uint32_t));
+
+    rsMeshGetIndices(con, (RsMesh)mesh, allocs, prims, (uint32_t)numIndices);
+
+    for(jint i = 0; i < numIndices; i ++) {
+        _env->SetIntArrayRegion(_idxIds, i, 1, (const jint*)&allocs[i]);
+        _env->SetIntArrayRegion(_primitives, i, 1, (const jint*)&prims[i]);
+    }
+
+    free(allocs);
+    free(prims);
 }
 
 // ---------------------------------------------------------------------------
@@ -1413,12 +1534,15 @@
 
 {"nElementCreate",                 "(IIZI)I",                              (void*)nElementCreate },
 {"nElementCreate2",                "([I[Ljava/lang/String;)I",             (void*)nElementCreate2 },
+{"nElementGetNativeData",         "(I[I)V",                               (void*)nElementGetNativeData },
+{"nElementGetSubElements",        "(I[I[Ljava/lang/String;)V",           (void*)nElementGetSubElements },
 
 {"nTypeBegin",                     "(I)V",                                 (void*)nTypeBegin },
 {"nTypeAdd",                       "(II)V",                                (void*)nTypeAdd },
 {"nTypeCreate",                    "()I",                                  (void*)nTypeCreate },
 {"nTypeFinalDestroy",              "(Landroid/renderscript/Type;)V",       (void*)nTypeFinalDestroy },
 {"nTypeSetupFields",               "(Landroid/renderscript/Type;[I[I[Ljava/lang/reflect/Field;)V", (void*)nTypeSetupFields },
+{"nTypeGetNativeData",             "(I[I)V",                                (void*)nTypeGetNativeData },
 
 {"nAllocationCreateTyped",         "(I)I",                                 (void*)nAllocationCreateTyped },
 {"nAllocationCreateFromBitmap",    "(IZLandroid/graphics/Bitmap;)I",       (void*)nAllocationCreateFromBitmap },
@@ -1437,6 +1561,7 @@
 {"nAllocationRead",                "(I[F)V",                               (void*)nAllocationRead_f },
 {"nAllocationSubDataFromObject",   "(ILandroid/renderscript/Type;ILjava/lang/Object;)V",   (void*)nAllocationSubDataFromObject },
 {"nAllocationSubReadFromObject",   "(ILandroid/renderscript/Type;ILjava/lang/Object;)V",   (void*)nAllocationSubReadFromObject },
+{"nAllocationGetType",              "(I)I",                                 (void*)nAllocationGetType},
 
 {"nAdapter1DBindAllocation",       "(II)V",                                (void*)nAdapter1DBindAllocation },
 {"nAdapter1DSetConstraint",        "(III)V",                               (void*)nAdapter1DSetConstraint },
@@ -1481,9 +1606,9 @@
 {"nProgramFragmentCreate",         "([I)I",                                (void*)nProgramFragmentCreate },
 {"nProgramFragmentCreate2",        "(Ljava/lang/String;[I)I",              (void*)nProgramFragmentCreate2 },
 
-{"nProgramRasterCreate",           "(IIZZZ)I",                             (void*)nProgramRasterCreate },
-{"nProgramRasterSetPointSize",     "(IF)V",                                (void*)nProgramRasterSetPointSize },
+{"nProgramRasterCreate",           "(ZZZ)I",                             (void*)nProgramRasterCreate },
 {"nProgramRasterSetLineWidth",     "(IF)V",                                (void*)nProgramRasterSetLineWidth },
+{"nProgramRasterSetCullMode",      "(II)V",                                (void*)nProgramRasterSetCullMode },
 
 {"nProgramVertexCreate",           "(Z)I",                                 (void*)nProgramVertexCreate },
 {"nProgramVertexCreate2",          "(Ljava/lang/String;[I)I",              (void*)nProgramVertexCreate2 },
@@ -1509,6 +1634,11 @@
 {"nMeshBindVertex",                "(III)V",                               (void*)nMeshBindVertex },
 {"nMeshBindIndex",                 "(IIII)V",                              (void*)nMeshBindIndex },
 
+{"nMeshGetVertexBufferCount",     "(I)I",                                 (void*)nMeshGetVertexBufferCount },
+{"nMeshGetIndexCount",             "(I)I",                                 (void*)nMeshGetIndexCount },
+{"nMeshGetVertices",               "(I[II)V",                             (void*)nMeshGetVertices },
+{"nMeshGetIndices",                "(I[I[II)V",                            (void*)nMeshGetIndices },
+
 };
 
 static int registerFuncs(JNIEnv *_env)
@@ -1541,3 +1671,4 @@
 bail:
     return result;
 }
+
diff --git a/include/android_runtime/android_app_NativeActivity.h b/include/android_runtime/android_app_NativeActivity.h
new file mode 100644
index 0000000..d7a9a2c
--- /dev/null
+++ b/include/android_runtime/android_app_NativeActivity.h
@@ -0,0 +1,95 @@
+/*
+ * 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.
+ */
+
+#ifndef _ANDROID_APP_NATIVEACTIVITY_H
+#define _ANDROID_APP_NATIVEACTIVITY_H
+
+#include <ui/InputTransport.h>
+
+#include <android/native_activity.h>
+
+#include "jni.h"
+
+namespace android {
+
+extern void android_NativeActivity_setWindowFormat(
+        ANativeActivity* activity, int32_t format);
+
+extern void android_NativeActivity_setWindowFlags(
+        ANativeActivity* activity, int32_t values, int32_t mask);
+
+extern void android_NativeActivity_showSoftInput(
+        ANativeActivity* activity, int32_t flags);
+
+extern void android_NativeActivity_hideSoftInput(
+        ANativeActivity* activity, int32_t flags);
+
+} // namespace android
+
+
+/*
+ * NDK input queue API.
+ */
+struct AInputQueue {
+public:
+    /* Creates a consumer associated with an input channel. */
+    explicit AInputQueue(const android::sp<android::InputChannel>& channel, int workWrite);
+
+    /* Destroys the consumer and releases its input channel. */
+    ~AInputQueue();
+
+    void attachLooper(ALooper* looper, ALooper_callbackFunc* callback, void* data);
+
+    void detachLooper();
+
+    int32_t hasEvents();
+
+    int32_t getEvent(AInputEvent** outEvent);
+
+    void finishEvent(AInputEvent* event, bool handled);
+
+
+    // ----------------------------------------------------------
+
+    inline android::InputConsumer& getConsumer() { return mConsumer; }
+
+    void dispatchEvent(android::KeyEvent* event);
+
+    android::KeyEvent* consumeUnhandledEvent();
+
+    int mWorkWrite;
+
+private:
+    void doDefaultKey(android::KeyEvent* keyEvent);
+
+    android::InputConsumer mConsumer;
+    android::PreallocatedInputEventFactory mInputEventFactory;
+    android::sp<android::PollLoop> mPollLoop;
+
+    int mDispatchKeyRead;
+    int mDispatchKeyWrite;
+
+    // This is only touched by the event reader thread.  It is the current
+    // key events that came out of the mDispatchingKeys list and are now
+    //Êdelivered to the app.
+    android::Vector<android::KeyEvent*> mDeliveringKeys;
+
+    android::Mutex mLock;
+    android::Vector<android::KeyEvent*> mPendingKeys;
+    android::Vector<android::KeyEvent*> mDispatchingKeys;
+};
+
+#endif // _ANDROID_APP_NATIVEACTIVITY_H
diff --git a/core/jni/android_view_Surface.h b/include/android_runtime/android_view_Surface.h
similarity index 100%
rename from core/jni/android_view_Surface.h
rename to include/android_runtime/android_view_Surface.h
diff --git a/include/binder/BinderService.h b/include/binder/BinderService.h
new file mode 100644
index 0000000..2316fef
--- /dev/null
+++ b/include/binder/BinderService.h
@@ -0,0 +1,60 @@
+/*
+ * 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.
+ */
+
+#ifndef ANDROID_BINDER_SERVICE_H
+#define ANDROID_BINDER_SERVICE_H
+
+#include <stdint.h>
+
+#include <utils/Errors.h>
+#include <utils/String16.h>
+
+#include <binder/IServiceManager.h>
+#include <binder/IPCThreadState.h>
+#include <binder/ProcessState.h>
+#include <binder/IServiceManager.h>
+
+// ---------------------------------------------------------------------------
+namespace android {
+
+template<typename SERVICE>
+class BinderService
+{
+public:
+    static status_t publish() {
+        sp<IServiceManager> sm(defaultServiceManager());
+        return sm->addService(String16(SERVICE::getServiceName()), new SERVICE());
+    }
+
+    static void publishAndJoinThreadPool() {
+        sp<ProcessState> proc(ProcessState::self());
+        sp<IServiceManager> sm(defaultServiceManager());
+        sm->addService(String16(SERVICE::getServiceName()), new SERVICE());
+        ProcessState::self()->startThreadPool();
+        IPCThreadState::self()->joinThreadPool();
+    }
+
+    static void instantiate() { publish(); }
+
+    static status_t shutdown() {
+        return NO_ERROR;
+    }
+};
+
+
+}; // namespace android
+// ---------------------------------------------------------------------------
+#endif // ANDROID_BINDER_SERVICE_H
diff --git a/include/binder/Parcel.h b/include/binder/Parcel.h
index 2cc4db9..3aba5f6 100644
--- a/include/binder/Parcel.h
+++ b/include/binder/Parcel.h
@@ -103,6 +103,11 @@
     
     status_t            writeObject(const flat_binder_object& val, bool nullMetaData);
 
+    // Like Parcel.java's writeNoException().  Just writes a zero int32.
+    // Currently the native implementation doesn't do any of the StrictMode
+    // stack gathering and serialization that the Java implementation does.
+    status_t            writeNoException();
+
     void                remove(size_t start, size_t amt);
     
     status_t            read(void* outData, size_t len) const;
@@ -125,7 +130,14 @@
     sp<IBinder>         readStrongBinder() const;
     wp<IBinder>         readWeakBinder() const;
     status_t            read(Flattenable& val) const;
-    
+
+    // Like Parcel.java's readExceptionCode().  Reads the first int32
+    // off of a Parcel's header, returning 0 or the negative error
+    // code on exceptions, but also deals with skipping over rich
+    // response headers.  Callers should use this to read & parse the
+    // response headers rather than doing it by hand.
+    int32_t             readExceptionCode() const;
+
     // Retrieve native_handle from the parcel. This returns a copy of the
     // parcel's native_handle (the caller takes ownership). The caller
     // must free the native_handle with native_handle_close() and 
diff --git a/include/gui/ISensorEventConnection.h b/include/gui/ISensorEventConnection.h
new file mode 100644
index 0000000..ed4e4cc
--- /dev/null
+++ b/include/gui/ISensorEventConnection.h
@@ -0,0 +1,57 @@
+/*
+ * 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.
+ */
+
+#ifndef ANDROID_GUI_ISENSOR_EVENT_CONNECTION_H
+#define ANDROID_GUI_ISENSOR_EVENT_CONNECTION_H
+
+#include <stdint.h>
+#include <sys/types.h>
+
+#include <utils/Errors.h>
+#include <utils/RefBase.h>
+
+#include <binder/IInterface.h>
+
+namespace android {
+// ----------------------------------------------------------------------------
+
+class SensorChannel;
+
+class ISensorEventConnection : public IInterface
+{
+public:
+    DECLARE_META_INTERFACE(SensorEventConnection);
+
+    virtual sp<SensorChannel> getSensorChannel() const = 0;
+    virtual status_t enableDisable(int handle, bool enabled) = 0;
+    virtual status_t setEventRate(int handle, nsecs_t ns) = 0;
+};
+
+// ----------------------------------------------------------------------------
+
+class BnSensorEventConnection : public BnInterface<ISensorEventConnection>
+{
+public:
+    virtual status_t    onTransact( uint32_t code,
+                                    const Parcel& data,
+                                    Parcel* reply,
+                                    uint32_t flags = 0);
+};
+
+// ----------------------------------------------------------------------------
+}; // namespace android
+
+#endif // ANDROID_GUI_ISENSOR_EVENT_CONNECTION_H
diff --git a/include/gui/ISensorServer.h b/include/gui/ISensorServer.h
new file mode 100644
index 0000000..3e05076
--- /dev/null
+++ b/include/gui/ISensorServer.h
@@ -0,0 +1,57 @@
+/*
+ * 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.
+ */
+
+#ifndef ANDROID_GUI_ISENSORSERVER_H
+#define ANDROID_GUI_ISENSORSERVER_H
+
+#include <stdint.h>
+#include <sys/types.h>
+
+#include <utils/Errors.h>
+#include <utils/RefBase.h>
+
+#include <binder/IInterface.h>
+
+namespace android {
+// ----------------------------------------------------------------------------
+
+class Sensor;
+class ISensorEventConnection;
+
+class ISensorServer : public IInterface
+{
+public:
+    DECLARE_META_INTERFACE(SensorServer);
+
+    virtual Vector<Sensor> getSensorList()= 0;
+    virtual sp<ISensorEventConnection> createSensorEventConnection() = 0;
+};
+
+// ----------------------------------------------------------------------------
+
+class BnSensorServer : public BnInterface<ISensorServer>
+{
+public:
+    virtual status_t    onTransact( uint32_t code,
+                                    const Parcel& data,
+                                    Parcel* reply,
+                                    uint32_t flags = 0);
+};
+
+// ----------------------------------------------------------------------------
+}; // namespace android
+
+#endif // ANDROID_GUI_ISENSORSERVER_H
diff --git a/include/gui/Sensor.h b/include/gui/Sensor.h
new file mode 100644
index 0000000..86a16f1
--- /dev/null
+++ b/include/gui/Sensor.h
@@ -0,0 +1,88 @@
+/*
+ * 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.
+ */
+
+#ifndef ANDROID_GUI_SENSOR_H
+#define ANDROID_GUI_SENSOR_H
+
+#include <stdint.h>
+#include <sys/types.h>
+
+#include <utils/Errors.h>
+#include <utils/String8.h>
+#include <utils/Flattenable.h>
+
+#include <hardware/sensors.h>
+
+#include <android/sensor.h>
+
+// ----------------------------------------------------------------------------
+// Concrete types for the NDK
+struct ASensor { };
+
+// ----------------------------------------------------------------------------
+namespace android {
+// ----------------------------------------------------------------------------
+
+class Parcel;
+
+// ----------------------------------------------------------------------------
+
+class Sensor : public ASensor, public Flattenable
+{
+public:
+    enum {
+        TYPE_ACCELEROMETER  = ASENSOR_TYPE_ACCELEROMETER,
+        TYPE_MAGNETIC_FIELD = ASENSOR_TYPE_MAGNETIC_FIELD,
+        TYPE_GYROSCOPE      = ASENSOR_TYPE_GYROSCOPE,
+        TYPE_LIGHT          = ASENSOR_TYPE_LIGHT,
+        TYPE_PROXIMITY      = ASENSOR_TYPE_PROXIMITY
+    };
+
+    Sensor();
+    virtual ~Sensor();
+
+    const String8& getName() const;
+    const String8& getVendor() const;
+    int32_t getHandle() const;
+    int32_t getType() const;
+    float getMinValue() const;
+    float getMaxValue() const;
+    float getResolution() const;
+    float getPowerUsage() const;
+
+    // Flattenable interface
+    virtual size_t getFlattenedSize() const;
+    virtual size_t getFdCount() const;
+    virtual status_t flatten(void* buffer, size_t size,
+            int fds[], size_t count) const;
+    virtual status_t unflatten(void const* buffer, size_t size,
+            int fds[], size_t count);
+
+private:
+    String8 mName;
+    String8 mVendor;
+    int32_t mHandle;
+    int32_t mType;
+    float   mMinValue;
+    float   mMaxValue;
+    float   mResolution;
+    float   mPower;
+};
+
+// ----------------------------------------------------------------------------
+}; // namespace android
+
+#endif // ANDROID_GUI_SENSOR_H
diff --git a/include/gui/SensorChannel.h b/include/gui/SensorChannel.h
new file mode 100644
index 0000000..bb54618
--- /dev/null
+++ b/include/gui/SensorChannel.h
@@ -0,0 +1,53 @@
+/*
+ * 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.
+ */
+
+#ifndef ANDROID_GUI_SENSOR_CHANNEL_H
+#define ANDROID_GUI_SENSOR_CHANNEL_H
+
+#include <stdint.h>
+#include <sys/types.h>
+
+#include <utils/Errors.h>
+#include <utils/RefBase.h>
+
+
+namespace android {
+// ----------------------------------------------------------------------------
+class Parcel;
+
+class SensorChannel : public RefBase
+{
+public:
+
+            SensorChannel();
+            SensorChannel(const Parcel& data);
+    virtual ~SensorChannel();
+
+    int getFd() const;
+    ssize_t write(void const* vaddr, size_t size);
+    ssize_t read(void* vaddr, size_t size);
+
+    status_t writeToParcel(Parcel* reply) const;
+
+private:
+    int mSendFd;
+    mutable int mReceiveFd;
+};
+
+// ----------------------------------------------------------------------------
+}; // namespace android
+
+#endif // ANDROID_GUI_SENSOR_CHANNEL_H
diff --git a/include/gui/SensorEventQueue.h b/include/gui/SensorEventQueue.h
new file mode 100644
index 0000000..d8d8128
--- /dev/null
+++ b/include/gui/SensorEventQueue.h
@@ -0,0 +1,71 @@
+/*
+ * 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.
+ */
+
+#ifndef ANDROID_SENSOR_EVENT_QUEUE_H
+#define ANDROID_SENSOR_EVENT_QUEUE_H
+
+#include <stdint.h>
+#include <sys/types.h>
+
+#include <utils/Errors.h>
+#include <utils/RefBase.h>
+#include <utils/Timers.h>
+
+#include <gui/SensorChannel.h>
+
+// ----------------------------------------------------------------------------
+
+struct ALooper;
+struct ASensorEvent;
+
+// Concrete types for the NDK
+struct ASensorEventQueue {
+    ALooper* looper;
+};
+
+// ----------------------------------------------------------------------------
+namespace android {
+// ----------------------------------------------------------------------------
+
+class ISensorEventConnection;
+class Sensor;
+
+// ----------------------------------------------------------------------------
+
+class SensorEventQueue : public ASensorEventQueue, public RefBase
+{
+public:
+            SensorEventQueue(const sp<ISensorEventConnection>& connection);
+    virtual ~SensorEventQueue();
+    virtual void onFirstRef();
+
+    int getFd() const;
+    ssize_t write(ASensorEvent const* events, size_t numEvents);
+    ssize_t read(ASensorEvent* events, size_t numEvents);
+
+    status_t enableSensor(Sensor const* sensor) const;
+    status_t disableSensor(Sensor const* sensor) const;
+    status_t setEventRate(Sensor const* sensor, nsecs_t ns) const;
+
+private:
+    sp<ISensorEventConnection> mSensorEventConnection;
+    sp<SensorChannel> mSensorChannel;
+};
+
+// ----------------------------------------------------------------------------
+}; // namespace android
+
+#endif // ANDROID_SENSOR_EVENT_QUEUE_H
diff --git a/include/gui/SensorManager.h b/include/gui/SensorManager.h
new file mode 100644
index 0000000..0d65334
--- /dev/null
+++ b/include/gui/SensorManager.h
@@ -0,0 +1,63 @@
+/*
+ * 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.
+ */
+
+#ifndef ANDROID_GUI_SENSOR_MANAGER_H
+#define ANDROID_GUI_SENSOR_MANAGER_H
+
+#include <stdint.h>
+#include <sys/types.h>
+
+#include <utils/Errors.h>
+#include <utils/RefBase.h>
+#include <utils/Singleton.h>
+#include <utils/Vector.h>
+
+#include <gui/SensorEventQueue.h>
+
+// ----------------------------------------------------------------------------
+// Concrete types for the NDK
+struct ASensorManager { };
+
+// ----------------------------------------------------------------------------
+namespace android {
+// ----------------------------------------------------------------------------
+
+class ISensorServer;
+class Sensor;
+class SensorEventQueue;
+
+// ----------------------------------------------------------------------------
+
+class SensorManager : public ASensorManager, public Singleton<SensorManager>
+{
+public:
+    SensorManager();
+    ~SensorManager();
+
+    ssize_t getSensorList(Sensor**) const;
+    Sensor* getDefaultSensor(int type);
+    sp<SensorEventQueue> createEventQueue();
+
+private:
+    sp<ISensorServer> mSensorServer;
+    Sensor* mSensorList;
+    Vector<Sensor> mSensors;
+};
+
+// ----------------------------------------------------------------------------
+}; // namespace android
+
+#endif // ANDROID_GUI_SENSOR_MANAGER_H
diff --git a/include/media/EffectApi.h b/include/media/EffectApi.h
index b4d738c..9f3d0b6 100644
--- a/include/media/EffectApi.h
+++ b/include/media/EffectApi.h
@@ -223,6 +223,11 @@
 //          samples as specified in output buffer descriptor. If the buffer descriptor
 //          is not specified the function must use either the buffer or the
 //          buffer provider function installed by the EFFECT_CMD_CONFIGURE command.
+//          The effect framework will call the process() function after the EFFECT_CMD_ENABLE
+//          command is received and until the EFFECT_CMD_DISABLE is received. When the engine
+//          receives the EFFECT_CMD_DISABLE command it should turn off the effect gracefully
+//          and when done indicate that it is OK to stop calling the process() function by
+//          returning the -ENODATA status.
 //
 //    NOTE: the process() function implementation should be "real-time safe" that is
 //      it should not perform blocking calls: malloc/free, sleep, read/write/open/close,
@@ -239,6 +244,8 @@
 //
 //    Output:
 //        returned value:    0 successful operation
+//                          -ENODATA the engine has finished the disable phase and the framework
+//                                  can stop calling process()
 //                          -EINVAL invalid interface handle or
 //                                  invalid input/output buffer description
 ////////////////////////////////////////////////////////////////////////////////
diff --git a/include/media/EffectBassBoostApi.h b/include/media/EffectBassBoostApi.h
new file mode 100644
index 0000000..b24a5f4
--- /dev/null
+++ b/include/media/EffectBassBoostApi.h
@@ -0,0 +1,42 @@
+/*
+ * 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.
+ */
+
+#ifndef ANDROID_EFFECTBASSBOOSTAPI_H_
+#define ANDROID_EFFECTBASSBOOSTAPI_H_
+
+#include <media/EffectApi.h>
+
+#if __cplusplus
+extern "C" {
+#endif
+
+// TODO: include OpenSLES_IID.h instead
+static const effect_uuid_t SL_IID_BASSBOOST_ = { 0x0634f220, 0xddd4, 0x11db, 0xa0fc, { 0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b } };
+const effect_uuid_t * const SL_IID_BASSBOOST = &SL_IID_BASSBOOST_;
+
+/* enumerated parameter settings for BassBoost effect */
+typedef enum
+{
+    BASSBOOST_PARAM_STRENGTH_SUPPORTED,
+    BASSBOOST_PARAM_STRENGTH
+} t_bassboost_params;
+
+#if __cplusplus
+}  // extern "C"
+#endif
+
+
+#endif /*ANDROID_EFFECTBASSBOOSTAPI_H_*/
diff --git a/include/media/EffectReverbApi.h b/include/media/EffectEnvironmentalReverbApi.h
similarity index 79%
rename from include/media/EffectReverbApi.h
rename to include/media/EffectEnvironmentalReverbApi.h
index 6371adb..d490f71 100644
--- a/include/media/EffectReverbApi.h
+++ b/include/media/EffectEnvironmentalReverbApi.h
@@ -14,8 +14,8 @@
  * limitations under the License.
  */
 
-#ifndef ANDROID_EFFECTREVERBAPI_H_
-#define ANDROID_EFFECTREVERBAPI_H_
+#ifndef ANDROID_EFFECTENVIRONMENTALREVERBAPI_H_
+#define ANDROID_EFFECTENVIRONMENTALREVERBAPI_H_
 
 #include <media/EffectApi.h>
 
@@ -27,14 +27,9 @@
 static const effect_uuid_t SL_IID_ENVIRONMENTALREVERB_ = { 0xc2e5d5f0, 0x94bd, 0x4763, 0x9cac, { 0x4e, 0x23, 0x4d, 0x6, 0x83, 0x9e } };
 const effect_uuid_t * const SL_IID_ENVIRONMENTALREVERB = &SL_IID_ENVIRONMENTALREVERB_;
 
-static const effect_uuid_t SL_IID_PRESETREVERB_ = { 0x47382d60, 0xddd8, 0x11db, 0xbf3a, { 0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b } };
-const effect_uuid_t * const SL_IID_PRESETREVERB = &SL_IID_PRESETREVERB_;
-
-/* enumerated parameter settings for Reverb effect */
+/* enumerated parameter settings for environmental reverb effect */
 typedef enum
 {
-    REVERB_PARAM_BYPASS,
-    REVERB_PARAM_PRESET,
     // Parameters below are as defined in OpenSL ES specification for environmental reverb interface
     REVERB_PARAM_ROOM_LEVEL,            // in millibels,    range -6000 to 0
     REVERB_PARAM_ROOM_HF_LEVEL,         // in millibels,    range -4000 to 0
@@ -46,17 +41,9 @@
     REVERB_PARAM_REVERB_DELAY,          // in milliseconds, range 0 to 65
     REVERB_PARAM_DIFFUSION,             // in permilles,    range 0 to 1000
     REVERB_PARAM_DENSITY,               // in permilles,    range 0 to 1000
-    REVERB_PARAM_PROPERTIES
-} t_reverb_params;
-
-
-typedef enum
-{
-    REVERB_PRESET_LARGE_HALL,
-    REVERB_PRESET_HALL,
-    REVERB_PRESET_CHAMBER,
-    REVERB_PRESET_ROOM,
-} t_reverb_presets;
+    REVERB_PARAM_PROPERTIES,
+    REVERB_PARAM_BYPASS
+} t_env_reverb_params;
 
 //t_reverb_properties is equal to SLEnvironmentalReverbSettings defined in OpenSL ES specification.
 typedef struct s_reverb_properties {
@@ -79,4 +66,4 @@
 #endif
 
 
-#endif /*ANDROID_EFFECTREVERBAPI_H_*/
+#endif /*ANDROID_EFFECTENVIRONMENTALREVERBAPI_H_*/
diff --git a/include/media/EffectEqualizerApi.h b/include/media/EffectEqualizerApi.h
index e3069d5..cb05b32 100644
--- a/include/media/EffectEqualizerApi.h
+++ b/include/media/EffectEqualizerApi.h
@@ -19,14 +19,13 @@
 
 #include <media/EffectApi.h>
 
+// for the definition of SL_IID_EQUALIZER
+#include "OpenSLES.h"
+
 #if __cplusplus
 extern "C" {
 #endif
 
-//TODO replace by openSL ES include when available
-static const effect_uuid_t SL_IID_EQUALIZER_ = { 0x0bed4300, 0xddd6, 0x11db, 0x8f34, { 0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b } };
-const effect_uuid_t * const SL_IID_EQUALIZER = &SL_IID_EQUALIZER_;
-
 /* enumerated parameters for Equalizer effect */
 typedef enum
 {
diff --git a/include/media/EffectPresetReverbApi.h b/include/media/EffectPresetReverbApi.h
new file mode 100644
index 0000000..34ffffe
--- /dev/null
+++ b/include/media/EffectPresetReverbApi.h
@@ -0,0 +1,54 @@
+/*
+ * 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.
+ */
+
+#ifndef ANDROID_EFFECTPRESETREVERBAPI_H_
+#define ANDROID_EFFECTPRESETREVERBAPI_H_
+
+#include <media/EffectApi.h>
+
+#if __cplusplus
+extern "C" {
+#endif
+
+// TODO: include OpenSLES_IID.h instead
+
+static const effect_uuid_t SL_IID_PRESETREVERB_ = { 0x47382d60, 0xddd8, 0x11db, 0xbf3a, { 0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b } };
+const effect_uuid_t * const SL_IID_PRESETREVERB = &SL_IID_PRESETREVERB_;
+
+/* enumerated parameter settings for preset reverb effect */
+typedef enum
+{
+    REVERB_PARAM_PRESET
+} t_preset_reverb_params;
+
+
+typedef enum
+{
+    REVERB_PRESET_NONE,
+    REVERB_PRESET_SMALLROOM,
+    REVERB_PRESET_MEDIUMROOM,
+    REVERB_PRESET_LARGEROOM,
+    REVERB_PRESET_MEDIUMHALL,
+    REVERB_PRESET_LARGEHALL,
+    REVERB_PRESET_PLATE
+} t_reverb_presets;
+
+#if __cplusplus
+}  // extern "C"
+#endif
+
+
+#endif /*ANDROID_EFFECTPRESETREVERBAPI_H_*/
diff --git a/include/media/EffectVirtualizerApi.h b/include/media/EffectVirtualizerApi.h
new file mode 100644
index 0000000..601c384
--- /dev/null
+++ b/include/media/EffectVirtualizerApi.h
@@ -0,0 +1,42 @@
+/*
+ * 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.
+ */
+
+#ifndef ANDROID_EFFECTVIRTUALIZERAPI_H_
+#define ANDROID_EFFECTVIRTUALIZERAPI_H_
+
+#include <media/EffectApi.h>
+
+#if __cplusplus
+extern "C" {
+#endif
+
+// TODO: include OpenSLES_IID.h instead
+static const effect_uuid_t SL_IID_VIRTUALIZER_ = { 0x37cc2c00, 0xdddd, 0x11db, 0x8577, { 0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b } };
+const effect_uuid_t * const SL_IID_VIRTUALIZER = &SL_IID_VIRTUALIZER_;
+
+/* enumerated parameter settings for virtualizer effect */
+typedef enum
+{
+    VIRTUALIZER_PARAM_STRENGTH_SUPPORTED,
+    VIRTUALIZER_PARAM_STRENGTH
+} t_virtualizer_params;
+
+#if __cplusplus
+}  // extern "C"
+#endif
+
+
+#endif /*ANDROID_EFFECTVIRTUALIZERAPI_H_*/
diff --git a/include/media/MediaRecorderBase.h b/include/media/MediaRecorderBase.h
index 497965c..5e9e368 100644
--- a/include/media/MediaRecorderBase.h
+++ b/include/media/MediaRecorderBase.h
@@ -48,6 +48,7 @@
     virtual status_t close() = 0;
     virtual status_t reset() = 0;
     virtual status_t getMaxAmplitude(int *max) = 0;
+    virtual status_t dump(int fd, const Vector<String16>& args) const = 0;
 
 private:
     MediaRecorderBase(const MediaRecorderBase &);
diff --git a/include/media/PVMediaRecorder.h b/include/media/PVMediaRecorder.h
index c04105e..f75d80d 100644
--- a/include/media/PVMediaRecorder.h
+++ b/include/media/PVMediaRecorder.h
@@ -52,6 +52,7 @@
     virtual status_t close();
     virtual status_t reset();
     virtual status_t getMaxAmplitude(int *max);
+    virtual status_t dump(int fd, const Vector<String16>& args) const;
 
 private:
     status_t doStop();
diff --git a/include/media/stagefright/MPEG4Writer.h b/include/media/stagefright/MPEG4Writer.h
index 962b38b..232583a 100644
--- a/include/media/stagefright/MPEG4Writer.h
+++ b/include/media/stagefright/MPEG4Writer.h
@@ -52,6 +52,7 @@
     void endBox();
     uint32_t interleaveDuration() const { return mInterleaveDurationUs; }
     status_t setInterleaveDuration(uint32_t duration);
+    int32_t getTimeScale() const { return mTimeScale; }
 
 protected:
     virtual ~MPEG4Writer();
@@ -72,6 +73,7 @@
     bool mStreamableFile;
     off_t mEstimatedMoovBoxSize;
     uint32_t mInterleaveDurationUs;
+    int32_t mTimeScale;
     int64_t mStartTimestampUs;
     Mutex mLock;
 
diff --git a/include/media/stagefright/MetaData.h b/include/media/stagefright/MetaData.h
index 73f5547..cdbf483 100644
--- a/include/media/stagefright/MetaData.h
+++ b/include/media/stagefright/MetaData.h
@@ -68,6 +68,7 @@
     kKeyDiscNumber        = 'dnum',  // cstring
     kKeyDate              = 'date',  // cstring
     kKeyWriter            = 'writ',  // cstring
+    kKeyTimeScale         = 'tmsl',  // int32_t
 
     // video profile and level
     kKeyVideoProfile      = 'vprf',  // int32_t
diff --git a/include/ui/Input.h b/include/ui/Input.h
index a2e0ba06..a7d23d4 100644
--- a/include/ui/Input.h
+++ b/include/ui/Input.h
@@ -43,7 +43,9 @@
 /*
  * Declare a concrete type for the NDK's input event forward declaration.
  */
-struct AInputEvent { };
+struct AInputEvent {
+    virtual ~AInputEvent() { }
+};
 
 namespace android {
 
diff --git a/include/ui/InputDevice.h b/include/ui/InputDevice.h
new file mode 100644
index 0000000..4420600
--- /dev/null
+++ b/include/ui/InputDevice.h
@@ -0,0 +1,338 @@
+/*
+ * 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.
+ */
+
+#ifndef _UI_INPUT_DEVICE_H
+#define _UI_INPUT_DEVICE_H
+
+#include <ui/EventHub.h>
+#include <ui/Input.h>
+#include <utils/KeyedVector.h>
+#include <utils/threads.h>
+#include <utils/Timers.h>
+#include <utils/RefBase.h>
+#include <utils/String8.h>
+#include <utils/BitSet.h>
+
+#include <stddef.h>
+#include <unistd.h>
+
+/* Maximum pointer id value supported.
+ * (This is limited by our use of BitSet32 to track pointer assignments.) */
+#define MAX_POINTER_ID 31
+
+/* Maximum number of historical samples to average. */
+#define AVERAGING_HISTORY_SIZE 5
+
+
+namespace android {
+
+extern int32_t updateMetaState(int32_t keyCode, bool down, int32_t oldMetaState);
+extern int32_t rotateKeyCode(int32_t keyCode, int32_t orientation);
+
+/*
+ * An input device structure tracks the state of a single input device.
+ *
+ * This structure is only used by ReaderThread and is not intended to be shared with
+ * DispatcherThread (because that would require locking).  This works out fine because
+ * DispatcherThread is only interested in cooked event data anyways and does not need
+ * any of the low-level data from InputDevice.
+ */
+struct InputDevice {
+    struct AbsoluteAxisInfo {
+        bool valid;        // set to true if axis parameters are known, false otherwise
+
+        int32_t minValue;  // minimum value
+        int32_t maxValue;  // maximum value
+        int32_t range;     // range of values, equal to maxValue - minValue
+        int32_t flat;      // center flat position, eg. flat == 8 means center is between -8 and 8
+        int32_t fuzz;      // error tolerance, eg. fuzz == 4 means value is +/- 4 due to noise
+    };
+
+    struct VirtualKey {
+        int32_t keyCode;
+        int32_t scanCode;
+        uint32_t flags;
+
+        // computed hit box, specified in touch screen coords based on known display size
+        int32_t hitLeft;
+        int32_t hitTop;
+        int32_t hitRight;
+        int32_t hitBottom;
+
+        inline bool isHit(int32_t x, int32_t y) const {
+            return x >= hitLeft && x <= hitRight && y >= hitTop && y <= hitBottom;
+        }
+    };
+
+    struct KeyboardState {
+        struct Current {
+            int32_t metaState;
+            nsecs_t downTime; // time of most recent key down
+        } current;
+
+        void reset();
+    };
+
+    struct TrackballState {
+        struct Accumulator {
+            enum {
+                FIELD_BTN_MOUSE = 1,
+                FIELD_REL_X = 2,
+                FIELD_REL_Y = 4
+            };
+
+            uint32_t fields;
+
+            bool btnMouse;
+            int32_t relX;
+            int32_t relY;
+
+            inline void clear() {
+                fields = 0;
+            }
+
+            inline bool isDirty() {
+                return fields != 0;
+            }
+        } accumulator;
+
+        struct Current {
+            bool down;
+            nsecs_t downTime;
+        } current;
+
+        struct Precalculated {
+            float xScale;
+            float yScale;
+            float xPrecision;
+            float yPrecision;
+        } precalculated;
+
+        void reset();
+    };
+
+    struct SingleTouchScreenState {
+        struct Accumulator {
+            enum {
+                FIELD_BTN_TOUCH = 1,
+                FIELD_ABS_X = 2,
+                FIELD_ABS_Y = 4,
+                FIELD_ABS_PRESSURE = 8,
+                FIELD_ABS_TOOL_WIDTH = 16
+            };
+
+            uint32_t fields;
+
+            bool btnTouch;
+            int32_t absX;
+            int32_t absY;
+            int32_t absPressure;
+            int32_t absToolWidth;
+
+            inline void clear() {
+                fields = 0;
+            }
+
+            inline bool isDirty() {
+                return fields != 0;
+            }
+        } accumulator;
+
+        struct Current {
+            bool down;
+            int32_t x;
+            int32_t y;
+            int32_t pressure;
+            int32_t size;
+        } current;
+
+        void reset();
+    };
+
+    struct MultiTouchScreenState {
+        struct Accumulator {
+            enum {
+                FIELD_ABS_MT_POSITION_X = 1,
+                FIELD_ABS_MT_POSITION_Y = 2,
+                FIELD_ABS_MT_TOUCH_MAJOR = 4,
+                FIELD_ABS_MT_WIDTH_MAJOR = 8,
+                FIELD_ABS_MT_TRACKING_ID = 16
+            };
+
+            uint32_t pointerCount;
+            struct Pointer {
+                uint32_t fields;
+
+                int32_t absMTPositionX;
+                int32_t absMTPositionY;
+                int32_t absMTTouchMajor;
+                int32_t absMTWidthMajor;
+                int32_t absMTTrackingId;
+
+                inline void clear() {
+                    fields = 0;
+                }
+            } pointers[MAX_POINTERS + 1]; // + 1 to remove the need for extra range checks
+
+            inline void clear() {
+                pointerCount = 0;
+                pointers[0].clear();
+            }
+
+            inline bool isDirty() {
+                return pointerCount != 0;
+            }
+        } accumulator;
+
+        void reset();
+    };
+
+    struct PointerData {
+        uint32_t id;
+        int32_t x;
+        int32_t y;
+        int32_t pressure;
+        int32_t size;
+    };
+
+    struct TouchData {
+        uint32_t pointerCount;
+        PointerData pointers[MAX_POINTERS];
+        BitSet32 idBits;
+        uint32_t idToIndex[MAX_POINTER_ID + 1];
+
+        void copyFrom(const TouchData& other);
+
+        inline void clear() {
+            pointerCount = 0;
+            idBits.clear();
+        }
+    };
+
+    // common state used for both single-touch and multi-touch screens after the initial
+    // touch decoding has been performed
+    struct TouchScreenState {
+        Vector<VirtualKey> virtualKeys;
+
+        struct Parameters {
+            bool useBadTouchFilter;
+            bool useJumpyTouchFilter;
+            bool useAveragingTouchFilter;
+
+            AbsoluteAxisInfo xAxis;
+            AbsoluteAxisInfo yAxis;
+            AbsoluteAxisInfo pressureAxis;
+            AbsoluteAxisInfo sizeAxis;
+        } parameters;
+
+        // The touch data of the current sample being processed.
+        TouchData currentTouch;
+
+        // The touch data of the previous sample that was processed.  This is updated
+        // incrementally while the current sample is being processed.
+        TouchData lastTouch;
+
+        // The time the primary pointer last went down.
+        nsecs_t downTime;
+
+        struct CurrentVirtualKeyState {
+            enum Status {
+                STATUS_UP,
+                STATUS_DOWN,
+                STATUS_CANCELED
+            };
+
+            Status status;
+            nsecs_t downTime;
+            int32_t keyCode;
+            int32_t scanCode;
+        } currentVirtualKey;
+
+        struct AveragingTouchFilterState {
+            // Individual history tracks are stored by pointer id
+            uint32_t historyStart[MAX_POINTERS];
+            uint32_t historyEnd[MAX_POINTERS];
+            struct {
+                struct {
+                    int32_t x;
+                    int32_t y;
+                    int32_t pressure;
+                } pointers[MAX_POINTERS];
+            } historyData[AVERAGING_HISTORY_SIZE];
+        } averagingTouchFilter;
+
+        struct JumpTouchFilterState {
+            int32_t jumpyPointsDropped;
+        } jumpyTouchFilter;
+
+        struct Precalculated {
+            int32_t xOrigin;
+            float xScale;
+
+            int32_t yOrigin;
+            float yScale;
+
+            int32_t pressureOrigin;
+            float pressureScale;
+
+            int32_t sizeOrigin;
+            float sizeScale;
+        } precalculated;
+
+        void reset();
+
+        bool applyBadTouchFilter();
+        bool applyJumpyTouchFilter();
+        void applyAveragingTouchFilter();
+        void calculatePointerIds();
+
+        bool isPointInsideDisplay(int32_t x, int32_t y) const;
+        const InputDevice::VirtualKey* findVirtualKeyHit() const;
+    };
+
+    InputDevice(int32_t id, uint32_t classes, String8 name);
+
+    int32_t id;
+    uint32_t classes;
+    String8 name;
+    bool ignored;
+
+    KeyboardState keyboard;
+    TrackballState trackball;
+    TouchScreenState touchScreen;
+    union {
+        SingleTouchScreenState singleTouchScreen;
+        MultiTouchScreenState multiTouchScreen;
+    };
+
+    void reset();
+
+    inline bool isKeyboard() const { return classes & INPUT_DEVICE_CLASS_KEYBOARD; }
+    inline bool isAlphaKey() const { return classes & INPUT_DEVICE_CLASS_ALPHAKEY; }
+    inline bool isTrackball() const { return classes & INPUT_DEVICE_CLASS_TRACKBALL; }
+    inline bool isDPad() const { return classes & INPUT_DEVICE_CLASS_DPAD; }
+    inline bool isSingleTouchScreen() const { return (classes
+            & (INPUT_DEVICE_CLASS_TOUCHSCREEN | INPUT_DEVICE_CLASS_TOUCHSCREEN_MT))
+            == INPUT_DEVICE_CLASS_TOUCHSCREEN; }
+    inline bool isMultiTouchScreen() const { return classes
+            & INPUT_DEVICE_CLASS_TOUCHSCREEN_MT; }
+    inline bool isTouchScreen() const { return classes
+            & (INPUT_DEVICE_CLASS_TOUCHSCREEN | INPUT_DEVICE_CLASS_TOUCHSCREEN_MT); }
+};
+
+} // namespace android
+
+#endif // _UI_INPUT_DEVICE_H
diff --git a/include/ui/InputReader.h b/include/ui/InputReader.h
index 781da35..85a0084 100644
--- a/include/ui/InputReader.h
+++ b/include/ui/InputReader.h
@@ -19,6 +19,7 @@
 
 #include <ui/EventHub.h>
 #include <ui/Input.h>
+#include <ui/InputDevice.h>
 #include <ui/InputDispatcher.h>
 #include <utils/KeyedVector.h>
 #include <utils/threads.h>
@@ -30,304 +31,8 @@
 #include <stddef.h>
 #include <unistd.h>
 
-/* Maximum pointer id value supported.
- * (This is limited by our use of BitSet32 to track pointer assignments.) */
-#define MAX_POINTER_ID 32
-
-/* Maximum number of historical samples to average. */
-#define AVERAGING_HISTORY_SIZE 5
-
-
 namespace android {
 
-extern int32_t updateMetaState(int32_t keyCode, bool down, int32_t oldMetaState);
-extern int32_t rotateKeyCode(int32_t keyCode, int32_t orientation);
-
-/*
- * An input device structure tracks the state of a single input device.
- *
- * This structure is only used by ReaderThread and is not intended to be shared with
- * DispatcherThread (because that would require locking).  This works out fine because
- * DispatcherThread is only interested in cooked event data anyways and does not need
- * any of the low-level data from InputDevice.
- */
-struct InputDevice {
-    struct AbsoluteAxisInfo {
-        bool valid;        // set to true if axis parameters are known, false otherwise
-
-        int32_t minValue;  // minimum value
-        int32_t maxValue;  // maximum value
-        int32_t range;     // range of values, equal to maxValue - minValue
-        int32_t flat;      // center flat position, eg. flat == 8 means center is between -8 and 8
-        int32_t fuzz;      // error tolerance, eg. fuzz == 4 means value is +/- 4 due to noise
-    };
-
-    struct VirtualKey {
-        int32_t keyCode;
-        int32_t scanCode;
-        uint32_t flags;
-
-        // computed hit box, specified in touch screen coords based on known display size
-        int32_t hitLeft;
-        int32_t hitTop;
-        int32_t hitRight;
-        int32_t hitBottom;
-
-        inline bool isHit(int32_t x, int32_t y) const {
-            return x >= hitLeft && x <= hitRight && y >= hitTop && y <= hitBottom;
-        }
-    };
-
-    struct KeyboardState {
-        struct Current {
-            int32_t metaState;
-            nsecs_t downTime; // time of most recent key down
-        } current;
-
-        void reset();
-    };
-
-    struct TrackballState {
-        struct Accumulator {
-            enum {
-                FIELD_BTN_MOUSE = 1,
-                FIELD_REL_X = 2,
-                FIELD_REL_Y = 4
-            };
-
-            uint32_t fields;
-
-            bool btnMouse;
-            int32_t relX;
-            int32_t relY;
-
-            inline void clear() {
-                fields = 0;
-            }
-
-            inline bool isDirty() {
-                return fields != 0;
-            }
-        } accumulator;
-
-        struct Current {
-            bool down;
-            nsecs_t downTime;
-        } current;
-
-        struct Precalculated {
-            float xScale;
-            float yScale;
-            float xPrecision;
-            float yPrecision;
-        } precalculated;
-
-        void reset();
-    };
-
-    struct SingleTouchScreenState {
-        struct Accumulator {
-            enum {
-                FIELD_BTN_TOUCH = 1,
-                FIELD_ABS_X = 2,
-                FIELD_ABS_Y = 4,
-                FIELD_ABS_PRESSURE = 8,
-                FIELD_ABS_TOOL_WIDTH = 16
-            };
-
-            uint32_t fields;
-
-            bool btnTouch;
-            int32_t absX;
-            int32_t absY;
-            int32_t absPressure;
-            int32_t absToolWidth;
-
-            inline void clear() {
-                fields = 0;
-            }
-
-            inline bool isDirty() {
-                return fields != 0;
-            }
-        } accumulator;
-
-        struct Current {
-            bool down;
-            int32_t x;
-            int32_t y;
-            int32_t pressure;
-            int32_t size;
-        } current;
-
-        void reset();
-    };
-
-    struct MultiTouchScreenState {
-        struct Accumulator {
-            enum {
-                FIELD_ABS_MT_POSITION_X = 1,
-                FIELD_ABS_MT_POSITION_Y = 2,
-                FIELD_ABS_MT_TOUCH_MAJOR = 4,
-                FIELD_ABS_MT_WIDTH_MAJOR = 8,
-                FIELD_ABS_MT_TRACKING_ID = 16
-            };
-
-            uint32_t pointerCount;
-            struct Pointer {
-                uint32_t fields;
-
-                int32_t absMTPositionX;
-                int32_t absMTPositionY;
-                int32_t absMTTouchMajor;
-                int32_t absMTWidthMajor;
-                int32_t absMTTrackingId;
-
-                inline void clear() {
-                    fields = 0;
-                }
-            } pointers[MAX_POINTERS + 1]; // + 1 to remove the need for extra range checks
-
-            inline void clear() {
-                pointerCount = 0;
-                pointers[0].clear();
-            }
-
-            inline bool isDirty() {
-                return pointerCount != 0;
-            }
-        } accumulator;
-
-        void reset();
-    };
-
-    struct PointerData {
-        uint32_t id;
-        int32_t x;
-        int32_t y;
-        int32_t pressure;
-        int32_t size;
-    };
-
-    struct TouchData {
-        uint32_t pointerCount;
-        PointerData pointers[MAX_POINTERS];
-        BitSet32 idBits;
-        uint32_t idToIndex[MAX_POINTER_ID];
-
-        void copyFrom(const TouchData& other);
-
-        inline void clear() {
-            pointerCount = 0;
-            idBits.clear();
-        }
-    };
-
-    // common state used for both single-touch and multi-touch screens after the initial
-    // touch decoding has been performed
-    struct TouchScreenState {
-        Vector<VirtualKey> virtualKeys;
-
-        struct Parameters {
-            bool useBadTouchFilter;
-            bool useJumpyTouchFilter;
-            bool useAveragingTouchFilter;
-
-            AbsoluteAxisInfo xAxis;
-            AbsoluteAxisInfo yAxis;
-            AbsoluteAxisInfo pressureAxis;
-            AbsoluteAxisInfo sizeAxis;
-        } parameters;
-
-        // The touch data of the current sample being processed.
-        TouchData currentTouch;
-
-        // The touch data of the previous sample that was processed.  This is updated
-        // incrementally while the current sample is being processed.
-        TouchData lastTouch;
-
-        // The time the primary pointer last went down.
-        nsecs_t downTime;
-
-        struct CurrentVirtualKeyState {
-            bool down;
-            nsecs_t downTime;
-            int32_t keyCode;
-            int32_t scanCode;
-        } currentVirtualKey;
-
-        struct AveragingTouchFilterState {
-            // Individual history tracks are stored by pointer id
-            uint32_t historyStart[MAX_POINTERS];
-            uint32_t historyEnd[MAX_POINTERS];
-            struct {
-                struct {
-                    int32_t x;
-                    int32_t y;
-                    int32_t pressure;
-                } pointers[MAX_POINTERS];
-            } historyData[AVERAGING_HISTORY_SIZE];
-        } averagingTouchFilter;
-
-        struct JumpTouchFilterState {
-            int32_t jumpyPointsDropped;
-        } jumpyTouchFilter;
-
-        struct Precalculated {
-            int32_t xOrigin;
-            float xScale;
-
-            int32_t yOrigin;
-            float yScale;
-
-            int32_t pressureOrigin;
-            float pressureScale;
-
-            int32_t sizeOrigin;
-            float sizeScale;
-        } precalculated;
-
-        void reset();
-
-        bool applyBadTouchFilter();
-        bool applyJumpyTouchFilter();
-        void applyAveragingTouchFilter();
-        void calculatePointerIds();
-
-        bool isPointInsideDisplay(int32_t x, int32_t y) const;
-    };
-
-    InputDevice(int32_t id, uint32_t classes, String8 name);
-
-    int32_t id;
-    uint32_t classes;
-    String8 name;
-    bool ignored;
-
-    KeyboardState keyboard;
-    TrackballState trackball;
-    TouchScreenState touchScreen;
-    union {
-        SingleTouchScreenState singleTouchScreen;
-        MultiTouchScreenState multiTouchScreen;
-    };
-
-    void reset();
-
-    inline bool isKeyboard() const { return classes & INPUT_DEVICE_CLASS_KEYBOARD; }
-    inline bool isAlphaKey() const { return classes & INPUT_DEVICE_CLASS_ALPHAKEY; }
-    inline bool isTrackball() const { return classes & INPUT_DEVICE_CLASS_TRACKBALL; }
-    inline bool isDPad() const { return classes & INPUT_DEVICE_CLASS_DPAD; }
-    inline bool isSingleTouchScreen() const { return (classes
-            & (INPUT_DEVICE_CLASS_TOUCHSCREEN | INPUT_DEVICE_CLASS_TOUCHSCREEN_MT))
-            == INPUT_DEVICE_CLASS_TOUCHSCREEN; }
-    inline bool isMultiTouchScreen() const { return classes
-            & INPUT_DEVICE_CLASS_TOUCHSCREEN_MT; }
-    inline bool isTouchScreen() const { return classes
-            & (INPUT_DEVICE_CLASS_TOUCHSCREEN | INPUT_DEVICE_CLASS_TOUCHSCREEN_MT); }
-};
-
-
 /*
  * Input reader policy interface.
  *
@@ -390,11 +95,9 @@
     virtual bool getDisplayInfo(int32_t displayId,
             int32_t* width, int32_t* height, int32_t* orientation) = 0;
 
-    /* Provides feedback for a virtual key.
+    /* Provides feedback for a virtual key down.
      */
-    virtual void virtualKeyFeedback(nsecs_t when, int32_t deviceId,
-            int32_t action, int32_t flags, int32_t keyCode,
-            int32_t scanCode, int32_t metaState, nsecs_t downTime) = 0;
+    virtual void virtualKeyDownFeedback() = 0;
 
     /* Intercepts a key event.
      * The policy can use this method as an opportunity to perform power management functions
diff --git a/include/ui/InputTransport.h b/include/ui/InputTransport.h
index 11714d5..226d1d5 100644
--- a/include/ui/InputTransport.h
+++ b/include/ui/InputTransport.h
@@ -331,30 +331,4 @@
 
 } // namespace android
 
-/*
- * NDK input queue API.
- */
-struct AInputQueue {
-public:
-    /* Creates a consumer associated with an input channel. */
-    explicit AInputQueue(const android::sp<android::InputChannel>& channel);
-
-    /* Destroys the consumer and releases its input channel. */
-    virtual ~AInputQueue();
-
-    inline android::InputConsumer& getConsumer() { return mConsumer; }
-    
-    android::status_t consume(android::InputEvent** event);
-    
-    void setPollLoop(const android::sp<android::PollLoop>& pollLoop) { mPollLoop = pollLoop; }
-    const android::sp<android::PollLoop> getPollLoop() const { return mPollLoop; }
-    
-    virtual void doDefaultKey(android::KeyEvent* keyEvent) = 0;
-    
-private:
-    android::InputConsumer mConsumer;
-    android::PreallocatedInputEventFactory mInputEventFactory;
-    android::sp<android::PollLoop> mPollLoop;
-};
-
 #endif // _UI_INPUT_TRANSPORT_H
diff --git a/include/ui/KeycodeLabels.h b/include/ui/KeycodeLabels.h
index e81d0f9..c8d6ffc 100755
--- a/include/ui/KeycodeLabels.h
+++ b/include/ui/KeycodeLabels.h
@@ -17,6 +17,8 @@
 #ifndef _UI_KEYCODE_LABELS_H
 #define _UI_KEYCODE_LABELS_H
 
+#include <android/keycodes.h>
+
 struct KeycodeLabel {
     const char *literal;
     int value;
@@ -118,117 +120,28 @@
     { "PAGE_DOWN", 93 },
     { "PICTSYMBOLS", 94 },
     { "SWITCH_CHARSET", 95 },
+    { "BUTTON_A", 96 },
+    { "BUTTON_B", 97 },
+    { "BUTTON_C", 98 },
+    { "BUTTON_X", 99 },
+    { "BUTTON_Y", 100 },
+    { "BUTTON_Z", 101 },
+    { "BUTTON_L1", 102 },
+    { "BUTTON_R1", 103 },
+    { "BUTTON_L2", 104 },
+    { "BUTTON_R2", 105 },
+    { "BUTTON_THUMBL", 106 },
+    { "BUTTON_THUMBR", 107 },
+    { "BUTTON_START", 108 },
+    { "BUTTON_SELECT", 109 },
+    { "BUTTON_MODE", 110 },
 
-    // NOTE: If you add a new keycode here you must also add it to:
-    //   (enum KeyCode, in this file)
-    //   frameworks/base/core/java/android/view/KeyEvent.java
-    //   tools/puppet_master/PuppetMaster.nav_keys.py
-    //   frameworks/base/core/res/res/values/attrs.xml
+    // NOTE: If you add a new keycode here you must also add it to several other files.
+    //       Refer to frameworks/base/core/java/android/view/KeyEvent.java for the full list.
 
     { NULL, 0 }
 };
 
-// These constants need to match the above mappings.
-typedef enum KeyCode {
-    kKeyCodeUnknown = 0,
-
-    kKeyCodeSoftLeft = 1,
-    kKeyCodeSoftRight = 2,
-    kKeyCodeHome = 3,
-    kKeyCodeBack = 4,
-    kKeyCodeCall = 5,
-    kKeyCodeEndCall = 6,
-    kKeyCode0 = 7,
-    kKeyCode1 = 8,
-    kKeyCode2 = 9,
-    kKeyCode3 = 10,
-    kKeyCode4 = 11,
-    kKeyCode5 = 12,
-    kKeyCode6 = 13,
-    kKeyCode7 = 14,
-    kKeyCode8 = 15,
-    kKeyCode9 = 16,
-    kKeyCodeStar = 17,
-    kKeyCodePound = 18,
-    kKeyCodeDpadUp = 19,
-    kKeyCodeDpadDown = 20,
-    kKeyCodeDpadLeft = 21,
-    kKeyCodeDpadRight = 22,
-    kKeyCodeDpadCenter = 23,
-    kKeyCodeVolumeUp = 24,
-    kKeyCodeVolumeDown = 25,
-    kKeyCodePower = 26,
-    kKeyCodeCamera = 27,
-    kKeyCodeClear = 28,
-    kKeyCodeA = 29,
-    kKeyCodeB = 30,
-    kKeyCodeC = 31,
-    kKeyCodeD = 32,
-    kKeyCodeE = 33,
-    kKeyCodeF = 34,
-    kKeyCodeG = 35,
-    kKeyCodeH = 36,
-    kKeyCodeI = 37,
-    kKeyCodeJ = 38,
-    kKeyCodeK = 39,
-    kKeyCodeL = 40,
-    kKeyCodeM = 41,
-    kKeyCodeN = 42,
-    kKeyCodeO = 43,
-    kKeyCodeP = 44,
-    kKeyCodeQ = 45,
-    kKeyCodeR = 46,
-    kKeyCodeS = 47,
-    kKeyCodeT = 48,
-    kKeyCodeU = 49,
-    kKeyCodeV = 50,
-    kKeyCodeW = 51,
-    kKeyCodeX = 52,
-    kKeyCodeY = 53,
-    kKeyCodeZ = 54,
-    kKeyCodeComma = 55,
-    kKeyCodePeriod = 56,
-    kKeyCodeAltLeft = 57,
-    kKeyCodeAltRight = 58,
-    kKeyCodeShiftLeft = 59,
-    kKeyCodeShiftRight = 60,
-    kKeyCodeTab = 61,
-    kKeyCodeSpace = 62,
-    kKeyCodeSym = 63,
-    kKeyCodeExplorer = 64,
-    kKeyCodeEnvelope = 65,
-    kKeyCodeNewline = 66,
-    kKeyCodeDel = 67,
-    kKeyCodeGrave = 68,
-    kKeyCodeMinus = 69,
-    kKeyCodeEquals = 70,
-    kKeyCodeLeftBracket = 71,
-    kKeyCodeRightBracket = 72,
-    kKeyCodeBackslash = 73,
-    kKeyCodeSemicolon = 74,
-    kKeyCodeApostrophe = 75,
-    kKeyCodeSlash = 76,
-    kKeyCodeAt = 77,
-    kKeyCodeNum = 78,
-    kKeyCodeHeadSetHook = 79,
-    kKeyCodeFocus = 80,
-    kKeyCodePlus = 81,
-    kKeyCodeMenu = 82,
-    kKeyCodeNotification = 83,
-    kKeyCodeSearch = 84,
-    kKeyCodePlayPause = 85,
-    kKeyCodeStop = 86,
-    kKeyCodeNextSong = 87,
-    kKeyCodePreviousSong = 88,
-    kKeyCodeRewind = 89,
-    kKeyCodeForward = 90,
-    kKeyCodeMute = 91,
-    kKeyCodePageUp = 92,
-    kKeyCodePageDown = 93,
-    kKeyCodePictSymbols = 94,
-    kKeyCodeSwitchCharset = 95
-} KeyCode;
-
 static const KeycodeLabel FLAGS[] = {
     { "WAKE", 0x00000001 },
     { "WAKE_DROPPED", 0x00000002 },
diff --git a/include/ui/Rect.h b/include/ui/Rect.h
index a213c09..4e65a2d 100644
--- a/include/ui/Rect.h
+++ b/include/ui/Rect.h
@@ -20,31 +20,28 @@
 #include <utils/TypeHelpers.h>
 #include <ui/Point.h>
 
+#include <android/rect.h>
+
 namespace android {
 
-class Rect
+class Rect : public ARect
 {
 public:
-    int left;
-    int top;
-    int right;
-    int bottom;
-
-    typedef int value_type;
+    typedef int32_t value_type;
 
     // we don't provide copy-ctor and operator= on purpose
     // because we want the compiler generated versions
 
     inline Rect() {
     }
-    inline Rect(int w, int h)
-        : left(0), top(0), right(w), bottom(h) {
+    inline Rect(int32_t w, int32_t h) {
+        left = top = 0; right = w; bottom = h;
     }
-    inline Rect(int l, int t, int r, int b)
-        : left(l), top(t), right(r), bottom(b) {
+    inline Rect(int32_t l, int32_t t, int32_t r, int32_t b) {
+        left = l; top = t; right = r; bottom = b;
     }
-    inline Rect(const Point& lt, const Point& rb) 
-        : left(lt.x), top(lt.y), right(rb.x), bottom(rb.y) {
+    inline Rect(const Point& lt, const Point& rb) {
+        left = lt.x; top = lt.y; right = rb.x; bottom = rb.y;
     }
 
     void makeInvalid();
@@ -68,12 +65,12 @@
     }
 
     // rectangle's width
-    inline int width() const {
+    inline int32_t width() const {
         return right-left;
     }
     
     // rectangle's height
-    inline int height() const {
+    inline int32_t height() const {
         return bottom-top;
     }
 
@@ -136,12 +133,12 @@
     const Rect operator + (const Point& rhs) const;
     const Rect operator - (const Point& rhs) const;
 
-    void translate(int dx, int dy) { // legacy, don't use.
+    void translate(int32_t dx, int32_t dy) { // legacy, don't use.
         offsetBy(dx, dy);
     }
  
-    Rect&   offsetTo(int x, int y);
-    Rect&   offsetBy(int x, int y);
+    Rect&   offsetTo(int32_t x, int32_t y);
+    Rect&   offsetBy(int32_t x, int32_t y);
     bool    intersect(const Rect& with, Rect* result) const;
 };
 
diff --git a/include/utils/ObbFile.h b/include/utils/ObbFile.h
new file mode 100644
index 0000000..075927c
--- /dev/null
+++ b/include/utils/ObbFile.h
@@ -0,0 +1,87 @@
+/*
+ * 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.
+ */
+
+#ifndef OBBFILE_H_
+#define OBBFILE_H_
+
+#include <stdint.h>
+
+#include <utils/RefBase.h>
+#include <utils/String8.h>
+
+namespace android {
+
+class ObbFile : public RefBase {
+protected:
+    virtual ~ObbFile();
+
+public:
+    ObbFile();
+
+    bool readFrom(const char* filename);
+    bool readFrom(int fd);
+    bool writeTo(const char* filename);
+    bool writeTo(int fd);
+
+    const char* getFileName() const {
+        return mFileName;
+    }
+
+    const String8 getPackageName() const {
+        return mPackageName;
+    }
+
+    int32_t getVersion() const {
+        return mVersion;
+    }
+
+    void setPackageName(String8 packageName) {
+        mPackageName = packageName;
+    }
+
+    void setVersion(int32_t version) {
+        mVersion = version;
+    }
+
+    static inline uint32_t get4LE(const unsigned char* buf) {
+        return buf[0] | (buf[1] << 8) | (buf[2] << 16) | (buf[3] << 24);
+    }
+
+    static inline void put4LE(unsigned char* buf, uint32_t val) {
+        buf[0] = val & 0xFF;
+        buf[1] = (val >> 8) & 0xFF;
+        buf[2] = (val >> 16) & 0xFF;
+        buf[3] = (val >> 24) & 0xFF;
+    }
+
+private:
+    /* Package name this ObbFile is associated with */
+    String8 mPackageName;
+
+    /* Package version this ObbFile is associated with */
+    int32_t mVersion;
+
+    const char* mFileName;
+
+    size_t mFileSize;
+
+    unsigned char* mReadBuf;
+
+    bool parseObbFile(int fd);
+};
+
+}
+#endif /* OBBFILE_H_ */
diff --git a/include/utils/PollLoop.h b/include/utils/PollLoop.h
index b3651ca..81230e8 100644
--- a/include/utils/PollLoop.h
+++ b/include/utils/PollLoop.h
@@ -42,7 +42,7 @@
     virtual ~PollLoop();
 
 public:
-    PollLoop();
+    PollLoop(bool allowNonCallbacks);
 
     /**
      * A callback that it to be invoked when an event occurs on a file descriptor.
@@ -54,6 +54,12 @@
      */
     typedef bool (*Callback)(int fd, int events, void* data);
 
+    enum {
+        POLL_CALLBACK = ALOOPER_POLL_CALLBACK,
+        POLL_TIMEOUT = ALOOPER_POLL_TIMEOUT,
+        POLL_ERROR = ALOOPER_POLL_ERROR,
+    };
+    
     /**
      * Performs a single call to poll() with optional timeout in milliseconds.
      * Invokes callbacks for all file descriptors on which an event occurred.
@@ -61,16 +67,25 @@
      * If the timeout is zero, returns immediately without blocking.
      * If the timeout is negative, waits indefinitely until awoken.
      *
-     * Returns true if a callback was invoked or if the loop was awoken by wake().
-     * Returns false if a timeout or error occurred.
+     * Returns ALOOPER_POLL_CALLBACK if a callback was invoked.
      *
-     * This method must only be called on the main thread.
+     * Returns ALOOPER_POLL_TIMEOUT if there was no data before the given
+     * timeout expired.
+     *
+     * Returns ALOPER_POLL_ERROR if an error occurred.
+     *
+     * Returns a value >= 0 containing a file descriptor if it has data
+     * and it has no callback function (requiring the caller here to handle it).
+     * In this (and only this) case outEvents and outData will contain the poll
+     * events and data associated with the fd.
+     *
+     * This method must only be called on the thread owning the PollLoop.
      * This method blocks until either a file descriptor is signalled, a timeout occurs,
      * or wake() is called.
      * This method does not return until it has finished invoking the appropriate callbacks
      * for all file descriptors that were signalled.
      */
-    bool pollOnce(int timeoutMillis);
+    int32_t pollOnce(int timeoutMillis, int* outEvents = NULL, void** outData = NULL);
 
     /**
      * Wakes the loop asynchronously.
@@ -81,6 +96,12 @@
     void wake();
 
     /**
+     * Control whether this PollLoop instance allows using IDs instead
+     * of callbacks.
+     */
+    bool getAllowNonCallbacks() const;
+    
+    /**
      * Sets the callback for a file descriptor, replacing the existing one, if any.
      * It is an error to call this method with events == 0 or callback == NULL.
      *
@@ -95,7 +116,8 @@
     /**
      * Like setCallback(), but for the NDK callback function.
      */
-    void setLooperCallback(int fd, int events, ALooper_callbackFunc* callback, void* data);
+    void setLooperCallback(int fd, int events, ALooper_callbackFunc* callback,
+            void* data);
     
     /**
      * Removes the callback for a file descriptor, if one exists.
@@ -141,7 +163,9 @@
         ALooper_callbackFunc* looperCallback;
         void* data;
     };
-
+    
+    const bool mAllowNonCallbacks;
+    
     Mutex mLock;
     bool mPolling;
     uint32_t mWaiters;
@@ -155,7 +179,9 @@
     Vector<RequestedCallback> mRequestedCallbacks;
 
     Vector<PendingCallback> mPendingCallbacks; // used privately by pollOnce
-
+    Vector<PendingCallback> mPendingFds;       // used privately by pollOnce
+    size_t mPendingFdsPos;
+    
     void openWakePipe();
     void closeWakePipe();
 
diff --git a/libs/binder/IPermissionController.cpp b/libs/binder/IPermissionController.cpp
index bff4c9b..e13036f 100644
--- a/libs/binder/IPermissionController.cpp
+++ b/libs/binder/IPermissionController.cpp
@@ -36,7 +36,7 @@
         : BpInterface<IPermissionController>(impl)
     {
     }
-        
+
     virtual bool checkPermission(const String16& permission, int32_t pid, int32_t uid)
     {
         Parcel data, reply;
@@ -46,7 +46,7 @@
         data.writeInt32(uid);
         remote()->transact(CHECK_PERMISSION_TRANSACTION, data, &reply);
         // fail on exception
-        if (reply.readInt32() != 0) return 0;
+        if (reply.readExceptionCode() != 0) return 0;
         return reply.readInt32() != 0;
     }
 };
@@ -66,8 +66,7 @@
             int32_t pid = data.readInt32();
             int32_t uid = data.readInt32();
             bool res = checkPermission(permission, pid, uid);
-            // write exception
-            reply->writeInt32(0);
+            reply->writeNoException();
             reply->writeInt32(res ? 1 : 0);
             return NO_ERROR;
         } break;
@@ -77,4 +76,3 @@
 }
 
 }; // namespace android
-
diff --git a/libs/binder/IServiceManager.cpp b/libs/binder/IServiceManager.cpp
index a3a3f0e..1fa4c35 100644
--- a/libs/binder/IServiceManager.cpp
+++ b/libs/binder/IServiceManager.cpp
@@ -158,7 +158,7 @@
         data.writeString16(name);
         data.writeStrongBinder(service);
         status_t err = remote()->transact(ADD_SERVICE_TRANSACTION, data, &reply);
-        return err == NO_ERROR ? reply.readInt32() : err;
+        return err == NO_ERROR ? reply.readExceptionCode() : err;
     }
 
     virtual Vector<String16> listServices()
diff --git a/libs/binder/Parcel.cpp b/libs/binder/Parcel.cpp
index c2574bd..47be1bf 100644
--- a/libs/binder/Parcel.cpp
+++ b/libs/binder/Parcel.cpp
@@ -754,6 +754,11 @@
     goto restart_write;
 }
 
+status_t Parcel::writeNoException()
+{
+    return writeInt32(0);
+}
+
 void Parcel::remove(size_t start, size_t amt)
 {
     LOG_ALWAYS_FATAL("Parcel::remove() not yet implemented!");
@@ -942,6 +947,12 @@
     return val;
 }
 
+int32_t Parcel::readExceptionCode() const
+{
+  int32_t exception_code = readAligned<int32_t>();
+  // TODO: skip over the response header here, once that's in.
+  return exception_code;
+}
 
 native_handle* Parcel::readNativeHandle() const
 {
diff --git a/libs/gui/Android.mk b/libs/gui/Android.mk
new file mode 100644
index 0000000..249558a
--- /dev/null
+++ b/libs/gui/Android.mk
@@ -0,0 +1,25 @@
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES:= \
+	ISensorEventConnection.cpp \
+	ISensorServer.cpp \
+	Sensor.cpp \
+	SensorChannel.cpp \
+	SensorEventQueue.cpp \
+	SensorManager.cpp
+
+LOCAL_SHARED_LIBRARIES := \
+	libcutils \
+	libutils \
+	libbinder \
+	libhardware \
+	libhardware_legacy
+
+LOCAL_MODULE:= libgui
+
+ifeq ($(TARGET_SIMULATOR),true)
+    LOCAL_LDLIBS += -lpthread
+endif
+
+include $(BUILD_SHARED_LIBRARY)
diff --git a/libs/gui/ISensorEventConnection.cpp b/libs/gui/ISensorEventConnection.cpp
new file mode 100644
index 0000000..3e9d456
--- /dev/null
+++ b/libs/gui/ISensorEventConnection.cpp
@@ -0,0 +1,108 @@
+/*
+ * 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.
+ */
+
+#include <stdint.h>
+#include <sys/types.h>
+
+#include <utils/Errors.h>
+#include <utils/RefBase.h>
+#include <utils/Timers.h>
+
+#include <binder/Parcel.h>
+#include <binder/IInterface.h>
+
+#include <gui/ISensorEventConnection.h>
+#include <gui/SensorChannel.h>
+
+namespace android {
+// ----------------------------------------------------------------------------
+
+enum {
+    GET_SENSOR_CHANNEL = IBinder::FIRST_CALL_TRANSACTION,
+    ENABLE_DISABLE,
+    SET_EVENT_RATE
+};
+
+class BpSensorEventConnection : public BpInterface<ISensorEventConnection>
+{
+public:
+    BpSensorEventConnection(const sp<IBinder>& impl)
+        : BpInterface<ISensorEventConnection>(impl)
+    {
+    }
+
+    virtual sp<SensorChannel> getSensorChannel() const
+    {
+        Parcel data, reply;
+        remote()->transact(GET_SENSOR_CHANNEL, data, &reply);
+        return new SensorChannel(reply);
+    }
+
+    virtual status_t enableDisable(int handle, bool enabled)
+    {
+        Parcel data, reply;
+        data.writeInt32(handle);
+        data.writeInt32(enabled);
+        remote()->transact(ENABLE_DISABLE, data, &reply);
+        return reply.readInt32();
+    }
+
+    virtual status_t setEventRate(int handle, nsecs_t ns)
+    {
+        Parcel data, reply;
+        data.writeInt32(handle);
+        data.writeInt64(ns);
+        remote()->transact(SET_EVENT_RATE, data, &reply);
+        return reply.readInt32();
+    }
+};
+
+IMPLEMENT_META_INTERFACE(SensorEventConnection, "android.gui.SensorEventConnection");
+
+// ----------------------------------------------------------------------------
+
+status_t BnSensorEventConnection::onTransact(
+    uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
+{
+    switch(code) {
+        case GET_SENSOR_CHANNEL: {
+            CHECK_INTERFACE(ISensorEventConnection, data, reply);
+            sp<SensorChannel> channel(getSensorChannel());
+            channel->writeToParcel(reply);
+            return NO_ERROR;
+        } break;
+        case ENABLE_DISABLE: {
+            CHECK_INTERFACE(ISensorEventConnection, data, reply);
+            int handle = data.readInt32();
+            int enabled = data.readInt32();
+            status_t result = enableDisable(handle, enabled);
+            reply->writeInt32(result);
+            return NO_ERROR;
+        } break;
+        case SET_EVENT_RATE: {
+            CHECK_INTERFACE(ISensorEventConnection, data, reply);
+            int handle = data.readInt32();
+            int ns = data.readInt64();
+            status_t result = setEventRate(handle, ns);
+            reply->writeInt32(result);
+            return NO_ERROR;
+        } break;
+    }
+    return BBinder::onTransact(code, data, reply, flags);
+}
+
+// ----------------------------------------------------------------------------
+}; // namespace android
diff --git a/libs/gui/ISensorServer.cpp b/libs/gui/ISensorServer.cpp
new file mode 100644
index 0000000..c6177bc
--- /dev/null
+++ b/libs/gui/ISensorServer.cpp
@@ -0,0 +1,100 @@
+/*
+ * 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.
+ */
+
+#include <stdint.h>
+#include <sys/types.h>
+
+#include <utils/Errors.h>
+#include <utils/RefBase.h>
+#include <utils/Vector.h>
+#include <utils/Timers.h>
+
+#include <binder/Parcel.h>
+#include <binder/IInterface.h>
+
+#include <gui/Sensor.h>
+#include <gui/ISensorServer.h>
+#include <gui/ISensorEventConnection.h>
+
+namespace android {
+// ----------------------------------------------------------------------------
+
+enum {
+    GET_SENSOR_LIST = IBinder::FIRST_CALL_TRANSACTION,
+    CREATE_SENSOR_EVENT_CONNECTION,
+};
+
+class BpSensorServer : public BpInterface<ISensorServer>
+{
+public:
+    BpSensorServer(const sp<IBinder>& impl)
+        : BpInterface<ISensorServer>(impl)
+    {
+    }
+
+    virtual Vector<Sensor> getSensorList()
+    {
+        Parcel data, reply;
+        remote()->transact(GET_SENSOR_LIST, data, &reply);
+        Sensor s;
+        Vector<Sensor> v;
+        int32_t n = reply.readInt32();
+        v.setCapacity(n);
+        while (n--) {
+            reply.read(static_cast<Flattenable&>(s));
+            v.add(s);
+        }
+        return v;
+    }
+
+    virtual sp<ISensorEventConnection> createSensorEventConnection()
+    {
+        Parcel data, reply;
+        remote()->transact(CREATE_SENSOR_EVENT_CONNECTION, data, &reply);
+        return interface_cast<ISensorEventConnection>(reply.readStrongBinder());
+    }
+};
+
+IMPLEMENT_META_INTERFACE(SensorServer, "android.gui.SensorServer");
+
+// ----------------------------------------------------------------------
+
+status_t BnSensorServer::onTransact(
+    uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
+{
+    switch(code) {
+        case GET_SENSOR_LIST: {
+            CHECK_INTERFACE(ISensorServer, data, reply);
+            Vector<Sensor> v(getSensorList());
+            size_t n = v.size();
+            reply->writeInt32(n);
+            for (size_t i=0 ; i<n ; i++) {
+                reply->write(static_cast<const Flattenable&>(v[i]));
+            }
+            return NO_ERROR;
+        } break;
+        case CREATE_SENSOR_EVENT_CONNECTION: {
+            CHECK_INTERFACE(ISensorServer, data, reply);
+            sp<ISensorEventConnection> connection(createSensorEventConnection());
+            reply->writeStrongBinder(connection->asBinder());
+            return NO_ERROR;
+        } break;
+    }
+    return BBinder::onTransact(code, data, reply, flags);
+}
+
+// ----------------------------------------------------------------------------
+}; // namespace android
diff --git a/libs/gui/Sensor.cpp b/libs/gui/Sensor.cpp
new file mode 100644
index 0000000..1fdd285
--- /dev/null
+++ b/libs/gui/Sensor.cpp
@@ -0,0 +1,165 @@
+/*
+ * 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.
+ */
+
+#include <stdint.h>
+#include <sys/types.h>
+
+#include <utils/Errors.h>
+#include <utils/String8.h>
+#include <utils/Flattenable.h>
+
+#include <hardware/sensors.h>
+
+#include <gui/Sensor.h>
+
+// ----------------------------------------------------------------------------
+namespace android {
+// ----------------------------------------------------------------------------
+
+Sensor::Sensor()
+    : mHandle(0), mType(0),
+      mMinValue(0), mMaxValue(0), mResolution(0),
+      mPower(0)
+{
+}
+
+Sensor::~Sensor()
+{
+}
+
+const String8& Sensor::getName() const {
+    return mName;
+}
+
+const String8& Sensor::getVendor() const {
+    return mVendor;
+}
+
+int32_t Sensor::getHandle() const {
+    return mHandle;
+}
+
+int32_t Sensor::getType() const {
+    return mType;
+}
+
+float Sensor::getMinValue() const {
+    return mMinValue;
+}
+
+float Sensor::getMaxValue() const {
+    return mMaxValue;
+}
+
+float Sensor::getResolution() const {
+    return mResolution;
+}
+
+float Sensor::getPowerUsage() const {
+    return mPower;
+}
+
+size_t Sensor::getFlattenedSize() const
+{
+    return  sizeof(int32_t) + ((mName.length() + 3) & ~3) +
+            sizeof(int32_t) + ((mVendor.length() + 3) & ~3) +
+            sizeof(int32_t) * 2 +
+            sizeof(float) * 3;
+}
+
+size_t Sensor::getFdCount() const
+{
+    return 0;
+}
+
+static inline
+size_t write(void* buffer, size_t offset, const String8& value) {
+    memcpy(static_cast<char*>(buffer) + offset, value.string(), value.length());
+    return (value.length() + 3) & ~3;
+}
+
+static inline
+size_t write(void* buffer, size_t offset, float value) {
+    *reinterpret_cast<float*>(static_cast<char*>(buffer) + offset) = value;
+    return sizeof(float);
+}
+
+static inline
+size_t write(void* buffer, size_t offset, int32_t value) {
+    *reinterpret_cast<int32_t*>(static_cast<char*>(buffer) + offset) = value;
+    return sizeof(int32_t);
+}
+
+status_t Sensor::flatten(void* buffer, size_t size,
+        int fds[], size_t count) const
+{
+    if (size < Sensor::getFlattenedSize())
+        return -ENOMEM;
+
+    size_t offset = 0;
+    offset += write(buffer, offset, int32_t(mName.length()));
+    offset += write(buffer, offset, mName);
+    offset += write(buffer, offset, int32_t(mVendor.length()));
+    offset += write(buffer, offset, mVendor);
+    offset += write(buffer, offset, mHandle);
+    offset += write(buffer, offset, mType);
+    offset += write(buffer, offset, mMinValue);
+    offset += write(buffer, offset, mMaxValue);
+    offset += write(buffer, offset, mResolution);
+    offset += write(buffer, offset, mPower);
+
+    return NO_ERROR;
+}
+
+static inline
+size_t read(void const* buffer, size_t offset, String8* value, int32_t len) {
+    value->setTo(static_cast<char const*>(buffer) + offset, len);
+    return (len + 3) & ~3;
+}
+
+static inline
+size_t read(void const* buffer, size_t offset, float* value) {
+    *value = *reinterpret_cast<float const*>(static_cast<char const*>(buffer) + offset);
+    return sizeof(float);
+}
+
+static inline
+size_t read(void const* buffer, size_t offset, int32_t* value) {
+    *value = *reinterpret_cast<int32_t const*>(static_cast<char const*>(buffer) + offset);
+    return sizeof(int32_t);
+}
+
+status_t Sensor::unflatten(void const* buffer, size_t size,
+        int fds[], size_t count)
+{
+    int32_t len;
+    size_t offset = 0;
+    offset += read(buffer, offset, &len);
+    offset += read(buffer, offset, &mName, len);
+    offset += read(buffer, offset, &len);
+    offset += read(buffer, offset, &mVendor, len);
+    offset += read(buffer, offset, &mHandle);
+    offset += read(buffer, offset, &mType);
+    offset += read(buffer, offset, &mMinValue);
+    offset += read(buffer, offset, &mMaxValue);
+    offset += read(buffer, offset, &mResolution);
+    offset += read(buffer, offset, &mPower);
+
+    return NO_ERROR;
+}
+
+// ----------------------------------------------------------------------------
+}; // namespace android
diff --git a/libs/gui/SensorChannel.cpp b/libs/gui/SensorChannel.cpp
new file mode 100644
index 0000000..147e1c2
--- /dev/null
+++ b/libs/gui/SensorChannel.cpp
@@ -0,0 +1,93 @@
+/*
+ * 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.
+ */
+
+#include <stdint.h>
+#include <sys/types.h>
+
+#include <unistd.h>
+#include <fcntl.h>
+
+#include <utils/Errors.h>
+
+#include <binder/Parcel.h>
+
+#include <gui/SensorChannel.h>
+
+namespace android {
+// ----------------------------------------------------------------------------
+
+SensorChannel::SensorChannel()
+    : mSendFd(-1), mReceiveFd(-1)
+{
+    int fds[2];
+    if (pipe(fds) == 0) {
+        mReceiveFd = fds[0];
+        mSendFd = fds[1];
+        fcntl(mReceiveFd, F_SETFL, O_NONBLOCK);
+        fcntl(mSendFd, F_SETFL, O_NONBLOCK);
+    }
+}
+
+SensorChannel::SensorChannel(const Parcel& data)
+    : mSendFd(-1), mReceiveFd(-1)
+{
+    mReceiveFd = dup(data.readFileDescriptor());
+    fcntl(mReceiveFd, F_SETFL, O_NONBLOCK);
+}
+
+SensorChannel::~SensorChannel()
+{
+    if (mSendFd >= 0)
+        close(mSendFd);
+
+    if (mReceiveFd >= 0)
+        close(mReceiveFd);
+}
+
+int SensorChannel::getFd() const
+{
+    return mReceiveFd;
+}
+
+ssize_t SensorChannel::write(void const* vaddr, size_t size)
+{
+    ssize_t len = ::write(mSendFd, vaddr, size);
+    if (len < 0)
+        return -errno;
+    return len;
+}
+
+ssize_t SensorChannel::read(void* vaddr, size_t size)
+{
+    ssize_t len = ::read(mReceiveFd, vaddr, size);
+    if (len < 0)
+        return -errno;
+    return len;
+}
+
+status_t SensorChannel::writeToParcel(Parcel* reply) const
+{
+    if (mReceiveFd < 0)
+        return -EINVAL;
+
+    status_t result = reply->writeDupFileDescriptor(mReceiveFd);
+    close(mReceiveFd);
+    mReceiveFd = -1;
+    return result;
+}
+
+// ----------------------------------------------------------------------------
+}; // namespace android
diff --git a/libs/gui/SensorEventQueue.cpp b/libs/gui/SensorEventQueue.cpp
new file mode 100644
index 0000000..f922ac4
--- /dev/null
+++ b/libs/gui/SensorEventQueue.cpp
@@ -0,0 +1,97 @@
+/*
+ * 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.
+ */
+#include <stdint.h>
+#include <sys/types.h>
+
+#include <utils/Errors.h>
+#include <utils/RefBase.h>
+
+#include <gui/Sensor.h>
+#include <gui/SensorChannel.h>
+#include <gui/SensorEventQueue.h>
+#include <gui/ISensorEventConnection.h>
+
+#include <android/sensor.h>
+
+// ----------------------------------------------------------------------------
+namespace android {
+// ----------------------------------------------------------------------------
+
+SensorEventQueue::SensorEventQueue(const sp<ISensorEventConnection>& connection)
+    : mSensorEventConnection(connection)
+{
+}
+
+SensorEventQueue::~SensorEventQueue()
+{
+}
+
+void SensorEventQueue::onFirstRef()
+{
+    mSensorChannel = mSensorEventConnection->getSensorChannel();
+}
+
+int SensorEventQueue::getFd() const
+{
+    return mSensorChannel->getFd();
+}
+
+ssize_t SensorEventQueue::write(ASensorEvent const* events, size_t numEvents)
+{
+    ssize_t size = mSensorChannel->write(events, numEvents * sizeof(events[0]));
+    if (size >= 0) {
+        if (size % sizeof(events[0])) {
+            // partial write!!! should never happen.
+            return -EINVAL;
+        }
+        // returns number of events written
+        size /= sizeof(events[0]);
+    }
+    return size;
+}
+
+ssize_t SensorEventQueue::read(ASensorEvent* events, size_t numEvents)
+{
+    ssize_t size = mSensorChannel->read(events, numEvents*sizeof(events[0]));
+    if (size >= 0) {
+        if (size % sizeof(events[0])) {
+            // partial write!!! should never happen.
+            return -EINVAL;
+        }
+        // returns number of events read
+        size /= sizeof(events[0]);
+    }
+    return size;
+}
+
+status_t SensorEventQueue::enableSensor(Sensor const* sensor) const
+{
+    return mSensorEventConnection->enableDisable(sensor->getHandle(), true);
+}
+
+status_t SensorEventQueue::disableSensor(Sensor const* sensor) const
+{
+    return mSensorEventConnection->enableDisable(sensor->getHandle(), false);
+}
+
+status_t SensorEventQueue::setEventRate(Sensor const* sensor, nsecs_t ns) const
+{
+    return mSensorEventConnection->setEventRate(sensor->getHandle(), ns);
+}
+
+// ----------------------------------------------------------------------------
+}; // namespace android
+
diff --git a/libs/gui/SensorManager.cpp b/libs/gui/SensorManager.cpp
new file mode 100644
index 0000000..cd89285
--- /dev/null
+++ b/libs/gui/SensorManager.cpp
@@ -0,0 +1,68 @@
+/*
+ * 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.
+ */
+
+#include <stdint.h>
+#include <sys/types.h>
+
+#include <utils/Errors.h>
+#include <utils/RefBase.h>
+#include <utils/Singleton.h>
+
+#include <gui/ISensorServer.h>
+#include <gui/ISensorEventConnection.h>
+#include <gui/Sensor.h>
+#include <gui/SensorManager.h>
+#include <gui/SensorEventQueue.h>
+
+// ----------------------------------------------------------------------------
+namespace android {
+// ----------------------------------------------------------------------------
+
+ANDROID_SINGLETON_STATIC_INSTANCE(SensorManager)
+
+SensorManager::SensorManager()
+    : mSensorList(0)
+{
+    mSensors = mSensorServer->getSensorList();
+    // TODO: needs implementation
+}
+
+SensorManager::~SensorManager()
+{
+    // TODO: needs implementation
+}
+
+ssize_t SensorManager::getSensorList(Sensor** list) const
+{
+    *list = mSensorList;
+    return mSensors.size();
+}
+
+Sensor* SensorManager::getDefaultSensor(int type)
+{
+    // TODO: needs implementation
+    return mSensorList;
+}
+
+sp<SensorEventQueue> SensorManager::createEventQueue()
+{
+    sp<SensorEventQueue> result = new SensorEventQueue(
+            mSensorServer->createSensorEventConnection());
+    return result;
+}
+
+// ----------------------------------------------------------------------------
+}; // namespace android
diff --git a/libs/hwui/Android.mk b/libs/hwui/Android.mk
index 9146ba6..809f74d6 100644
--- a/libs/hwui/Android.mk
+++ b/libs/hwui/Android.mk
@@ -5,6 +5,8 @@
 	LayerCache.cpp \
 	Matrix.cpp \
 	OpenGLRenderer.cpp \
+	Patch.cpp \
+	PatchCache.cpp \
 	Program.cpp \
 	TextureCache.cpp
 
diff --git a/libs/hwui/Layer.h b/libs/hwui/Layer.h
index 586a05e..d4db782 100644
--- a/libs/hwui/Layer.h
+++ b/libs/hwui/Layer.h
@@ -17,6 +17,8 @@
 #ifndef ANDROID_UI_LAYER_H
 #define ANDROID_UI_LAYER_H
 
+#include <sys/types.h>
+
 #include <GLES2/gl2.h>
 
 #include <SkXfermode.h>
@@ -54,7 +56,7 @@
     bool operator==(const LayerSize& rhs) const {
         return width == rhs.width && height == rhs.height;
     }
-};
+}; // struct LayerSize
 
 /**
  * A layer has dimensions and is backed by an OpenGL texture.
diff --git a/libs/hwui/LayerCache.cpp b/libs/hwui/LayerCache.cpp
index 882ad83..bcda45e7 100644
--- a/libs/hwui/LayerCache.cpp
+++ b/libs/hwui/LayerCache.cpp
@@ -18,6 +18,8 @@
 
 #include <GLES2/gl2.h>
 
+#include <utils/Log.h>
+
 #include "LayerCache.h"
 
 namespace android {
@@ -84,11 +86,55 @@
     mCache.setOnEntryRemovedListener(NULL);
 }
 
-Layer* LayerCache::get(LayerSize& size) {
+Layer* LayerCache::get(LayerSize& size, GLuint previousFbo) {
     Layer* layer = mCache.remove(size);
     if (layer) {
+        LAYER_LOGD("Reusing layer");
+
         mSize -= layer->layer.getWidth() * layer->layer.getHeight() * 4;
+    } else {
+        LAYER_LOGD("Creating new layer");
+
+        layer = new Layer;
+        layer->blend = true;
+
+        // Generate the FBO and attach the texture
+        glGenFramebuffers(1, &layer->fbo);
+        glBindFramebuffer(GL_FRAMEBUFFER, layer->fbo);
+
+        // Generate the texture in which the FBO will draw
+        glGenTextures(1, &layer->texture);
+        glBindTexture(GL_TEXTURE_2D, layer->texture);
+
+        // The FBO will not be scaled, so we can use lower quality filtering
+        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+
+        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+
+        glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, size.width, size.height, 0,
+                GL_RGBA, GL_UNSIGNED_BYTE, NULL);
+        glBindTexture(GL_TEXTURE_2D, 0);
+
+        // Bind texture to FBO
+        glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,
+                layer->texture, 0);
+
+        GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
+        if (status != GL_FRAMEBUFFER_COMPLETE) {
+            LOGE("Framebuffer incomplete (GL error code 0x%x)", status);
+
+            glBindFramebuffer(GL_FRAMEBUFFER, previousFbo);
+
+            glDeleteFramebuffers(1, &layer->fbo);
+            glDeleteTextures(1, &layer->texture);
+            delete layer;
+
+            return NULL;
+        }
     }
+
     return layer;
 }
 
diff --git a/libs/hwui/LayerCache.h b/libs/hwui/LayerCache.h
index 519552d..2580551 100644
--- a/libs/hwui/LayerCache.h
+++ b/libs/hwui/LayerCache.h
@@ -23,6 +23,24 @@
 namespace android {
 namespace uirenderer {
 
+///////////////////////////////////////////////////////////////////////////////
+// Defines
+///////////////////////////////////////////////////////////////////////////////
+
+// Debug
+#define DEBUG_LAYERS 0
+
+// Debug
+#if DEBUG_LAYERS
+    #define LAYER_LOGD(...) LOGD(__VA_ARGS__)
+#else
+    #define LAYER_LOGD(...)
+#endif
+
+///////////////////////////////////////////////////////////////////////////////
+// Cache
+///////////////////////////////////////////////////////////////////////////////
+
 class LayerCache: public OnEntryRemoved<LayerSize, Layer*> {
 public:
     LayerCache(uint32_t maxByteSize);
@@ -32,16 +50,28 @@
      * Used as a callback when an entry is removed from the cache.
      * Do not invoke directly.
      */
-    void operator()(LayerSize& bitmap, Layer*& texture);
+    void operator()(LayerSize& size, Layer*& layer);
 
     /**
-     * Returns the layer of specified dimensions, NULL if cannot be found.
+     * Returns the layer of specified dimensions. If not suitable layer
+     * can be found, a new one is created and returned. If creating a new
+     * layer fails, NULL is returned.
+     *
+     * When a layer is obtained from the cache, it is removed and the total
+     * size of the cache goes down.
+     *
+     * @param size The dimensions of the desired layer
+     * @param previousFbo The name of the FBO to bind to if creating a new
+     *        layer fails
      */
-    Layer* get(LayerSize& size);
+    Layer* get(LayerSize& size, GLuint previousFbo);
     /**
      * Adds the layer to the cache. The layer will not be added if there is
      * not enough space available.
      *
+     * @param size The dimensions of the layer
+     * @param layer The layer to add to the cache
+     *
      * @return True if the layer was added, false otherwise.
      */
     bool put(LayerSize& size, Layer* layer);
diff --git a/libs/hwui/Matrix.h b/libs/hwui/Matrix.h
index 40c80fa..ba5be03 100644
--- a/libs/hwui/Matrix.h
+++ b/libs/hwui/Matrix.h
@@ -88,6 +88,9 @@
     void copyTo(float* v) const;
     void copyTo(SkMatrix& v) const;
 
+    /**
+     * Does not apply rotations!
+     */
     void mapRect(Rect& r) const;
 
     float getTranslateX();
diff --git a/libs/hwui/OpenGLRenderer.cpp b/libs/hwui/OpenGLRenderer.cpp
index ae7719c..decfecf 100644
--- a/libs/hwui/OpenGLRenderer.cpp
+++ b/libs/hwui/OpenGLRenderer.cpp
@@ -34,15 +34,13 @@
 // Defines
 ///////////////////////////////////////////////////////////////////////////////
 
-// Debug
-#define DEBUG_LAYERS 0
-
 // These properties are defined in mega-bytes
 #define PROPERTY_TEXTURE_CACHE_SIZE "ro.hwui.texture_cache_size"
 #define PROPERTY_LAYER_CACHE_SIZE "ro.hwui.layer_cache_size"
 
 #define DEFAULT_TEXTURE_CACHE_SIZE 20
 #define DEFAULT_LAYER_CACHE_SIZE 10
+#define DEFAULT_PATCH_CACHE_SIZE 100
 
 // Converts a number of mega-bytes into bytes
 #define MB(s) s * 1024 * 1024
@@ -51,13 +49,6 @@
 #define SV(x, y) { { x, y } }
 #define FV(x, y, u, v) { { x, y }, { u, v } }
 
-// Debug
-#if DEBUG_LAYERS
-    #define LAYER_LOGD(...) LOGD(__VA_ARGS__)
-#else
-    #define LAYER_LOGD(...)
-#endif
-
 ///////////////////////////////////////////////////////////////////////////////
 // Globals
 ///////////////////////////////////////////////////////////////////////////////
@@ -99,13 +90,21 @@
         { SkXfermode::kXor_Mode,     GL_ONE_MINUS_DST_ALPHA,  GL_ONE_MINUS_SRC_ALPHA }
 };
 
+static const GLint gTileModes[] = {
+        GL_CLAMP_TO_EDGE,   // == SkShader::kClamp_TileMode
+        GL_REPEAT,          // == SkShader::kRepeat_Mode
+        GL_MIRRORED_REPEAT  // == SkShader::kMirror_TileMode
+};
+
 ///////////////////////////////////////////////////////////////////////////////
 // Constructors/destructor
 ///////////////////////////////////////////////////////////////////////////////
 
 OpenGLRenderer::OpenGLRenderer():
+        mBlend(false), mLastSrcMode(GL_ZERO), mLastDstMode(GL_ZERO),
         mTextureCache(MB(DEFAULT_TEXTURE_CACHE_SIZE)),
-        mLayerCache(MB(DEFAULT_LAYER_CACHE_SIZE)) {
+        mLayerCache(MB(DEFAULT_LAYER_CACHE_SIZE)),
+        mPatchCache(DEFAULT_PATCH_CACHE_SIZE) {
     LOGD("Create OpenGLRenderer");
 
     char property[PROPERTY_VALUE_MAX];
@@ -123,8 +122,15 @@
         LOGD("  Using default layer cache size of %dMB", DEFAULT_LAYER_CACHE_SIZE);
     }
 
-    mDrawColorShader = new DrawColorProgram;
-    mDrawTextureShader = new DrawTextureProgram;
+    mDrawColorProgram = new DrawColorProgram;
+    mDrawTextureProgram = new DrawTextureProgram;
+    mCurrentProgram = mDrawTextureProgram;
+
+    mShader = kShaderNone;
+    mShaderTileX = SkShader::kClamp_TileMode;
+    mShaderTileY = SkShader::kClamp_TileMode;
+    mShaderMatrix = NULL;
+    mShaderBitmap = NULL;
 
     memcpy(mDrawTextureVertices, gDrawTextureVertices, sizeof(gDrawTextureVertices));
 }
@@ -134,6 +140,7 @@
 
     mTextureCache.clear();
     mLayerCache.clear();
+    mPatchCache.clear();
 }
 
 ///////////////////////////////////////////////////////////////////////////////
@@ -143,9 +150,7 @@
 void OpenGLRenderer::setViewport(int width, int height) {
     glViewport(0, 0, width, height);
 
-    mat4 ortho;
-    ortho.loadOrtho(0, width, height, 0, -1, 1);
-    ortho.copyTo(mOrthoMatrix);
+    mOrthoMatrix.loadOrtho(0, width, height, 0, -1, 1);
 
     mWidth = width;
     mHeight = height;
@@ -215,7 +220,7 @@
     sp<Snapshot> previous = mSnapshot->previous;
 
     if (restoreOrtho) {
-        memcpy(mOrthoMatrix, current->orthoMatrix, sizeof(mOrthoMatrix));
+        mOrthoMatrix.load(current->orthoMatrix);
     }
 
     if (restoreLayer) {
@@ -250,9 +255,11 @@
     const Rect& rect = layer->layer;
 
     drawTextureRect(rect.left, rect.top, rect.right, rect.bottom,
-            layer->texture, layer->alpha, layer->mode, layer->blend, true);
+            layer->texture, layer->alpha, layer->mode, layer->blend);
 
     LayerSize size(rect.getWidth(), rect.getHeight());
+    // Failing to add the layer to the cache should happen only if the
+    // layer is too large
     if (!mLayerCache.put(size, layer)) {
         LAYER_LOGD("Deleting layer");
 
@@ -300,63 +307,19 @@
 bool OpenGLRenderer::createLayer(sp<Snapshot> snapshot, float left, float top,
         float right, float bottom, int alpha, SkXfermode::Mode mode,int flags) {
 
-    LayerSize size(right - left, bottom - top);
-    Layer* layer = mLayerCache.get(size);
-
-    LAYER_LOGD("Requesting layer %dx%d", size.width, size.height);
+    LAYER_LOGD("Requesting layer %fx%f", right - left, bottom - top);
     LAYER_LOGD("Layer cache size = %d", mLayerCache.getSize());
 
+    GLuint previousFbo = snapshot->previous.get() ? snapshot->previous->fbo : 0;
+    LayerSize size(right - left, bottom - top);
+
+    Layer* layer = mLayerCache.get(size, previousFbo);
     if (!layer) {
-        LAYER_LOGD("Creating new layer");
-
-        layer = new Layer;
-        layer->blend = true;
-
-        // Generate the FBO and attach the texture
-        glGenFramebuffers(1, &layer->fbo);
-        glBindFramebuffer(GL_FRAMEBUFFER, layer->fbo);
-
-        // Generate the texture in which the FBO will draw
-        glGenTextures(1, &layer->texture);
-        glBindTexture(GL_TEXTURE_2D, layer->texture);
-
-        // The FBO will not be scaled, so we can use lower quality filtering
-        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
-        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
-
-        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
-        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
-
-        // TODO VERY IMPORTANT: Fix TextView to not call saveLayer() all the time
-
-        const GLsizei width = right - left;
-        const GLsizei height = bottom - top;
-
-        glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
-        glBindTexture(GL_TEXTURE_2D, 0);
-
-        // Bind texture to FBO
-        glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,
-                layer->texture, 0);
-
-        GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
-        if (status != GL_FRAMEBUFFER_COMPLETE) {
-            LOGD("Framebuffer incomplete (GL error code 0x%x)", status);
-
-            GLuint previousFbo = snapshot->previous.get() ? snapshot->previous->fbo : 0;
-            glBindFramebuffer(GL_FRAMEBUFFER, previousFbo);
-
-            glDeleteFramebuffers(1, &layer->fbo);
-            glDeleteTextures(1, &layer->texture);
-            delete layer;
-
-            return false;
-        }
-    } else {
-        LAYER_LOGD("Reusing layer");
-        glBindFramebuffer(GL_FRAMEBUFFER, layer->fbo);
+        return false;
     }
 
+    glBindFramebuffer(GL_FRAMEBUFFER, layer->fbo);
+
     // Clear the FBO
     glDisable(GL_SCISSOR_TEST);
     glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
@@ -376,18 +339,16 @@
     saveSnapshot();
     // TODO: This doesn't preserve other transformations (check Skia first)
     mSnapshot->transform.loadTranslate(-left, -top, 0.0f);
-    mSnapshot->clipRect.set(left, top, right, bottom);
+    mSnapshot->setClip(left, top, right, bottom);
     mSnapshot->height = bottom - top;
     setScissorFromClip();
 
     mSnapshot->flags = Snapshot::kFlagDirtyTransform | Snapshot::kFlagDirtyOrtho |
             Snapshot::kFlagClipSet;
-    memcpy(mSnapshot->orthoMatrix, mOrthoMatrix, sizeof(mOrthoMatrix));
+    mSnapshot->orthoMatrix.load(mOrthoMatrix);
 
     // Change the ortho projection
-    mat4 ortho;
-    ortho.loadOrtho(0.0f, right - left, bottom - top, 0.0f, 0.0f, 1.0f);
-    ortho.copyTo(mOrthoMatrix);
+    mOrthoMatrix.loadOrtho(0.0f, right - left, bottom - top, 0.0f, 0.0f, 1.0f);
 
     return true;
 }
@@ -457,7 +418,7 @@
 }
 
 bool OpenGLRenderer::clipRect(float left, float top, float right, float bottom) {
-    bool clipped = mSnapshot->clipRect.intersect(left, top, right, bottom);
+    bool clipped = mSnapshot->clip(left, top, right, bottom);
     if (clipped) {
         mSnapshot->flags |= Snapshot::kFlagClipSet;
         setScissorFromClip();
@@ -470,14 +431,15 @@
 ///////////////////////////////////////////////////////////////////////////////
 
 void OpenGLRenderer::drawBitmap(SkBitmap* bitmap, float left, float top, const SkPaint* paint) {
+    const float right = left + bitmap->width();
+    const float bottom = top + bitmap->height();
+
+    if (quickReject(left, top, right, bottom)) {
+        return;
+    }
+
     const Texture* texture = mTextureCache.get(bitmap);
-
-    int alpha;
-    SkXfermode::Mode mode;
-    getAlphaAndMode(paint, &alpha, &mode);
-
-    drawTextureRect(left, top, left + texture->width, top + texture->height, texture->id,
-            alpha / 255.0f, mode, texture->blend, true);
+    drawTextureRect(left, top, right, bottom, texture, paint);
 }
 
 void OpenGLRenderer::drawBitmap(SkBitmap* bitmap, const SkMatrix* matrix, const SkPaint* paint) {
@@ -485,25 +447,23 @@
     const mat4 transform(*matrix);
     transform.mapRect(r);
 
+    if (quickReject(r.left, r.top, r.right, r.bottom)) {
+        return;
+    }
+
     const Texture* texture = mTextureCache.get(bitmap);
-
-    int alpha;
-    SkXfermode::Mode mode;
-    getAlphaAndMode(paint, &alpha, &mode);
-
-    drawTextureRect(r.left, r.top, r.right, r.bottom, texture->id,
-            alpha / 255.0f, mode, texture->blend, true);
+    drawTextureRect(r.left, r.top, r.right, r.bottom, texture, paint);
 }
 
 void OpenGLRenderer::drawBitmap(SkBitmap* bitmap,
          float srcLeft, float srcTop, float srcRight, float srcBottom,
          float dstLeft, float dstTop, float dstRight, float dstBottom,
          const SkPaint* paint) {
-    const Texture* texture = mTextureCache.get(bitmap);
+    if (quickReject(dstLeft, dstTop, dstRight, dstBottom)) {
+        return;
+    }
 
-    int alpha;
-    SkXfermode::Mode mode;
-    getAlphaAndMode(paint, &alpha, &mode);
+    const Texture* texture = mTextureCache.get(bitmap);
 
     const float width = texture->width;
     const float height = texture->height;
@@ -515,24 +475,44 @@
 
     resetDrawTextureTexCoords(u1, v1, u2, v2);
 
-    drawTextureRect(dstLeft, dstTop, dstRight, dstBottom, texture->id,
-            alpha / 255.0f, mode, texture->blend, true);
+    drawTextureRect(dstLeft, dstTop, dstRight, dstBottom, texture, paint);
 
     resetDrawTextureTexCoords(0.0f, 0.0f, 1.0f, 1.0f);
 }
 
 void OpenGLRenderer::drawPatch(SkBitmap* bitmap, Res_png_9patch* patch,
         float left, float top, float right, float bottom, const SkPaint* paint) {
-    // TODO: Implement
-    LOGD("Draw 9patch, paddingLeft=%d", patch->paddingLeft);
+    if (quickReject(left, top, right, bottom)) {
+        return;
+    }
+
+    const Texture* texture = mTextureCache.get(bitmap);
+
+    int alpha;
+    SkXfermode::Mode mode;
+    getAlphaAndMode(paint, &alpha, &mode);
+
+    Patch* mesh = mPatchCache.get(patch);
+    mesh->updateVertices(bitmap, left, top, right, bottom,
+            &patch->xDivs[0], &patch->yDivs[0], patch->numXDivs, patch->numYDivs);
+
+    // Specify right and bottom as +1.0f from left/top to prevent scaling since the
+    // patch mesh already defines the final size
+    drawTextureMesh(left, top, left + 1.0f, top + 1.0f, texture->id, alpha / 255.0f,
+            mode, texture->blend, &mesh->vertices[0].position[0],
+            &mesh->vertices[0].texture[0], mesh->indices, mesh->indicesCount);
 }
 
 void OpenGLRenderer::drawColor(int color, SkXfermode::Mode mode) {
-    const Rect& clip = mSnapshot->clipRect;
-    drawColorRect(clip.left, clip.top, clip.right, clip.bottom, color, mode);
+    const Rect& clip = mSnapshot->getMappedClip();
+    drawColorRect(clip.left, clip.top, clip.right, clip.bottom, color, mode, true);
 }
 
 void OpenGLRenderer::drawRect(float left, float top, float right, float bottom, const SkPaint* p) {
+    if (quickReject(left, top, right, bottom)) {
+        return;
+    }
+
     SkXfermode::Mode mode;
 
     const bool isMode = SkXfermode::IsMode(p->getXfermode(), &mode);
@@ -544,104 +524,216 @@
     // Skia draws using the color's alpha channel if < 255
     // Otherwise, it uses the paint's alpha
     int color = p->getColor();
-    if (((color >> 24) & 0xFF) == 255) {
+    if (((color >> 24) & 0xff) == 255) {
         color |= p->getAlpha() << 24;
     }
 
     drawColorRect(left, top, right, bottom, color, mode);
 }
 
+///////////////////////////////////////////////////////////////////////////////
+// Shaders
+///////////////////////////////////////////////////////////////////////////////
+
+void OpenGLRenderer::resetShader() {
+    mShader = OpenGLRenderer::kShaderNone;
+    mShaderBlend = false;
+    mShaderTileX = SkShader::kClamp_TileMode;
+    mShaderTileY = SkShader::kClamp_TileMode;
+}
+
+void OpenGLRenderer::setupBitmapShader(SkBitmap* bitmap, SkShader::TileMode tileX,
+        SkShader::TileMode tileY, SkMatrix* matrix, bool hasAlpha) {
+    mShader = kShaderBitmap;
+    mShaderBlend = hasAlpha;
+    mShaderBitmap = bitmap;
+    mShaderTileX = tileX;
+    mShaderTileY = tileY;
+    mShaderMatrix = matrix;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// Drawing implementation
+///////////////////////////////////////////////////////////////////////////////
+
 void OpenGLRenderer::drawColorRect(float left, float top, float right, float bottom,
-        int color, SkXfermode::Mode mode) {
-    const int alpha = (color >> 24) & 0xFF;
-    const bool blend = alpha < 255 || mode != SkXfermode::kSrcOver_Mode;
-
-    const GLfloat a = alpha                  / 255.0f;
-    const GLfloat r = ((color >> 16) & 0xFF) / 255.0f;
-    const GLfloat g = ((color >>  8) & 0xFF) / 255.0f;
-    const GLfloat b = ((color      ) & 0xFF) / 255.0f;
-
-    if (blend) {
-        glEnable(GL_BLEND);
-        glBlendFunc(gBlends[mode].src, gBlends[mode].dst);
+        int color, SkXfermode::Mode mode, bool ignoreTransform) {
+    // If a shader is set, preserve only the alpha
+    if (mShader != kShaderNone) {
+        color |= 0x00ffffff;
     }
 
+    // Render using pre-multiplied alpha
+    const int alpha = (color >> 24) & 0xFF;
+    const GLfloat a = alpha / 255.0f;
+    const GLfloat r = a * ((color >> 16) & 0xFF) / 255.0f;
+    const GLfloat g = a * ((color >>  8) & 0xFF) / 255.0f;
+    const GLfloat b = a * ((color      ) & 0xFF) / 255.0f;
+
+    switch (mShader) {
+        case kShaderBitmap:
+            drawBitmapShader(left, top, right, bottom, a, mode);
+            return;
+        default:
+            break;
+    }
+
+    // Pre-multiplication happens when setting the shader color
+    chooseBlending(alpha < 255 || mShaderBlend, mode);
+
     mModelView.loadTranslate(left, top, 0.0f);
     mModelView.scale(right - left, bottom - top, 1.0f);
 
-    mDrawColorShader->use(&mOrthoMatrix[0], &mModelView.data[0], &mSnapshot->transform.data[0]);
+    // TODO: Pick the program matching the current shader
+    sp<DrawColorProgram> program = mDrawColorProgram;
+    if (!useProgram(program)) {
+        const GLvoid* p = &gDrawColorVertices[0].position[0];
+        glVertexAttribPointer(program->position, 2, GL_FLOAT, GL_FALSE,
+                gDrawColorVertexStride, p);
+    }
 
-    const GLvoid* p = &gDrawColorVertices[0].position[0];
+    if (!ignoreTransform) {
+        program->set(mOrthoMatrix, mModelView, mSnapshot->transform);
+    } else {
+        mat4 identity;
+        program->set(mOrthoMatrix, mModelView, identity);
+    }
 
-    glEnableVertexAttribArray(mDrawColorShader->position);
-    glVertexAttribPointer(mDrawColorShader->position, 2, GL_FLOAT, GL_FALSE,
-            gDrawColorVertexStride, p);
-    glVertexAttrib4f(mDrawColorShader->color, r, g, b, a);
+    glUniform4f(program->color, r, g, b, a);
 
     glDrawArrays(GL_TRIANGLE_STRIP, 0, gDrawColorVertexCount);
+}
 
-    glDisableVertexAttribArray(mDrawColorShader->position);
+void OpenGLRenderer::drawBitmapShader(float left, float top, float right, float bottom,
+        float alpha, SkXfermode::Mode mode) {
+    const Texture* texture = mTextureCache.get(mShaderBitmap);
 
-    if (blend) {
-        glDisable(GL_BLEND);
+    const float width = texture->width;
+    const float height = texture->height;
+
+    // This could be done in the vertex shader but we have only 4 vertices
+    float u1 = 0.0f;
+    float v1 = 0.0f;
+    float u2 = right - left;
+    float v2 = bottom - top;
+
+    if (mShaderMatrix) {
+        SkMatrix inverse;
+        mShaderMatrix->invert(&inverse);
+        mat4 m(inverse);
+        Rect r(u1, v1, u2, v2);
+        m.mapRect(r);
+
+        u1 = r.left;
+        u2 = r.right;
+        v1 = r.top;
+        v2 = r.bottom;
     }
+
+    u1 /= width;
+    u2 /= width;
+    v1 /= height;
+    v2 /= height;
+
+    resetDrawTextureTexCoords(u1, v1, u2, v2);
+
+    drawTextureMesh(left, top, right, bottom, texture->id, alpha, mode, texture->blend,
+            &mDrawTextureVertices[0].position[0], &mDrawTextureVertices[0].texture[0], NULL);
+
+    resetDrawTextureTexCoords(0.0f, 0.0f, 1.0f, 1.0f);
 }
 
 void OpenGLRenderer::drawTextureRect(float left, float top, float right, float bottom,
-        GLuint texture, float alpha, SkXfermode::Mode mode, bool blend, bool isPremultiplied) {
+        const Texture* texture, const SkPaint* paint) {
+    int alpha;
+    SkXfermode::Mode mode;
+    getAlphaAndMode(paint, &alpha, &mode);
+
+    drawTextureMesh(left, top, right, bottom, texture->id, alpha / 255.0f, mode, texture->blend,
+            &mDrawTextureVertices[0].position[0], &mDrawTextureVertices[0].texture[0], NULL);
+}
+
+void OpenGLRenderer::drawTextureRect(float left, float top, float right, float bottom,
+        GLuint texture, float alpha, SkXfermode::Mode mode, bool blend) {
+    drawTextureMesh(left, top, right, bottom, texture, alpha, mode, blend,
+            &mDrawTextureVertices[0].position[0], &mDrawTextureVertices[0].texture[0], NULL);
+}
+
+void OpenGLRenderer::drawTextureMesh(float left, float top, float right, float bottom,
+        GLuint texture, float alpha, SkXfermode::Mode mode, bool blend,
+        GLvoid* vertices, GLvoid* texCoords, GLvoid* indices, GLsizei elementsCount) {
     mModelView.loadTranslate(left, top, 0.0f);
     mModelView.scale(right - left, bottom - top, 1.0f);
 
-    mDrawTextureShader->use(&mOrthoMatrix[0], &mModelView.data[0], &mSnapshot->transform.data[0]);
+    useProgram(mDrawTextureProgram);
+    mDrawTextureProgram->set(mOrthoMatrix, mModelView, mSnapshot->transform);
 
-    if (blend || alpha < 1.0f || mode != SkXfermode::kSrcOver_Mode) {
+    chooseBlending(blend || alpha < 1.0f, mode);
+
+    // TODO: Only bind/set parameters when needed
+    glBindTexture(GL_TEXTURE_2D, texture);
+    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, gTileModes[mShaderTileX]);
+    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, gTileModes[mShaderTileY]);
+
+    // Always premultiplied
+    glUniform4f(mDrawTextureProgram->color, alpha, alpha, alpha, alpha);
+
+    glVertexAttribPointer(mDrawTextureProgram->position, 2, GL_FLOAT, GL_FALSE,
+            gDrawTextureVertexStride, vertices);
+    glVertexAttribPointer(mDrawTextureProgram->texCoords, 2, GL_FLOAT, GL_FALSE,
+            gDrawTextureVertexStride, texCoords);
+
+    if (!indices) {
+        glDrawArrays(GL_TRIANGLE_STRIP, 0, gDrawTextureVertexCount);
+    } else {
+        glDrawElements(GL_TRIANGLES, elementsCount, GL_UNSIGNED_SHORT, indices);
+    }
+
+    glBindTexture(GL_TEXTURE_2D, 0);
+}
+
+void OpenGLRenderer::chooseBlending(bool blend, SkXfermode::Mode mode, bool isPremultiplied) {
+    // In theory we should not blend if the mode is Src, but it's rare enough
+    // that it's not worth it
+    blend = blend || mode != SkXfermode::kSrcOver_Mode;
+    if (blend) {
+        if (!mBlend) {
+            glEnable(GL_BLEND);
+        }
+
         GLenum sourceMode = gBlends[mode].src;
+        GLenum destMode = gBlends[mode].dst;
         if (!isPremultiplied && sourceMode == GL_ONE) {
             sourceMode = GL_SRC_ALPHA;
         }
 
-        glEnable(GL_BLEND);
-        glBlendFunc(sourceMode, gBlends[mode].dst);
+        if (sourceMode != mLastSrcMode || destMode != mLastDstMode) {
+            glBlendFunc(sourceMode, destMode);
+            mLastSrcMode = sourceMode;
+            mLastDstMode = destMode;
+        }
+    } else if (mBlend) {
+        glDisable(GL_BLEND);
     }
+    mBlend = blend;
+}
 
-    glBindTexture(GL_TEXTURE_2D, texture);
-
-    // TODO handle tiling and filtering here
-
-    glActiveTexture(GL_TEXTURE0);
-    glUniform1i(mDrawTextureShader->sampler, 0);
-
-    const GLvoid* p = &mDrawTextureVertices[0].position[0];
-    const GLvoid* t = &mDrawTextureVertices[0].texture[0];
-
-    glEnableVertexAttribArray(mDrawTextureShader->position);
-    glVertexAttribPointer(mDrawTextureShader->position, 2, GL_FLOAT, GL_FALSE,
-            gDrawTextureVertexStride, p);
-
-    glEnableVertexAttribArray(mDrawTextureShader->texCoords);
-    glVertexAttribPointer(mDrawTextureShader->texCoords, 2, GL_FLOAT, GL_FALSE,
-            gDrawTextureVertexStride, t);
-
-    glVertexAttrib4f(mDrawTextureShader->color, 1.0f, 1.0f, 1.0f, alpha);
-
-    glDrawArrays(GL_TRIANGLE_STRIP, 0, gDrawTextureVertexCount);
-
-    glDisableVertexAttribArray(mDrawTextureShader->position);
-    glDisableVertexAttribArray(mDrawTextureShader->texCoords);
-
-    glBindTexture(GL_TEXTURE_2D, 0);
-    glDisable(GL_BLEND);
+bool OpenGLRenderer::useProgram(const sp<Program>& program) {
+    if (!program->isInUse()) {
+        mCurrentProgram->remove();
+        program->use();
+        mCurrentProgram = program;
+        return false;
+    }
+    return true;
 }
 
 void OpenGLRenderer::resetDrawTextureTexCoords(float u1, float v1, float u2, float v2) {
-    mDrawTextureVertices[0].texture[0] = u1;
-    mDrawTextureVertices[0].texture[1] = v1;
-    mDrawTextureVertices[1].texture[0] = u2;
-    mDrawTextureVertices[1].texture[1] = v1;
-    mDrawTextureVertices[2].texture[0] = u1;
-    mDrawTextureVertices[2].texture[1] = v2;
-    mDrawTextureVertices[3].texture[0] = u2;
-    mDrawTextureVertices[3].texture[1] = v2;
+    TextureVertex* v = &mDrawTextureVertices[0];
+    TextureVertex::setUV(v++, u1, v1);
+    TextureVertex::setUV(v++, u2, v1);
+    TextureVertex::setUV(v++, u1, v2);
+    TextureVertex::setUV(v++, u2, v2);
 }
 
 void OpenGLRenderer::getAlphaAndMode(const SkPaint* paint, int* alpha, SkXfermode::Mode* mode) {
diff --git a/libs/hwui/OpenGLRenderer.h b/libs/hwui/OpenGLRenderer.h
index 9da4b8e..2a96432 100644
--- a/libs/hwui/OpenGLRenderer.h
+++ b/libs/hwui/OpenGLRenderer.h
@@ -23,6 +23,7 @@
 #include <SkBitmap.h>
 #include <SkMatrix.h>
 #include <SkPaint.h>
+#include <SkShader.h>
 #include <SkXfermode.h>
 
 #include <utils/RefBase.h>
@@ -32,10 +33,10 @@
 #include "Program.h"
 #include "Rect.h"
 #include "Snapshot.h"
-#include "Texture.h"
-#include "Layer.h"
 #include "TextureCache.h"
 #include "LayerCache.h"
+#include "PatchCache.h"
+#include "Vertex.h"
 
 namespace android {
 namespace uirenderer {
@@ -45,22 +46,6 @@
 ///////////////////////////////////////////////////////////////////////////////
 
 /**
- * Simple structure to describe a vertex with a position.
- * This is used to draw filled rectangles without a texture.
- */
-struct SimpleVertex {
-    float position[2];
-}; // struct SimpleVertex
-
-/**
- * Simple structure to describe a vertex with a position and a texture.
- */
-struct TextureVertex {
-    float position[2];
-    float texture[2];
-}; // struct TextureVertex
-
-/**
  * Structure mapping Skia xfermodes to OpenGL blending factors.
  */
 struct Blender {
@@ -114,8 +99,23 @@
     void drawColor(int color, SkXfermode::Mode mode);
     void drawRect(float left, float top, float right, float bottom, const SkPaint* paint);
 
+    void resetShader();
+    void setupBitmapShader(SkBitmap* bitmap, SkShader::TileMode tileX, SkShader::TileMode tileY,
+            SkMatrix* matrix, bool hasAlpha);
+
 private:
     /**
+     * Type of Skia shader in use.
+     */
+    enum ShaderType {
+        kShaderNone,
+        kShaderBitmap,
+        kShaderLinearGradient,
+        kShaderCircularGradient,
+        kShaderSweepGradient
+    };
+
+    /**
      * Saves the current state of the renderer as a new snapshot.
      * The new snapshot is saved in mSnapshot and the previous snapshot
      * is linked from mSnapshot->previous.
@@ -176,9 +176,10 @@
      * @param bottom The bottom coordinate of the rectangle
      * @param color The rectangle's ARGB color, defined as a packed 32 bits word
      * @param mode The Skia xfermode to use
+     * @param ignoreTransform True if the current transform should be ignored
      */
     void drawColorRect(float left, float top, float right, float bottom,
-    		int color, SkXfermode::Mode mode);
+    		int color, SkXfermode::Mode mode, bool ignoreTransform = false);
 
     /**
      * Draws a textured rectangle with the specified texture. The specified coordinates
@@ -192,10 +193,57 @@
      * @param alpha An additional translucency parameter, between 0.0f and 1.0f
      * @param mode The blending mode
      * @param blend True if the texture contains an alpha channel
-     * @param isPremultiplied Indicates whether the texture has premultiplied alpha
      */
     void drawTextureRect(float left, float top, float right, float bottom, GLuint texture,
-            float alpha, SkXfermode::Mode mode, bool blend, bool isPremultiplied = false);
+            float alpha, SkXfermode::Mode mode, bool blend);
+
+    /**
+     * Draws a textured rectangle with the specified texture. The specified coordinates
+     * are transformed by the current snapshot's transform matrix.
+     *
+     * @param left The left coordinate of the rectangle
+     * @param top The top coordinate of the rectangle
+     * @param right The right coordinate of the rectangle
+     * @param bottom The bottom coordinate of the rectangle
+     * @param texture The texture to use
+     * @param paint The paint containing the alpha, blending mode, etc.
+     */
+    void drawTextureRect(float left, float top, float right, float bottom,
+            const Texture* texture, const SkPaint* paint);
+
+    /**
+     * Draws a textured mesh with the specified texture. If the indices are omitted, the
+     * mesh is drawn as a simple quad.
+     *
+     * @param left The left coordinate of the rectangle
+     * @param top The top coordinate of the rectangle
+     * @param right The right coordinate of the rectangle
+     * @param bottom The bottom coordinate of the rectangle
+     * @param texture The texture name to map onto the rectangle
+     * @param alpha An additional translucency parameter, between 0.0f and 1.0f
+     * @param mode The blending mode
+     * @param blend True if the texture contains an alpha channel
+     * @param vertices The vertices that define the mesh
+     * @param texCoords The texture coordinates of each vertex
+     * @param indices The indices of the vertices, can be NULL
+     * @param elementsCount The number of elements in the mesh, required by indices
+     */
+    void drawTextureMesh(float left, float top, float right, float bottom, GLuint texture,
+            float alpha, SkXfermode::Mode mode, bool blend,
+            GLvoid* vertices, GLvoid* texCoords, GLvoid* indices, GLsizei elementsCount = 0);
+
+    /**
+     * Fills the specified rectangle with the currently set bitmap shader.
+     *
+     * @param left The left coordinate of the rectangle
+     * @param top The top coordinate of the rectangle
+     * @param right The right coordinate of the rectangle
+     * @param bottom The bottom coordinate of the rectangle
+     * @param alpha An additional translucency parameter, between 0.0f and 1.0f
+     * @param mode The blending mode
+     */
+    void drawBitmapShader(float left, float top, float right, float bottom, float alpha,
+            SkXfermode::Mode mode);
 
     /**
      * Resets the texture coordinates stored in mDrawTextureVertices. Setting the values
@@ -220,11 +268,29 @@
      */
     inline void getAlphaAndMode(const SkPaint* paint, int* alpha, SkXfermode::Mode* mode);
 
+    /**
+     * Enable or disable blending as necessary. This function sets the appropriate
+     * blend function based on the specified xfermode.
+     */
+    inline void chooseBlending(bool blend, SkXfermode::Mode mode, bool isPremultiplied = true);
+
+    /**
+     * Use the specified program with the current GL context. If the program is already
+     * in use, it will not be bound again. If it is not in use, the current program is
+     * marked unused and the specified program becomes used and becomes the new
+     * current program.
+     *
+     * @param program The program to use
+     *
+     * @return true If the specified program was already in use, false otherwise.
+     */
+    inline bool useProgram(const sp<Program>& program);
+
     // Dimensions of the drawing surface
     int mWidth, mHeight;
 
     // Matrix used for ortho projection in shaders
-    float mOrthoMatrix[16];
+    mat4 mOrthoMatrix;
 
     // Model-view matrix used to position/size objects
     mat4 mModelView;
@@ -237,15 +303,30 @@
     sp<Snapshot> mSnapshot;
 
     // Shaders
-    sp<DrawColorProgram> mDrawColorShader;
-    sp<DrawTextureProgram> mDrawTextureShader;
+    sp<Program> mCurrentProgram;
+    sp<DrawColorProgram> mDrawColorProgram;
+    sp<DrawTextureProgram> mDrawTextureProgram;
 
     // Used to draw textured quads
     TextureVertex mDrawTextureVertices[4];
 
-    // Used to cache all drawBitmap textures
+    // Last known blend state
+    bool mBlend;
+    GLenum mLastSrcMode;
+    GLenum mLastDstMode;
+
+    // Skia shader
+    ShaderType mShader;
+    bool mShaderBlend;
+    SkBitmap* mShaderBitmap;
+    SkShader::TileMode mShaderTileX;
+    SkShader::TileMode mShaderTileY;
+    SkMatrix* mShaderMatrix;
+
+    // Various caches
     TextureCache mTextureCache;
     LayerCache mLayerCache;
+    PatchCache mPatchCache;
 }; // class OpenGLRenderer
 
 }; // namespace uirenderer
diff --git a/libs/hwui/Patch.cpp b/libs/hwui/Patch.cpp
new file mode 100644
index 0000000..4b6bb37
--- /dev/null
+++ b/libs/hwui/Patch.cpp
@@ -0,0 +1,188 @@
+/*
+ * 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.
+ */
+
+#define LOG_TAG "OpenGLRenderer"
+
+#include <cstring>
+
+#include <utils/Log.h>
+
+#include "Patch.h"
+
+namespace android {
+namespace uirenderer {
+
+///////////////////////////////////////////////////////////////////////////////
+// Constructors/destructor
+///////////////////////////////////////////////////////////////////////////////
+
+Patch::Patch(const uint32_t xCount, const uint32_t yCount):
+        xCount(xCount + 2), yCount(yCount + 2) {
+    verticesCount = (xCount + 2) * (yCount + 2);
+    vertices = new TextureVertex[verticesCount];
+
+    // 2 triangles per patch, 3 vertices per triangle
+    indicesCount = (xCount + 1) * (yCount + 1) * 2 * 3;
+    indices = new uint16_t[indicesCount];
+
+    const uint32_t xNum = xCount + 1;
+    const uint32_t yNum = yCount + 1;
+
+    uint16_t* startIndices = indices;
+    uint32_t n = 0;
+    for (uint32_t y = 0; y < yNum; y++) {
+        for (uint32_t x = 0; x < xNum; x++) {
+            *startIndices++ = n;
+            *startIndices++ = n + 1;
+            *startIndices++ = n + xNum + 2;
+
+            *startIndices++ = n;
+            *startIndices++ = n + xNum + 2;
+            *startIndices++ = n + xNum + 1;
+
+            n += 1;
+        }
+        n += 1;
+    }
+}
+
+Patch::~Patch() {
+    delete indices;
+    delete vertices;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// Vertices management
+///////////////////////////////////////////////////////////////////////////////
+
+void Patch::updateVertices(const SkBitmap* bitmap, float left, float top, float right,
+        float bottom, const int32_t* xDivs,  const int32_t* yDivs, const uint32_t width,
+        const uint32_t height) {
+    const uint32_t xStretchCount = (width + 1) >> 1;
+    const uint32_t yStretchCount = (height + 1) >> 1;
+
+    float xStretch = 0;
+    float yStretch = 0;
+    float xStretchTex = 0;
+    float yStretchTex = 0;
+
+    const float meshWidth = right - left;
+
+    const float bitmapWidth = float(bitmap->width());
+    const float bitmapHeight = float(bitmap->height());
+
+    if (xStretchCount > 0) {
+        uint32_t stretchSize = 0;
+        for (uint32_t i = 1; i < width; i += 2) {
+            stretchSize += xDivs[i] - xDivs[i - 1];
+        }
+        xStretchTex = (stretchSize / bitmapWidth) / xStretchCount;
+        const float fixed = bitmapWidth - stretchSize;
+        xStretch = (right - left - fixed) / xStretchCount;
+    }
+
+    if (yStretchCount > 0) {
+        uint32_t stretchSize = 0;
+        for (uint32_t i = 1; i < height; i += 2) {
+            stretchSize += yDivs[i] - yDivs[i - 1];
+        }
+        yStretchTex = (stretchSize / bitmapHeight) / yStretchCount;
+        const float fixed = bitmapHeight - stretchSize;
+        yStretch = (bottom - top - fixed) / yStretchCount;
+    }
+
+    float vy = 0.0f;
+    float ty = 0.0f;
+    TextureVertex* vertex = vertices;
+
+    generateVertices(vertex, 0.0f, 0.0f, xDivs, width, xStretch, xStretchTex,
+            meshWidth, bitmapWidth);
+    vertex += width + 2;
+
+    for (uint32_t y = 0; y < height; y++) {
+        if (y & 1) {
+            vy += yStretch;
+            ty += yStretchTex;
+        } else {
+            const float step = float(yDivs[y]);
+            vy += step;
+            ty += step / bitmapHeight;
+        }
+        generateVertices(vertex, vy, ty, xDivs, width, xStretch, xStretchTex,
+                meshWidth, bitmapWidth);
+        vertex += width + 2;
+    }
+
+    generateVertices(vertex, bottom - top, 1.0f, xDivs, width, xStretch, xStretchTex,
+            meshWidth, bitmapWidth);
+}
+
+inline void Patch::generateVertices(TextureVertex* vertex, float y, float v,
+        const int32_t xDivs[], uint32_t xCount, float xStretch, float xStretchTex,
+        float width, float widthTex) {
+    float vx = 0.0f;
+    float tx = 0.0f;
+
+    TextureVertex::set(vertex, vx, y, tx, v);
+    vertex++;
+
+    for (uint32_t x = 0; x < xCount; x++) {
+        if (x & 1) {
+            vx += xStretch;
+            tx += xStretchTex;
+        } else {
+            const float step = float(xDivs[x]);
+            vx += step;
+            tx += step / widthTex;
+        }
+
+        TextureVertex::set(vertex, vx, y, tx, v);
+        vertex++;
+    }
+
+    TextureVertex::set(vertex, width, y, 1.0f, v);
+    vertex++;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// Debug tools
+///////////////////////////////////////////////////////////////////////////////
+
+void Patch::dump() {
+    LOGD("Vertices [");
+    for (uint32_t y = 0; y < yCount; y++) {
+        char buffer[512];
+        buffer[0] = '\0';
+        uint32_t offset = 0;
+        for (uint32_t x = 0; x < xCount; x++) {
+            TextureVertex* v = &vertices[y * xCount + x];
+            offset += sprintf(&buffer[offset], " (%.4f,%.4f)-(%.4f,%.4f)",
+                    v->position[0], v->position[1], v->texture[0], v->texture[1]);
+        }
+        LOGD("  [%s ]", buffer);
+    }
+    LOGD("]\nIndices [ ");
+    char buffer[4096];
+    buffer[0] = '\0';
+    uint32_t offset = 0;
+    for (uint32_t i = 0; i < indicesCount; i++) {
+        offset += sprintf(&buffer[offset], "%d ", indices[i]);
+    }
+    LOGD("  %s\n]", buffer);
+}
+
+}; // namespace uirenderer
+}; // namespace android
diff --git a/libs/hwui/Patch.h b/libs/hwui/Patch.h
new file mode 100644
index 0000000..5d3ad03
--- /dev/null
+++ b/libs/hwui/Patch.h
@@ -0,0 +1,85 @@
+/*
+ * 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.
+ */
+
+#ifndef ANDROID_UI_PATCH_H
+#define ANDROID_UI_PATCH_H
+
+#include <sys/types.h>
+
+#include <SkBitmap.h>
+
+#include "Vertex.h"
+
+namespace android {
+namespace uirenderer {
+
+/**
+ * Description of a patch.
+ */
+struct PatchDescription {
+    PatchDescription(): xCount(0), yCount(0) { }
+    PatchDescription(const uint32_t xCount, const uint32_t yCount):
+            xCount(xCount), yCount(yCount) { }
+    PatchDescription(const PatchDescription& description):
+            xCount(description.xCount), yCount(description.yCount) { }
+
+    uint32_t xCount;
+    uint32_t yCount;
+
+    bool operator<(const PatchDescription& rhs) const {
+        if (xCount == rhs.xCount) {
+            return yCount < rhs.yCount;
+        }
+        return xCount < rhs.xCount;
+    }
+
+    bool operator==(const PatchDescription& rhs) const {
+        return xCount == rhs.xCount && yCount == rhs.yCount;
+    }
+}; // struct PatchDescription
+
+/**
+ * An OpenGL patch. This contains an array of vertices and an array of
+ * indices to render the vertices.
+ */
+struct Patch {
+    Patch(const uint32_t xCount, const uint32_t yCount);
+    ~Patch();
+
+    void updateVertices(const SkBitmap* bitmap, float left, float top, float right, float bottom,
+            const int32_t* xDivs,  const int32_t* yDivs,
+            const uint32_t width, const uint32_t height);
+    void dump();
+
+    uint32_t xCount;
+    uint32_t yCount;
+
+    uint16_t* indices;
+    uint32_t indicesCount;
+
+    TextureVertex* vertices;
+    uint32_t verticesCount;
+
+private:
+    static inline void generateVertices(TextureVertex* vertex, float y, float v,
+            const int32_t xDivs[], uint32_t xCount, float xStretch, float xStretchTex,
+            float width, float widthTex);
+}; // struct Patch
+
+}; // namespace uirenderer
+}; // namespace android
+
+#endif // ANDROID_UI_PATCH_H
diff --git a/libs/hwui/PatchCache.cpp b/libs/hwui/PatchCache.cpp
new file mode 100644
index 0000000..694e3fd
--- /dev/null
+++ b/libs/hwui/PatchCache.cpp
@@ -0,0 +1,72 @@
+/*
+ * 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.
+ */
+
+#define LOG_TAG "OpenGLRenderer"
+
+#include <utils/Log.h>
+#include <utils/ResourceTypes.h>
+
+#include "PatchCache.h"
+
+namespace android {
+namespace uirenderer {
+
+///////////////////////////////////////////////////////////////////////////////
+// Constructors/destructor
+///////////////////////////////////////////////////////////////////////////////
+
+PatchCache::PatchCache(uint32_t maxEntries): mCache(maxEntries) {
+}
+
+PatchCache::~PatchCache() {
+    clear();
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// Callbacks
+///////////////////////////////////////////////////////////////////////////////
+
+void PatchCache::operator()(PatchDescription& description, Patch*& mesh) {
+    if (mesh) delete mesh;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// Caching
+///////////////////////////////////////////////////////////////////////////////
+
+void PatchCache::clear() {
+    mCache.setOnEntryRemovedListener(this);
+    mCache.clear();
+    mCache.setOnEntryRemovedListener(NULL);
+}
+
+Patch* PatchCache::get(const Res_png_9patch* patch) {
+    const uint32_t width = patch->numXDivs;
+    const uint32_t height = patch->numYDivs;
+    const PatchDescription description(width, height);
+
+    Patch* mesh = mCache.get(description);
+    if (!mesh) {
+        PATCH_LOGD("Creating new patch mesh, w=%d h=%d", width, height);
+        mesh = new Patch(width, height);
+        mCache.put(description, mesh);
+    }
+
+    return mesh;
+}
+
+}; // namespace uirenderer
+}; // namespace android
diff --git a/libs/hwui/PatchCache.h b/libs/hwui/PatchCache.h
new file mode 100644
index 0000000..de95087
--- /dev/null
+++ b/libs/hwui/PatchCache.h
@@ -0,0 +1,65 @@
+/*
+ * 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.
+ */
+
+#ifndef ANDROID_UI_PATCH_CACHE_H
+#define ANDROID_UI_PATCH_CACHE_H
+
+#include "Patch.h"
+#include "GenerationCache.h"
+
+namespace android {
+namespace uirenderer {
+
+///////////////////////////////////////////////////////////////////////////////
+// Defines
+///////////////////////////////////////////////////////////////////////////////
+
+// Debug
+#define DEBUG_PATCHES 0
+
+// Debug
+#if DEBUG_PATCHES
+    #define PATCH_LOGD(...) LOGD(__VA_ARGS__)
+#else
+    #define PATCH_LOGD(...)
+#endif
+
+///////////////////////////////////////////////////////////////////////////////
+// Cache
+///////////////////////////////////////////////////////////////////////////////
+
+class PatchCache: public OnEntryRemoved<PatchDescription, Patch*> {
+public:
+    PatchCache(uint32_t maxCapacity);
+    ~PatchCache();
+
+    /**
+     * Used as a callback when an entry is removed from the cache.
+     * Do not invoke directly.
+     */
+    void operator()(PatchDescription& description, Patch*& mesh);
+
+    Patch* get(const Res_png_9patch* patch);
+    void clear();
+
+private:
+    GenerationCache<PatchDescription, Patch*> mCache;
+}; // class PatchCache
+
+}; // namespace uirenderer
+}; // namespace android
+
+#endif // ANDROID_UI_PATCH_CACHE_H
diff --git a/libs/hwui/Program.cpp b/libs/hwui/Program.cpp
index 2acddfc..609b28a 100644
--- a/libs/hwui/Program.cpp
+++ b/libs/hwui/Program.cpp
@@ -59,6 +59,8 @@
         }
         glDeleteProgram(id);
     }
+
+    mUse = false;
 }
 
 Program::~Program() {
@@ -69,6 +71,11 @@
 
 void Program::use() {
     glUseProgram(id);
+    mUse = true;
+}
+
+void Program::remove() {
+    mUse = false;
 }
 
 int Program::addAttrib(const char* name) {
@@ -126,18 +133,27 @@
 
 void DrawColorProgram::getAttribsAndUniforms() {
     position = addAttrib("position");
-    color = addAttrib("color");
-    projection = addUniform("projection");
-    modelView = addUniform("modelView");
+    color = addUniform("color");
     transform = addUniform("transform");
 }
 
-void DrawColorProgram::use(const GLfloat* projectionMatrix, const GLfloat* modelViewMatrix,
-        const GLfloat* transformMatrix) {
+void DrawColorProgram::set(const mat4& projectionMatrix, const mat4& modelViewMatrix,
+        const mat4& transformMatrix) {
+    mat4 t(projectionMatrix);
+    t.multiply(transformMatrix);
+    t.multiply(modelViewMatrix);
+
+    glUniformMatrix4fv(transform, 1, GL_FALSE, &t.data[0]);
+}
+
+void DrawColorProgram::use() {
     Program::use();
-    glUniformMatrix4fv(projection, 1, GL_FALSE, projectionMatrix);
-    glUniformMatrix4fv(modelView, 1, GL_FALSE, modelViewMatrix);
-    glUniformMatrix4fv(transform, 1, GL_FALSE, transformMatrix);
+    glEnableVertexAttribArray(position);
+}
+
+void DrawColorProgram::remove() {
+    Program::remove();
+    glDisableVertexAttribArray(position);
 }
 
 ///////////////////////////////////////////////////////////////////////////////
@@ -150,5 +166,17 @@
     sampler = addUniform("sampler");
 }
 
+void DrawTextureProgram::use() {
+    DrawColorProgram::use();
+    glActiveTexture(GL_TEXTURE0);
+    glUniform1i(sampler, 0);
+    glEnableVertexAttribArray(texCoords);
+}
+
+void DrawTextureProgram::remove() {
+    DrawColorProgram::remove();
+    glDisableVertexAttribArray(texCoords);
+}
+
 }; // namespace uirenderer
 }; // namespace android
diff --git a/libs/hwui/Program.h b/libs/hwui/Program.h
index ee16a92..d90bcaf 100644
--- a/libs/hwui/Program.h
+++ b/libs/hwui/Program.h
@@ -23,6 +23,8 @@
 #include <utils/KeyedVector.h>
 #include <utils/RefBase.h>
 
+#include "Matrix.h"
+
 namespace android {
 namespace uirenderer {
 
@@ -37,12 +39,26 @@
      * shaders sources.
      */
     Program(const char* vertex, const char* fragment);
-    ~Program();
+    virtual ~Program();
 
     /**
      * Binds this program to the GL context.
      */
-    void use();
+    virtual void use();
+
+    /**
+     * Marks this program as unused. This will not unbind
+     * the program from the GL context.
+     */
+    virtual void remove();
+
+    /**
+     * Indicates whether this program is currently in use with
+     * the GL context.
+     */
+    inline bool isInUse() const {
+        return mUse;
+    }
 
 protected:
     /**
@@ -85,6 +101,8 @@
     // Keeps track of attributes and uniforms slots
     KeyedVector<const char*, int> attributes;
     KeyedVector<const char*, int> uniforms;
+
+    bool mUse;
 }; // class Program
 
 /**
@@ -107,26 +125,29 @@
      * Binds the program with the specified projection, modelView and
      * transform matrices.
      */
-    void use(const GLfloat* projectionMatrix, const GLfloat* modelViewMatrix,
-             const GLfloat* transformMatrix);
+    void set(const mat4& projectionMatrix, const mat4& modelViewMatrix,
+             const mat4& transformMatrix);
+
+    /**
+     * Binds this program to the GL context.
+     */
+    virtual void use();
+
+    /**
+     * Marks this program as unused. This will not unbind
+     * the program from the GL context.
+     */
+    virtual void remove();
 
     /**
      * Name of the position attribute.
      */
     int position;
-    /**
-     * Name of the color attribute.
-     */
-    int color;
 
     /**
-     * Name of the projection uniform.
+     * Name of the color uniform.
      */
-    int projection;
-    /**
-     * Name of the modelView uniform.
-     */
-    int modelView;
+    int color;
     /**
      * Name of the transform uniform.
      */
@@ -146,7 +167,25 @@
 public:
     DrawTextureProgram();
 
+    /**
+     * Binds this program to the GL context.
+     */
+    virtual void use();
+
+    /**
+     * Marks this program as unused. This will not unbind
+     * the program from the GL context.
+     */
+    virtual void remove();
+
+    /**
+     * Name of the texture sampler uniform.
+     */
     int sampler;
+
+    /**
+     * Name of the texture coordinates attribute.
+     */
     int texCoords;
 };
 
diff --git a/libs/hwui/Snapshot.h b/libs/hwui/Snapshot.h
index 17ca440..32fee32 100644
--- a/libs/hwui/Snapshot.h
+++ b/libs/hwui/Snapshot.h
@@ -56,6 +56,8 @@
             previous(s),
             layer(NULL),
             fbo(s->fbo) {
+        mappedClip.set(s->clipRect);
+        transform.mapRect(mappedClip);
     }
 
     /**
@@ -87,12 +89,32 @@
      * Returns the current clip region mapped by the current transform.
      */
     const Rect& getMappedClip() {
+        return mappedClip;
+    }
+
+    /**
+     * Intersects the current clip with the new clip rectangle.
+     */
+    bool clip(float left, float top, float right, float bottom) {
+        bool clipped = clipRect.intersect(left, top, right, bottom);
         if (flags & kFlagDirtyTransform) {
             flags &= ~kFlagDirtyTransform;
             mappedClip.set(clipRect);
             transform.mapRect(mappedClip);
         }
-        return mappedClip;
+        return clipped;
+    }
+
+    /**
+     * Sets the current clip.
+     */
+    void setClip(float left, float top, float right, float bottom) {
+        clipRect.set(left, top, right, bottom);
+        if (flags & kFlagDirtyTransform) {
+            flags &= ~kFlagDirtyTransform;
+            mappedClip.set(clipRect);
+            transform.mapRect(mappedClip);
+        }
     }
 
     /**
@@ -130,7 +152,7 @@
     /**
      * Contains the previous ortho matrix.
      */
-    float orthoMatrix[16];
+    mat4 orthoMatrix;
 
 private:
     // Clipping rectangle mapped with the transform
diff --git a/libs/hwui/TextureCache.cpp b/libs/hwui/TextureCache.cpp
index 612f04e..4977f46 100644
--- a/libs/hwui/TextureCache.cpp
+++ b/libs/hwui/TextureCache.cpp
@@ -133,7 +133,7 @@
                 GL_RGB, GL_UNSIGNED_SHORT_5_6_5, bitmap->getPixels());
         break;
     case SkBitmap::kARGB_8888_Config:
-        texture->blend = true;
+        texture->blend = !bitmap->isOpaque();
         glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, bitmap->rowBytesAsPixels(), texture->height, 0,
                 GL_RGBA, GL_UNSIGNED_BYTE, bitmap->getPixels());
         break;
diff --git a/libs/hwui/Vertex.h b/libs/hwui/Vertex.h
new file mode 100644
index 0000000..ffd0633
--- /dev/null
+++ b/libs/hwui/Vertex.h
@@ -0,0 +1,54 @@
+/*
+ * 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.
+ */
+
+#ifndef ANDROID_UI_VERTEX_H
+#define ANDROID_UI_VERTEX_H
+
+namespace android {
+namespace uirenderer {
+
+/**
+ * Simple structure to describe a vertex with a position.
+ * This is used to draw filled rectangles without a texture.
+ */
+struct SimpleVertex {
+    float position[2];
+}; // struct SimpleVertex
+
+/**
+ * Simple structure to describe a vertex with a position and a texture.
+ */
+struct TextureVertex {
+    float position[2];
+    float texture[2];
+
+    static inline void set(TextureVertex* vertex, float x, float y, float u, float v) {
+        vertex[0].position[0] = x;
+        vertex[0].position[1] = y;
+        vertex[0].texture[0] = u;
+        vertex[0].texture[1] = v;
+    }
+
+    static inline void setUV(TextureVertex* vertex, float u, float v) {
+        vertex[0].texture[0] = u;
+        vertex[0].texture[1] = v;
+    }
+}; // struct TextureVertex
+
+}; // namespace uirenderer
+}; // namespace android
+
+#endif // ANDROID_UI_VERTEX_H
diff --git a/libs/hwui/shaders/drawColor.frag b/libs/hwui/shaders/drawColor.frag
index e84c47b..1d6cb8b 100644
--- a/libs/hwui/shaders/drawColor.frag
+++ b/libs/hwui/shaders/drawColor.frag
@@ -1,9 +1,11 @@
 SHADER_SOURCE(gDrawColorFragmentShader,
 
-varying lowp vec4 outColor;
+precision mediump float;
+
+uniform vec4 color;
 
 void main(void) {
-    gl_FragColor = outColor;
+    gl_FragColor = color;
 }
 
 );
diff --git a/libs/hwui/shaders/drawColor.vert b/libs/hwui/shaders/drawColor.vert
index cef6e49..20e2636 100644
--- a/libs/hwui/shaders/drawColor.vert
+++ b/libs/hwui/shaders/drawColor.vert
@@ -1,17 +1,11 @@
 SHADER_SOURCE(gDrawColorVertexShader,
 
 attribute vec4 position;
-attribute vec4 color;
 
-uniform mat4 projection;
-uniform mat4 modelView;
 uniform mat4 transform;
 
-varying vec4 outColor;
-
 void main(void) {
-    outColor = color;
-    gl_Position = projection * transform * modelView * position;
+    gl_Position = transform * position;
 }
 
 );
diff --git a/libs/hwui/shaders/drawTexture.frag b/libs/hwui/shaders/drawTexture.frag
index 5bd420e..8390d8e 100644
--- a/libs/hwui/shaders/drawTexture.frag
+++ b/libs/hwui/shaders/drawTexture.frag
@@ -1,12 +1,14 @@
 SHADER_SOURCE(gDrawTextureFragmentShader,
 
-varying lowp vec4 outColor;
-varying mediump vec2 outTexCoords;
+precision mediump float;
 
+varying vec2 outTexCoords;
+
+uniform vec4 color;
 uniform sampler2D sampler;
 
 void main(void) {
-    gl_FragColor = texture2D(sampler, outTexCoords) * outColor;
+    gl_FragColor = texture2D(sampler, outTexCoords) * color;
 }
 
 );
diff --git a/libs/hwui/shaders/drawTexture.vert b/libs/hwui/shaders/drawTexture.vert
index 310a812..240aebf 100644
--- a/libs/hwui/shaders/drawTexture.vert
+++ b/libs/hwui/shaders/drawTexture.vert
@@ -2,19 +2,14 @@
 
 attribute vec4 position;
 attribute vec2 texCoords;
-attribute vec4 color;
 
-uniform mat4 projection;
-uniform mat4 modelView;
 uniform mat4 transform;
 
-varying vec4 outColor;
 varying vec2 outTexCoords;
 
 void main(void) {
-    outColor = color;
     outTexCoords = texCoords;
-    gl_Position = projection * transform * modelView * position;
+    gl_Position = transform * position;
 }
 
 );
diff --git a/libs/rs/RenderScript.h b/libs/rs/RenderScript.h
index 8e6b5c6..6636fef 100644
--- a/libs/rs/RenderScript.h
+++ b/libs/rs/RenderScript.h
@@ -244,11 +244,30 @@
     RS_A3D_CLASS_ID_SCRIPT_C
 };
 
+enum RsCullMode {
+    RS_CULL_BACK,
+    RS_CULL_FRONT,
+    RS_CULL_NONE
+};
+
 typedef struct {
     RsA3DClassID classID;
     const char* objectName;
 } RsFileIndexEntry;
 
+// Script to Script
+typedef struct {
+    uint32_t xStart;
+    uint32_t xEnd;
+    uint32_t yStart;
+    uint32_t yEnd;
+    uint32_t zStart;
+    uint32_t zEnd;
+    uint32_t arrayStart;
+    uint32_t arrayEnd;
+
+} RsScriptCall;
+
 #ifndef NO_RS_FUNCS
 #include "rsgApiFuncDecl.h"
 #endif
diff --git a/libs/rs/java/ImageProcessing/res/raw/horizontal_blur.rs b/libs/rs/java/ImageProcessing/res/raw/horizontal_blur.rs
new file mode 100644
index 0000000..7b0e6bc
--- /dev/null
+++ b/libs/rs/java/ImageProcessing/res/raw/horizontal_blur.rs
@@ -0,0 +1,43 @@
+#pragma version(1)
+
+#include "../../../../scriptc/rs_types.rsh"
+#include "../../../../scriptc/rs_math.rsh"
+
+#include "ip.rsh"
+
+uchar4 * ScratchPixel;
+
+#pragma rs export_var(ScratchPixel)
+
+void root(const void *v_in, void *v_out, const void *usrData, uint32_t x, uint32_t y) {
+    uchar4 *output = (uchar4 *)v_out;
+    const uchar4 *input = (uchar4 *)v_in;
+    const FilterStruct *fs = (const FilterStruct *)usrData;
+
+    float4 blurredPixel = 0;
+    float4 currentPixel = 0;
+    for(int r = -fs->radius; r <= fs->radius; r ++) {
+        // Stepping left and right away from the pixel
+        int validW = x + r;
+        // Clamp to zero and width max() isn't exposed for ints yet
+        if(validW < 0) {
+            validW = 0;
+        }
+        if(validW > fs->width - 1) {
+            validW = fs->width - 1;
+        }
+        //int validW = rsClamp(w + r, 0, width - 1);
+
+        float weight = fs->gaussian[r + fs->radius];
+        currentPixel.x = (float)(input[validW].x);
+        currentPixel.y = (float)(input[validW].y);
+        currentPixel.z = (float)(input[validW].z);
+        //currentPixel.w = (float)(input->a);
+
+        blurredPixel += currentPixel * weight;
+    }
+
+    output->x = (uint8_t)blurredPixel.x;
+    output->y = (uint8_t)blurredPixel.y;
+    output->z = (uint8_t)blurredPixel.z;
+}
diff --git a/libs/rs/java/ImageProcessing/res/raw/horizontal_blur_bc.bc b/libs/rs/java/ImageProcessing/res/raw/horizontal_blur_bc.bc
new file mode 100644
index 0000000..c9ba5d9
--- /dev/null
+++ b/libs/rs/java/ImageProcessing/res/raw/horizontal_blur_bc.bc
Binary files differ
diff --git a/libs/rs/java/ImageProcessing/res/raw/ip.rsh b/libs/rs/java/ImageProcessing/res/raw/ip.rsh
new file mode 100644
index 0000000..4073304
--- /dev/null
+++ b/libs/rs/java/ImageProcessing/res/raw/ip.rsh
@@ -0,0 +1,15 @@
+#pragma rs java_package_name(com.android.rs.image)
+
+#define MAX_RADIUS 25
+
+typedef struct {
+    float *gaussian; //[MAX_RADIUS * 2 + 1];
+    rs_matrix3x3 colorMat;
+
+    int height;
+    int width;
+    int radius;
+
+} FilterStruct;
+
+
diff --git a/libs/rs/java/ImageProcessing/res/raw/threshold.rs b/libs/rs/java/ImageProcessing/res/raw/threshold.rs
index 9585e92..ecbfac4 100644
--- a/libs/rs/java/ImageProcessing/res/raw/threshold.rs
+++ b/libs/rs/java/ImageProcessing/res/raw/threshold.rs
@@ -2,12 +2,8 @@
 
 #include "../../../../scriptc/rs_types.rsh"
 #include "../../../../scriptc/rs_math.rsh"
-#include "../../../../scriptc/rs_graphics.rsh"
 
-#pragma rs java_package_name(com.android.rs.image)
-
-
-#define MAX_RADIUS 25
+#include "ip.rsh"
 
 int height;
 int width;
@@ -28,11 +24,15 @@
 static float inWMinInB;
 static float outWMinOutB;
 static float overInWMinInB;
-//static float3 gammaV;
+static FilterStruct filterStruct;
 
-#pragma rs export_var(height, width, radius, InPixel, OutPixel, ScratchPixel, inBlack, outBlack, inWhite, outWhite, gamma, saturation, InPixel, OutPixel, ScratchPixel)
+#pragma rs export_var(height, width, radius, InPixel, OutPixel, ScratchPixel, inBlack, outBlack, inWhite, outWhite, gamma, saturation, InPixel, OutPixel, ScratchPixel, vBlurScript, hBlurScript)
 #pragma rs export_func(filter, filterBenchmark);
 
+rs_script vBlurScript;
+rs_script hBlurScript;
+
+
 // Store our coefficients here
 static float gaussian[MAX_RADIUS * 2 + 1];
 static rs_matrix3x3 colorMat;
@@ -145,48 +145,6 @@
     rsSendToClient(&count, 1, 4, 0);
 }
 
-static void horizontalBlur() {
-    float4 blurredPixel = 0;
-    float4 currentPixel = 0;
-    // Horizontal blur
-    int w, h, r;
-    for(h = 0; h < height; h ++) {
-        uchar4 *input = InPixel + h*width;
-        uchar4 *output = ScratchPixel + h*width;
-
-        for(w = 0; w < width; w ++) {
-            blurredPixel = 0;
-
-            for(r = -radius; r <= radius; r ++) {
-                // Stepping left and right away from the pixel
-                int validW = w + r;
-                // Clamp to zero and width max() isn't exposed for ints yet
-                if(validW < 0) {
-                    validW = 0;
-                }
-                if(validW > width - 1) {
-                    validW = width - 1;
-                }
-                //int validW = rsClamp(w + r, 0, width - 1);
-
-                float weight = gaussian[r + radius];
-                currentPixel.x = (float)(input[validW].x);
-                currentPixel.y = (float)(input[validW].y);
-                currentPixel.z = (float)(input[validW].z);
-                //currentPixel.w = (float)(input->a);
-
-                blurredPixel += currentPixel*weight;
-            }
-
-            output->x = (uint8_t)blurredPixel.x;
-            output->y = (uint8_t)blurredPixel.y;
-            output->z = (uint8_t)blurredPixel.z;
-            //output->a = (uint8_t)blurredPixel.w;
-            output++;
-        }
-    }
-}
-
 static void horizontalBlurLevels() {
     float4 blurredPixel = 0;
     float4 currentPixel = 0;
@@ -232,52 +190,11 @@
     }
 }
 
-static void verticalBlur() {
-    float4 blurredPixel = 0;
-    float4 currentPixel = 0;
-    // Vertical blur
-    int w, h, r;
-    for(h = 0; h < height; h ++) {
-        uchar4 *output = OutPixel + h*width;
-
-        for(w = 0; w < width; w ++) {
-
-            blurredPixel = 0;
-            for(r = -radius; r <= radius; r ++) {
-#if 1
-                int validH = h + r;
-                // Clamp to zero and width
-                if(validH < 0) {
-                    validH = 0;
-                }
-                if(validH > height - 1) {
-                    validH = height - 1;
-                }
-
-                uchar4 *input = ScratchPixel + validH*width + w;
-
-                float weight = gaussian[r + radius];
-
-                currentPixel.x = (float)(input->x);
-                currentPixel.y = (float)(input->y);
-                currentPixel.z = (float)(input->z);
-
-                blurredPixel.xyz += currentPixel.xyz * weight;
-#else
-                int validH = rsClamp(h + r, 0, height - 1);
-                uchar4 *input = ScratchPixel + validH*width + w;
-                blurredPixel.xyz += convert_float3(input->xyz) * gaussian[r + radius];
-#endif
-            }
-
-            //output->xyz = convert_uchar3(blurredPixel.xyz);
-            output->x = (uint8_t)blurredPixel.x;
-            output->y = (uint8_t)blurredPixel.y;
-            output->z = (uint8_t)blurredPixel.z;
-            //output->a = (uint8_t)blurredPixel.w;
-            output++;
-        }
-    }
+static void initStructs() {
+    filterStruct.gaussian = gaussian;
+    filterStruct.width = width;
+    filterStruct.height = height;
+    filterStruct.radius = radius;
 }
 
 void filter() {
@@ -285,6 +202,8 @@
     RS_DEBUG(width);
     RS_DEBUG(radius);
 
+    initStructs();
+
     computeColorMatrix();
 
     if(radius == 0) {
@@ -295,18 +214,30 @@
     computeGaussianWeights();
 
     horizontalBlurLevels();
-    verticalBlur();
+
+    rsForEach(vBlurScript,
+              rsGetAllocation(InPixel),
+              rsGetAllocation(OutPixel),
+              &filterStruct);
 
     int count = 0;
     rsSendToClient(&count, 1, 4, 0);
 }
 
 void filterBenchmark() {
+    initStructs();
 
     computeGaussianWeights();
 
-    horizontalBlur();
-    verticalBlur();
+    rsForEach(hBlurScript,
+              rsGetAllocation(InPixel),
+              rsGetAllocation(OutPixel),
+              &filterStruct);
+
+    rsForEach(vBlurScript,
+              rsGetAllocation(InPixel),
+              rsGetAllocation(OutPixel),
+              &filterStruct);
 
     int count = 0;
     rsSendToClient(&count, 1, 4, 0);
diff --git a/libs/rs/java/ImageProcessing/res/raw/threshold_bc.bc b/libs/rs/java/ImageProcessing/res/raw/threshold_bc.bc
index 95dcd8d..8f37fdc 100644
--- a/libs/rs/java/ImageProcessing/res/raw/threshold_bc.bc
+++ b/libs/rs/java/ImageProcessing/res/raw/threshold_bc.bc
Binary files differ
diff --git a/libs/rs/java/ImageProcessing/res/raw/vertical_blur.rs b/libs/rs/java/ImageProcessing/res/raw/vertical_blur.rs
new file mode 100644
index 0000000..846f515
--- /dev/null
+++ b/libs/rs/java/ImageProcessing/res/raw/vertical_blur.rs
@@ -0,0 +1,51 @@
+#pragma version(1)
+
+#include "../../../../scriptc/rs_types.rsh"
+#include "../../../../scriptc/rs_math.rsh"
+
+#include "ip.rsh"
+
+uchar4 * ScratchPixel;
+
+#pragma rs export_var(ScratchPixel)
+
+void root(const void *v_in, void *v_out, const void *usrData, uint32_t x, uint32_t y) {
+    uchar4 *output = (uchar4 *)v_out;
+    const uchar4 *input = (uchar4 *)v_in;
+    const FilterStruct *fs = (const FilterStruct *)usrData;
+
+    float4 blurredPixel = 0;
+    float4 currentPixel = 0;
+    for(int r = -fs->radius; r <= fs->radius; r ++) {
+#if 1
+        int validH = y + r;
+        // Clamp to zero and width
+        if(validH < 0) {
+            validH = 0;
+        }
+        if(validH > fs->height - 1) {
+            validH = fs->height - 1;
+        }
+
+        uchar4 *input = ScratchPixel + validH * fs->width + x;
+
+        float weight = fs->gaussian[r + fs->radius];
+
+        currentPixel.x = (float)(input->x);
+        currentPixel.y = (float)(input->y);
+        currentPixel.z = (float)(input->z);
+
+        blurredPixel.xyz += currentPixel.xyz * weight;
+#else
+        int validH = rsClamp(y + r, 0, height - 1);
+        uchar4 *input = ScratchPixel + validH * width + x;
+        blurredPixel.xyz += convert_float3(input->xyz) * gaussian[r + fs->radius];
+#endif
+    }
+
+    //output->xyz = convert_uchar3(blurredPixel.xyz);
+    output->x = (uint8_t)blurredPixel.x;
+    output->y = (uint8_t)blurredPixel.y;
+    output->z = (uint8_t)blurredPixel.z;
+}
+
diff --git a/libs/rs/java/ImageProcessing/res/raw/vertical_blur_bc.bc b/libs/rs/java/ImageProcessing/res/raw/vertical_blur_bc.bc
new file mode 100644
index 0000000..af1cd8e
--- /dev/null
+++ b/libs/rs/java/ImageProcessing/res/raw/vertical_blur_bc.bc
Binary files differ
diff --git a/libs/rs/java/ImageProcessing/src/com/android/rs/image/ImageProcessingActivity.java b/libs/rs/java/ImageProcessing/src/com/android/rs/image/ImageProcessingActivity.java
index 7bf6596..21c3d74 100644
--- a/libs/rs/java/ImageProcessing/src/com/android/rs/image/ImageProcessingActivity.java
+++ b/libs/rs/java/ImageProcessing/src/com/android/rs/image/ImageProcessingActivity.java
@@ -42,6 +42,8 @@
     private Bitmap mBitmapOut;
     private Bitmap mBitmapScratch;
     private ScriptC_Threshold mScript;
+    private ScriptC_Vertical_blur mScriptVBlur;
+    private ScriptC_Horizontal_blur mScriptHBlur;
     private int mRadius = 0;
     private SeekBar mRadiusSeekBar;
 
@@ -373,6 +375,12 @@
         mOutPixelsAllocation = Allocation.createBitmapRef(mRS, mBitmapOut);
         mScratchPixelsAllocation = Allocation.createBitmapRef(mRS, mBitmapScratch);
 
+        mScriptVBlur = new ScriptC_Vertical_blur(mRS, getResources(), R.raw.vertical_blur_bc, false);
+        mScriptVBlur.bind_ScratchPixel(mScratchPixelsAllocation);
+
+        mScriptHBlur = new ScriptC_Horizontal_blur(mRS, getResources(), R.raw.horizontal_blur_bc, false);
+        mScriptHBlur.bind_ScratchPixel(mScratchPixelsAllocation);
+
         mScript = new ScriptC_Threshold(mRS, getResources(), R.raw.threshold_bc, false);
         mScript.set_width(mBitmapIn.getWidth());
         mScript.set_height(mBitmapIn.getHeight());
@@ -388,6 +396,9 @@
         mScript.bind_InPixel(mInPixelsAllocation);
         mScript.bind_OutPixel(mOutPixelsAllocation);
         mScript.bind_ScratchPixel(mScratchPixelsAllocation);
+
+        mScript.set_vBlurScript(mScriptVBlur);
+        mScript.set_hBlurScript(mScriptHBlur);
     }
 
     private Bitmap loadBitmap(int resource) {
diff --git a/libs/rs/java/ImageProcessing/src/com/android/rs/image/ScriptC_Horizontal_blur.java b/libs/rs/java/ImageProcessing/src/com/android/rs/image/ScriptC_Horizontal_blur.java
new file mode 100644
index 0000000..8ee50a8
--- /dev/null
+++ b/libs/rs/java/ImageProcessing/src/com/android/rs/image/ScriptC_Horizontal_blur.java
@@ -0,0 +1,42 @@
+/*
+ * 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 com.android.rs.image;
+
+import android.renderscript.*;
+import android.content.res.Resources;
+import android.util.Log;
+
+public class ScriptC_Horizontal_blur extends ScriptC {
+    // Constructor
+    public  ScriptC_Horizontal_blur(RenderScript rs, Resources resources, int id, boolean isRoot) {
+        super(rs, resources, id, isRoot);
+    }
+
+    private final static int mExportVarIdx_ScratchPixel = 0;
+    private Allocation mExportVar_ScratchPixel;
+    public void bind_ScratchPixel(Allocation v) {
+        mExportVar_ScratchPixel = v;
+        if(v == null) bindAllocation(null, mExportVarIdx_ScratchPixel);
+        else bindAllocation(v, mExportVarIdx_ScratchPixel);
+    }
+
+    public Allocation get_ScratchPixel() {
+        return mExportVar_ScratchPixel;
+    }
+
+}
+
diff --git a/libs/rs/java/ImageProcessing/src/com/android/rs/image/ScriptC_Threshold.java b/libs/rs/java/ImageProcessing/src/com/android/rs/image/ScriptC_Threshold.java
index ea363d3..c23dca1 100644
--- a/libs/rs/java/ImageProcessing/src/com/android/rs/image/ScriptC_Threshold.java
+++ b/libs/rs/java/ImageProcessing/src/com/android/rs/image/ScriptC_Threshold.java
@@ -161,6 +161,28 @@
         return mExportVar_saturation;
     }
 
+    private final static int mExportVarIdx_vBlurScript = 12;
+    private Script mExportVar_vBlurScript;
+    public void set_vBlurScript(Script v) {
+        mExportVar_vBlurScript = v;
+        setVar(mExportVarIdx_vBlurScript, (v == null) ? 0 : v.getID());
+    }
+
+    public Script get_vBlurScript() {
+        return mExportVar_vBlurScript;
+    }
+
+    private final static int mExportVarIdx_hBlurScript = 13;
+    private Script mExportVar_hBlurScript;
+    public void set_hBlurScript(Script v) {
+        mExportVar_hBlurScript = v;
+        setVar(mExportVarIdx_hBlurScript, (v == null) ? 0 : v.getID());
+    }
+
+    public Script get_hBlurScript() {
+        return mExportVar_hBlurScript;
+    }
+
     private final static int mExportFuncIdx_filter = 0;
     public void invoke_filter() {
         invoke(mExportFuncIdx_filter);
diff --git a/libs/rs/java/ImageProcessing/src/com/android/rs/image/ScriptC_Vertical_blur.java b/libs/rs/java/ImageProcessing/src/com/android/rs/image/ScriptC_Vertical_blur.java
new file mode 100644
index 0000000..0215f60
--- /dev/null
+++ b/libs/rs/java/ImageProcessing/src/com/android/rs/image/ScriptC_Vertical_blur.java
@@ -0,0 +1,42 @@
+/*
+ * 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 com.android.rs.image;
+
+import android.renderscript.*;
+import android.content.res.Resources;
+import android.util.Log;
+
+public class ScriptC_Vertical_blur extends ScriptC {
+    // Constructor
+    public  ScriptC_Vertical_blur(RenderScript rs, Resources resources, int id, boolean isRoot) {
+        super(rs, resources, id, isRoot);
+    }
+
+    private final static int mExportVarIdx_ScratchPixel = 0;
+    private Allocation mExportVar_ScratchPixel;
+    public void bind_ScratchPixel(Allocation v) {
+        mExportVar_ScratchPixel = v;
+        if(v == null) bindAllocation(null, mExportVarIdx_ScratchPixel);
+        else bindAllocation(v, mExportVarIdx_ScratchPixel);
+    }
+
+    public Allocation get_ScratchPixel() {
+        return mExportVar_ScratchPixel;
+    }
+
+}
+
diff --git a/libs/rs/java/ModelViewer/res/raw/robot.a3d b/libs/rs/java/ModelViewer/res/raw/robot.a3d
index d220c81..2d7d32b 100644
--- a/libs/rs/java/ModelViewer/res/raw/robot.a3d
+++ b/libs/rs/java/ModelViewer/res/raw/robot.a3d
Binary files differ
diff --git a/libs/rs/rs.spec b/libs/rs/rs.spec
index 136c05d..1b81591 100644
--- a/libs/rs/rs.spec
+++ b/libs/rs/rs.spec
@@ -78,6 +78,19 @@
 	ret RsElement
 	}
 
+ElementGetNativeData {
+	param RsElement elem
+	param uint32_t *elemData
+	param uint32_t elemDataSize
+	}
+
+ElementGetSubElements {
+	param RsElement elem
+	param uint32_t *ids
+	param const char **names
+	param uint32_t dataSize
+	}
+
 TypeBegin {
 	param RsElement type
 	}
@@ -91,6 +104,12 @@
 	ret RsType
 	}
 
+TypeGetNativeData {
+	param RsType type
+	param uint32_t * typeData
+	param uint32_t typeDataSize
+	}
+
 AllocationCreateTyped {
 	param RsType type
 	ret RsAllocation
@@ -231,6 +250,11 @@
 	param const void *data
 	}
 
+AllocationGetType {
+	param RsAllocation va
+	ret const void*
+	}
+
 SamplerBegin {
 	}
 
@@ -347,8 +371,6 @@
 	}
 
 ProgramRasterCreate {
-	param RsElement in
-	param RsElement out
 	param bool pointSmooth
 	param bool lineSmooth
 	param bool pointSprite
@@ -360,12 +382,11 @@
 	param float lw
 }
 
-ProgramRasterSetPointSize{
+ProgramRasterSetCullMode {
 	param RsProgramRaster pr
-	param float ps
+	param RsCullMode mode
 }
 
-
 ProgramBindConstants {
 	param RsProgram vp
 	param uint32_t slot
@@ -497,6 +518,29 @@
 	param uint32_t slot
 	}
 
+MeshGetVertexBufferCount {
+	param RsMesh mesh
+	param int32_t *numVtx
+	}
+
+MeshGetIndexCount {
+	param RsMesh mesh
+	param int32_t *numIdx
+	}
+
+MeshGetVertices {
+	param RsMesh mv
+	param RsAllocation *vtxData
+	param uint32_t vtxDataCount
+	}
+
+MeshGetIndices {
+	param RsMesh mv
+	param RsAllocation *va
+	param uint32_t *primType
+	param uint32_t idxDataCount
+	}
+
 AnimationCreate {
 	param const float *inValues
 	param const float *outValues
diff --git a/libs/rs/rsAllocation.cpp b/libs/rs/rsAllocation.cpp
index d9d0bc5..6560101 100644
--- a/libs/rs/rsAllocation.cpp
+++ b/libs/rs/rsAllocation.cpp
@@ -683,6 +683,14 @@
     a->read(data);
 }
 
+const void* rsi_AllocationGetType(Context *rsc, RsAllocation va)
+{
+    Allocation *a = static_cast<Allocation *>(va);
+    a->getType()->incUserRef();
+
+    return a->getType();
+}
+
 #endif //ANDROID_RS_BUILD_FOR_HOST
 
 }
diff --git a/libs/rs/rsElement.cpp b/libs/rs/rsElement.cpp
index aa20275..37b8bd6 100644
--- a/libs/rs/rsElement.cpp
+++ b/libs/rs/rsElement.cpp
@@ -293,6 +293,32 @@
     return (RsElement)e;
 }
 
+void rsi_ElementGetNativeData(Context *rsc, RsElement elem, uint32_t *elemData, uint32_t elemDataSize)
+{
+    rsAssert(elemDataSize == 5);
+    // we will pack mType; mKind; mNormalized; mVectorSize; NumSubElements
+    Element *e = static_cast<Element *>(elem);
+
+    (*elemData++) = (uint32_t)e->getType();
+    (*elemData++) = (uint32_t)e->getKind();
+    (*elemData++) = e->getComponent().getIsNormalized() ? 1 : 0;
+    (*elemData++) = e->getComponent().getVectorSize();
+    (*elemData++) = e->getFieldCount();
+
+}
+
+void rsi_ElementGetSubElements(Context *rsc, RsElement elem, uint32_t *ids, const char **names, uint32_t dataSize)
+{
+    Element *e = static_cast<Element *>(elem);
+    rsAssert(e->getFieldCount() == dataSize);
+
+    for(uint32_t i = 0; i < dataSize; i ++) {
+        ids[i] = (uint32_t)e->getField(i);
+        names[i] = e->getFieldName(i);
+    }
+
+}
+
 
 }
 }
diff --git a/libs/rs/rsFont.cpp b/libs/rs/rsFont.cpp
index 2a47ca4..d1346fc 100644
--- a/libs/rs/rsFont.cpp
+++ b/libs/rs/rsFont.cpp
@@ -511,6 +511,9 @@
     ObjectBaseRef<const ProgramVertex> tmpV(mRSC->getVertex());
     mRSC->setVertex(mRSC->getDefaultProgramVertex());
 
+    ObjectBaseRef<const ProgramRaster> tmpR(mRSC->getRaster());
+    mRSC->setRaster(mRSC->getDefaultProgramRaster());
+
     ObjectBaseRef<const ProgramFragment> tmpF(mRSC->getFragment());
     mRSC->setFragment(mFontShaderF.get());
 
@@ -519,6 +522,7 @@
 
     if (!mRSC->setupCheck()) {
         mRSC->setVertex((ProgramVertex *)tmpV.get());
+        mRSC->setRaster((ProgramRaster *)tmpR.get());
         mRSC->setFragment((ProgramFragment *)tmpF.get());
         mRSC->setFragmentStore((ProgramStore *)tmpPS.get());
         return;
@@ -538,6 +542,7 @@
 
     // Reset the state
     mRSC->setVertex((ProgramVertex *)tmpV.get());
+    mRSC->setRaster((ProgramRaster *)tmpR.get());
     mRSC->setFragment((ProgramFragment *)tmpF.get());
     mRSC->setFragmentStore((ProgramStore *)tmpPS.get());
 }
diff --git a/libs/rs/rsMesh.cpp b/libs/rs/rsMesh.cpp
index d1b5581..9026578 100644
--- a/libs/rs/rsMesh.cpp
+++ b/libs/rs/rsMesh.cpp
@@ -271,4 +271,45 @@
     sm->updateGLPrimitives();
 }
 
+void rsi_MeshGetVertexBufferCount(Context *rsc, RsMesh mv, int32_t *numVtx)
+{
+    Mesh *sm = static_cast<Mesh *>(mv);
+    *numVtx = sm->mVertexBufferCount;
+}
+
+void rsi_MeshGetIndexCount(Context *rsc, RsMesh mv, int32_t *numIdx)
+{
+    Mesh *sm = static_cast<Mesh *>(mv);
+    *numIdx = sm->mPrimitivesCount;
+}
+
+void rsi_MeshGetVertices(Context *rsc, RsMesh mv, RsAllocation *vtxData, uint32_t vtxDataCount)
+{
+    Mesh *sm = static_cast<Mesh *>(mv);
+    rsAssert(vtxDataCount == sm->mVertexBufferCount);
+
+    for(uint32_t ct = 0; ct < vtxDataCount; ct ++) {
+        vtxData[ct] = sm->mVertexBuffers[ct].get();
+        sm->mVertexBuffers[ct]->incUserRef();
+    }
+}
+
+void rsi_MeshGetIndices(Context *rsc, RsMesh mv, RsAllocation *va, uint32_t *primType, uint32_t idxDataCount)
+{
+    Mesh *sm = static_cast<Mesh *>(mv);
+    rsAssert(idxDataCount == sm->mPrimitivesCount);
+
+    for(uint32_t ct = 0; ct < idxDataCount; ct ++) {
+        va[ct] = sm->mPrimitives[ct]->mIndexBuffer.get();
+        primType[ct] = sm->mPrimitives[ct]->mPrimitive;
+        if(sm->mPrimitives[ct]->mIndexBuffer.get()) {
+            sm->mPrimitives[ct]->mIndexBuffer->incUserRef();
+        }
+    }
+
+}
+
+
+
+
 }}
diff --git a/libs/rs/rsProgramRaster.cpp b/libs/rs/rsProgramRaster.cpp
index 66f6ef8..5b69370 100644
--- a/libs/rs/rsProgramRaster.cpp
+++ b/libs/rs/rsProgramRaster.cpp
@@ -41,9 +41,8 @@
     mPointSmooth = pointSmooth;
     mLineSmooth = lineSmooth;
     mPointSprite = pointSprite;
-
-    mPointSize = 1.0f;
     mLineWidth = 1.0f;
+    mCull = RS_CULL_BACK;
 }
 
 ProgramRaster::~ProgramRaster()
@@ -53,21 +52,23 @@
 void ProgramRaster::setLineWidth(float s)
 {
     mLineWidth = s;
+    mDirty = true;
 }
 
-void ProgramRaster::setPointSize(float s)
+void ProgramRaster::setCullMode(RsCullMode mode)
 {
-    mPointSize = s;
+    mCull = mode;
+    mDirty = true;
 }
 
 void ProgramRaster::setupGL(const Context *rsc, ProgramRasterState *state)
 {
-    if (state->mLast.get() == this) {
+    if (state->mLast.get() == this && !mDirty) {
         return;
     }
     state->mLast.set(this);
+    mDirty = false;
 
-    glPointSize(mPointSize);
     if (mPointSmooth) {
         glEnable(GL_POINT_SMOOTH);
     } else {
@@ -90,19 +91,48 @@
         }
 #endif //ANDROID_RS_BUILD_FOR_HOST
     }
+
+    switch(mCull) {
+        case RS_CULL_BACK:
+            glEnable(GL_CULL_FACE);
+            glCullFace(GL_BACK);
+            break;
+        case RS_CULL_FRONT:
+            glEnable(GL_CULL_FACE);
+            glCullFace(GL_FRONT);
+            break;
+        case RS_CULL_NONE:
+            glDisable(GL_CULL_FACE);
+            break;
+    }
 }
 
 void ProgramRaster::setupGL2(const Context *rsc, ProgramRasterState *state)
 {
-    if (state->mLast.get() == this) {
+    if (state->mLast.get() == this && !mDirty) {
         return;
     }
     state->mLast.set(this);
+    mDirty = false;
+
+    switch(mCull) {
+        case RS_CULL_BACK:
+            glEnable(GL_CULL_FACE);
+            glCullFace(GL_BACK);
+            break;
+        case RS_CULL_FRONT:
+            glEnable(GL_CULL_FACE);
+            glCullFace(GL_FRONT);
+            break;
+        case RS_CULL_NONE:
+            glDisable(GL_CULL_FACE);
+            break;
+    }
 }
 
 void ProgramRaster::serialize(OStream *stream) const
 {
-    
+
 }
 
 ProgramRaster *ProgramRaster::createFromStream(Context *rsc, IStream *stream)
@@ -134,7 +164,7 @@
 namespace android {
 namespace renderscript {
 
-RsProgramRaster rsi_ProgramRasterCreate(Context * rsc, RsElement in, RsElement out,
+RsProgramRaster rsi_ProgramRasterCreate(Context * rsc,
                                       bool pointSmooth,
                                       bool lineSmooth,
                                       bool pointSprite)
@@ -147,18 +177,18 @@
     return pr;
 }
 
-void rsi_ProgramRasterSetPointSize(Context * rsc, RsProgramRaster vpr, float s)
-{
-    ProgramRaster *pr = static_cast<ProgramRaster *>(vpr);
-    pr->setPointSize(s);
-}
-
 void rsi_ProgramRasterSetLineWidth(Context * rsc, RsProgramRaster vpr, float s)
 {
     ProgramRaster *pr = static_cast<ProgramRaster *>(vpr);
     pr->setLineWidth(s);
 }
 
+void rsi_ProgramRasterSetCullMode(Context * rsc, RsProgramRaster vpr, RsCullMode mode)
+{
+    ProgramRaster *pr = static_cast<ProgramRaster *>(vpr);
+    pr->setCullMode(mode);
+}
+
 
 }
 }
diff --git a/libs/rs/rsProgramRaster.h b/libs/rs/rsProgramRaster.h
index 79b14753..801ab2a 100644
--- a/libs/rs/rsProgramRaster.h
+++ b/libs/rs/rsProgramRaster.h
@@ -41,17 +41,14 @@
     static ProgramRaster *createFromStream(Context *rsc, IStream *stream);
 
     void setLineWidth(float w);
-    void setPointSize(float s);
+    void setCullMode(RsCullMode mode);
 
 protected:
     bool mPointSmooth;
     bool mLineSmooth;
     bool mPointSprite;
-
-    float mPointSize;
     float mLineWidth;
-
-
+    RsCullMode mCull;
 };
 
 class ProgramRasterState
diff --git a/libs/rs/rsProgramVertex.cpp b/libs/rs/rsProgramVertex.cpp
index 85d90c7..5558007 100644
--- a/libs/rs/rsProgramVertex.cpp
+++ b/libs/rs/rsProgramVertex.cpp
@@ -191,7 +191,6 @@
         mShader.append("attribute vec4 ATTRIB_position;\n");
         mShader.append("attribute vec4 ATTRIB_color;\n");
         mShader.append("attribute vec3 ATTRIB_normal;\n");
-        mShader.append("attribute float ATTRIB_pointSize;\n");
         mShader.append("attribute vec4 ATTRIB_texture0;\n");
 
         for (uint32_t ct=0; ct < mUniformCount; ct++) {
@@ -202,7 +201,7 @@
 
         mShader.append("void main() {\n");
         mShader.append("  gl_Position = UNI_MVP * ATTRIB_position;\n");
-        mShader.append("  gl_PointSize = ATTRIB_pointSize;\n");
+        mShader.append("  gl_PointSize = 1.0;\n");
 
         mShader.append("  varColor = ATTRIB_color;\n");
         if (mTextureMatrixEnable) {
@@ -210,9 +209,6 @@
         } else {
             mShader.append("  varTex0 = ATTRIB_texture0;\n");
         }
-        //mShader.append("  pos.x = pos.x / 480.0;\n");
-        //mShader.append("  pos.y = pos.y / 800.0;\n");
-        //mShader.append("  gl_Position = pos;\n");
         mShader.append("}\n");
     }
 }
diff --git a/libs/rs/rsScript.h b/libs/rs/rsScript.h
index ea6aec5..0717059 100644
--- a/libs/rs/rsScript.h
+++ b/libs/rs/rsScript.h
@@ -64,9 +64,11 @@
 
     void setVar(uint32_t slot, const void *val, uint32_t len);
 
-    virtual void runForEach(Context *rsc, const Allocation *ain, Allocation *aout) = 0;
-    virtual void runForEach(Context *rsc, const Allocation *ain, Allocation *aout, uint32_t xStart, uint32_t xEnd) = 0;
-    virtual void runForEach(Context *rsc, const Allocation *ain, Allocation *aout, uint32_t xStart, uint32_t yStart, uint32_t xEnd, uint32_t yEnd) = 0;
+    virtual void runForEach(Context *rsc,
+                            const Allocation * ain,
+                            Allocation * aout,
+                            const void * usr,
+                            const RsScriptCall *sc = NULL) = 0;
 
     virtual void Invoke(Context *rsc, uint32_t slot, const void *data, uint32_t len) = 0;
     virtual void setupScript(Context *rsc) = 0;
diff --git a/libs/rs/rsScriptC.cpp b/libs/rs/rsScriptC.cpp
index 975b704..b87ac28 100644
--- a/libs/rs/rsScriptC.cpp
+++ b/libs/rs/rsScriptC.cpp
@@ -136,55 +136,95 @@
     return ret;
 }
 
-void ScriptC::runForEach(Context *rsc, const Allocation *ain, Allocation *aout,
-                         uint32_t xStart, uint32_t yStart, uint32_t xEnd, uint32_t yEnd)
-{
-    LOGE("ScriptC::runForEach not implemented");
-}
 
-void ScriptC::runForEach(Context *rsc, const Allocation *ain, Allocation *aout, uint32_t xStart, uint32_t xEnd)
+void ScriptC::runForEach(Context *rsc,
+                         const Allocation * ain,
+                         Allocation * aout,
+                         const void * usr,
+                         const RsScriptCall *sc)
 {
     uint32_t dimX = ain->getType()->getDimX();
-    rsAssert(xStart < dimX);
-    rsAssert(xEnd <= dimX);
-    rsAssert(ain->getType()->getDimY() == 0);
-    rsAssert(ain->getType()->getDimZ() == 0);
+    uint32_t dimY = ain->getType()->getDimY();
+    uint32_t dimZ = ain->getType()->getDimZ();
+    uint32_t dimA = 0;//ain->getType()->getDimArray();
 
-    if (xStart >= dimX) xStart = dimX - 1;
-    if (xEnd >= dimX) xEnd = dimX - 1;
-    if (xStart > xEnd) return;
+    uint32_t xStart = 0;
+    uint32_t xEnd = 0;
+    uint32_t yStart = 0;
+    uint32_t yEnd = 0;
+    uint32_t zStart = 0;
+    uint32_t zEnd = 0;
+    uint32_t arrayStart = 0;
+    uint32_t arrayEnd = 0;
+
+    if (!sc || (sc->xEnd == 0)) {
+        xStart = 0;
+        xEnd = ain->getType()->getDimX();
+    } else {
+        rsAssert(xStart < dimX);
+        rsAssert(xEnd <= dimX);
+        rsAssert(sc->xStart < sc->xEnd);
+        xStart = rsMin(dimX, sc->xStart);
+        xEnd = rsMin(dimX, sc->xEnd);
+        if (xStart >= xEnd) return;
+    }
+
+    if (!sc || (sc->yEnd == 0)) {
+        yStart = 0;
+        yEnd = ain->getType()->getDimY();
+    } else {
+        rsAssert(yStart < dimY);
+        rsAssert(yEnd <= dimY);
+        rsAssert(sc->yStart < sc->yEnd);
+        yStart = rsMin(dimY, sc->yStart);
+        yEnd = rsMin(dimY, sc->yEnd);
+        if (yStart >= yEnd) return;
+    }
+
+    xEnd = rsMax((uint32_t)1, xEnd);
+    yEnd = rsMax((uint32_t)1, yEnd);
+    zEnd = rsMax((uint32_t)1, zEnd);
+    arrayEnd = rsMax((uint32_t)1, arrayEnd);
+
+    rsAssert(ain->getType()->getDimZ() == 0);
 
     setupScript(rsc);
     Script * oldTLS = setTLS(this);
 
-    typedef int (*rs_t)(const void *, void *, uint32_t);
+    typedef int (*rs_t)(const void *, void *, const void *, uint32_t, uint32_t, uint32_t, uint32_t);
+
     const uint8_t *ptrIn = (const uint8_t *)ain->getPtr();
-    uint32_t strideIn = ain->getType()->getElementSizeBytes();
+    uint32_t eStrideIn = ain->getType()->getElementSizeBytes();
 
     uint8_t *ptrOut = NULL;
-    uint32_t strideOut = 0;
+    uint32_t eStrideOut = 0;
     if (aout) {
         ptrOut = (uint8_t *)aout->getPtr();
-        strideOut = aout->getType()->getElementSizeBytes();
+        eStrideOut = aout->getType()->getElementSizeBytes();
     }
 
-    for (uint32_t ct=xStart; ct < xEnd; ct++) {
-        ((rs_t)mProgram.mRoot) (ptrIn + (strideIn * ct), ptrOut + (strideOut * ct), ct);
+    for (uint32_t ar = arrayStart; ar < arrayEnd; ar++) {
+        for (uint32_t z = zStart; z < zEnd; z++) {
+            for (uint32_t y = yStart; y < yEnd; y++) {
+                uint32_t offset = dimX * dimY * dimZ * ar +
+                                  dimX * dimY * z +
+                                  dimX * y;
+                uint8_t *xPtrOut = ptrOut + (eStrideOut * offset);
+                const uint8_t *xPtrIn = ptrIn + (eStrideIn * offset);
+
+                for (uint32_t x = xStart; x < xEnd; x++) {
+                    ((rs_t)mProgram.mRoot) (xPtrIn, xPtrOut, usr, x, y, z, ar);
+                    xPtrIn += eStrideIn;
+                    xPtrOut += eStrideOut;
+                }
+            }
+        }
+
     }
 
     setTLS(oldTLS);
 }
 
-void ScriptC::runForEach(Context *rsc, const Allocation *ain, Allocation *aout)
-{
-    if (ain->getType()->getDimY()) {
-        runForEach(rsc, ain, aout, 0, 0, 0xffffffff, 0xffffffff);
-    } else {
-        runForEach(rsc, ain, aout, 0, 0xffffffff);
-    }
-}
-
-
 void ScriptC::Invoke(Context *rsc, uint32_t slot, const void *data, uint32_t len)
 {
     //LOGE("rsi_ScriptInvoke %i", slot);
@@ -246,7 +286,7 @@
 
 void ScriptCState::runCompiler(Context *rsc, ScriptC *s)
 {
-    LOGE("ScriptCState::runCompiler ");
+    LOGV("ScriptCState::runCompiler ");
 
     s->mBccScript = bccCreateScript();
     bccScriptBitcode(s->mBccScript, s->mEnviroment.mScriptText, s->mEnviroment.mScriptTextLength);
@@ -254,7 +294,7 @@
     bccCompileScript(s->mBccScript);
     bccGetScriptLabel(s->mBccScript, "root", (BCCvoid**) &s->mProgram.mRoot);
     bccGetScriptLabel(s->mBccScript, "init", (BCCvoid**) &s->mProgram.mInit);
-    LOGE("root %p,  init %p", s->mProgram.mRoot, s->mProgram.mInit);
+    LOGV("root %p,  init %p", s->mProgram.mRoot, s->mProgram.mInit);
 
     if (s->mProgram.mInit) {
         s->mProgram.mInit();
@@ -268,24 +308,9 @@
         bccGetExportFuncs(s->mBccScript, NULL, s->mEnviroment.mInvokeFunctionCount, (BCCvoid **) s->mEnviroment.mInvokeFunctions);
     }
 
-//    s->mEnviroment.mInvokeFunctions = (Script::InvokeFunc_t *)calloc(100, sizeof(void *));
-//    BCCchar **labels = new char*[100];
-//    bccGetFunctions(s->mBccScript, (BCCsizei *)&s->mEnviroment.mInvokeFunctionCount,
-//                    100, (BCCchar **)labels);
-    //LOGE("func count %i", s->mEnviroment.mInvokeFunctionCount);
-//    for (uint32_t i=0; i < s->mEnviroment.mInvokeFunctionCount; i++) {
-//        BCCsizei length;
-//        bccGetFunctionBinary(s->mBccScript, labels[i], (BCCvoid **)&(s->mEnviroment.mInvokeFunctions[i]), &length);
-        //LOGE("func %i %p", i, s->mEnviroment.mInvokeFunctions[i]);
-  //  }
-
     s->mEnviroment.mFieldAddress = (void **)calloc(100, sizeof(void *));
     bccGetExportVars(s->mBccScript, (BCCsizei *)&s->mEnviroment.mFieldCount,
                      100, s->mEnviroment.mFieldAddress);
-    //LOGE("var count %i", s->mEnviroment.mFieldCount);
-    for (uint32_t i=0; i < s->mEnviroment.mFieldCount; i++) {
-        //LOGE("var %i %p", i, s->mEnviroment.mFieldAddress[i]);
-    }
 
     s->mEnviroment.mFragment.set(rsc->getDefaultProgramFragment());
     s->mEnviroment.mVertex.set(rsc->getDefaultProgramVertex());
diff --git a/libs/rs/rsScriptC.h b/libs/rs/rsScriptC.h
index 50e8a4c..9d09b0b 100644
--- a/libs/rs/rsScriptC.h
+++ b/libs/rs/rsScriptC.h
@@ -57,9 +57,11 @@
 
     virtual uint32_t run(Context *);
 
-    virtual void runForEach(Context *rsc, const Allocation *ain, Allocation *aout);
-    virtual void runForEach(Context *rsc, const Allocation *ain, Allocation *aout, uint32_t xStart, uint32_t xEnd);
-    virtual void runForEach(Context *rsc, const Allocation *ain, Allocation *aout, uint32_t xStart, uint32_t yStart, uint32_t xEnd, uint32_t yEnd);
+    virtual void runForEach(Context *rsc,
+                            const Allocation * ain,
+                            Allocation * aout,
+                            const void * usr,
+                            const RsScriptCall *sc = NULL);
 
     virtual void serialize(OStream *stream) const {    }
     virtual RsA3DClassID getClassId() const { return RS_A3D_CLASS_ID_SCRIPT_C; }
diff --git a/libs/rs/rsScriptC_Lib.cpp b/libs/rs/rsScriptC_Lib.cpp
index ea01134..8d9ca9f 100644
--- a/libs/rs/rsScriptC_Lib.cpp
+++ b/libs/rs/rsScriptC_Lib.cpp
@@ -376,58 +376,31 @@
 }
 
 
-void SC_ForEachii(RsScript vs, RsAllocation vin)
+void SC_ForEach(RsScript vs,
+                RsAllocation vin,
+                RsAllocation vout,
+                const void *usr)
 {
     GET_TLS();
-    Script *s = static_cast<Script *>(vs);
-    Allocation *ain = static_cast<Allocation *>(vin);
-    s->runForEach(rsc, ain, NULL);
-}
-
-void SC_ForEachiii(RsScript vs, RsAllocation vin, RsAllocation vout)
-{
-    GET_TLS();
-    Script *s = static_cast<Script *>(vs);
-    Allocation *ain = static_cast<Allocation *>(vin);
+    const Allocation *ain = static_cast<const Allocation *>(vin);
     Allocation *aout = static_cast<Allocation *>(vout);
-    s->runForEach(rsc, ain, aout);
+    Script *s = static_cast<Script *>(vs);
+    s->runForEach(rsc, ain, aout, usr);
 }
 
-void SC_ForEachiiii(RsScript vs, RsAllocation vin, int xStart, int xEnd)
+void SC_ForEach2(RsScript vs,
+                RsAllocation vin,
+                RsAllocation vout,
+                const void *usr,
+                const RsScriptCall *call)
 {
     GET_TLS();
-    Script *s = static_cast<Script *>(vs);
-    Allocation *ain = static_cast<Allocation *>(vin);
-    s->runForEach(rsc, ain, NULL, xStart, xEnd);
-}
-
-void SC_ForEachiiiii(RsScript vs, RsAllocation vin, RsAllocation vout, int xStart, int xEnd)
-{
-    GET_TLS();
-    Script *s = static_cast<Script *>(vs);
-    Allocation *ain = static_cast<Allocation *>(vin);
+    const Allocation *ain = static_cast<const Allocation *>(vin);
     Allocation *aout = static_cast<Allocation *>(vout);
-    s->runForEach(rsc, ain, aout, xStart, xEnd);
-}
-
-void SC_ForEachiiiiii(RsScript vs, RsAllocation vin, int xStart, int yStart, int xEnd, int yEnd)
-{
-    GET_TLS();
     Script *s = static_cast<Script *>(vs);
-    Allocation *ain = static_cast<Allocation *>(vin);
-    s->runForEach(rsc, ain, NULL, xStart, yStart, xEnd, yEnd);
+    s->runForEach(rsc, ain, aout, usr, call);
 }
 
-void SC_ForEachiiiiiii(RsScript vs, RsAllocation vin, RsAllocation vout, int xStart, int yStart, int xEnd, int yEnd)
-{
-    GET_TLS();
-    Script *s = static_cast<Script *>(vs);
-    Allocation *ain = static_cast<Allocation *>(vin);
-    Allocation *aout = static_cast<Allocation *>(vout);
-    s->runForEach(rsc, ain, aout, xStart, yStart, xEnd, yEnd);
-}
-
-
 //////////////////////////////////////////////////////////////////////////////
 // Class implementation
 //////////////////////////////////////////////////////////////////////////////
@@ -502,12 +475,8 @@
     { "rsMatrixScale", (void *)&SC_matrixScale },
     { "rsMatrixTranslate", (void *)&SC_matrixTranslate },
 
-    { "_Z9rsForEachii", (void *)&SC_ForEachii },
-    { "_Z9rsForEachiii", (void *)&SC_ForEachiii },
-    { "_Z9rsForEachiiii", (void *)&SC_ForEachiiii },
-    { "_Z9rsForEachiiiii", (void *)&SC_ForEachiiiii },
-    { "_Z9rsForEachiiiiii", (void *)&SC_ForEachiiiiii },
-    { "_Z9rsForEachiiiiiii", (void *)&SC_ForEachiiiiiii },
+    { "_Z9rsForEach9rs_script13rs_allocationS0_PKv", (void *)&SC_ForEach },
+    //{ "_Z9rsForEach9rs_script13rs_allocationS0_PKv", (void *)&SC_ForEach2 },
 
 ////////////////////////////////////////////////////////////////////
 
diff --git a/libs/rs/rsShaderCache.cpp b/libs/rs/rsShaderCache.cpp
index 504ffba..5c073b3 100644
--- a/libs/rs/rsShaderCache.cpp
+++ b/libs/rs/rsShaderCache.cpp
@@ -101,8 +101,7 @@
             glBindAttribLocation(pgm, 0, "ATTRIB_position");
             glBindAttribLocation(pgm, 1, "ATTRIB_color");
             glBindAttribLocation(pgm, 2, "ATTRIB_normal");
-            glBindAttribLocation(pgm, 3, "ATTRIB_pointSize");
-            glBindAttribLocation(pgm, 4, "ATTRIB_texture0");
+            glBindAttribLocation(pgm, 3, "ATTRIB_texture0");
         }
 
         //LOGE("e2 %x", glGetError());
diff --git a/libs/rs/rsType.cpp b/libs/rs/rsType.cpp
index 8dca0fe..52e0d52 100644
--- a/libs/rs/rsType.cpp
+++ b/libs/rs/rsType.cpp
@@ -91,7 +91,7 @@
     if (mLODCount != oldLODCount) {
         if(mLODs){
             delete [] mLODs;
-        }        
+        }
         mLODs = new LOD[mLODCount];
     }
 
@@ -340,6 +340,22 @@
     return st;
 }
 
+void rsi_TypeGetNativeData(Context *rsc, RsType type, uint32_t *typeData, uint32_t typeDataSize)
+{
+    rsAssert(typeDataSize == 6);
+    // Pack the data in the follofing way mDimX; mDimY; mDimZ;
+    // mDimLOD; mDimFaces; mElement; into typeData
+    Type *t = static_cast<Type *>(type);
+
+    (*typeData++) = t->getDimX();
+    (*typeData++) = t->getDimY();
+    (*typeData++) = t->getDimZ();
+    (*typeData++) = t->getDimLOD();
+    (*typeData++) = t->getDimFaces() ? 1 : 0;
+    (*typeData++) = (uint32_t)t->getElement();
+
+}
+
 
 }
 }
diff --git a/libs/rs/rsVertexArray.cpp b/libs/rs/rsVertexArray.cpp
index 6937a85..001927c 100644
--- a/libs/rs/rsVertexArray.cpp
+++ b/libs/rs/rsVertexArray.cpp
@@ -144,10 +144,8 @@
                 slot = 1;
             } else if (mAttribs[ct].name == "normal") {
                 slot = 2;
-            } else if (mAttribs[ct].name == "pointSize") {
-                slot = 3;
             } else if (mAttribs[ct].name == "texture0") {
-                slot = 4;
+                slot = 3;
             } else {
                 continue;
             }
diff --git a/libs/rs/scriptc/rs_math.rsh b/libs/rs/scriptc/rs_math.rsh
index 3709296..e11c832 100644
--- a/libs/rs/scriptc/rs_math.rsh
+++ b/libs/rs/scriptc/rs_math.rsh
@@ -48,11 +48,27 @@
 extern int rsSendToClient(void *data, int cmdID, int len, int waitForSpace);
 
 // Script to Script
-extern void __attribute__((overloadable))rsForEach(rs_script, rs_allocation input);
-extern void __attribute__((overloadable))rsForEach(rs_script, rs_allocation input, rs_allocation output);
-extern void __attribute__((overloadable))rsForEach(rs_script, rs_allocation input, int xStart, int xEnd);
-extern void __attribute__((overloadable))rsForEach(rs_script, rs_allocation input, rs_allocation output, int xStart, int xEnd);
-extern void __attribute__((overloadable))rsForEach(rs_script, rs_allocation input, int xStart, int yStart, int xEnd, int yEnd);
-extern void __attribute__((overloadable))rsForEach(rs_script, rs_allocation input, rs_allocation output, int xStart, int yStart, int xEnd, int yEnd);
+typedef struct rs_script_call {
+    uint32_t xStart;
+    uint32_t xEnd;
+    uint32_t yStart;
+    uint32_t yEnd;
+    uint32_t zStart;
+    uint32_t zEnd;
+    uint32_t arrayStart;
+    uint32_t arrayEnd;
+
+} rs_script_call_t;
+
+extern void __attribute__((overloadable))rsForEach(rs_script script,
+                                                   rs_allocation input,
+                                                   rs_allocation output,
+                                                   const void * usrData);
+
+extern void __attribute__((overloadable))rsForEach(rs_script script,
+                                                   rs_allocation input,
+                                                   rs_allocation output,
+                                                   const void * usrData,
+                                                   const rs_script_call_t *);
 
 #endif
diff --git a/libs/ui/Android.mk b/libs/ui/Android.mk
index 24cdc78..4243bbf 100644
--- a/libs/ui/Android.mk
+++ b/libs/ui/Android.mk
@@ -12,6 +12,7 @@
 	KeyLayoutMap.cpp \
 	KeyCharacterMap.cpp \
 	Input.cpp \
+	InputDevice.cpp \
 	InputDispatcher.cpp \
 	InputManager.cpp \
 	InputReader.cpp \
@@ -38,3 +39,13 @@
 endif
 
 include $(BUILD_SHARED_LIBRARY)
+
+
+# Include subdirectory makefiles
+# ============================================================
+
+# If we're building with ONE_SHOT_MAKEFILE (mm, mmm), then what the framework
+# team really wants is to build the stuff defined by this makefile.
+ifeq (,$(ONE_SHOT_MAKEFILE))
+include $(call first-makefiles-under,$(LOCAL_PATH))
+endif
diff --git a/libs/ui/EventHub.cpp b/libs/ui/EventHub.cpp
index 27895f2..768b04e 100644
--- a/libs/ui/EventHub.cpp
+++ b/libs/ui/EventHub.cpp
@@ -54,6 +54,9 @@
  */
 #define test_bit(bit, array)    (array[bit/8] & (1<<(bit%8)))
 
+/* this macro computes the number of bytes needed to represent a bit array of the specified size */
+#define sizeof_bit_array(bits)  ((bits + 7) / 8)
+
 #define ID_MASK  0x0000ffff
 #define SEQ_MASK 0x7fff0000
 #define SEQ_SHIFT 16
@@ -182,7 +185,7 @@
 }
 
 int32_t EventHub::getScanCodeStateLocked(device_t* device, int32_t scanCode) const {
-    uint8_t key_bitmask[(KEY_MAX + 7) / 8];
+    uint8_t key_bitmask[sizeof_bit_array(KEY_MAX + 1)];
     memset(key_bitmask, 0, sizeof(key_bitmask));
     if (ioctl(mFDs[id_to_index(device->id)].fd,
                EVIOCGKEY(sizeof(key_bitmask)), key_bitmask) >= 0) {
@@ -218,7 +221,7 @@
     Vector<int32_t> scanCodes;
     device->layoutMap->findScancodes(keyCode, &scanCodes);
 
-    uint8_t key_bitmask[(KEY_MAX + 7) / 8];
+    uint8_t key_bitmask[sizeof_bit_array(KEY_MAX + 1)];
     memset(key_bitmask, 0, sizeof(key_bitmask));
     if (ioctl(mFDs[id_to_index(device->id)].fd,
                EVIOCGKEY(sizeof(key_bitmask)), key_bitmask) >= 0) {
@@ -264,7 +267,7 @@
 }
 
 int32_t EventHub::getSwitchStateLocked(device_t* device, int32_t sw) const {
-    uint8_t sw_bitmask[(SW_MAX + 7) / 8];
+    uint8_t sw_bitmask[sizeof_bit_array(SW_MAX + 1)];
     memset(sw_bitmask, 0, sizeof(sw_bitmask));
     if (ioctl(mFDs[id_to_index(device->id)].fd,
                EVIOCGSW(sizeof(sw_bitmask)), sw_bitmask) >= 0) {
@@ -409,7 +412,7 @@
                             LOGV("iev.code=%d outKeycode=%d outFlags=0x%08x err=%d\n",
                                 iev.code, *outKeycode, *outFlags, err);
                             if (err != 0) {
-                                *outKeycode = 0;
+                                *outKeycode = AKEYCODE_UNKNOWN;
                                 *outFlags = 0;
                             }
                         } else {
@@ -509,6 +512,26 @@
 
 // ----------------------------------------------------------------------------
 
+static bool containsNonZeroByte(const uint8_t* array, uint32_t startIndex, uint32_t endIndex) {
+    const uint8_t* end = array + endIndex;
+    array += startIndex;
+    while (array != end) {
+        if (*(array++) != 0) {
+            return true;
+        }
+    }
+    return false;
+}
+
+static const int32_t GAMEPAD_KEYCODES[] = {
+        AKEYCODE_BUTTON_A, AKEYCODE_BUTTON_B, AKEYCODE_BUTTON_C,
+        AKEYCODE_BUTTON_X, AKEYCODE_BUTTON_Y, AKEYCODE_BUTTON_Z,
+        AKEYCODE_BUTTON_L1, AKEYCODE_BUTTON_R1,
+        AKEYCODE_BUTTON_L2, AKEYCODE_BUTTON_R2,
+        AKEYCODE_BUTTON_THUMBL, AKEYCODE_BUTTON_THUMBR,
+        AKEYCODE_BUTTON_START, AKEYCODE_BUTTON_SELECT, AKEYCODE_BUTTON_MODE
+};
+
 int EventHub::open_device(const char *deviceName)
 {
     int version;
@@ -626,27 +649,27 @@
     mFDs[mFDCount].fd = fd;
     mFDs[mFDCount].events = POLLIN;
 
-    // figure out the kinds of events the device reports
+    // Figure out the kinds of events the device reports.
     
-    // See if this is a keyboard, and classify it.  Note that we only
-    // consider up through the function keys; we don't want to include
-    // ones after that (play cd etc) so we don't mistakenly consider a
-    // controller to be a keyboard.
-    uint8_t key_bitmask[(KEY_MAX+7)/8];
+    uint8_t key_bitmask[sizeof_bit_array(KEY_MAX + 1)];
     memset(key_bitmask, 0, sizeof(key_bitmask));
+
     LOGV("Getting keys...");
     if (ioctl(fd, EVIOCGBIT(EV_KEY, sizeof(key_bitmask)), key_bitmask) >= 0) {
         //LOGI("MAP\n");
-        //for (int i=0; i<((KEY_MAX+7)/8); i++) {
+        //for (int i = 0; i < sizeof(key_bitmask); i++) {
         //    LOGI("%d: 0x%02x\n", i, key_bitmask[i]);
         //}
-        for (int i=0; i<((BTN_MISC+7)/8); i++) {
-            if (key_bitmask[i] != 0) {
-                device->classes |= INPUT_DEVICE_CLASS_KEYBOARD;
-                break;
-            }
-        }
-        if ((device->classes & INPUT_DEVICE_CLASS_KEYBOARD) != 0) {
+
+        // See if this is a keyboard.  Ignore everything in the button range except for
+        // gamepads which are also considered keyboards.
+        if (containsNonZeroByte(key_bitmask, 0, sizeof_bit_array(BTN_MISC))
+                || containsNonZeroByte(key_bitmask, sizeof_bit_array(BTN_GAMEPAD),
+                        sizeof_bit_array(BTN_DIGI))
+                || containsNonZeroByte(key_bitmask, sizeof_bit_array(KEY_OK),
+                        sizeof_bit_array(KEY_MAX + 1))) {
+            device->classes |= INPUT_DEVICE_CLASS_KEYBOARD;
+
             device->keyBitmask = new uint8_t[sizeof(key_bitmask)];
             if (device->keyBitmask != NULL) {
                 memcpy(device->keyBitmask, key_bitmask, sizeof(key_bitmask));
@@ -658,39 +681,39 @@
         }
     }
     
-    // See if this is a trackball.
+    // See if this is a trackball (or mouse).
     if (test_bit(BTN_MOUSE, key_bitmask)) {
-        uint8_t rel_bitmask[(REL_MAX+7)/8];
+        uint8_t rel_bitmask[sizeof_bit_array(REL_MAX + 1)];
         memset(rel_bitmask, 0, sizeof(rel_bitmask));
         LOGV("Getting relative controllers...");
-        if (ioctl(fd, EVIOCGBIT(EV_REL, sizeof(rel_bitmask)), rel_bitmask) >= 0)
-        {
+        if (ioctl(fd, EVIOCGBIT(EV_REL, sizeof(rel_bitmask)), rel_bitmask) >= 0) {
             if (test_bit(REL_X, rel_bitmask) && test_bit(REL_Y, rel_bitmask)) {
                 device->classes |= INPUT_DEVICE_CLASS_TRACKBALL;
             }
         }
     }
-    
-    uint8_t abs_bitmask[(ABS_MAX+7)/8];
+
+    // See if this is a touch pad.
+    uint8_t abs_bitmask[sizeof_bit_array(ABS_MAX + 1)];
     memset(abs_bitmask, 0, sizeof(abs_bitmask));
     LOGV("Getting absolute controllers...");
-    ioctl(fd, EVIOCGBIT(EV_ABS, sizeof(abs_bitmask)), abs_bitmask);
-    
-    // Is this a new modern multi-touch driver?
-    if (test_bit(ABS_MT_TOUCH_MAJOR, abs_bitmask)
-            && test_bit(ABS_MT_POSITION_X, abs_bitmask)
-            && test_bit(ABS_MT_POSITION_Y, abs_bitmask)) {
-        device->classes |= INPUT_DEVICE_CLASS_TOUCHSCREEN | INPUT_DEVICE_CLASS_TOUCHSCREEN_MT;
-        
-    // Is this an old style single-touch driver?
-    } else if (test_bit(BTN_TOUCH, key_bitmask)
-            && test_bit(ABS_X, abs_bitmask) && test_bit(ABS_Y, abs_bitmask)) {
-        device->classes |= INPUT_DEVICE_CLASS_TOUCHSCREEN;
+    if (ioctl(fd, EVIOCGBIT(EV_ABS, sizeof(abs_bitmask)), abs_bitmask) >= 0) {
+        // Is this a new modern multi-touch driver?
+        if (test_bit(ABS_MT_TOUCH_MAJOR, abs_bitmask)
+                && test_bit(ABS_MT_POSITION_X, abs_bitmask)
+                && test_bit(ABS_MT_POSITION_Y, abs_bitmask)) {
+            device->classes |= INPUT_DEVICE_CLASS_TOUCHSCREEN | INPUT_DEVICE_CLASS_TOUCHSCREEN_MT;
+
+        // Is this an old style single-touch driver?
+        } else if (test_bit(BTN_TOUCH, key_bitmask)
+                && test_bit(ABS_X, abs_bitmask) && test_bit(ABS_Y, abs_bitmask)) {
+            device->classes |= INPUT_DEVICE_CLASS_TOUCHSCREEN;
+        }
     }
 
 #ifdef EV_SW
     // figure out the switches this device reports
-    uint8_t sw_bitmask[(SW_MAX+7)/8];
+    uint8_t sw_bitmask[sizeof_bit_array(SW_MAX + 1)];
     memset(sw_bitmask, 0, sizeof(sw_bitmask));
     if (ioctl(fd, EVIOCGBIT(EV_SW, sizeof(sw_bitmask)), sw_bitmask) >= 0) {
         for (int i=0; i<EV_SW; i++) {
@@ -726,7 +749,10 @@
                      "%s/usr/keylayout/%s", root, "qwerty.kl");
             defaultKeymap = true;
         }
-        device->layoutMap->load(keylayoutFilename);
+        status_t status = device->layoutMap->load(keylayoutFilename);
+        if (status) {
+            LOGE("Error %d loading key layout.", status);
+        }
 
         // tell the world about the devname (the descriptive name)
         if (!mHaveFirstKeyboard && !defaultKeymap && strstr(name, "-keypad")) {
@@ -746,19 +772,27 @@
         property_set(propName, name);
 
         // 'Q' key support = cheap test of whether this is an alpha-capable kbd
-        if (hasKeycode(device, kKeyCodeQ)) {
+        if (hasKeycode(device, AKEYCODE_Q)) {
             device->classes |= INPUT_DEVICE_CLASS_ALPHAKEY;
         }
         
-        // See if this has a DPAD.
-        if (hasKeycode(device, kKeyCodeDpadUp) &&
-                hasKeycode(device, kKeyCodeDpadDown) &&
-                hasKeycode(device, kKeyCodeDpadLeft) &&
-                hasKeycode(device, kKeyCodeDpadRight) &&
-                hasKeycode(device, kKeyCodeDpadCenter)) {
+        // See if this device has a DPAD.
+        if (hasKeycode(device, AKEYCODE_DPAD_UP) &&
+                hasKeycode(device, AKEYCODE_DPAD_DOWN) &&
+                hasKeycode(device, AKEYCODE_DPAD_LEFT) &&
+                hasKeycode(device, AKEYCODE_DPAD_RIGHT) &&
+                hasKeycode(device, AKEYCODE_DPAD_CENTER)) {
             device->classes |= INPUT_DEVICE_CLASS_DPAD;
         }
         
+        // See if this device has a gamepad.
+        for (size_t i = 0; i < sizeof(GAMEPAD_KEYCODES); i++) {
+            if (hasKeycode(device, GAMEPAD_KEYCODES[i])) {
+                device->classes |= INPUT_DEVICE_CLASS_GAMEPAD;
+                break;
+            }
+        }
+
         LOGI("New keyboard: device->id=0x%x devname='%s' propName='%s' keylayout='%s'\n",
                 device->id, name, propName, keylayoutFilename);
     }
diff --git a/libs/ui/Input.cpp b/libs/ui/Input.cpp
index a64251f..1f19c2c 100644
--- a/libs/ui/Input.cpp
+++ b/libs/ui/Input.cpp
@@ -22,26 +22,26 @@
 
 bool KeyEvent::hasDefaultAction(int32_t keyCode) {
     switch (keyCode) {
-        case KEYCODE_HOME:
-        case KEYCODE_BACK:
-        case KEYCODE_CALL:
-        case KEYCODE_ENDCALL:
-        case KEYCODE_VOLUME_UP:
-        case KEYCODE_VOLUME_DOWN:
-        case KEYCODE_POWER:
-        case KEYCODE_CAMERA:
-        case KEYCODE_HEADSETHOOK:
-        case KEYCODE_MENU:
-        case KEYCODE_NOTIFICATION:
-        case KEYCODE_FOCUS:
-        case KEYCODE_SEARCH:
-        case KEYCODE_MEDIA_PLAY_PAUSE:
-        case KEYCODE_MEDIA_STOP:
-        case KEYCODE_MEDIA_NEXT:
-        case KEYCODE_MEDIA_PREVIOUS:
-        case KEYCODE_MEDIA_REWIND:
-        case KEYCODE_MEDIA_FAST_FORWARD:
-        case KEYCODE_MUTE:
+        case AKEYCODE_HOME:
+        case AKEYCODE_BACK:
+        case AKEYCODE_CALL:
+        case AKEYCODE_ENDCALL:
+        case AKEYCODE_VOLUME_UP:
+        case AKEYCODE_VOLUME_DOWN:
+        case AKEYCODE_POWER:
+        case AKEYCODE_CAMERA:
+        case AKEYCODE_HEADSETHOOK:
+        case AKEYCODE_MENU:
+        case AKEYCODE_NOTIFICATION:
+        case AKEYCODE_FOCUS:
+        case AKEYCODE_SEARCH:
+        case AKEYCODE_MEDIA_PLAY_PAUSE:
+        case AKEYCODE_MEDIA_STOP:
+        case AKEYCODE_MEDIA_NEXT:
+        case AKEYCODE_MEDIA_PREVIOUS:
+        case AKEYCODE_MEDIA_REWIND:
+        case AKEYCODE_MEDIA_FAST_FORWARD:
+        case AKEYCODE_MUTE:
             return true;
     }
     
@@ -54,26 +54,26 @@
 
 bool KeyEvent::isSystemKey(int32_t keyCode) {
     switch (keyCode) {
-        case KEYCODE_MENU:
-        case KEYCODE_SOFT_RIGHT:
-        case KEYCODE_HOME:
-        case KEYCODE_BACK:
-        case KEYCODE_CALL:
-        case KEYCODE_ENDCALL:
-        case KEYCODE_VOLUME_UP:
-        case KEYCODE_VOLUME_DOWN:
-        case KEYCODE_MUTE:
-        case KEYCODE_POWER:
-        case KEYCODE_HEADSETHOOK:
-        case KEYCODE_MEDIA_PLAY_PAUSE:
-        case KEYCODE_MEDIA_STOP:
-        case KEYCODE_MEDIA_NEXT:
-        case KEYCODE_MEDIA_PREVIOUS:
-        case KEYCODE_MEDIA_REWIND:
-        case KEYCODE_MEDIA_FAST_FORWARD:
-        case KEYCODE_CAMERA:
-        case KEYCODE_FOCUS:
-        case KEYCODE_SEARCH:
+        case AKEYCODE_MENU:
+        case AKEYCODE_SOFT_RIGHT:
+        case AKEYCODE_HOME:
+        case AKEYCODE_BACK:
+        case AKEYCODE_CALL:
+        case AKEYCODE_ENDCALL:
+        case AKEYCODE_VOLUME_UP:
+        case AKEYCODE_VOLUME_DOWN:
+        case AKEYCODE_MUTE:
+        case AKEYCODE_POWER:
+        case AKEYCODE_HEADSETHOOK:
+        case AKEYCODE_MEDIA_PLAY_PAUSE:
+        case AKEYCODE_MEDIA_STOP:
+        case AKEYCODE_MEDIA_NEXT:
+        case AKEYCODE_MEDIA_PREVIOUS:
+        case AKEYCODE_MEDIA_REWIND:
+        case AKEYCODE_MEDIA_FAST_FORWARD:
+        case AKEYCODE_CAMERA:
+        case AKEYCODE_FOCUS:
+        case AKEYCODE_SEARCH:
             return true;
     }
     
diff --git a/libs/ui/InputDevice.cpp b/libs/ui/InputDevice.cpp
new file mode 100644
index 0000000..6014017
--- /dev/null
+++ b/libs/ui/InputDevice.cpp
@@ -0,0 +1,729 @@
+//
+// Copyright 2010 The Android Open Source Project
+//
+// The input reader.
+//
+#define LOG_TAG "InputDevice"
+
+//#define LOG_NDEBUG 0
+
+// Log debug messages for each raw event received from the EventHub.
+#define DEBUG_RAW_EVENTS 0
+
+// Log debug messages about touch screen filtering hacks.
+#define DEBUG_HACKS 0
+
+// Log debug messages about virtual key processing.
+#define DEBUG_VIRTUAL_KEYS 0
+
+// Log debug messages about pointers.
+#define DEBUG_POINTERS 0
+
+// Log debug messages about pointer assignment calculations.
+#define DEBUG_POINTER_ASSIGNMENT 0
+
+#include <cutils/log.h>
+#include <ui/InputDevice.h>
+
+#include <stddef.h>
+#include <unistd.h>
+#include <errno.h>
+#include <limits.h>
+
+/* Slop distance for jumpy pointer detection.
+ * The vertical range of the screen divided by this is our epsilon value. */
+#define JUMPY_EPSILON_DIVISOR 212
+
+/* Number of jumpy points to drop for touchscreens that need it. */
+#define JUMPY_TRANSITION_DROPS 3
+#define JUMPY_DROP_LIMIT 3
+
+/* Maximum squared distance for averaging.
+ * If moving farther than this, turn of averaging to avoid lag in response. */
+#define AVERAGING_DISTANCE_LIMIT (75 * 75)
+
+
+namespace android {
+
+// --- Static Functions ---
+
+template<typename T>
+inline static T abs(const T& value) {
+    return value < 0 ? - value : value;
+}
+
+template<typename T>
+inline static T min(const T& a, const T& b) {
+    return a < b ? a : b;
+}
+
+template<typename T>
+inline static void swap(T& a, T& b) {
+    T temp = a;
+    a = b;
+    b = temp;
+}
+
+
+// --- InputDevice ---
+
+InputDevice::InputDevice(int32_t id, uint32_t classes, String8 name) :
+    id(id), classes(classes), name(name), ignored(false) {
+}
+
+void InputDevice::reset() {
+    if (isKeyboard()) {
+        keyboard.reset();
+    }
+
+    if (isTrackball()) {
+        trackball.reset();
+    }
+
+    if (isMultiTouchScreen()) {
+        multiTouchScreen.reset();
+    } else if (isSingleTouchScreen()) {
+        singleTouchScreen.reset();
+    }
+
+    if (isTouchScreen()) {
+        touchScreen.reset();
+    }
+}
+
+
+// --- InputDevice::TouchData ---
+
+void InputDevice::TouchData::copyFrom(const TouchData& other) {
+    pointerCount = other.pointerCount;
+    idBits = other.idBits;
+
+    for (uint32_t i = 0; i < pointerCount; i++) {
+        pointers[i] = other.pointers[i];
+        idToIndex[i] = other.idToIndex[i];
+    }
+}
+
+
+// --- InputDevice::KeyboardState ---
+
+void InputDevice::KeyboardState::reset() {
+    current.metaState = META_NONE;
+    current.downTime = 0;
+}
+
+
+// --- InputDevice::TrackballState ---
+
+void InputDevice::TrackballState::reset() {
+    accumulator.clear();
+    current.down = false;
+    current.downTime = 0;
+}
+
+
+// --- InputDevice::TouchScreenState ---
+
+void InputDevice::TouchScreenState::reset() {
+    lastTouch.clear();
+    downTime = 0;
+    currentVirtualKey.status = CurrentVirtualKeyState::STATUS_UP;
+
+    for (uint32_t i = 0; i < MAX_POINTERS; i++) {
+        averagingTouchFilter.historyStart[i] = 0;
+        averagingTouchFilter.historyEnd[i] = 0;
+    }
+
+    jumpyTouchFilter.jumpyPointsDropped = 0;
+}
+
+struct PointerDistanceHeapElement {
+    uint32_t currentPointerIndex : 8;
+    uint32_t lastPointerIndex : 8;
+    uint64_t distance : 48; // squared distance
+};
+
+void InputDevice::TouchScreenState::calculatePointerIds() {
+    uint32_t currentPointerCount = currentTouch.pointerCount;
+    uint32_t lastPointerCount = lastTouch.pointerCount;
+
+    if (currentPointerCount == 0) {
+        // No pointers to assign.
+        currentTouch.idBits.clear();
+    } else if (lastPointerCount == 0) {
+        // All pointers are new.
+        currentTouch.idBits.clear();
+        for (uint32_t i = 0; i < currentPointerCount; i++) {
+            currentTouch.pointers[i].id = i;
+            currentTouch.idToIndex[i] = i;
+            currentTouch.idBits.markBit(i);
+        }
+    } else if (currentPointerCount == 1 && lastPointerCount == 1) {
+        // Only one pointer and no change in count so it must have the same id as before.
+        uint32_t id = lastTouch.pointers[0].id;
+        currentTouch.pointers[0].id = id;
+        currentTouch.idToIndex[id] = 0;
+        currentTouch.idBits.value = BitSet32::valueForBit(id);
+    } else {
+        // General case.
+        // We build a heap of squared euclidean distances between current and last pointers
+        // associated with the current and last pointer indices.  Then, we find the best
+        // match (by distance) for each current pointer.
+        PointerDistanceHeapElement heap[MAX_POINTERS * MAX_POINTERS];
+
+        uint32_t heapSize = 0;
+        for (uint32_t currentPointerIndex = 0; currentPointerIndex < currentPointerCount;
+                currentPointerIndex++) {
+            for (uint32_t lastPointerIndex = 0; lastPointerIndex < lastPointerCount;
+                    lastPointerIndex++) {
+                int64_t deltaX = currentTouch.pointers[currentPointerIndex].x
+                        - lastTouch.pointers[lastPointerIndex].x;
+                int64_t deltaY = currentTouch.pointers[currentPointerIndex].y
+                        - lastTouch.pointers[lastPointerIndex].y;
+
+                uint64_t distance = uint64_t(deltaX * deltaX + deltaY * deltaY);
+
+                // Insert new element into the heap (sift up).
+                heap[heapSize].currentPointerIndex = currentPointerIndex;
+                heap[heapSize].lastPointerIndex = lastPointerIndex;
+                heap[heapSize].distance = distance;
+                heapSize += 1;
+            }
+        }
+
+        // Heapify
+        for (uint32_t startIndex = heapSize / 2; startIndex != 0; ) {
+            startIndex -= 1;
+            for (uint32_t parentIndex = startIndex; ;) {
+                uint32_t childIndex = parentIndex * 2 + 1;
+                if (childIndex >= heapSize) {
+                    break;
+                }
+
+                if (childIndex + 1 < heapSize
+                        && heap[childIndex + 1].distance < heap[childIndex].distance) {
+                    childIndex += 1;
+                }
+
+                if (heap[parentIndex].distance <= heap[childIndex].distance) {
+                    break;
+                }
+
+                swap(heap[parentIndex], heap[childIndex]);
+                parentIndex = childIndex;
+            }
+        }
+
+#if DEBUG_POINTER_ASSIGNMENT
+        LOGD("calculatePointerIds - initial distance min-heap: size=%d", heapSize);
+        for (size_t i = 0; i < heapSize; i++) {
+            LOGD("  heap[%d]: cur=%d, last=%d, distance=%lld",
+                    i, heap[i].currentPointerIndex, heap[i].lastPointerIndex,
+                    heap[i].distance);
+        }
+#endif
+
+        // Pull matches out by increasing order of distance.
+        // To avoid reassigning pointers that have already been matched, the loop keeps track
+        // of which last and current pointers have been matched using the matchedXXXBits variables.
+        // It also tracks the used pointer id bits.
+        BitSet32 matchedLastBits(0);
+        BitSet32 matchedCurrentBits(0);
+        BitSet32 usedIdBits(0);
+        bool first = true;
+        for (uint32_t i = min(currentPointerCount, lastPointerCount); i > 0; i--) {
+            for (;;) {
+                if (first) {
+                    // The first time through the loop, we just consume the root element of
+                    // the heap (the one with smallest distance).
+                    first = false;
+                } else {
+                    // Previous iterations consumed the root element of the heap.
+                    // Pop root element off of the heap (sift down).
+                    heapSize -= 1;
+                    assert(heapSize > 0);
+
+                    // Sift down.
+                    heap[0] = heap[heapSize];
+                    for (uint32_t parentIndex = 0; ;) {
+                        uint32_t childIndex = parentIndex * 2 + 1;
+                        if (childIndex >= heapSize) {
+                            break;
+                        }
+
+                        if (childIndex + 1 < heapSize
+                                && heap[childIndex + 1].distance < heap[childIndex].distance) {
+                            childIndex += 1;
+                        }
+
+                        if (heap[parentIndex].distance <= heap[childIndex].distance) {
+                            break;
+                        }
+
+                        swap(heap[parentIndex], heap[childIndex]);
+                        parentIndex = childIndex;
+                    }
+
+#if DEBUG_POINTER_ASSIGNMENT
+                    LOGD("calculatePointerIds - reduced distance min-heap: size=%d", heapSize);
+                    for (size_t i = 0; i < heapSize; i++) {
+                        LOGD("  heap[%d]: cur=%d, last=%d, distance=%lld",
+                                i, heap[i].currentPointerIndex, heap[i].lastPointerIndex,
+                                heap[i].distance);
+                    }
+#endif
+                }
+
+                uint32_t currentPointerIndex = heap[0].currentPointerIndex;
+                if (matchedCurrentBits.hasBit(currentPointerIndex)) continue; // already matched
+
+                uint32_t lastPointerIndex = heap[0].lastPointerIndex;
+                if (matchedLastBits.hasBit(lastPointerIndex)) continue; // already matched
+
+                matchedCurrentBits.markBit(currentPointerIndex);
+                matchedLastBits.markBit(lastPointerIndex);
+
+                uint32_t id = lastTouch.pointers[lastPointerIndex].id;
+                currentTouch.pointers[currentPointerIndex].id = id;
+                currentTouch.idToIndex[id] = currentPointerIndex;
+                usedIdBits.markBit(id);
+
+#if DEBUG_POINTER_ASSIGNMENT
+                LOGD("calculatePointerIds - matched: cur=%d, last=%d, id=%d, distance=%lld",
+                        lastPointerIndex, currentPointerIndex, id, heap[0].distance);
+#endif
+                break;
+            }
+        }
+
+        // Assign fresh ids to new pointers.
+        if (currentPointerCount > lastPointerCount) {
+            for (uint32_t i = currentPointerCount - lastPointerCount; ;) {
+                uint32_t currentPointerIndex = matchedCurrentBits.firstUnmarkedBit();
+                uint32_t id = usedIdBits.firstUnmarkedBit();
+
+                currentTouch.pointers[currentPointerIndex].id = id;
+                currentTouch.idToIndex[id] = currentPointerIndex;
+                usedIdBits.markBit(id);
+
+#if DEBUG_POINTER_ASSIGNMENT
+                LOGD("calculatePointerIds - assigned: cur=%d, id=%d",
+                        currentPointerIndex, id);
+#endif
+
+                if (--i == 0) break; // done
+                matchedCurrentBits.markBit(currentPointerIndex);
+            }
+        }
+
+        // Fix id bits.
+        currentTouch.idBits = usedIdBits;
+    }
+}
+
+/* Special hack for devices that have bad screen data: if one of the
+ * points has moved more than a screen height from the last position,
+ * then drop it. */
+bool InputDevice::TouchScreenState::applyBadTouchFilter() {
+    // This hack requires valid axis parameters.
+    if (! parameters.yAxis.valid) {
+        return false;
+    }
+
+    uint32_t pointerCount = currentTouch.pointerCount;
+
+    // Nothing to do if there are no points.
+    if (pointerCount == 0) {
+        return false;
+    }
+
+    // Don't do anything if a finger is going down or up.  We run
+    // here before assigning pointer IDs, so there isn't a good
+    // way to do per-finger matching.
+    if (pointerCount != lastTouch.pointerCount) {
+        return false;
+    }
+
+    // We consider a single movement across more than a 7/16 of
+    // the long size of the screen to be bad.  This was a magic value
+    // determined by looking at the maximum distance it is feasible
+    // to actually move in one sample.
+    int32_t maxDeltaY = parameters.yAxis.range * 7 / 16;
+
+    // XXX The original code in InputDevice.java included commented out
+    //     code for testing the X axis.  Note that when we drop a point
+    //     we don't actually restore the old X either.  Strange.
+    //     The old code also tries to track when bad points were previously
+    //     detected but it turns out that due to the placement of a "break"
+    //     at the end of the loop, we never set mDroppedBadPoint to true
+    //     so it is effectively dead code.
+    // Need to figure out if the old code is busted or just overcomplicated
+    // but working as intended.
+
+    // Look through all new points and see if any are farther than
+    // acceptable from all previous points.
+    for (uint32_t i = pointerCount; i-- > 0; ) {
+        int32_t y = currentTouch.pointers[i].y;
+        int32_t closestY = INT_MAX;
+        int32_t closestDeltaY = 0;
+
+#if DEBUG_HACKS
+        LOGD("BadTouchFilter: Looking at next point #%d: y=%d", i, y);
+#endif
+
+        for (uint32_t j = pointerCount; j-- > 0; ) {
+            int32_t lastY = lastTouch.pointers[j].y;
+            int32_t deltaY = abs(y - lastY);
+
+#if DEBUG_HACKS
+            LOGD("BadTouchFilter: Comparing with last point #%d: y=%d deltaY=%d",
+                    j, lastY, deltaY);
+#endif
+
+            if (deltaY < maxDeltaY) {
+                goto SkipSufficientlyClosePoint;
+            }
+            if (deltaY < closestDeltaY) {
+                closestDeltaY = deltaY;
+                closestY = lastY;
+            }
+        }
+
+        // Must not have found a close enough match.
+#if DEBUG_HACKS
+        LOGD("BadTouchFilter: Dropping bad point #%d: newY=%d oldY=%d deltaY=%d maxDeltaY=%d",
+                i, y, closestY, closestDeltaY, maxDeltaY);
+#endif
+
+        currentTouch.pointers[i].y = closestY;
+        return true; // XXX original code only corrects one point
+
+    SkipSufficientlyClosePoint: ;
+    }
+
+    // No change.
+    return false;
+}
+
+/* Special hack for devices that have bad screen data: drop points where
+ * the coordinate value for one axis has jumped to the other pointer's location.
+ */
+bool InputDevice::TouchScreenState::applyJumpyTouchFilter() {
+    // This hack requires valid axis parameters.
+    if (! parameters.yAxis.valid) {
+        return false;
+    }
+
+    uint32_t pointerCount = currentTouch.pointerCount;
+    if (lastTouch.pointerCount != pointerCount) {
+#if DEBUG_HACKS
+        LOGD("JumpyTouchFilter: Different pointer count %d -> %d",
+                lastTouch.pointerCount, pointerCount);
+        for (uint32_t i = 0; i < pointerCount; i++) {
+            LOGD("  Pointer %d (%d, %d)", i,
+                    currentTouch.pointers[i].x, currentTouch.pointers[i].y);
+        }
+#endif
+
+        if (jumpyTouchFilter.jumpyPointsDropped < JUMPY_TRANSITION_DROPS) {
+            if (lastTouch.pointerCount == 1 && pointerCount == 2) {
+                // Just drop the first few events going from 1 to 2 pointers.
+                // They're bad often enough that they're not worth considering.
+                currentTouch.pointerCount = 1;
+                jumpyTouchFilter.jumpyPointsDropped += 1;
+
+#if DEBUG_HACKS
+                LOGD("JumpyTouchFilter: Pointer 2 dropped");
+#endif
+                return true;
+            } else if (lastTouch.pointerCount == 2 && pointerCount == 1) {
+                // The event when we go from 2 -> 1 tends to be messed up too
+                currentTouch.pointerCount = 2;
+                currentTouch.pointers[0] = lastTouch.pointers[0];
+                currentTouch.pointers[1] = lastTouch.pointers[1];
+                jumpyTouchFilter.jumpyPointsDropped += 1;
+
+#if DEBUG_HACKS
+                for (int32_t i = 0; i < 2; i++) {
+                    LOGD("JumpyTouchFilter: Pointer %d replaced (%d, %d)", i,
+                            currentTouch.pointers[i].x, currentTouch.pointers[i].y);
+                }
+#endif
+                return true;
+            }
+        }
+        // Reset jumpy points dropped on other transitions or if limit exceeded.
+        jumpyTouchFilter.jumpyPointsDropped = 0;
+
+#if DEBUG_HACKS
+        LOGD("JumpyTouchFilter: Transition - drop limit reset");
+#endif
+        return false;
+    }
+
+    // We have the same number of pointers as last time.
+    // A 'jumpy' point is one where the coordinate value for one axis
+    // has jumped to the other pointer's location. No need to do anything
+    // else if we only have one pointer.
+    if (pointerCount < 2) {
+        return false;
+    }
+
+    if (jumpyTouchFilter.jumpyPointsDropped < JUMPY_DROP_LIMIT) {
+        int jumpyEpsilon = parameters.yAxis.range / JUMPY_EPSILON_DIVISOR;
+
+        // We only replace the single worst jumpy point as characterized by pointer distance
+        // in a single axis.
+        int32_t badPointerIndex = -1;
+        int32_t badPointerReplacementIndex = -1;
+        int32_t badPointerDistance = INT_MIN; // distance to be corrected
+
+        for (uint32_t i = pointerCount; i-- > 0; ) {
+            int32_t x = currentTouch.pointers[i].x;
+            int32_t y = currentTouch.pointers[i].y;
+
+#if DEBUG_HACKS
+            LOGD("JumpyTouchFilter: Point %d (%d, %d)", i, x, y);
+#endif
+
+            // Check if a touch point is too close to another's coordinates
+            bool dropX = false, dropY = false;
+            for (uint32_t j = 0; j < pointerCount; j++) {
+                if (i == j) {
+                    continue;
+                }
+
+                if (abs(x - currentTouch.pointers[j].x) <= jumpyEpsilon) {
+                    dropX = true;
+                    break;
+                }
+
+                if (abs(y - currentTouch.pointers[j].y) <= jumpyEpsilon) {
+                    dropY = true;
+                    break;
+                }
+            }
+            if (! dropX && ! dropY) {
+                continue; // not jumpy
+            }
+
+            // Find a replacement candidate by comparing with older points on the
+            // complementary (non-jumpy) axis.
+            int32_t distance = INT_MIN; // distance to be corrected
+            int32_t replacementIndex = -1;
+
+            if (dropX) {
+                // X looks too close.  Find an older replacement point with a close Y.
+                int32_t smallestDeltaY = INT_MAX;
+                for (uint32_t j = 0; j < pointerCount; j++) {
+                    int32_t deltaY = abs(y - lastTouch.pointers[j].y);
+                    if (deltaY < smallestDeltaY) {
+                        smallestDeltaY = deltaY;
+                        replacementIndex = j;
+                    }
+                }
+                distance = abs(x - lastTouch.pointers[replacementIndex].x);
+            } else {
+                // Y looks too close.  Find an older replacement point with a close X.
+                int32_t smallestDeltaX = INT_MAX;
+                for (uint32_t j = 0; j < pointerCount; j++) {
+                    int32_t deltaX = abs(x - lastTouch.pointers[j].x);
+                    if (deltaX < smallestDeltaX) {
+                        smallestDeltaX = deltaX;
+                        replacementIndex = j;
+                    }
+                }
+                distance = abs(y - lastTouch.pointers[replacementIndex].y);
+            }
+
+            // If replacing this pointer would correct a worse error than the previous ones
+            // considered, then use this replacement instead.
+            if (distance > badPointerDistance) {
+                badPointerIndex = i;
+                badPointerReplacementIndex = replacementIndex;
+                badPointerDistance = distance;
+            }
+        }
+
+        // Correct the jumpy pointer if one was found.
+        if (badPointerIndex >= 0) {
+#if DEBUG_HACKS
+            LOGD("JumpyTouchFilter: Replacing bad pointer %d with (%d, %d)",
+                    badPointerIndex,
+                    lastTouch.pointers[badPointerReplacementIndex].x,
+                    lastTouch.pointers[badPointerReplacementIndex].y);
+#endif
+
+            currentTouch.pointers[badPointerIndex].x =
+                    lastTouch.pointers[badPointerReplacementIndex].x;
+            currentTouch.pointers[badPointerIndex].y =
+                    lastTouch.pointers[badPointerReplacementIndex].y;
+            jumpyTouchFilter.jumpyPointsDropped += 1;
+            return true;
+        }
+    }
+
+    jumpyTouchFilter.jumpyPointsDropped = 0;
+    return false;
+}
+
+/* Special hack for devices that have bad screen data: aggregate and
+ * compute averages of the coordinate data, to reduce the amount of
+ * jitter seen by applications. */
+void InputDevice::TouchScreenState::applyAveragingTouchFilter() {
+    for (uint32_t currentIndex = 0; currentIndex < currentTouch.pointerCount; currentIndex++) {
+        uint32_t id = currentTouch.pointers[currentIndex].id;
+        int32_t x = currentTouch.pointers[currentIndex].x;
+        int32_t y = currentTouch.pointers[currentIndex].y;
+        int32_t pressure = currentTouch.pointers[currentIndex].pressure;
+
+        if (lastTouch.idBits.hasBit(id)) {
+            // Pointer was down before and is still down now.
+            // Compute average over history trace.
+            uint32_t start = averagingTouchFilter.historyStart[id];
+            uint32_t end = averagingTouchFilter.historyEnd[id];
+
+            int64_t deltaX = x - averagingTouchFilter.historyData[end].pointers[id].x;
+            int64_t deltaY = y - averagingTouchFilter.historyData[end].pointers[id].y;
+            uint64_t distance = uint64_t(deltaX * deltaX + deltaY * deltaY);
+
+#if DEBUG_HACKS
+            LOGD("AveragingTouchFilter: Pointer id %d - Distance from last sample: %lld",
+                    id, distance);
+#endif
+
+            if (distance < AVERAGING_DISTANCE_LIMIT) {
+                // Increment end index in preparation for recording new historical data.
+                end += 1;
+                if (end > AVERAGING_HISTORY_SIZE) {
+                    end = 0;
+                }
+
+                // If the end index has looped back to the start index then we have filled
+                // the historical trace up to the desired size so we drop the historical
+                // data at the start of the trace.
+                if (end == start) {
+                    start += 1;
+                    if (start > AVERAGING_HISTORY_SIZE) {
+                        start = 0;
+                    }
+                }
+
+                // Add the raw data to the historical trace.
+                averagingTouchFilter.historyStart[id] = start;
+                averagingTouchFilter.historyEnd[id] = end;
+                averagingTouchFilter.historyData[end].pointers[id].x = x;
+                averagingTouchFilter.historyData[end].pointers[id].y = y;
+                averagingTouchFilter.historyData[end].pointers[id].pressure = pressure;
+
+                // Average over all historical positions in the trace by total pressure.
+                int32_t averagedX = 0;
+                int32_t averagedY = 0;
+                int32_t totalPressure = 0;
+                for (;;) {
+                    int32_t historicalX = averagingTouchFilter.historyData[start].pointers[id].x;
+                    int32_t historicalY = averagingTouchFilter.historyData[start].pointers[id].y;
+                    int32_t historicalPressure = averagingTouchFilter.historyData[start]
+                            .pointers[id].pressure;
+
+                    averagedX += historicalX * historicalPressure;
+                    averagedY += historicalY * historicalPressure;
+                    totalPressure += historicalPressure;
+
+                    if (start == end) {
+                        break;
+                    }
+
+                    start += 1;
+                    if (start > AVERAGING_HISTORY_SIZE) {
+                        start = 0;
+                    }
+                }
+
+                averagedX /= totalPressure;
+                averagedY /= totalPressure;
+
+#if DEBUG_HACKS
+                LOGD("AveragingTouchFilter: Pointer id %d - "
+                        "totalPressure=%d, averagedX=%d, averagedY=%d", id, totalPressure,
+                        averagedX, averagedY);
+#endif
+
+                currentTouch.pointers[currentIndex].x = averagedX;
+                currentTouch.pointers[currentIndex].y = averagedY;
+            } else {
+#if DEBUG_HACKS
+                LOGD("AveragingTouchFilter: Pointer id %d - Exceeded max distance", id);
+#endif
+            }
+        } else {
+#if DEBUG_HACKS
+            LOGD("AveragingTouchFilter: Pointer id %d - Pointer went up", id);
+#endif
+        }
+
+        // Reset pointer history.
+        averagingTouchFilter.historyStart[id] = 0;
+        averagingTouchFilter.historyEnd[id] = 0;
+        averagingTouchFilter.historyData[0].pointers[id].x = x;
+        averagingTouchFilter.historyData[0].pointers[id].y = y;
+        averagingTouchFilter.historyData[0].pointers[id].pressure = pressure;
+    }
+}
+
+bool InputDevice::TouchScreenState::isPointInsideDisplay(int32_t x, int32_t y) const {
+    if (! parameters.xAxis.valid || ! parameters.yAxis.valid) {
+        // Assume all points on a touch screen without valid axis parameters are
+        // inside the display.
+        return true;
+    }
+
+    return x >= parameters.xAxis.minValue
+        && x <= parameters.xAxis.maxValue
+        && y >= parameters.yAxis.minValue
+        && y <= parameters.yAxis.maxValue;
+}
+
+const InputDevice::VirtualKey* InputDevice::TouchScreenState::findVirtualKeyHit() const {
+    int32_t x = currentTouch.pointers[0].x;
+    int32_t y = currentTouch.pointers[0].y;
+    for (size_t i = 0; i < virtualKeys.size(); i++) {
+        const InputDevice::VirtualKey& virtualKey = virtualKeys[i];
+
+#if DEBUG_VIRTUAL_KEYS
+        LOGD("VirtualKeys: Hit test (%d, %d): keyCode=%d, scanCode=%d, "
+                "left=%d, top=%d, right=%d, bottom=%d",
+                x, y,
+                virtualKey.keyCode, virtualKey.scanCode,
+                virtualKey.hitLeft, virtualKey.hitTop,
+                virtualKey.hitRight, virtualKey.hitBottom);
+#endif
+
+        if (virtualKey.isHit(x, y)) {
+            return & virtualKey;
+        }
+    }
+
+    return NULL;
+}
+
+
+// --- InputDevice::SingleTouchScreenState ---
+
+void InputDevice::SingleTouchScreenState::reset() {
+    accumulator.clear();
+    current.down = false;
+    current.x = 0;
+    current.y = 0;
+    current.pressure = 0;
+    current.size = 0;
+}
+
+
+// --- InputDevice::MultiTouchScreenState ---
+
+void InputDevice::MultiTouchScreenState::reset() {
+    accumulator.clear();
+}
+
+} // namespace android
diff --git a/libs/ui/InputDispatcher.cpp b/libs/ui/InputDispatcher.cpp
index 8f6d1fe..c4ffce1 100644
--- a/libs/ui/InputDispatcher.cpp
+++ b/libs/ui/InputDispatcher.cpp
@@ -40,10 +40,10 @@
 
 // TODO, this needs to be somewhere else, perhaps in the policy
 static inline bool isMovementKey(int32_t keyCode) {
-    return keyCode == KEYCODE_DPAD_UP
-            || keyCode == KEYCODE_DPAD_DOWN
-            || keyCode == KEYCODE_DPAD_LEFT
-            || keyCode == KEYCODE_DPAD_RIGHT;
+    return keyCode == AKEYCODE_DPAD_UP
+            || keyCode == AKEYCODE_DPAD_DOWN
+            || keyCode == AKEYCODE_DPAD_LEFT
+            || keyCode == AKEYCODE_DPAD_RIGHT;
 }
 
 static inline nsecs_t now() {
@@ -54,7 +54,7 @@
 
 InputDispatcher::InputDispatcher(const sp<InputDispatcherPolicyInterface>& policy) :
     mPolicy(policy) {
-    mPollLoop = new PollLoop();
+    mPollLoop = new PollLoop(false);
 
     mInboundQueue.head.refCount = -1;
     mInboundQueue.head.type = EventEntry::TYPE_SENTINEL;
@@ -299,14 +299,13 @@
     uint32_t policyFlags = entry->policyFlags & POLICY_FLAG_RAW_MASK;
     if (entry->refCount == 1) {
         entry->eventTime = currentTime;
-        entry->downTime = currentTime;
         entry->policyFlags = policyFlags;
         entry->repeatCount += 1;
     } else {
         KeyEntry* newEntry = mAllocator.obtainKeyEntry(currentTime,
                 entry->deviceId, entry->nature, policyFlags,
                 entry->action, entry->flags, entry->keyCode, entry->scanCode,
-                entry->metaState, entry->repeatCount + 1, currentTime);
+                entry->metaState, entry->repeatCount + 1, entry->downTime);
 
         mKeyRepeatState.lastKeyEntry = newEntry;
         mAllocator.releaseKeyEntry(entry);
@@ -314,6 +313,10 @@
         entry = newEntry;
     }
 
+    if (entry->repeatCount == 1) {
+        entry->flags |= KEY_EVENT_FLAG_LONG_PRESS;
+    }
+
     mKeyRepeatState.nextRepeatTime = currentTime + keyRepeatTimeout;
 
 #if DEBUG_OUTBOUND_EVENT_DETAILS
diff --git a/libs/ui/InputReader.cpp b/libs/ui/InputReader.cpp
index 899027c..0a21db7 100644
--- a/libs/ui/InputReader.cpp
+++ b/libs/ui/InputReader.cpp
@@ -33,18 +33,6 @@
 /** Amount that trackball needs to move in order to generate a key event. */
 #define TRACKBALL_MOVEMENT_THRESHOLD 6
 
-/* Slop distance for jumpy pointer detection.
- * The vertical range of the screen divided by this is our epsilon value. */
-#define JUMPY_EPSILON_DIVISOR 212
-
-/* Number of jumpy points to drop for touchscreens that need it. */
-#define JUMPY_TRANSITION_DROPS 3
-#define JUMPY_DROP_LIMIT 3
-
-/* Maximum squared distance for averaging.
- * If moving farther than this, turn of averaging to avoid lag in response. */
-#define AVERAGING_DISTANCE_LIMIT (75 * 75)
-
 
 namespace android {
 
@@ -71,19 +59,19 @@
 int32_t updateMetaState(int32_t keyCode, bool down, int32_t oldMetaState) {
     int32_t mask;
     switch (keyCode) {
-    case KEYCODE_ALT_LEFT:
+    case AKEYCODE_ALT_LEFT:
         mask = META_ALT_LEFT_ON;
         break;
-    case KEYCODE_ALT_RIGHT:
+    case AKEYCODE_ALT_RIGHT:
         mask = META_ALT_RIGHT_ON;
         break;
-    case KEYCODE_SHIFT_LEFT:
+    case AKEYCODE_SHIFT_LEFT:
         mask = META_SHIFT_LEFT_ON;
         break;
-    case KEYCODE_SHIFT_RIGHT:
+    case AKEYCODE_SHIFT_RIGHT:
         mask = META_SHIFT_RIGHT_ON;
         break;
-    case KEYCODE_SYM:
+    case AKEYCODE_SYM:
         mask = META_SYM_ON;
         break;
     default:
@@ -107,10 +95,10 @@
 static const int32_t keyCodeRotationMap[][4] = {
         // key codes enumerated counter-clockwise with the original (unrotated) key first
         // no rotation,        90 degree rotation,  180 degree rotation, 270 degree rotation
-        { KEYCODE_DPAD_DOWN,   KEYCODE_DPAD_RIGHT,  KEYCODE_DPAD_UP,     KEYCODE_DPAD_LEFT },
-        { KEYCODE_DPAD_RIGHT,  KEYCODE_DPAD_UP,     KEYCODE_DPAD_LEFT,   KEYCODE_DPAD_DOWN },
-        { KEYCODE_DPAD_UP,     KEYCODE_DPAD_LEFT,   KEYCODE_DPAD_DOWN,   KEYCODE_DPAD_RIGHT },
-        { KEYCODE_DPAD_LEFT,   KEYCODE_DPAD_DOWN,   KEYCODE_DPAD_RIGHT,  KEYCODE_DPAD_UP },
+        { AKEYCODE_DPAD_DOWN,   AKEYCODE_DPAD_RIGHT,  AKEYCODE_DPAD_UP,     AKEYCODE_DPAD_LEFT },
+        { AKEYCODE_DPAD_RIGHT,  AKEYCODE_DPAD_UP,     AKEYCODE_DPAD_LEFT,   AKEYCODE_DPAD_DOWN },
+        { AKEYCODE_DPAD_UP,     AKEYCODE_DPAD_LEFT,   AKEYCODE_DPAD_DOWN,   AKEYCODE_DPAD_RIGHT },
+        { AKEYCODE_DPAD_LEFT,   AKEYCODE_DPAD_DOWN,   AKEYCODE_DPAD_RIGHT,  AKEYCODE_DPAD_UP },
 };
 static const int keyCodeRotationMapSize =
         sizeof(keyCodeRotationMap) / sizeof(keyCodeRotationMap[0]);
@@ -127,645 +115,6 @@
 }
 
 
-// --- InputDevice ---
-
-InputDevice::InputDevice(int32_t id, uint32_t classes, String8 name) :
-    id(id), classes(classes), name(name), ignored(false) {
-}
-
-void InputDevice::reset() {
-    if (isKeyboard()) {
-        keyboard.reset();
-    }
-
-    if (isTrackball()) {
-        trackball.reset();
-    }
-
-    if (isMultiTouchScreen()) {
-        multiTouchScreen.reset();
-    } else if (isSingleTouchScreen()) {
-        singleTouchScreen.reset();
-    }
-
-    if (isTouchScreen()) {
-        touchScreen.reset();
-    }
-}
-
-
-// --- InputDevice::TouchData ---
-
-void InputDevice::TouchData::copyFrom(const TouchData& other) {
-    pointerCount = other.pointerCount;
-    idBits = other.idBits;
-
-    for (uint32_t i = 0; i < pointerCount; i++) {
-        pointers[i] = other.pointers[i];
-        idToIndex[i] = other.idToIndex[i];
-    }
-}
-
-
-// --- InputDevice::KeyboardState ---
-
-void InputDevice::KeyboardState::reset() {
-    current.metaState = META_NONE;
-    current.downTime = 0;
-}
-
-
-// --- InputDevice::TrackballState ---
-
-void InputDevice::TrackballState::reset() {
-    accumulator.clear();
-    current.down = false;
-    current.downTime = 0;
-}
-
-
-// --- InputDevice::TouchScreenState ---
-
-void InputDevice::TouchScreenState::reset() {
-    lastTouch.clear();
-    downTime = 0;
-    currentVirtualKey.down = false;
-
-    for (uint32_t i = 0; i < MAX_POINTERS; i++) {
-        averagingTouchFilter.historyStart[i] = 0;
-        averagingTouchFilter.historyEnd[i] = 0;
-    }
-
-    jumpyTouchFilter.jumpyPointsDropped = 0;
-}
-
-struct PointerDistanceHeapElement {
-    uint32_t currentPointerIndex : 8;
-    uint32_t lastPointerIndex : 8;
-    uint64_t distance : 48; // squared distance
-};
-
-void InputDevice::TouchScreenState::calculatePointerIds() {
-    uint32_t currentPointerCount = currentTouch.pointerCount;
-    uint32_t lastPointerCount = lastTouch.pointerCount;
-
-    if (currentPointerCount == 0) {
-        // No pointers to assign.
-        currentTouch.idBits.clear();
-    } else if (lastPointerCount == 0) {
-        // All pointers are new.
-        currentTouch.idBits.clear();
-        for (uint32_t i = 0; i < currentPointerCount; i++) {
-            currentTouch.pointers[i].id = i;
-            currentTouch.idToIndex[i] = i;
-            currentTouch.idBits.markBit(i);
-        }
-    } else if (currentPointerCount == 1 && lastPointerCount == 1) {
-        // Only one pointer and no change in count so it must have the same id as before.
-        uint32_t id = lastTouch.pointers[0].id;
-        currentTouch.pointers[0].id = id;
-        currentTouch.idToIndex[id] = 0;
-        currentTouch.idBits.value = BitSet32::valueForBit(id);
-    } else {
-        // General case.
-        // We build a heap of squared euclidean distances between current and last pointers
-        // associated with the current and last pointer indices.  Then, we find the best
-        // match (by distance) for each current pointer.
-        PointerDistanceHeapElement heap[MAX_POINTERS * MAX_POINTERS];
-
-        uint32_t heapSize = 0;
-        for (uint32_t currentPointerIndex = 0; currentPointerIndex < currentPointerCount;
-                currentPointerIndex++) {
-            for (uint32_t lastPointerIndex = 0; lastPointerIndex < lastPointerCount;
-                    lastPointerIndex++) {
-                int64_t deltaX = currentTouch.pointers[currentPointerIndex].x
-                        - lastTouch.pointers[lastPointerIndex].x;
-                int64_t deltaY = currentTouch.pointers[currentPointerIndex].y
-                        - lastTouch.pointers[lastPointerIndex].y;
-
-                uint64_t distance = uint64_t(deltaX * deltaX + deltaY * deltaY);
-
-                // Insert new element into the heap (sift up).
-                heap[heapSize].currentPointerIndex = currentPointerIndex;
-                heap[heapSize].lastPointerIndex = lastPointerIndex;
-                heap[heapSize].distance = distance;
-                heapSize += 1;
-            }
-        }
-
-        // Heapify
-        for (uint32_t startIndex = heapSize / 2; startIndex != 0; ) {
-            startIndex -= 1;
-            for (uint32_t parentIndex = startIndex; ;) {
-                uint32_t childIndex = parentIndex * 2 + 1;
-                if (childIndex >= heapSize) {
-                    break;
-                }
-
-                if (childIndex + 1 < heapSize
-                        && heap[childIndex + 1].distance < heap[childIndex].distance) {
-                    childIndex += 1;
-                }
-
-                if (heap[parentIndex].distance <= heap[childIndex].distance) {
-                    break;
-                }
-
-                swap(heap[parentIndex], heap[childIndex]);
-                parentIndex = childIndex;
-            }
-        }
-
-#if DEBUG_POINTER_ASSIGNMENT
-        LOGD("calculatePointerIds - initial distance min-heap: size=%d", heapSize);
-        for (size_t i = 0; i < heapSize; i++) {
-            LOGD("  heap[%d]: cur=%d, last=%d, distance=%lld",
-                    i, heap[i].currentPointerIndex, heap[i].lastPointerIndex,
-                    heap[i].distance);
-        }
-#endif
-
-        // Pull matches out by increasing order of distance.
-        // To avoid reassigning pointers that have already been matched, the loop keeps track
-        // of which last and current pointers have been matched using the matchedXXXBits variables.
-        // It also tracks the used pointer id bits.
-        BitSet32 matchedLastBits(0);
-        BitSet32 matchedCurrentBits(0);
-        BitSet32 usedIdBits(0);
-        bool first = true;
-        for (uint32_t i = min(currentPointerCount, lastPointerCount); i > 0; i--) {
-            for (;;) {
-                if (first) {
-                    // The first time through the loop, we just consume the root element of
-                    // the heap (the one with smallest distance).
-                    first = false;
-                } else {
-                    // Previous iterations consumed the root element of the heap.
-                    // Pop root element off of the heap (sift down).
-                    heapSize -= 1;
-                    assert(heapSize > 0);
-
-                    // Sift down.
-                    heap[0] = heap[heapSize];
-                    for (uint32_t parentIndex = 0; ;) {
-                        uint32_t childIndex = parentIndex * 2 + 1;
-                        if (childIndex >= heapSize) {
-                            break;
-                        }
-
-                        if (childIndex + 1 < heapSize
-                                && heap[childIndex + 1].distance < heap[childIndex].distance) {
-                            childIndex += 1;
-                        }
-
-                        if (heap[parentIndex].distance <= heap[childIndex].distance) {
-                            break;
-                        }
-
-                        swap(heap[parentIndex], heap[childIndex]);
-                        parentIndex = childIndex;
-                    }
-
-#if DEBUG_POINTER_ASSIGNMENT
-                    LOGD("calculatePointerIds - reduced distance min-heap: size=%d", heapSize);
-                    for (size_t i = 0; i < heapSize; i++) {
-                        LOGD("  heap[%d]: cur=%d, last=%d, distance=%lld",
-                                i, heap[i].currentPointerIndex, heap[i].lastPointerIndex,
-                                heap[i].distance);
-                    }
-#endif
-                }
-
-                uint32_t currentPointerIndex = heap[0].currentPointerIndex;
-                if (matchedCurrentBits.hasBit(currentPointerIndex)) continue; // already matched
-
-                uint32_t lastPointerIndex = heap[0].lastPointerIndex;
-                if (matchedLastBits.hasBit(lastPointerIndex)) continue; // already matched
-
-                matchedCurrentBits.markBit(currentPointerIndex);
-                matchedLastBits.markBit(lastPointerIndex);
-
-                uint32_t id = lastTouch.pointers[lastPointerIndex].id;
-                currentTouch.pointers[currentPointerIndex].id = id;
-                currentTouch.idToIndex[id] = currentPointerIndex;
-                usedIdBits.markBit(id);
-
-#if DEBUG_POINTER_ASSIGNMENT
-                LOGD("calculatePointerIds - matched: cur=%d, last=%d, id=%d, distance=%lld",
-                        lastPointerIndex, currentPointerIndex, id, heap[0].distance);
-#endif
-                break;
-            }
-        }
-
-        // Assign fresh ids to new pointers.
-        if (currentPointerCount > lastPointerCount) {
-            for (uint32_t i = currentPointerCount - lastPointerCount; ;) {
-                uint32_t currentPointerIndex = matchedCurrentBits.firstUnmarkedBit();
-                uint32_t id = usedIdBits.firstUnmarkedBit();
-
-                currentTouch.pointers[currentPointerIndex].id = id;
-                currentTouch.idToIndex[id] = currentPointerIndex;
-                usedIdBits.markBit(id);
-
-#if DEBUG_POINTER_ASSIGNMENT
-                LOGD("calculatePointerIds - assigned: cur=%d, id=%d",
-                        currentPointerIndex, id);
-#endif
-
-                if (--i == 0) break; // done
-                matchedCurrentBits.markBit(currentPointerIndex);
-            }
-        }
-
-        // Fix id bits.
-        currentTouch.idBits = usedIdBits;
-    }
-}
-
-/* Special hack for devices that have bad screen data: if one of the
- * points has moved more than a screen height from the last position,
- * then drop it. */
-bool InputDevice::TouchScreenState::applyBadTouchFilter() {
-    // This hack requires valid axis parameters.
-    if (! parameters.yAxis.valid) {
-        return false;
-    }
-
-    uint32_t pointerCount = currentTouch.pointerCount;
-
-    // Nothing to do if there are no points.
-    if (pointerCount == 0) {
-        return false;
-    }
-
-    // Don't do anything if a finger is going down or up.  We run
-    // here before assigning pointer IDs, so there isn't a good
-    // way to do per-finger matching.
-    if (pointerCount != lastTouch.pointerCount) {
-        return false;
-    }
-
-    // We consider a single movement across more than a 7/16 of
-    // the long size of the screen to be bad.  This was a magic value
-    // determined by looking at the maximum distance it is feasible
-    // to actually move in one sample.
-    int32_t maxDeltaY = parameters.yAxis.range * 7 / 16;
-
-    // XXX The original code in InputDevice.java included commented out
-    //     code for testing the X axis.  Note that when we drop a point
-    //     we don't actually restore the old X either.  Strange.
-    //     The old code also tries to track when bad points were previously
-    //     detected but it turns out that due to the placement of a "break"
-    //     at the end of the loop, we never set mDroppedBadPoint to true
-    //     so it is effectively dead code.
-    // Need to figure out if the old code is busted or just overcomplicated
-    // but working as intended.
-
-    // Look through all new points and see if any are farther than
-    // acceptable from all previous points.
-    for (uint32_t i = pointerCount; i-- > 0; ) {
-        int32_t y = currentTouch.pointers[i].y;
-        int32_t closestY = INT_MAX;
-        int32_t closestDeltaY = 0;
-
-#if DEBUG_HACKS
-        LOGD("BadTouchFilter: Looking at next point #%d: y=%d", i, y);
-#endif
-
-        for (uint32_t j = pointerCount; j-- > 0; ) {
-            int32_t lastY = lastTouch.pointers[j].y;
-            int32_t deltaY = abs(y - lastY);
-
-#if DEBUG_HACKS
-            LOGD("BadTouchFilter: Comparing with last point #%d: y=%d deltaY=%d",
-                    j, lastY, deltaY);
-#endif
-
-            if (deltaY < maxDeltaY) {
-                goto SkipSufficientlyClosePoint;
-            }
-            if (deltaY < closestDeltaY) {
-                closestDeltaY = deltaY;
-                closestY = lastY;
-            }
-        }
-
-        // Must not have found a close enough match.
-#if DEBUG_HACKS
-        LOGD("BadTouchFilter: Dropping bad point #%d: newY=%d oldY=%d deltaY=%d maxDeltaY=%d",
-                i, y, closestY, closestDeltaY, maxDeltaY);
-#endif
-
-        currentTouch.pointers[i].y = closestY;
-        return true; // XXX original code only corrects one point
-
-    SkipSufficientlyClosePoint: ;
-    }
-
-    // No change.
-    return false;
-}
-
-/* Special hack for devices that have bad screen data: drop points where
- * the coordinate value for one axis has jumped to the other pointer's location.
- */
-bool InputDevice::TouchScreenState::applyJumpyTouchFilter() {
-    // This hack requires valid axis parameters.
-    if (! parameters.yAxis.valid) {
-        return false;
-    }
-
-    uint32_t pointerCount = currentTouch.pointerCount;
-    if (lastTouch.pointerCount != pointerCount) {
-#if DEBUG_HACKS
-        LOGD("JumpyTouchFilter: Different pointer count %d -> %d",
-                lastTouch.pointerCount, pointerCount);
-        for (uint32_t i = 0; i < pointerCount; i++) {
-            LOGD("  Pointer %d (%d, %d)", i,
-                    currentTouch.pointers[i].x, currentTouch.pointers[i].y);
-        }
-#endif
-
-        if (jumpyTouchFilter.jumpyPointsDropped < JUMPY_TRANSITION_DROPS) {
-            if (lastTouch.pointerCount == 1 && pointerCount == 2) {
-                // Just drop the first few events going from 1 to 2 pointers.
-                // They're bad often enough that they're not worth considering.
-                currentTouch.pointerCount = 1;
-                jumpyTouchFilter.jumpyPointsDropped += 1;
-
-#if DEBUG_HACKS
-                LOGD("JumpyTouchFilter: Pointer 2 dropped");
-#endif
-                return true;
-            } else if (lastTouch.pointerCount == 2 && pointerCount == 1) {
-                // The event when we go from 2 -> 1 tends to be messed up too
-                currentTouch.pointerCount = 2;
-                currentTouch.pointers[0] = lastTouch.pointers[0];
-                currentTouch.pointers[1] = lastTouch.pointers[1];
-                jumpyTouchFilter.jumpyPointsDropped += 1;
-
-#if DEBUG_HACKS
-                for (int32_t i = 0; i < 2; i++) {
-                    LOGD("JumpyTouchFilter: Pointer %d replaced (%d, %d)", i,
-                            currentTouch.pointers[i].x, currentTouch.pointers[i].y);
-                }
-#endif
-                return true;
-            }
-        }
-        // Reset jumpy points dropped on other transitions or if limit exceeded.
-        jumpyTouchFilter.jumpyPointsDropped = 0;
-
-#if DEBUG_HACKS
-        LOGD("JumpyTouchFilter: Transition - drop limit reset");
-#endif
-        return false;
-    }
-
-    // We have the same number of pointers as last time.
-    // A 'jumpy' point is one where the coordinate value for one axis
-    // has jumped to the other pointer's location. No need to do anything
-    // else if we only have one pointer.
-    if (pointerCount < 2) {
-        return false;
-    }
-
-    if (jumpyTouchFilter.jumpyPointsDropped < JUMPY_DROP_LIMIT) {
-        int jumpyEpsilon = parameters.yAxis.range / JUMPY_EPSILON_DIVISOR;
-
-        // We only replace the single worst jumpy point as characterized by pointer distance
-        // in a single axis.
-        int32_t badPointerIndex = -1;
-        int32_t badPointerReplacementIndex = -1;
-        int32_t badPointerDistance = INT_MIN; // distance to be corrected
-
-        for (uint32_t i = pointerCount; i-- > 0; ) {
-            int32_t x = currentTouch.pointers[i].x;
-            int32_t y = currentTouch.pointers[i].y;
-
-#if DEBUG_HACKS
-            LOGD("JumpyTouchFilter: Point %d (%d, %d)", i, x, y);
-#endif
-
-            // Check if a touch point is too close to another's coordinates
-            bool dropX = false, dropY = false;
-            for (uint32_t j = 0; j < pointerCount; j++) {
-                if (i == j) {
-                    continue;
-                }
-
-                if (abs(x - currentTouch.pointers[j].x) <= jumpyEpsilon) {
-                    dropX = true;
-                    break;
-                }
-
-                if (abs(y - currentTouch.pointers[j].y) <= jumpyEpsilon) {
-                    dropY = true;
-                    break;
-                }
-            }
-            if (! dropX && ! dropY) {
-                continue; // not jumpy
-            }
-
-            // Find a replacement candidate by comparing with older points on the
-            // complementary (non-jumpy) axis.
-            int32_t distance = INT_MIN; // distance to be corrected
-            int32_t replacementIndex = -1;
-
-            if (dropX) {
-                // X looks too close.  Find an older replacement point with a close Y.
-                int32_t smallestDeltaY = INT_MAX;
-                for (uint32_t j = 0; j < pointerCount; j++) {
-                    int32_t deltaY = abs(y - lastTouch.pointers[j].y);
-                    if (deltaY < smallestDeltaY) {
-                        smallestDeltaY = deltaY;
-                        replacementIndex = j;
-                    }
-                }
-                distance = abs(x - lastTouch.pointers[replacementIndex].x);
-            } else {
-                // Y looks too close.  Find an older replacement point with a close X.
-                int32_t smallestDeltaX = INT_MAX;
-                for (uint32_t j = 0; j < pointerCount; j++) {
-                    int32_t deltaX = abs(x - lastTouch.pointers[j].x);
-                    if (deltaX < smallestDeltaX) {
-                        smallestDeltaX = deltaX;
-                        replacementIndex = j;
-                    }
-                }
-                distance = abs(y - lastTouch.pointers[replacementIndex].y);
-            }
-
-            // If replacing this pointer would correct a worse error than the previous ones
-            // considered, then use this replacement instead.
-            if (distance > badPointerDistance) {
-                badPointerIndex = i;
-                badPointerReplacementIndex = replacementIndex;
-                badPointerDistance = distance;
-            }
-        }
-
-        // Correct the jumpy pointer if one was found.
-        if (badPointerIndex >= 0) {
-#if DEBUG_HACKS
-            LOGD("JumpyTouchFilter: Replacing bad pointer %d with (%d, %d)",
-                    badPointerIndex,
-                    lastTouch.pointers[badPointerReplacementIndex].x,
-                    lastTouch.pointers[badPointerReplacementIndex].y);
-#endif
-
-            currentTouch.pointers[badPointerIndex].x =
-                    lastTouch.pointers[badPointerReplacementIndex].x;
-            currentTouch.pointers[badPointerIndex].y =
-                    lastTouch.pointers[badPointerReplacementIndex].y;
-            jumpyTouchFilter.jumpyPointsDropped += 1;
-            return true;
-        }
-    }
-
-    jumpyTouchFilter.jumpyPointsDropped = 0;
-    return false;
-}
-
-/* Special hack for devices that have bad screen data: aggregate and
- * compute averages of the coordinate data, to reduce the amount of
- * jitter seen by applications. */
-void InputDevice::TouchScreenState::applyAveragingTouchFilter() {
-    for (uint32_t currentIndex = 0; currentIndex < currentTouch.pointerCount; currentIndex++) {
-        uint32_t id = currentTouch.pointers[currentIndex].id;
-        int32_t x = currentTouch.pointers[currentIndex].x;
-        int32_t y = currentTouch.pointers[currentIndex].y;
-        int32_t pressure = currentTouch.pointers[currentIndex].pressure;
-
-        if (lastTouch.idBits.hasBit(id)) {
-            // Pointer was down before and is still down now.
-            // Compute average over history trace.
-            uint32_t start = averagingTouchFilter.historyStart[id];
-            uint32_t end = averagingTouchFilter.historyEnd[id];
-
-            int64_t deltaX = x - averagingTouchFilter.historyData[end].pointers[id].x;
-            int64_t deltaY = y - averagingTouchFilter.historyData[end].pointers[id].y;
-            uint64_t distance = uint64_t(deltaX * deltaX + deltaY * deltaY);
-
-#if DEBUG_HACKS
-            LOGD("AveragingTouchFilter: Pointer id %d - Distance from last sample: %lld",
-                    id, distance);
-#endif
-
-            if (distance < AVERAGING_DISTANCE_LIMIT) {
-                // Increment end index in preparation for recording new historical data.
-                end += 1;
-                if (end > AVERAGING_HISTORY_SIZE) {
-                    end = 0;
-                }
-
-                // If the end index has looped back to the start index then we have filled
-                // the historical trace up to the desired size so we drop the historical
-                // data at the start of the trace.
-                if (end == start) {
-                    start += 1;
-                    if (start > AVERAGING_HISTORY_SIZE) {
-                        start = 0;
-                    }
-                }
-
-                // Add the raw data to the historical trace.
-                averagingTouchFilter.historyStart[id] = start;
-                averagingTouchFilter.historyEnd[id] = end;
-                averagingTouchFilter.historyData[end].pointers[id].x = x;
-                averagingTouchFilter.historyData[end].pointers[id].y = y;
-                averagingTouchFilter.historyData[end].pointers[id].pressure = pressure;
-
-                // Average over all historical positions in the trace by total pressure.
-                int32_t averagedX = 0;
-                int32_t averagedY = 0;
-                int32_t totalPressure = 0;
-                for (;;) {
-                    int32_t historicalX = averagingTouchFilter.historyData[start].pointers[id].x;
-                    int32_t historicalY = averagingTouchFilter.historyData[start].pointers[id].y;
-                    int32_t historicalPressure = averagingTouchFilter.historyData[start]
-                            .pointers[id].pressure;
-
-                    averagedX += historicalX * historicalPressure;
-                    averagedY += historicalY * historicalPressure;
-                    totalPressure += historicalPressure;
-
-                    if (start == end) {
-                        break;
-                    }
-
-                    start += 1;
-                    if (start > AVERAGING_HISTORY_SIZE) {
-                        start = 0;
-                    }
-                }
-
-                averagedX /= totalPressure;
-                averagedY /= totalPressure;
-
-#if DEBUG_HACKS
-                LOGD("AveragingTouchFilter: Pointer id %d - "
-                        "totalPressure=%d, averagedX=%d, averagedY=%d", id, totalPressure,
-                        averagedX, averagedY);
-#endif
-
-                currentTouch.pointers[currentIndex].x = averagedX;
-                currentTouch.pointers[currentIndex].y = averagedY;
-            } else {
-#if DEBUG_HACKS
-                LOGD("AveragingTouchFilter: Pointer id %d - Exceeded max distance", id);
-#endif
-            }
-        } else {
-#if DEBUG_HACKS
-            LOGD("AveragingTouchFilter: Pointer id %d - Pointer went up", id);
-#endif
-        }
-
-        // Reset pointer history.
-        averagingTouchFilter.historyStart[id] = 0;
-        averagingTouchFilter.historyEnd[id] = 0;
-        averagingTouchFilter.historyData[0].pointers[id].x = x;
-        averagingTouchFilter.historyData[0].pointers[id].y = y;
-        averagingTouchFilter.historyData[0].pointers[id].pressure = pressure;
-    }
-}
-
-bool InputDevice::TouchScreenState::isPointInsideDisplay(int32_t x, int32_t y) const {
-    if (! parameters.xAxis.valid || ! parameters.yAxis.valid) {
-        // Assume all points on a touch screen without valid axis parameters are
-        // inside the display.
-        return true;
-    }
-
-    return x >= parameters.xAxis.minValue
-        && x <= parameters.xAxis.maxValue
-        && y >= parameters.yAxis.minValue
-        && y <= parameters.yAxis.maxValue;
-}
-
-
-// --- InputDevice::SingleTouchScreenState ---
-
-void InputDevice::SingleTouchScreenState::reset() {
-    accumulator.clear();
-    current.down = false;
-    current.x = 0;
-    current.y = 0;
-    current.pressure = 0;
-    current.size = 0;
-}
-
-
-// --- InputDevice::MultiTouchScreenState ---
-
-void InputDevice::MultiTouchScreenState::reset() {
-    accumulator.clear();
-}
-
-
 // --- InputReader ---
 
 InputReader::InputReader(const sp<EventHubInterface>& eventHub,
@@ -904,32 +253,30 @@
     bool down = rawEvent->value != 0;
     int32_t scanCode = rawEvent->scanCode;
 
-    if (device->isKeyboard() && (scanCode < BTN_FIRST || scanCode > BTN_LAST)) {
-        int32_t keyCode = rawEvent->keyCode;
-        onKey(rawEvent->when, device, down, keyCode, scanCode, rawEvent->flags);
-    } else if (device->isSingleTouchScreen()) {
+    if (device->isSingleTouchScreen()) {
         switch (rawEvent->scanCode) {
         case BTN_TOUCH:
             device->singleTouchScreen.accumulator.fields |=
                     InputDevice::SingleTouchScreenState::Accumulator::FIELD_BTN_TOUCH;
             device->singleTouchScreen.accumulator.btnTouch = down;
-            break;
+            return;
         }
-    } else if (device->isTrackball()) {
+    }
+
+    if (device->isTrackball()) {
         switch (rawEvent->scanCode) {
         case BTN_MOUSE:
             device->trackball.accumulator.fields |=
                     InputDevice::TrackballState::Accumulator::FIELD_BTN_MOUSE;
             device->trackball.accumulator.btnMouse = down;
-
-            // send the down immediately
-            // XXX this emulates the old behavior of KeyInputQueue, unclear whether it is
-            //     necessary or if we can wait until the next sync
-            onTrackballStateChanged(rawEvent->when, device);
-            device->trackball.accumulator.clear();
-            break;
+            return;
         }
     }
+
+    if (device->isKeyboard()) {
+        int32_t keyCode = rawEvent->keyCode;
+        onKey(rawEvent->when, device, down, keyCode, scanCode, rawEvent->flags);
+    }
 }
 
 void InputReader::handleRelativeMotion(const RawEvent* rawEvent) {
@@ -1269,81 +616,76 @@
 
 bool InputReader::consumeVirtualKeyTouches(nsecs_t when,
         InputDevice* device, uint32_t policyFlags) {
-    if (device->touchScreen.currentVirtualKey.down) {
+    switch (device->touchScreen.currentVirtualKey.status) {
+    case InputDevice::TouchScreenState::CurrentVirtualKeyState::STATUS_CANCELED:
         if (device->touchScreen.currentTouch.pointerCount == 0) {
-            // Pointer went up while virtual key was down.  Send key up event.
-            device->touchScreen.currentVirtualKey.down = false;
+            // Pointer went up after virtual key canceled.
+            device->touchScreen.currentVirtualKey.status =
+                    InputDevice::TouchScreenState::CurrentVirtualKeyState::STATUS_UP;
+        }
+        return true; // consumed
 
+    case InputDevice::TouchScreenState::CurrentVirtualKeyState::STATUS_DOWN:
+        if (device->touchScreen.currentTouch.pointerCount == 0) {
+            // Pointer went up while virtual key was down.
+            device->touchScreen.currentVirtualKey.status =
+                    InputDevice::TouchScreenState::CurrentVirtualKeyState::STATUS_UP;
 #if DEBUG_VIRTUAL_KEYS
             LOGD("VirtualKeys: Generating key up: keyCode=%d, scanCode=%d",
                     device->touchScreen.currentVirtualKey.keyCode,
                     device->touchScreen.currentVirtualKey.scanCode);
 #endif
-
             dispatchVirtualKey(when, device, policyFlags, KEY_EVENT_ACTION_UP,
                     KEY_EVENT_FLAG_FROM_SYSTEM | KEY_EVENT_FLAG_VIRTUAL_HARD_KEY);
             return true; // consumed
         }
 
-        int32_t x = device->touchScreen.currentTouch.pointers[0].x;
-        int32_t y = device->touchScreen.currentTouch.pointers[0].y;
-        if (device->touchScreen.isPointInsideDisplay(x, y)
-                || device->touchScreen.currentTouch.pointerCount != 1) {
-            // Pointer moved inside the display area or another pointer also went down.
-            // Send key cancellation.
-            device->touchScreen.currentVirtualKey.down = false;
-
-#if DEBUG_VIRTUAL_KEYS
-            LOGD("VirtualKeys: Canceling key: keyCode=%d, scanCode=%d",
-                    device->touchScreen.currentVirtualKey.keyCode,
-                    device->touchScreen.currentVirtualKey.scanCode);
-#endif
-
-            dispatchVirtualKey(when, device, policyFlags, KEY_EVENT_ACTION_UP,
-                    KEY_EVENT_FLAG_FROM_SYSTEM | KEY_EVENT_FLAG_VIRTUAL_HARD_KEY
-                            | KEY_EVENT_FLAG_CANCELED);
-
-            // Clear the last touch data so we will consider the pointer as having just been
-            // pressed down when generating subsequent motion events.
-            device->touchScreen.lastTouch.clear();
-            return false; // not consumed
+        if (device->touchScreen.currentTouch.pointerCount == 1) {
+            const InputDevice::VirtualKey* virtualKey = device->touchScreen.findVirtualKeyHit();
+            if (virtualKey
+                    && virtualKey->keyCode == device->touchScreen.currentVirtualKey.keyCode) {
+                // Pointer is still within the space of the virtual key.
+                return true; // consumed
+            }
         }
-    } else if (device->touchScreen.currentTouch.pointerCount == 1
-            && device->touchScreen.lastTouch.pointerCount == 0) {
-        int32_t x = device->touchScreen.currentTouch.pointers[0].x;
-        int32_t y = device->touchScreen.currentTouch.pointers[0].y;
-        for (size_t i = 0; i < device->touchScreen.virtualKeys.size(); i++) {
-            const InputDevice::VirtualKey& virtualKey = device->touchScreen.virtualKeys[i];
 
+        // Pointer left virtual key area or another pointer also went down.
+        // Send key cancellation.
+        device->touchScreen.currentVirtualKey.status =
+                InputDevice::TouchScreenState::CurrentVirtualKeyState::STATUS_CANCELED;
 #if DEBUG_VIRTUAL_KEYS
-            LOGD("VirtualKeys: Hit test (%d, %d): keyCode=%d, scanCode=%d, "
-                    "left=%d, top=%d, right=%d, bottom=%d",
-                    x, y,
-                    virtualKey.keyCode, virtualKey.scanCode,
-                    virtualKey.hitLeft, virtualKey.hitTop,
-                    virtualKey.hitRight, virtualKey.hitBottom);
+        LOGD("VirtualKeys: Canceling key: keyCode=%d, scanCode=%d",
+                device->touchScreen.currentVirtualKey.keyCode,
+                device->touchScreen.currentVirtualKey.scanCode);
 #endif
+        dispatchVirtualKey(when, device, policyFlags, KEY_EVENT_ACTION_UP,
+                KEY_EVENT_FLAG_FROM_SYSTEM | KEY_EVENT_FLAG_VIRTUAL_HARD_KEY
+                        | KEY_EVENT_FLAG_CANCELED);
+        return true; // consumed
 
-            if (virtualKey.isHit(x, y)) {
-                device->touchScreen.currentVirtualKey.down = true;
+    default:
+        if (device->touchScreen.currentTouch.pointerCount == 1
+                && device->touchScreen.lastTouch.pointerCount == 0) {
+            // Pointer just went down.  Check for virtual key hit.
+            const InputDevice::VirtualKey* virtualKey = device->touchScreen.findVirtualKeyHit();
+            if (virtualKey) {
+                device->touchScreen.currentVirtualKey.status =
+                        InputDevice::TouchScreenState::CurrentVirtualKeyState::STATUS_DOWN;
                 device->touchScreen.currentVirtualKey.downTime = when;
-                device->touchScreen.currentVirtualKey.keyCode = virtualKey.keyCode;
-                device->touchScreen.currentVirtualKey.scanCode = virtualKey.scanCode;
-
+                device->touchScreen.currentVirtualKey.keyCode = virtualKey->keyCode;
+                device->touchScreen.currentVirtualKey.scanCode = virtualKey->scanCode;
 #if DEBUG_VIRTUAL_KEYS
-                    LOGD("VirtualKeys: Generating key down: keyCode=%d, scanCode=%d",
-                            device->touchScreen.currentVirtualKey.keyCode,
-                            device->touchScreen.currentVirtualKey.scanCode);
+                LOGD("VirtualKeys: Generating key down: keyCode=%d, scanCode=%d",
+                        device->touchScreen.currentVirtualKey.keyCode,
+                        device->touchScreen.currentVirtualKey.scanCode);
 #endif
-
                 dispatchVirtualKey(when, device, policyFlags, KEY_EVENT_ACTION_DOWN,
                         KEY_EVENT_FLAG_FROM_SYSTEM | KEY_EVENT_FLAG_VIRTUAL_HARD_KEY);
                 return true; // consumed
             }
         }
+        return false; // not consumed
     }
-
-    return false; // not consumed
 }
 
 void InputReader::dispatchVirtualKey(nsecs_t when,
@@ -1356,8 +698,9 @@
     nsecs_t downTime = device->touchScreen.currentVirtualKey.downTime;
     int32_t metaState = globalMetaState();
 
-    mPolicy->virtualKeyFeedback(when, device->id, keyEventAction, keyEventFlags,
-            keyCode, scanCode, metaState, downTime);
+    if (keyEventAction == KEY_EVENT_ACTION_DOWN) {
+        mPolicy->virtualKeyDownFeedback();
+    }
 
     int32_t policyActions = mPolicy->interceptKey(when, device->id,
             keyEventAction == KEY_EVENT_ACTION_DOWN, keyCode, scanCode, policyFlags);
@@ -1852,7 +1195,7 @@
         uint32_t flags;
         if (mEventHub->scancodeToKeycode(device->id, virtualKey.scanCode,
                 & keyCode, & flags)) {
-            LOGI("  VirtualKey %d: could not obtain key code, ignoring", virtualKey.scanCode);
+            LOGW("  VirtualKey %d: could not obtain key code, ignoring", virtualKey.scanCode);
             device->touchScreen.virtualKeys.pop(); // drop the key
             continue;
         }
@@ -1933,7 +1276,8 @@
     for (size_t i = 0; i < mDevices.size(); i++) {
         InputDevice* device = mDevices.valueAt(i);
         if (device->isTouchScreen()) {
-            if (device->touchScreen.currentVirtualKey.down) {
+            if (device->touchScreen.currentVirtualKey.status
+                    == InputDevice::TouchScreenState::CurrentVirtualKeyState::STATUS_DOWN) {
                 keyCode = device->touchScreen.currentVirtualKey.keyCode;
                 scanCode = device->touchScreen.currentVirtualKey.scanCode;
             }
diff --git a/libs/ui/InputTransport.cpp b/libs/ui/InputTransport.cpp
index 25def3c..fc83e31 100644
--- a/libs/ui/InputTransport.cpp
+++ b/libs/ui/InputTransport.cpp
@@ -690,22 +690,3 @@
 }
 
 } // namespace android
-
-// --- AInputQueue ---
-
-using android::InputEvent;
-using android::InputChannel;
-using android::InputConsumer;
-using android::sp;
-using android::status_t;
-
-AInputQueue::AInputQueue(const sp<InputChannel>& channel) :
-        mConsumer(channel) {
-}
-
-AInputQueue::~AInputQueue() {
-}
-
-status_t AInputQueue::consume(InputEvent** event) {
-    return mConsumer.consume(&mInputEventFactory, event);
-}
diff --git a/libs/ui/PixelFormat.cpp b/libs/ui/PixelFormat.cpp
index b205418..edf1aed 100644
--- a/libs/ui/PixelFormat.cpp
+++ b/libs/ui/PixelFormat.cpp
@@ -60,7 +60,6 @@
     switch (format) {
     case HAL_PIXEL_FORMAT_YCbCr_422_SP:
     case HAL_PIXEL_FORMAT_YCbCr_422_I:
-    case HAL_PIXEL_FORMAT_YV16:
         info->bitsPerPixel = 16;
         goto done;
     case HAL_PIXEL_FORMAT_YCrCb_420_SP:
diff --git a/libs/ui/Rect.cpp b/libs/ui/Rect.cpp
index 66b9576..5694e00 100644
--- a/libs/ui/Rect.cpp
+++ b/libs/ui/Rect.cpp
@@ -18,11 +18,11 @@
 
 namespace android {
 
-static inline int min(int a, int b) {
+static inline int32_t min(int32_t a, int32_t b) {
     return (a<b) ? a : b;
 }
 
-static inline int max(int a, int b) {
+static inline int32_t max(int32_t a, int32_t b) {
     return (a>b) ? a : b;
 }
 
@@ -53,7 +53,7 @@
     return false;
 }
 
-Rect& Rect::offsetTo(int x, int y)
+Rect& Rect::offsetTo(int32_t x, int32_t y)
 {
     right -= left - x;
     bottom -= top - y;
@@ -62,7 +62,7 @@
     return *this;
 }
 
-Rect& Rect::offsetBy(int x, int y)
+Rect& Rect::offsetBy(int32_t x, int32_t y)
 {
     left += x;
     top  += y;
diff --git a/libs/ui/tests/Android.mk b/libs/ui/tests/Android.mk
index 46d7493..62f824f 100644
--- a/libs/ui/tests/Android.mk
+++ b/libs/ui/tests/Android.mk
@@ -2,6 +2,9 @@
 LOCAL_PATH:= $(call my-dir)
 include $(CLEAR_VARS)
 
+ifneq ($(TARGET_SIMULATOR),true)
+
+# Build the unit tests.
 test_src_files := \
     InputChannel_test.cpp \
     InputDispatcher_test.cpp \
@@ -43,3 +46,5 @@
 
 # Build the manual test programs.
 include $(call all-subdir-makefiles)
+
+endif
\ No newline at end of file
diff --git a/libs/ui/tests/InputPublisherAndConsumer_test.cpp b/libs/ui/tests/InputPublisherAndConsumer_test.cpp
index 2d6b531..55504f2 100644
--- a/libs/ui/tests/InputPublisherAndConsumer_test.cpp
+++ b/libs/ui/tests/InputPublisherAndConsumer_test.cpp
@@ -76,7 +76,7 @@
     const int32_t nature = INPUT_EVENT_NATURE_KEY;
     const int32_t action = KEY_EVENT_ACTION_DOWN;
     const int32_t flags = KEY_EVENT_FLAG_FROM_SYSTEM;
-    const int32_t keyCode = KEYCODE_ENTER;
+    const int32_t keyCode = AKEYCODE_ENTER;
     const int32_t scanCode = 13;
     const int32_t metaState = META_ALT_LEFT_ON | META_ALT_ON;
     const int32_t repeatCount = 1;
diff --git a/libs/utils/Android.mk b/libs/utils/Android.mk
index 7d4524a..8bd5823 100644
--- a/libs/utils/Android.mk
+++ b/libs/utils/Android.mk
@@ -26,6 +26,7 @@
 	Debug.cpp \
 	FileMap.cpp \
 	Flattenable.cpp \
+	ObbFile.cpp \
 	Pool.cpp \
 	RefBase.cpp \
 	ResourceTypes.cpp \
@@ -65,6 +66,11 @@
 endif
 endif
 
+ifeq ($(HOST_OS),darwin)
+# MacOS doesn't have lseek64. However, off_t is 64-bit anyway.
+LOCAL_CFLAGS += -DOFF_T_IS_64_BIT
+endif
+
 include $(BUILD_HOST_STATIC_LIBRARY)
 
 
@@ -116,3 +122,13 @@
 include $(BUILD_STATIC_LIBRARY)
 endif
 endif
+
+
+# Include subdirectory makefiles
+# ============================================================
+
+# If we're building with ONE_SHOT_MAKEFILE (mm, mmm), then what the framework
+# team really wants is to build the stuff defined by this makefile.
+ifeq (,$(ONE_SHOT_MAKEFILE))
+include $(call first-makefiles-under,$(LOCAL_PATH))
+endif
\ No newline at end of file
diff --git a/libs/utils/ObbFile.cpp b/libs/utils/ObbFile.cpp
new file mode 100644
index 0000000..fe49300
--- /dev/null
+++ b/libs/utils/ObbFile.cpp
@@ -0,0 +1,296 @@
+/*
+ * 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.
+ */
+
+#include <errno.h>
+#include <fcntl.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#define LOG_TAG "ObbFile"
+#include <utils/Log.h>
+#include <utils/ObbFile.h>
+
+//#define DEBUG 1
+
+#define kFooterTagSize 8  /* last two 32-bit integers */
+
+#define kFooterMinSize 21 /* 32-bit signature version
+                           * 32-bit package version
+                           * 32-bit package name size
+                           * 1-character package name
+                           * 32-bit footer size
+                           * 32-bit footer marker
+                           */
+
+#define kMaxBufSize    32768 /* Maximum file read buffer */
+
+#define kSignature     0x01059983U /* ObbFile signature */
+
+#define kSigVersion    1 /* We only know about signature version 1 */
+
+/* offsets in version 1 of the header */
+#define kPackageVersionOffset 4
+#define kPackageNameLenOffset 8
+#define kPackageNameOffset    12
+
+/*
+ * TEMP_FAILURE_RETRY is defined by some, but not all, versions of
+ * <unistd.h>. (Alas, it is not as standard as we'd hoped!) So, if it's
+ * not already defined, then define it here.
+ */
+#ifndef TEMP_FAILURE_RETRY
+/* Used to retry syscalls that can return EINTR. */
+#define TEMP_FAILURE_RETRY(exp) ({         \
+    typeof (exp) _rc;                      \
+    do {                                   \
+        _rc = (exp);                       \
+    } while (_rc == -1 && errno == EINTR); \
+    _rc; })
+#endif
+
+/*
+ * Work around situations where off_t is 64-bit and use off64_t in
+ * situations where it's 32-bit.
+ */
+#ifdef OFF_T_IS_64_BIT
+#define my_lseek64 lseek
+typedef off_t my_off64_t;
+#else
+#define my_lseek64 lseek64
+typedef off64_t my_off64_t;
+#endif
+
+namespace android {
+
+ObbFile::ObbFile() :
+        mVersion(-1) {
+}
+
+ObbFile::~ObbFile() {
+}
+
+bool ObbFile::readFrom(const char* filename)
+{
+    int fd;
+    bool success = false;
+
+    fd = ::open(filename, O_RDONLY);
+    if (fd < 0) {
+        LOGW("couldn't open file %s: %s", filename, strerror(errno));
+        goto out;
+    }
+    success = readFrom(fd);
+    close(fd);
+
+    if (!success) {
+        LOGW("failed to read from %s (fd=%d)\n", filename, fd);
+    }
+
+out:
+    return success;
+}
+
+bool ObbFile::readFrom(int fd)
+{
+    if (fd < 0) {
+        LOGW("attempt to read from invalid fd\n");
+        return false;
+    }
+
+    return parseObbFile(fd);
+}
+
+bool ObbFile::parseObbFile(int fd)
+{
+    my_off64_t fileLength = my_lseek64(fd, 0, SEEK_END);
+
+    if (fileLength < kFooterMinSize) {
+        if (fileLength < 0) {
+            LOGW("error seeking in ObbFile: %s\n", strerror(errno));
+        } else {
+            LOGW("file is only %lld (less than %d minimum)\n", fileLength, kFooterMinSize);
+        }
+        return false;
+    }
+
+    ssize_t actual;
+    size_t footerSize;
+
+    {
+        my_lseek64(fd, fileLength - kFooterTagSize, SEEK_SET);
+
+        char *footer = new char[kFooterTagSize];
+        actual = TEMP_FAILURE_RETRY(read(fd, footer, kFooterTagSize));
+        if (actual != kFooterTagSize) {
+            LOGW("couldn't read footer signature: %s\n", strerror(errno));
+            return false;
+        }
+
+        unsigned int fileSig = get4LE((unsigned char*)footer + sizeof(int32_t));
+        if (fileSig != kSignature) {
+            LOGW("footer didn't match magic string (expected 0x%08x; got 0x%08x)\n",
+                    kSignature, fileSig);
+            return false;
+        }
+
+        footerSize = get4LE((unsigned char*)footer);
+        if (footerSize > (size_t)fileLength - kFooterTagSize
+                || footerSize > kMaxBufSize) {
+            LOGW("claimed footer size is too large (0x%08zx; file size is 0x%08llx)\n",
+                    footerSize, fileLength);
+            return false;
+        }
+
+        if (footerSize < kFooterMinSize) {
+            LOGW("claimed footer size is too small (%08zx; minimum size is 0x%x)\n",
+                    footerSize, kFooterMinSize);
+            return false;
+        }
+    }
+
+    my_off64_t fileOffset = fileLength - footerSize - kFooterTagSize;
+    if (my_lseek64(fd, fileOffset, SEEK_SET) != fileOffset) {
+        LOGW("seek %lld failed: %s\n", fileOffset, strerror(errno));
+        return false;
+    }
+
+    char* scanBuf = (char*)malloc(footerSize);
+    if (scanBuf == NULL) {
+        LOGW("couldn't allocate scanBuf: %s\n", strerror(errno));
+        return false;
+    }
+
+    actual = TEMP_FAILURE_RETRY(read(fd, scanBuf, footerSize));
+    // readAmount is guaranteed to be less than kMaxBufSize
+    if (actual != (ssize_t)footerSize) {
+        LOGI("couldn't read ObbFile footer: %s\n", strerror(errno));
+        free(scanBuf);
+        return false;
+    }
+
+#ifdef DEBUG
+    for (int i = 0; i < footerSize; ++i) {
+        LOGI("char: 0x%02x", scanBuf[i]);
+    }
+#endif
+
+    uint32_t sigVersion = get4LE((unsigned char*)scanBuf);
+    if (sigVersion != kSigVersion) {
+        LOGW("Unsupported ObbFile version %d\n", sigVersion);
+        free(scanBuf);
+        return false;
+    }
+
+    mVersion = (int32_t) get4LE((unsigned char*)scanBuf + kPackageVersionOffset);
+
+    uint32_t packageNameLen = get4LE((unsigned char*)scanBuf + kPackageNameLenOffset);
+    if (packageNameLen <= 0
+            || packageNameLen > (footerSize - kPackageNameOffset)) {
+        LOGW("bad ObbFile package name length (0x%04x; 0x%04x possible)\n",
+                packageNameLen, footerSize - kPackageNameOffset);
+        free(scanBuf);
+        return false;
+    }
+
+    char* packageName = reinterpret_cast<char*>(scanBuf + kPackageNameOffset);
+    mPackageName = String8(const_cast<char*>(packageName), packageNameLen);
+
+    free(scanBuf);
+
+#ifdef DEBUG
+    LOGI("Obb scan succeeded: packageName=%s, version=%d\n", mPackageName.string(), mVersion);
+#endif
+
+    return true;
+}
+
+bool ObbFile::writeTo(const char* filename)
+{
+    int fd;
+    bool success = false;
+
+    fd = ::open(filename, O_WRONLY);
+    if (fd < 0) {
+        goto out;
+    }
+    success = writeTo(fd);
+    close(fd);
+
+out:
+    if (!success) {
+        LOGW("failed to write to %s: %s\n", filename, strerror(errno));
+    }
+    return success;
+}
+
+bool ObbFile::writeTo(int fd)
+{
+    if (fd < 0) {
+        return false;
+    }
+
+    my_lseek64(fd, 0, SEEK_END);
+
+    if (mPackageName.size() == 0 || mVersion == -1) {
+        LOGW("tried to write uninitialized ObbFile data");
+        return false;
+    }
+
+    unsigned char intBuf[sizeof(uint32_t)+1];
+    memset(&intBuf, 0, sizeof(intBuf));
+
+    put4LE(intBuf, kSigVersion);
+    if (write(fd, &intBuf, sizeof(uint32_t)) != (ssize_t)sizeof(uint32_t)) {
+        LOGW("couldn't write signature version: %s", strerror(errno));
+        return false;
+    }
+
+    put4LE(intBuf, mVersion);
+    if (write(fd, &intBuf, sizeof(uint32_t)) != (ssize_t)sizeof(uint32_t)) {
+        LOGW("couldn't write package version");
+        return false;
+    }
+
+    size_t packageNameLen = mPackageName.size();
+    put4LE(intBuf, packageNameLen);
+    if (write(fd, &intBuf, sizeof(uint32_t)) != (ssize_t)sizeof(uint32_t)) {
+        LOGW("couldn't write package name length: %s", strerror(errno));
+        return false;
+    }
+
+    if (write(fd, mPackageName.string(), packageNameLen) != (ssize_t)packageNameLen) {
+        LOGW("couldn't write package name: %s", strerror(errno));
+        return false;
+    }
+
+    put4LE(intBuf, 3*sizeof(uint32_t) + packageNameLen);
+    if (write(fd, &intBuf, sizeof(uint32_t)) != (ssize_t)sizeof(uint32_t)) {
+        LOGW("couldn't write footer size: %s", strerror(errno));
+        return false;
+    }
+
+    put4LE(intBuf, kSignature);
+    if (write(fd, &intBuf, sizeof(uint32_t)) != (ssize_t)sizeof(uint32_t)) {
+        LOGW("couldn't write footer magic signature: %s", strerror(errno));
+        return false;
+    }
+
+    return true;
+}
+
+}
diff --git a/libs/utils/PollLoop.cpp b/libs/utils/PollLoop.cpp
index 58fe141..f740fa0 100644
--- a/libs/utils/PollLoop.cpp
+++ b/libs/utils/PollLoop.cpp
@@ -25,8 +25,9 @@
 static bool gHaveTLS = false;
 static pthread_key_t gTLS = 0;
 
-PollLoop::PollLoop() :
-        mPolling(false), mWaiters(0) {
+PollLoop::PollLoop(bool allowNonCallbacks) :
+        mAllowNonCallbacks(allowNonCallbacks), mPolling(false),
+        mWaiters(0), mPendingFdsPos(0) {
     openWakePipe();
 }
 
@@ -106,7 +107,18 @@
     //       method is currently only called by the destructor.
 }
 
-bool PollLoop::pollOnce(int timeoutMillis) {
+int32_t PollLoop::pollOnce(int timeoutMillis, int* outEvents, void** outData) {
+    // If there are still pending fds from the last call, dispatch those
+    // first, to avoid an earlier fd from starving later ones.
+    const size_t pendingFdsCount = mPendingFds.size();
+    if (mPendingFdsPos < pendingFdsCount) {
+        const PendingCallback& pending = mPendingFds.itemAt(mPendingFdsPos);
+        mPendingFdsPos++;
+        if (outEvents != NULL) *outEvents = pending.events;
+        if (outData != NULL) *outData = pending.data;
+        return pending.fd;
+    }
+    
     mLock.lock();
     while (mWaiters != 0) {
         mResume.wait(mLock);
@@ -114,7 +126,7 @@
     mPolling = true;
     mLock.unlock();
 
-    bool result;
+    int32_t result;
     size_t requestedCount = mRequestedFds.size();
 
 #if DEBUG_POLL_AND_WAKE
@@ -131,7 +143,7 @@
 #if DEBUG_POLL_AND_WAKE
         LOGD("%p ~ pollOnce - timeout", this);
 #endif
-        result = false;
+        result = POLL_TIMEOUT;
         goto Done;
     }
 
@@ -143,7 +155,7 @@
         if (errno != EINTR) {
             LOGW("Poll failed with an unexpected error, errno=%d", errno);
         }
-        result = false;
+        result = POLL_ERROR;
         goto Done;
     }
 
@@ -156,38 +168,44 @@
 #endif
 
     mPendingCallbacks.clear();
+    mPendingFds.clear();
+    mPendingFdsPos = 0;
+    if (outEvents != NULL) *outEvents = 0;
+    if (outData != NULL) *outData = NULL;
+    
+    result = POLL_CALLBACK;
     for (size_t i = 0; i < requestedCount; i++) {
         const struct pollfd& requestedFd = mRequestedFds.itemAt(i);
 
         short revents = requestedFd.revents;
         if (revents) {
             const RequestedCallback& requestedCallback = mRequestedCallbacks.itemAt(i);
-            Callback callback = requestedCallback.callback;
-            ALooper_callbackFunc* looperCallback = requestedCallback.looperCallback;
+            PendingCallback pending;
+            pending.fd = requestedFd.fd;
+            pending.events = revents;
+            pending.callback = requestedCallback.callback;
+            pending.looperCallback = requestedCallback.looperCallback;
+            pending.data = requestedCallback.data;
 
-            if (callback || looperCallback) {
-                PendingCallback pendingCallback;
-                pendingCallback.fd = requestedFd.fd;
-                pendingCallback.events = requestedFd.revents;
-                pendingCallback.callback = callback;
-                pendingCallback.looperCallback = looperCallback;
-                pendingCallback.data = requestedCallback.data;
-                mPendingCallbacks.push(pendingCallback);
-            } else {
-                if (requestedFd.fd == mWakeReadPipeFd) {
-#if DEBUG_POLL_AND_WAKE
-                    LOGD("%p ~ pollOnce - awoken", this);
-#endif
-                    char buffer[16];
-                    ssize_t nRead;
-                    do {
-                        nRead = read(mWakeReadPipeFd, buffer, sizeof(buffer));
-                    } while (nRead == sizeof(buffer));
+            if (pending.callback || pending.looperCallback) {
+                mPendingCallbacks.push(pending);
+            } else if (pending.fd != mWakeReadPipeFd) {
+                if (result == POLL_CALLBACK) {
+                    result = pending.fd;
+                    if (outEvents != NULL) *outEvents = pending.events;
+                    if (outData != NULL) *outData = pending.data;
                 } else {
-#if DEBUG_POLL_AND_WAKE || DEBUG_CALLBACKS
-                    LOGD("%p ~ pollOnce - fd %d has no callback!", this, requestedFd.fd);
-#endif
+                    mPendingFds.push(pending);
                 }
+            } else {
+#if DEBUG_POLL_AND_WAKE
+                LOGD("%p ~ pollOnce - awoken", this);
+#endif
+                char buffer[16];
+                ssize_t nRead;
+                do {
+                    nRead = read(mWakeReadPipeFd, buffer, sizeof(buffer));
+                } while (nRead == sizeof(buffer));
             }
 
             respondedCount -= 1;
@@ -196,7 +214,6 @@
             }
         }
     }
-    result = true;
 
 Done:
     mLock.lock();
@@ -206,7 +223,7 @@
     }
     mLock.unlock();
 
-    if (result) {
+    if (result == POLL_CALLBACK || result >= 0) {
         size_t pendingCount = mPendingCallbacks.size();
         for (size_t i = 0; i < pendingCount; i++) {
             const PendingCallback& pendingCallback = mPendingCallbacks.itemAt(i);
@@ -247,6 +264,10 @@
     }
 }
 
+bool PollLoop::getAllowNonCallbacks() const {
+    return mAllowNonCallbacks;
+}
+
 void PollLoop::setCallback(int fd, int events, Callback callback, void* data) {
     setCallbackCommon(fd, events, callback, NULL, data);
 }
@@ -263,12 +284,18 @@
     LOGD("%p ~ setCallback - fd=%d, events=%d", this, fd, events);
 #endif
 
-    if (! events || (! callback && ! looperCallback)) {
-        LOGE("Invalid attempt to set a callback with no selected poll events or no callback.");
+    if (! events) {
+        LOGE("Invalid attempt to set a callback with no selected poll events.");
         removeCallback(fd);
         return;
     }
 
+    if (! callback && ! looperCallback && ! mAllowNonCallbacks) {
+        LOGE("Invalid attempt to set NULL callback but not allowed.");
+        removeCallback(fd);
+        return;
+    }
+    
     wakeAndLock();
 
     struct pollfd requestedFd;
diff --git a/libs/utils/tests/Android.mk b/libs/utils/tests/Android.mk
index 92ebfd7c..b9f206a 100644
--- a/libs/utils/tests/Android.mk
+++ b/libs/utils/tests/Android.mk
@@ -2,7 +2,11 @@
 LOCAL_PATH := $(call my-dir)
 include $(CLEAR_VARS)
 
+ifneq ($(TARGET_SIMULATOR),true)
+
+# Build the unit tests.
 test_src_files := \
+	ObbFile_test.cpp \
 	PollLoop_test.cpp
 
 shared_libraries := \
@@ -36,3 +40,5 @@
     $(eval LOCAL_MODULE_TAGS := $(module_tags)) \
     $(eval include $(BUILD_EXECUTABLE)) \
 )
+
+endif
\ No newline at end of file
diff --git a/libs/utils/tests/ObbFile_test.cpp b/libs/utils/tests/ObbFile_test.cpp
new file mode 100644
index 0000000..29bb70a
--- /dev/null
+++ b/libs/utils/tests/ObbFile_test.cpp
@@ -0,0 +1,82 @@
+/*
+ * 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.
+ */
+
+#define LOG_TAG "ObbFile_test"
+#include <utils/Log.h>
+#include <utils/ObbFile.h>
+#include <utils/RefBase.h>
+#include <utils/String8.h>
+
+#include <gtest/gtest.h>
+
+#include <fcntl.h>
+
+namespace android {
+
+#define TEST_FILENAME "/test.obb"
+
+class ObbFileTest : public testing::Test {
+protected:
+    sp<ObbFile> mObbFile;
+    char* mExternalStorage;
+    char* mFileName;
+
+    virtual void SetUp() {
+        mObbFile = new ObbFile();
+        mExternalStorage = getenv("EXTERNAL_STORAGE");
+
+        const int totalLen = strlen(mExternalStorage) + strlen(TEST_FILENAME) + 1;
+        mFileName = new char[totalLen];
+        snprintf(mFileName, totalLen, "%s%s", mExternalStorage, TEST_FILENAME);
+
+        int fd = ::open(mFileName, O_CREAT | O_TRUNC);
+        if (fd < 0) {
+            FAIL() << "Couldn't create " << mFileName << " for tests";
+        }
+    }
+
+    virtual void TearDown() {
+    }
+};
+
+TEST_F(ObbFileTest, ReadFailure) {
+    EXPECT_FALSE(mObbFile->readFrom(-1))
+            << "No failure on invalid file descriptor";
+}
+
+TEST_F(ObbFileTest, WriteThenRead) {
+    const char* packageName = "com.example.obbfile";
+    const int32_t versionNum = 1;
+
+    mObbFile->setPackageName(String8(packageName));
+    mObbFile->setVersion(versionNum);
+
+    EXPECT_TRUE(mObbFile->writeTo(mFileName))
+            << "couldn't write to fake .obb file";
+
+    mObbFile = new ObbFile();
+
+    EXPECT_TRUE(mObbFile->readFrom(mFileName))
+            << "couldn't read from fake .obb file";
+
+    EXPECT_EQ(versionNum, mObbFile->getVersion())
+            << "version didn't come out the same as it went in";
+    const char* currentPackageName = mObbFile->getPackageName().string();
+    EXPECT_STREQ(packageName, currentPackageName)
+            << "package name didn't come out the same as it went in";
+}
+
+}
diff --git a/libs/utils/tests/PollLoop_test.cpp b/libs/utils/tests/PollLoop_test.cpp
index 4848c0f..02f1808 100644
--- a/libs/utils/tests/PollLoop_test.cpp
+++ b/libs/utils/tests/PollLoop_test.cpp
@@ -87,7 +87,7 @@
     sp<PollLoop> mPollLoop;
 
     virtual void SetUp() {
-        mPollLoop = new PollLoop();
+        mPollLoop = new PollLoop(false);
     }
 
     virtual void TearDown() {
@@ -98,26 +98,26 @@
 
 TEST_F(PollLoopTest, PollOnce_WhenNonZeroTimeoutAndNotAwoken_WaitsForTimeoutAndReturnsFalse) {
     StopWatch stopWatch("pollOnce");
-    bool result = mPollLoop->pollOnce(100);
+    int32_t result = mPollLoop->pollOnce(100);
     int32_t elapsedMillis = ns2ms(stopWatch.elapsedTime());
 
     EXPECT_NEAR(100, elapsedMillis, TIMING_TOLERANCE_MS)
             << "elapsed time should approx. equal timeout";
-    EXPECT_FALSE(result)
-            << "pollOnce result should be false because timeout occurred";
+    EXPECT_EQ(result, PollLoop::POLL_TIMEOUT)
+            << "pollOnce result should be POLL_TIMEOUT";
 }
 
 TEST_F(PollLoopTest, PollOnce_WhenNonZeroTimeoutAndAwokenBeforeWaiting_ImmediatelyReturnsTrue) {
     mPollLoop->wake();
 
     StopWatch stopWatch("pollOnce");
-    bool result = mPollLoop->pollOnce(1000);
+    int32_t result = mPollLoop->pollOnce(1000);
     int32_t elapsedMillis = ns2ms(stopWatch.elapsedTime());
 
     EXPECT_NEAR(0, elapsedMillis, TIMING_TOLERANCE_MS)
             << "elapsed time should approx. zero because wake() was called before waiting";
-    EXPECT_TRUE(result)
-            << "pollOnce result should be true because loop was awoken";
+    EXPECT_EQ(result, PollLoop::POLL_CALLBACK)
+            << "pollOnce result should be POLL_CALLBACK because loop was awoken";
 }
 
 TEST_F(PollLoopTest, PollOnce_WhenNonZeroTimeoutAndAwokenWhileWaiting_PromptlyReturnsTrue) {
@@ -125,24 +125,24 @@
     delayedWake->run();
 
     StopWatch stopWatch("pollOnce");
-    bool result = mPollLoop->pollOnce(1000);
+    int32_t result = mPollLoop->pollOnce(1000);
     int32_t elapsedMillis = ns2ms(stopWatch.elapsedTime());
 
     EXPECT_NEAR(100, elapsedMillis, TIMING_TOLERANCE_MS)
             << "elapsed time should approx. equal wake delay";
-    EXPECT_TRUE(result)
-            << "pollOnce result should be true because loop was awoken";
+    EXPECT_EQ(result, PollLoop::POLL_CALLBACK)
+            << "pollOnce result should be POLL_CALLBACK because loop was awoken";
 }
 
 TEST_F(PollLoopTest, PollOnce_WhenZeroTimeoutAndNoRegisteredFDs_ImmediatelyReturnsFalse) {
     StopWatch stopWatch("pollOnce");
-    bool result = mPollLoop->pollOnce(0);
+    int32_t result = mPollLoop->pollOnce(0);
     int32_t elapsedMillis = ns2ms(stopWatch.elapsedTime());
 
     EXPECT_NEAR(0, elapsedMillis, TIMING_TOLERANCE_MS)
             << "elapsed time should be approx. zero";
-    EXPECT_FALSE(result)
-            << "pollOnce result should be false because timeout occurred";
+    EXPECT_EQ(result, PollLoop::POLL_TIMEOUT)
+            << "pollOnce result should be POLL_TIMEOUT";
 }
 
 TEST_F(PollLoopTest, PollOnce_WhenZeroTimeoutAndNoSignalledFDs_ImmediatelyReturnsFalse) {
@@ -152,13 +152,13 @@
     handler.setCallback(mPollLoop, pipe.receiveFd, POLL_IN);
 
     StopWatch stopWatch("pollOnce");
-    bool result = mPollLoop->pollOnce(0);
+    int32_t result = mPollLoop->pollOnce(0);
     int32_t elapsedMillis = ns2ms(stopWatch.elapsedTime());
 
     EXPECT_NEAR(0, elapsedMillis, TIMING_TOLERANCE_MS)
             << "elapsed time should be approx. zero";
-    EXPECT_FALSE(result)
-            << "pollOnce result should be false because timeout occurred";
+    EXPECT_EQ(result, PollLoop::POLL_TIMEOUT)
+            << "pollOnce result should be POLL_TIMEOUT";
     EXPECT_EQ(0, handler.callbackCount)
             << "callback should not have been invoked because FD was not signalled";
 }
@@ -171,13 +171,13 @@
     handler.setCallback(mPollLoop, pipe.receiveFd, POLL_IN);
 
     StopWatch stopWatch("pollOnce");
-    bool result = mPollLoop->pollOnce(0);
+    int32_t result = mPollLoop->pollOnce(0);
     int32_t elapsedMillis = ns2ms(stopWatch.elapsedTime());
 
     EXPECT_NEAR(0, elapsedMillis, TIMING_TOLERANCE_MS)
             << "elapsed time should be approx. zero";
-    EXPECT_TRUE(result)
-            << "pollOnce result should be true because FD was signalled";
+    EXPECT_EQ(result, PollLoop::POLL_CALLBACK)
+            << "pollOnce result should be POLL_CALLBACK because FD was signalled";
     EXPECT_EQ(1, handler.callbackCount)
             << "callback should be invoked exactly once";
     EXPECT_EQ(pipe.receiveFd, handler.fd)
@@ -193,13 +193,13 @@
     handler.setCallback(mPollLoop, pipe.receiveFd, POLL_IN);
 
     StopWatch stopWatch("pollOnce");
-    bool result = mPollLoop->pollOnce(100);
+    int32_t result = mPollLoop->pollOnce(100);
     int32_t elapsedMillis = ns2ms(stopWatch.elapsedTime());
 
     EXPECT_NEAR(100, elapsedMillis, TIMING_TOLERANCE_MS)
             << "elapsed time should approx. equal timeout";
-    EXPECT_FALSE(result)
-            << "pollOnce result should be false because timeout occurred";
+    EXPECT_EQ(result, PollLoop::POLL_TIMEOUT)
+            << "pollOnce result should be POLL_TIMEOUT";
     EXPECT_EQ(0, handler.callbackCount)
             << "callback should not have been invoked because FD was not signalled";
 }
@@ -212,15 +212,15 @@
     handler.setCallback(mPollLoop, pipe.receiveFd, POLL_IN);
 
     StopWatch stopWatch("pollOnce");
-    bool result = mPollLoop->pollOnce(100);
+    int32_t result = mPollLoop->pollOnce(100);
     int32_t elapsedMillis = ns2ms(stopWatch.elapsedTime());
 
     ASSERT_EQ(OK, pipe.readSignal())
             << "signal should actually have been written";
     EXPECT_NEAR(0, elapsedMillis, TIMING_TOLERANCE_MS)
             << "elapsed time should be approx. zero";
-    EXPECT_TRUE(result)
-            << "pollOnce result should be true because FD was signalled";
+    EXPECT_EQ(result, PollLoop::POLL_CALLBACK)
+            << "pollOnce result should be POLL_CALLBACK because FD was signalled";
     EXPECT_EQ(1, handler.callbackCount)
             << "callback should be invoked exactly once";
     EXPECT_EQ(pipe.receiveFd, handler.fd)
@@ -238,15 +238,15 @@
     delayedWriteSignal->run();
 
     StopWatch stopWatch("pollOnce");
-    bool result = mPollLoop->pollOnce(1000);
+    int32_t result = mPollLoop->pollOnce(1000);
     int32_t elapsedMillis = ns2ms(stopWatch.elapsedTime());
 
     ASSERT_EQ(OK, pipe.readSignal())
             << "signal should actually have been written";
     EXPECT_NEAR(100, elapsedMillis, TIMING_TOLERANCE_MS)
             << "elapsed time should approx. equal signal delay";
-    EXPECT_TRUE(result)
-            << "pollOnce result should be true because FD was signalled";
+    EXPECT_EQ(result, PollLoop::POLL_CALLBACK)
+            << "pollOnce result should be POLL_CALLBACK because FD was signalled";
     EXPECT_EQ(1, handler.callbackCount)
             << "callback should be invoked exactly once";
     EXPECT_EQ(pipe.receiveFd, handler.fd)
@@ -264,15 +264,15 @@
     mPollLoop->removeCallback(pipe.receiveFd);
 
     StopWatch stopWatch("pollOnce");
-    bool result = mPollLoop->pollOnce(100);
+    int32_t result = mPollLoop->pollOnce(100);
     int32_t elapsedMillis = ns2ms(stopWatch.elapsedTime());
 
     ASSERT_EQ(OK, pipe.readSignal())
             << "signal should actually have been written";
     EXPECT_NEAR(100, elapsedMillis, TIMING_TOLERANCE_MS)
             << "elapsed time should approx. equal timeout because FD was no longer registered";
-    EXPECT_FALSE(result)
-            << "pollOnce result should be false because timeout occurred";
+    EXPECT_EQ(result, PollLoop::POLL_TIMEOUT)
+            << "pollOnce result should be POLL_TIMEOUT";
     EXPECT_EQ(0, handler.callbackCount)
             << "callback should not be invoked";
 }
@@ -287,15 +287,15 @@
     pipe.writeSignal();
 
     StopWatch stopWatch("pollOnce");
-    bool result = mPollLoop->pollOnce(0);
+    int32_t result = mPollLoop->pollOnce(0);
     int32_t elapsedMillis = ns2ms(stopWatch.elapsedTime());
 
     ASSERT_EQ(OK, pipe.readSignal())
             << "signal should actually have been written";
     EXPECT_NEAR(0, elapsedMillis, TIMING_TOLERANCE_MS)
             << "elapsed time should approx. equal zero because FD was already signalled";
-    EXPECT_TRUE(result)
-            << "pollOnce result should be true because FD was signalled";
+    EXPECT_EQ(result, PollLoop::POLL_CALLBACK)
+            << "pollOnce result should be POLL_CALLBACK because FD was signalled";
     EXPECT_EQ(1, handler.callbackCount)
             << "callback should be invoked";
 
@@ -310,8 +310,8 @@
             << "signal should actually have been written";
     EXPECT_NEAR(0, elapsedMillis, TIMING_TOLERANCE_MS)
             << "elapsed time should approx. equal zero because timeout was zero";
-    EXPECT_FALSE(result)
-            << "pollOnce result should be false because timeout occurred";
+    EXPECT_EQ(result, PollLoop::POLL_TIMEOUT)
+            << "pollOnce result should be POLL_TIMEOUT";
     EXPECT_EQ(1, handler.callbackCount)
             << "callback should not be invoked this time";
 }
@@ -351,15 +351,15 @@
     pipe.writeSignal(); // would cause FD to be considered signalled
 
     StopWatch stopWatch("pollOnce");
-    bool result = mPollLoop->pollOnce(100);
+    int32_t result = mPollLoop->pollOnce(100);
     int32_t elapsedMillis = ns2ms(stopWatch.elapsedTime());
 
     ASSERT_EQ(OK, pipe.readSignal())
             << "signal should actually have been written";
     EXPECT_NEAR(0, elapsedMillis, TIMING_TOLERANCE_MS)
             << "elapsed time should approx. zero because FD was already signalled";
-    EXPECT_TRUE(result)
-            << "pollOnce result should be true because FD was signalled";
+    EXPECT_EQ(result, PollLoop::POLL_CALLBACK)
+            << "pollOnce result should be POLL_CALLBACK because FD was signalled";
     EXPECT_EQ(0, handler1.callbackCount)
             << "original handler callback should not be invoked because it was replaced";
     EXPECT_EQ(1, handler2.callbackCount)
diff --git a/media/java/android/media/AudioFormat.java b/media/java/android/media/AudioFormat.java
index b3aae72..403a68e 100644
--- a/media/java/android/media/AudioFormat.java
+++ b/media/java/android/media/AudioFormat.java
@@ -31,9 +31,9 @@
     public static final int ENCODING_INVALID = 0;
     /** Default audio data format */
     public static final int ENCODING_DEFAULT = 1;
-    /** Audio data format: PCM 16 bit per sample */
+    /** Audio data format: PCM 16 bit per sample. Guaranteed to be supported by devices. */
     public static final int ENCODING_PCM_16BIT = 2; // accessed by native code
-    /** Audio data format: PCM 8 bit per sample */
+    /** Audio data format: PCM 8 bit per sample. Not guaranteed to be supported by devices. */
     public static final int ENCODING_PCM_8BIT = 3;  // accessed by native code
 
     /** Invalid audio channel configuration */
diff --git a/media/java/android/media/AudioRecord.java b/media/java/android/media/AudioRecord.java
index c48eaad..c567a6e 100644
--- a/media/java/android/media/AudioRecord.java
+++ b/media/java/android/media/AudioRecord.java
@@ -194,11 +194,13 @@
      * Class constructor.
      * @param audioSource the recording source. See {@link MediaRecorder.AudioSource} for
      *    recording source definitions.
-     * @param sampleRateInHz the sample rate expressed in Hertz. Examples of rates are (but
-     *   not limited to) 44100, 22050 and 11025.
+     * @param sampleRateInHz the sample rate expressed in Hertz. 44100Hz is currently the only
+     *   rate that is guaranteed to work on all devices, but other rates such as 22050,
+     *   16000, and 11025 may work on some devices.
      * @param channelConfig describes the configuration of the audio channels. 
      *   See {@link AudioFormat#CHANNEL_IN_MONO} and
-     *   {@link AudioFormat#CHANNEL_IN_STEREO}
+     *   {@link AudioFormat#CHANNEL_IN_STEREO}.  {@link AudioFormat#CHANNEL_IN_MONO} is guaranteed
+     *   to work on all devices.
      * @param audioFormat the format in which the audio data is represented. 
      *   See {@link AudioFormat#ENCODING_PCM_16BIT} and 
      *   {@link AudioFormat#ENCODING_PCM_8BIT}
@@ -444,6 +446,8 @@
      *  or {@link #ERROR} if the implementation was unable to query the hardware for its 
      *  output properties, 
      *   or the minimum buffer size expressed in bytes.
+     * @see #AudioRecord(int, int, int, int, int) for more information on valid
+     *   configuration values.
      */
     static public int getMinBufferSize(int sampleRateInHz, int channelConfig, int audioFormat) {
         int channelCount = 0;
diff --git a/media/java/android/media/BassBoost.java b/media/java/android/media/BassBoost.java
new file mode 100644
index 0000000..ef4ce05
--- /dev/null
+++ b/media/java/android/media/BassBoost.java
@@ -0,0 +1,213 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.media;
+
+import android.app.Activity;
+import android.content.Context;
+import android.content.Intent;
+import android.os.Bundle;
+import android.util.Log;
+import java.nio.ByteOrder;
+import java.nio.ByteBuffer;
+import java.nio.CharBuffer;
+
+import android.media.AudioEffect;
+
+/**
+ * Bass boost is an audio effect to boost or amplify low frequencies of the sound. It is comparable
+ * to an simple equalizer but limited to one band amplification in the low frequency range.
+ * <p>An application creates a BassBoost object to instantiate and control a bass boost engine
+ * in the audio framework.
+ * <p>The methods, parameter types and units exposed by the BassBoost implementation are directly
+ * mapping those defined by the OpenSL ES 1.0.1 Specification (http://www.khronos.org/opensles/)
+ * for the SLBassBoostItf interface. Please refer to this specification for more details.
+ * <p>To attach the BassBoost to a particular AudioTrack or MediaPlayer, specify the audio session
+ * ID of this AudioTrack or MediaPlayer when constructing the BassBoost. If the audio session ID 0
+ * is specified, the BassBoost applies to the main audio output mix.
+ // TODO when AudioEffect is unhidden
+ // <p> See {_at_link android.media.AudioEffect} class for more details on controlling audio effects.
+ *
+ * {@hide Pending API council review}
+ */
+
+public class BassBoost extends AudioEffect {
+
+    private final static String TAG = "BassBoost";
+
+    // These constants must be synchronized with those in
+    // frameworks/base/include/media/EffectBassBoostApi.h
+    /**
+     * Is strength parameter supported by bass boost engine. Parameter ID for getParameter().
+     */
+    public static final int PARAM_STRENGTH_SUPPORTED = 0;
+    /**
+     * Bass boost effect strength. Parameter ID for
+     * {@link android.media.BassBoost.OnParameterChangeListener}
+     */
+    public static final int PARAM_STRENGTH = 1;
+
+    /**
+     * Indicates if strength parameter is supported by the bass boost engine
+     */
+    private boolean mStrengthSupported = false;
+
+    /**
+     * Registered listener for parameter changes.
+     */
+    private OnParameterChangeListener mParamListener = null;
+
+    /**
+     * Listener used internally to to receive raw parameter change event from AudioEffect super class
+     */
+    private BaseParameterListener mBaseParamListener = null;
+
+    /**
+     * Lock for access to mParamListener
+     */
+    private final Object mParamListenerLock = new Object();
+
+    /**
+     * Class constructor.
+     * @param priority the priority level requested by the application for controlling the BassBoost
+     * engine. As the same engine can be shared by several applications, this parameter indicates
+     * how much the requesting application needs control of effect parameters. The normal priority
+     * is 0, above normal is a positive number, below normal a negative number.
+     * @param audioSession  System wide unique audio session identifier. If audioSession
+     *  is not 0, the BassBoost will be attached to the MediaPlayer or AudioTrack in the
+     *  same audio session. Otherwise, the BassBoost will apply to the output mix.
+     *
+     * @throws java.lang.IllegalStateException
+     * @throws java.lang.IllegalArgumentException
+     * @throws java.lang.UnsupportedOperationException
+     * @throws java.lang.RuntimeException
+     */
+    public BassBoost(int priority, int audioSession)
+    throws IllegalStateException, IllegalArgumentException,
+           UnsupportedOperationException, RuntimeException {
+        super(EFFECT_TYPE_BASS_BOOST, EFFECT_TYPE_NULL, priority, audioSession);
+
+        short[] value = new short[1];
+        checkStatus(getParameter(PARAM_STRENGTH_SUPPORTED, value));
+        mStrengthSupported = (value[0] != 0);
+    }
+
+    /**
+     * Indicates whether setting strength is supported. If this method returns false, only one
+     * strength is supported and the setStrength() method always rounds to that value.
+     * @return true is strength parameter is supported, false otherwise
+     */
+    public boolean getStrengthSupported() {
+       return mStrengthSupported;
+    }
+
+    /**
+     * Sets the strength of the bass boost effect. If the implementation does not support per mille
+     * accuracy for setting the strength, it is allowed to round the given strength to the nearest
+     * supported value. You can use the {@link #getRoundedStrength()} method to query the
+     * (possibly rounded) value that was actually set.
+     * @param strength Strength of the effect. The valid range for strength strength is [0, 1000],
+     * where 0 per mille designates the mildest effect and 1000 per mille designates the strongest.
+     * @throws IllegalStateException
+     * @throws IllegalArgumentException
+     * @throws UnsupportedOperationException
+     */
+    public void setStrength(short strength)
+    throws IllegalStateException, IllegalArgumentException, UnsupportedOperationException {
+        checkStatus(setParameter(PARAM_STRENGTH, strength));
+    }
+
+    /**
+     * Gets the current strength of the effect.
+     * @return The strength of the effect. The valid range for strength is [0, 1000], where 0 per
+     * mille designates the mildest effect and 1000 per mille the strongest
+     * @throws IllegalStateException
+     * @throws IllegalArgumentException
+     * @throws UnsupportedOperationException
+     */
+    public short getRoundedStrength()
+    throws IllegalStateException, IllegalArgumentException, UnsupportedOperationException {
+        short[] value = new short[1];
+        checkStatus(getParameter(PARAM_STRENGTH, value));
+        return value[0];
+    }
+
+    /**
+     * The OnParameterChangeListener interface defines a method called by the BassBoost when a
+     * parameter value has changed.
+     */
+    public interface OnParameterChangeListener  {
+        /**
+         * Method called when a parameter value has changed. The method is called only if the
+         * parameter was changed by another application having the control of the same
+         * BassBoost engine.
+         * @param effect the BassBoost on which the interface is registered.
+         * @param status status of the set parameter operation.
+         // TODO when AudioEffect is unhidden
+         // See {_at_link android.media.AudioEffect#setParameter(byte[], byte[])}.
+         * @param param ID of the modified parameter. See {@link #PARAM_STRENGTH} ...
+         * @param value the new parameter value.
+         */
+        void onParameterChange(BassBoost effect, int status, int param, short value);
+    }
+
+    /**
+     * Listener used internally to receive unformatted parameter change events from AudioEffect
+     * super class.
+     */
+    private class BaseParameterListener implements AudioEffect.OnParameterChangeListener {
+        private BaseParameterListener() {
+
+        }
+        public void onParameterChange(AudioEffect effect, int status, byte[] param, byte[] value) {
+            OnParameterChangeListener l = null;
+
+            synchronized (mParamListenerLock) {
+                if (mParamListener != null) {
+                    l = mParamListener;
+                }
+            }
+            if (l != null) {
+                int p = -1;
+                short v = -1;
+
+                if (param.length == 4) {
+                    p = byteArrayToInt(param, 0);
+                }
+                if (value.length == 2) {
+                    v = byteArrayToShort(value, 0);
+                }
+                if (p != -1 && v != -1) {
+                    l.onParameterChange(BassBoost.this, status, p, v);
+                }
+            }
+        }
+    }
+
+    /**
+     * Registers an OnParameterChangeListener interface.
+     * @param listener OnParameterChangeListener interface registered
+     */
+    public void setParameterListener(OnParameterChangeListener listener) {
+        synchronized (mParamListenerLock) {
+            if (mParamListener == null) {
+                mParamListener = listener;
+                mBaseParamListener = new BaseParameterListener();
+                super.setParameterListener(mBaseParamListener);
+            }
+        }
+    }
+}
diff --git a/media/java/android/media/EnvironmentalReverb.java b/media/java/android/media/EnvironmentalReverb.java
new file mode 100644
index 0000000..88230fc
--- /dev/null
+++ b/media/java/android/media/EnvironmentalReverb.java
@@ -0,0 +1,504 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.media;
+
+import android.app.Activity;
+import android.content.Context;
+import android.content.Intent;
+import android.os.Bundle;
+import android.util.Log;
+import java.nio.ByteOrder;
+import java.nio.ByteBuffer;
+
+import android.media.AudioEffect;
+
+/**
+ * A sound generated within a room travels in many directions. The listener first hears the
+ * direct sound from the source itself. Later, he or she hears discrete echoes caused by sound
+ * bouncing off nearby walls, the ceiling and the floor. As sound waves arrive after
+ * undergoing more and more reflections, individual reflections become indistinguishable and
+ * the listener hears continuous reverberation that decays over time.
+ * Reverb is vital for modeling a listener's environment. It can be used in music applications
+ * to simulate music being played back in various environments, or in games to immerse the
+ * listener within the game's environment.
+ * The EnvironmentalReverb class allows an application to control each reverb engine property in a
+ * global reverb environment and is more suitable for games. For basic control, more suitable for
+ * music applications, it is recommended to use the
+ // TODO when PresetReverb is unhidden
+ // {_at_link android.media.PresetReverb} class.
+ * <p>An application creates a EnvironmentalReverb object to instantiate and control a reverb engine
+ * in the audio framework.
+ * <p>The methods, parameter types and units exposed by the EnvironmentalReverb implementation are
+ * directly mapping those defined by the OpenSL ES 1.0.1 Specification
+ * (http://www.khronos.org/opensles/) for the SLEnvironmentalReverbItf interface.
+ * Please refer to this specification for more details.
+ * <p>The EnvironmentalReverb is an output mix auxiliary effect and should be created on
+ * Audio session 0. In order for a MediaPlayer or AudioTrack to be fed into this effect,
+ * they must be explicitely attached to it and a send level must be specified. Use the effect ID
+ * returned by getId() method to designate this particular effect when attaching it to the
+ * MediaPlayer or AudioTrack.
+ // TODO when AudioEffect is unhidden
+ // <p> See {_at_link android.media.AudioEffect} class for more details on controlling
+ * audio effects.
+ *
+ * {@hide Pending API council review}
+ */
+
+public class EnvironmentalReverb extends AudioEffect {
+
+    private final static String TAG = "EnvironmentalReverb";
+
+    // These constants must be synchronized with those in
+    // frameworks/base/include/media/EffectEnvironmentalReverbApi.h
+
+    /**
+     * Room level. Parameter ID for
+     * {@link android.media.EnvironmentalReverb.OnParameterChangeListener}
+     */
+    public static final int PARAM_ROOM_LEVEL = 0;
+    /**
+     * Room HF level. Parameter ID for OnParameterChangeListener
+     */
+    public static final int PARAM_ROOM_HF_LEVEL = 1;
+    /**
+     * Decay time. Parameter ID for OnParameterChangeListener
+     */
+    public static final int PARAM_DECAY_TIME = 2;
+    /**
+     * Decay HF ratio. Parameter ID for OnParameterChangeListener
+     */
+    public static final int PARAM_DECAY_HF_RATIO = 3;
+    /**
+     * Early reflections level. Parameter ID for OnParameterChangeListener
+     */
+    public static final int PARAM_REFLECTIONS_LEVEL = 4;
+    /**
+     * Early reflections delay. Parameter ID for OnParameterChangeListener
+     */
+    public static final int PARAM_REFLECTIONS_DELAY = 5;
+    /**
+     * Reverb level. Parameter ID for OnParameterChangeListener
+     */
+    public static final int PARAM_REVERB_LEVEL = 6;
+    /**
+     * Reverb delay. Parameter ID for OnParameterChangeListener
+     */
+    public static final int PARAM_REVERB_DELAY = 7;
+    /**
+     * Diffusion. Parameter ID for OnParameterChangeListener
+     */
+    public static final int PARAM_DIFFUSION = 8;
+    /**
+     * Density. Parameter ID for OnParameterChangeListener
+     */
+    public static final int PARAM_DENSITY = 9;
+
+    /**
+     * Registered listener for parameter changes
+     */
+    private OnParameterChangeListener mParamListener = null;
+
+    /**
+     * Listener used internally to to receive raw parameter change event from AudioEffect super
+     * class
+     */
+    private BaseParameterListener mBaseParamListener = null;
+
+    /**
+     * Lock for access to mParamListener
+     */
+    private final Object mParamListenerLock = new Object();
+
+    /**
+     * Class constructor.
+     * @param priority the priority level requested by the application for controlling the
+     * EnvironmentalReverb engine. As the same engine can be shared by several applications, this
+     * parameter indicates how much the requesting application needs control of effect parameters.
+     * The normal priority is 0, above normal is a positive number, below normal a negative number.
+     * @param audioSession  System wide unique audio session identifier. If audioSession
+     *  is not 0, the EnvironmentalReverb will be attached to the MediaPlayer or AudioTrack in the
+     *  same audio session. Otherwise, the EnvironmentalReverb will apply to the output mix.
+     *  As the EnvironmentalReverb is an auxiliary effect it is recommended to instantiate it on
+     *  audio session 0 and to attach it to the MediaPLayer auxiliary output.
+     *
+     * @throws java.lang.IllegalArgumentException
+     * @throws java.lang.UnsupportedOperationException
+     * @throws java.lang.RuntimeException
+     */
+    public EnvironmentalReverb(int priority, int audioSession)
+    throws IllegalArgumentException, UnsupportedOperationException, RuntimeException {
+        super(EFFECT_TYPE_ENV_REVERB, EFFECT_TYPE_NULL, priority, audioSession);
+        Log.e(TAG, "contructor");
+    }
+
+    /**
+     * Sets the master volume level of the environmental reverb effect.
+     * @param room Room level in millibels. The valid range is [-9000, 0].
+     * @throws IllegalStateException
+     * @throws IllegalArgumentException
+     * @throws UnsupportedOperationException
+     */
+    public void setRoomLevel(short room)
+    throws IllegalStateException, IllegalArgumentException, UnsupportedOperationException {
+        byte[] param = shortToByteArray(room);
+        checkStatus(setParameter(PARAM_ROOM_LEVEL, param));
+    }
+
+    /**
+     * Gets the master volume level of the environmental reverb effect.
+     * @return the room level in millibels.
+     * @throws IllegalStateException
+     * @throws IllegalArgumentException
+     * @throws UnsupportedOperationException
+     */
+    public short getRoomLevel()
+    throws IllegalStateException, IllegalArgumentException, UnsupportedOperationException {
+        byte[] param = new byte[2];
+        checkStatus(getParameter(PARAM_ROOM_LEVEL, param));
+        return byteArrayToShort(param);
+    }
+
+    /**
+     * Sets the volume level at 5 kHz relative to the volume level at low frequencies of the
+     * overall reverb effect.
+     * <p>This controls a low-pass filter that will reduce the level of the high-frequency.
+     * @param roomHF High frequency attenuation level in millibels. The valid range is [-9000, 0].
+     * @throws IllegalStateException
+     * @throws IllegalArgumentException
+     * @throws UnsupportedOperationException
+     */
+    public void setRoomHFLevel(short roomHF)
+    throws IllegalStateException, IllegalArgumentException, UnsupportedOperationException {
+        byte[] param = shortToByteArray(roomHF);
+        checkStatus(setParameter(PARAM_ROOM_HF_LEVEL, param));
+    }
+
+    /**
+     * Gets the room HF level.
+     * @return the room HF level in millibels.
+     * @throws IllegalStateException
+     * @throws IllegalArgumentException
+     * @throws UnsupportedOperationException
+     */
+    public short getRoomHFLevel()
+    throws IllegalStateException, IllegalArgumentException, UnsupportedOperationException {
+        byte[] param = new byte[2];
+        checkStatus(getParameter(PARAM_ROOM_HF_LEVEL, param));
+        return byteArrayToShort(param);
+    }
+
+    /**
+     * Sets the time taken for the level of reverberation to decay by 60 dB.
+     * @param decayTime Decay time in milliseconds. The valid range is [100, 20000].
+     * @throws IllegalStateException
+     * @throws IllegalArgumentException
+     * @throws UnsupportedOperationException
+     */
+    public void setDecayTime(int decayTime)
+    throws IllegalStateException, IllegalArgumentException, UnsupportedOperationException {
+        byte[] param = intToByteArray(decayTime);
+        checkStatus(setParameter(PARAM_DECAY_TIME, param));
+    }
+
+    /**
+     * Gets the decay time.
+     * @return the decay time in milliseconds.
+     * @throws IllegalStateException
+     * @throws IllegalArgumentException
+     * @throws UnsupportedOperationException
+     */
+    public int getDecayTime()
+    throws IllegalStateException, IllegalArgumentException, UnsupportedOperationException {
+        byte[] param = new byte[4];
+        checkStatus(getParameter(PARAM_DECAY_TIME, param));
+        return byteArrayToInt(param);
+    }
+
+    /**
+     * Sets the ratio of high frequency decay time (at 5 kHz) relative to the decay time at low
+     * frequencies.
+     * @param decayHFRatio High frequency decay ratio using a permille scale. The valid range is
+     * [100, 2000]. A ratio of 1000 indicates that all frequencies decay at the same rate.
+     * @throws IllegalStateException
+     * @throws IllegalArgumentException
+     * @throws UnsupportedOperationException
+     */
+    public void setDecayHFRatio(short decayHFRatio)
+    throws IllegalStateException, IllegalArgumentException, UnsupportedOperationException {
+        byte[] param = shortToByteArray(decayHFRatio);
+        checkStatus(setParameter(PARAM_DECAY_HF_RATIO, param));
+    }
+
+    /**
+     * Gets the ratio of high frequency decay time (at 5 kHz) relative to low frequencies.
+     * @return the decay HF ration. See {@link #setDecayHFRatio(short)} for units.
+     * @throws IllegalStateException
+     * @throws IllegalArgumentException
+     * @throws UnsupportedOperationException
+     */
+    public short getDecayHFRatio()
+    throws IllegalStateException, IllegalArgumentException, UnsupportedOperationException {
+        byte[] param = new byte[2];
+        checkStatus(getParameter(PARAM_DECAY_HF_RATIO, param));
+        return byteArrayToShort(param);
+    }
+
+    /**
+     * Sets the volume level of the early reflections.
+     * <p>This level is combined with the overall room level
+     * (set using {@link #setRoomLevel(short)}).
+     * @param reflectionsLevel Reflection level in millibels. The valid range is [-9000, 1000].
+     * @throws IllegalStateException
+     * @throws IllegalArgumentException
+     * @throws UnsupportedOperationException
+     */
+    public void setReflectionsLevel(short reflectionsLevel)
+    throws IllegalStateException, IllegalArgumentException, UnsupportedOperationException {
+        byte[] param = shortToByteArray(reflectionsLevel);
+        checkStatus(setParameter(PARAM_REFLECTIONS_LEVEL, param));
+    }
+
+    /**
+     * Gets the volume level of the early reflections.
+     * @return the early reflections level in millibels.
+     * @throws IllegalStateException
+     * @throws IllegalArgumentException
+     * @throws UnsupportedOperationException
+     */
+    public short getReflectionsLevel()
+    throws IllegalStateException, IllegalArgumentException, UnsupportedOperationException {
+        byte[] param = new byte[2];
+        checkStatus(getParameter(PARAM_REFLECTIONS_LEVEL, param));
+        return byteArrayToShort(param);
+    }
+
+    /**
+     * Sets the delay time for the early reflections.
+     * <p>This method sets the time between when the direct path is heard and when the first
+     * reflection is heard.
+     * @param reflectionsDelay Reflections delay in milliseconds. The valid range is [0, 300].
+     * @throws IllegalStateException
+     * @throws IllegalArgumentException
+     * @throws UnsupportedOperationException
+     */
+    public void setReflectionsDelay(int reflectionsDelay)
+    throws IllegalStateException, IllegalArgumentException, UnsupportedOperationException {
+        byte[] param = intToByteArray(reflectionsDelay);
+        checkStatus(setParameter(PARAM_REFLECTIONS_DELAY, param));
+    }
+
+    /**
+     * Gets the reflections delay.
+     * @return the early reflections delay in milliseconds.
+     * @throws IllegalStateException
+     * @throws IllegalArgumentException
+     * @throws UnsupportedOperationException
+     */
+    public int getReflectionsDelay()
+    throws IllegalStateException, IllegalArgumentException, UnsupportedOperationException {
+        byte[] param = new byte[4];
+        checkStatus(getParameter(PARAM_REFLECTIONS_DELAY, param));
+        return byteArrayToInt(param);
+    }
+
+    /**
+     * Sets the volume level of the late reverberation.
+     * <p>This level is combined with the overall room level (set using {@link #setRoomLevel(short)}).
+     * @param reverbLevel Reverb level in millibels. The valid range is [-9000, 2000].
+     * @throws IllegalStateException
+     * @throws IllegalArgumentException
+     * @throws UnsupportedOperationException
+     */
+    public void setReverbLevel(short reverbLevel)
+    throws IllegalStateException, IllegalArgumentException, UnsupportedOperationException {
+        byte[] param = shortToByteArray(reverbLevel);
+        checkStatus(setParameter(PARAM_REVERB_LEVEL, param));
+    }
+
+    /**
+     * Gets the reverb level.
+     * @return the reverb level in millibels.
+     * @throws IllegalStateException
+     * @throws IllegalArgumentException
+     * @throws UnsupportedOperationException
+     */
+    public short getReverbLevel()
+    throws IllegalStateException, IllegalArgumentException, UnsupportedOperationException {
+        byte[] param = new byte[2];
+        checkStatus(getParameter(PARAM_REVERB_LEVEL, param));
+        return byteArrayToShort(param);
+    }
+
+    /**
+     * Sets the time between the first reflection and the reverberation.
+     * @param reverbDelay Reverb delay in milliseconds. The valid range is [0, 100].
+     * @throws IllegalStateException
+     * @throws IllegalArgumentException
+     * @throws UnsupportedOperationException
+     */
+    public void setReverbDelay(int reverbDelay)
+    throws IllegalStateException, IllegalArgumentException, UnsupportedOperationException {
+        byte[] param = intToByteArray(reverbDelay);
+        checkStatus(setParameter(PARAM_REVERB_DELAY, param));
+    }
+
+    /**
+     * Gets the reverb delay.
+     * @return the reverb delay in milliseconds.
+     * @throws IllegalStateException
+     * @throws IllegalArgumentException
+     * @throws UnsupportedOperationException
+     */
+    public int getReverbDelay()
+    throws IllegalStateException, IllegalArgumentException, UnsupportedOperationException {
+        byte[] param = new byte[4];
+        checkStatus(getParameter(PARAM_REVERB_DELAY, param));
+        return byteArrayToInt(param);
+    }
+
+    /**
+     * Sets the echo density in the late reverberation decay.
+     * <p>The scale should approximately map linearly to the perceived change in reverberation.
+     * @param diffusion Diffusion specified using a permille scale. The diffusion valid range is
+     * [0, 1000]. A value of 1000 o/oo indicates a smooth reverberation decay.
+     * Values below this level give a more <i>grainy</i> character.
+     * @throws IllegalStateException
+     * @throws IllegalArgumentException
+     * @throws UnsupportedOperationException
+     */
+    public void setDiffusion(short diffusion)
+    throws IllegalStateException, IllegalArgumentException, UnsupportedOperationException {
+        byte[] param = shortToByteArray(diffusion);
+        checkStatus(setParameter(PARAM_DIFFUSION, param));
+    }
+
+    /**
+     * Gets diffusion level.
+     * @return the diffusion level. See {@link #setDiffusion(short)} for units.
+     * @throws IllegalStateException
+     * @throws IllegalArgumentException
+     * @throws UnsupportedOperationException
+     */
+    public short getDiffusion()
+    throws IllegalStateException, IllegalArgumentException, UnsupportedOperationException {
+        byte[] param = new byte[2];
+        checkStatus(getParameter(PARAM_DIFFUSION, param));
+        return byteArrayToShort(param);
+    }
+
+
+    /**
+     * Controls the modal density of the late reverberation decay.
+     * <p> The scale should approximately map linearly to the perceived change in reverberation.
+     * A lower density creates a hollow sound that is useful for simulating small reverberation
+     * spaces such as bathrooms.
+     * @param density Density specified using a permille scale. The valid range is [0, 1000].
+     * A value of 1000 o/oo indicates a natural sounding reverberation. Values below this level
+     * produce a more colored effect.
+     * @throws IllegalStateException
+     * @throws IllegalArgumentException
+     * @throws UnsupportedOperationException
+     */
+    public void setDensity(short density)
+    throws IllegalStateException, IllegalArgumentException, UnsupportedOperationException {
+        byte[] param = shortToByteArray(density);
+        checkStatus(setParameter(PARAM_DENSITY, param));
+    }
+
+    /**
+     * Gets the density level.
+     * @return the density level. See {@link #setDiffusion(short)} for units.
+     * @throws IllegalStateException
+     * @throws IllegalArgumentException
+     * @throws UnsupportedOperationException
+     */
+    public short getDensity()
+    throws IllegalStateException, IllegalArgumentException, UnsupportedOperationException {
+        byte[] param = new byte[2];
+        checkStatus(getParameter(PARAM_DENSITY, param));
+        return byteArrayToShort(param);
+    }
+
+
+    /**
+     * The OnParameterChangeListener interface defines a method called by the EnvironmentalReverb
+     * when a parameter value has changed.
+     */
+    public interface OnParameterChangeListener  {
+        /**
+         * Method called when a parameter value has changed. The method is called only if the
+         * parameter was changed by another application having the control of the same
+         * EnvironmentalReverb engine.
+         * @param effect the EnvironmentalReverb on which the interface is registered.
+         * @param status status of the set parameter operation.
+         // TODO when AudioEffect is unhidden
+         // See {_at_link android.media.AudioEffect#setParameter(byte[], byte[])}.
+         * @param param ID of the modified parameter. See {@link #PARAM_ROOM_LEVEL} ...
+         * @param value the new parameter value.
+         */
+        void onParameterChange(EnvironmentalReverb effect, int status, int param, int value);
+    }
+
+    /**
+     * Listener used internally to receive unformatted parameter change events from AudioEffect
+     * super class.
+     */
+    private class BaseParameterListener implements AudioEffect.OnParameterChangeListener {
+        private BaseParameterListener() {
+
+        }
+        public void onParameterChange(AudioEffect effect, int status, byte[] param, byte[] value) {
+            OnParameterChangeListener l = null;
+
+            synchronized (mParamListenerLock) {
+                if (mParamListener != null) {
+                    l = mParamListener;
+                }
+            }
+            if (l != null) {
+                int p = -1;
+                int v = -1;
+
+                if (param.length == 4) {
+                    p = byteArrayToInt(param, 0);
+                }
+                if (value.length == 2) {
+                    v = (int)byteArrayToShort(value, 0);
+                } else if (value.length == 4) {
+                    v = byteArrayToInt(value, 0);
+                }
+                if (p != -1 && v != -1) {
+                    l.onParameterChange(EnvironmentalReverb.this, status, p, v);
+                }
+            }
+        }
+    }
+
+    /**
+     * Registers an OnParameterChangeListener interface.
+     * @param listener OnParameterChangeListener interface registered
+     */
+    public void setParameterListener(OnParameterChangeListener listener) {
+        synchronized (mParamListenerLock) {
+            if (mParamListener == null) {
+                mParamListener = listener;
+                mBaseParamListener = new BaseParameterListener();
+                super.setParameterListener(mBaseParamListener);
+            }
+        }
+    }
+}
diff --git a/media/java/android/media/Equalizer.java b/media/java/android/media/Equalizer.java
new file mode 100644
index 0000000..082f694
--- /dev/null
+++ b/media/java/android/media/Equalizer.java
@@ -0,0 +1,443 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.media;
+
+import android.app.Activity;
+import android.content.Context;
+import android.content.Intent;
+import android.os.Bundle;
+import android.util.Log;
+import java.nio.ByteOrder;
+import java.nio.ByteBuffer;
+import java.nio.CharBuffer;
+
+import android.media.AudioEffect;
+
+/**
+ * An Equalizer is used to alter the frequency response of a particular music source or of the main
+ * output mix.
+ * <p>An application creates an Equalizer object to instantiate and control an Equalizer engine
+ * in the audio framework. The application can either simply use predefined presets or have a more
+ * precise control of the gain in each frequency band controlled by the equalizer.
+ * <p>The methods, parameter types and units exposed by the Equalizer implementation are directly
+ * mapping those defined by the OpenSL ES 1.0.1 Specification (http://www.khronos.org/opensles/)
+ * for the SLEqualizerItf interface. Please refer to this specification for more details.
+ * <p>To attach the Equalizer to a particular AudioTrack or MediaPlayer, specify the audio session
+ * ID of this AudioTrack or MediaPlayer when constructing the Equalizer. If the audio session ID 0
+ * is specified, the Equalizer applies to the main audio output mix.
+ // TODO when AudioEffect is unhidden
+ // <p> See {_at_link android.media.AudioEffect} class for more details on controlling audio effects.
+ *
+ * {@hide Pending API council review}
+ */
+
+public class Equalizer extends AudioEffect {
+
+    private final static String TAG = "Equalizer";
+
+    // These constants must be synchronized with those in
+    // frameworks/base/include/media/EffectEqualizerApi.h
+    /**
+     * Number of bands. Parameter ID for {@link android.media.Equalizer.OnParameterChangeListener}
+     */
+    public static final int PARAM_NUM_BANDS = 0;
+    /**
+     * Band level range. Parameter ID for OnParameterChangeListener
+     */
+    public static final int PARAM_LEVEL_RANGE = 1;
+    /**
+     * Band level. Parameter ID for OnParameterChangeListener
+     */
+    public static final int PARAM_BAND_LEVEL = 2;
+    /**
+     * Band center frequency. Parameter ID for OnParameterChangeListener
+     */
+    public static final int PARAM_CENTER_FREQ = 3;
+    /**
+     * Band frequency range. Parameter ID for OnParameterChangeListener
+     */
+    public static final int PARAM_BAND_FREQ_RANGE = 4;
+    /**
+     * Band for a given frequency. Parameter ID for OnParameterChangeListener
+     */
+    public static final int PARAM_GET_BAND = 5;
+    /**
+     * Current preset. Parameter ID for OnParameterChangeListener
+     */
+    public static final int PARAM_CURRENT_PRESET = 6;
+    /**
+     * Request number of presets. Parameter ID for OnParameterChangeListener
+     */
+    public static final int PARAM_GET_NUM_OF_PRESETS = 7;
+    /**
+     * Request preset name. Parameter ID for OnParameterChangeListener
+     */
+    public static final int PARAM_GET_PRESET_NAME = 8;
+    /**
+     * maximum size for perset name
+     */
+    public static final int PARAM_STRING_SIZE_MAX = 32;
+
+    /**
+     * Number of presets implemented by Equalizer engine
+     */
+    private int mNumPresets;
+    /**
+     * Names of presets implemented by Equalizer engine
+     */
+    private String[] mPresetNames;
+
+    /**
+     * Registered listener for parameter changes.
+     */
+    private OnParameterChangeListener mParamListener = null;
+
+    /**
+     * Listener used internally to to receive raw parameter change event from AudioEffect super class
+     */
+    private BaseParameterListener mBaseParamListener = null;
+
+    /**
+     * Lock for access to mParamListener
+     */
+    private final Object mParamListenerLock = new Object();
+
+    /**
+     * Class constructor.
+     * @param priority the priority level requested by the application for controlling the Equalizer
+     * engine. As the same engine can be shared by several applications, this parameter indicates
+     * how much the requesting application needs control of effect parameters. The normal priority
+     * is 0, above normal is a positive number, below normal a negative number.
+     * @param audioSession  System wide unique audio session identifier. If audioSession
+     *  is not 0, the Equalizer will be attached to the MediaPlayer or AudioTrack in the
+     *  same audio session. Otherwise, the Equalizer will apply to the output mix.
+     *
+     * @throws java.lang.IllegalStateException
+     * @throws java.lang.IllegalArgumentException
+     * @throws java.lang.UnsupportedOperationException
+     * @throws java.lang.RuntimeException
+     */
+    public Equalizer(int priority, int audioSession)
+    throws IllegalStateException, IllegalArgumentException,
+           UnsupportedOperationException, RuntimeException {
+        super(EFFECT_TYPE_EQUALIZER, EFFECT_TYPE_NULL, priority, audioSession);
+
+        mNumPresets = (int)getNumberOfPresets();
+
+        if (mNumPresets != 0) {
+            mPresetNames = new String[mNumPresets];
+            byte[] value = new byte[PARAM_STRING_SIZE_MAX];
+            int[] param = new int[2];
+            param[0] = PARAM_GET_PRESET_NAME;
+            for (int i = 0; i < mNumPresets; i++) {
+                param[1] = i;
+                checkStatus(getParameter(param, value));
+                int length = 0;
+                while (value[length] != 0) length++;
+                try {
+                    mPresetNames[i] = new String(value, 0, length, "ISO-8859-1");
+                    Log.e(TAG, "preset #: "+i+" name: "+mPresetNames[i]+" length: "+length);
+                } catch (java.io.UnsupportedEncodingException e) {
+                    Log.e(TAG, "preset name decode error");
+                }
+            }
+        }
+    }
+
+    /**
+     * Gets the number of frequency bands supported by the Equalizer engine.
+     * @return the number of bands
+     * @throws IllegalStateException
+     * @throws IllegalArgumentException
+     * @throws UnsupportedOperationException
+     */
+    public short getNumberOfBands()
+    throws IllegalStateException, IllegalArgumentException, UnsupportedOperationException {
+        int[] param = new int[1];
+        param[0] = PARAM_NUM_BANDS;
+        short[] value = new short[1];
+        checkStatus(getParameter(param, value));
+        return value[0];
+    }
+
+    /**
+     * Gets the level range for use by {@link #setBandLevel(int,short)}. The level is expressed in
+     * milliBel.
+     * @return the band level range in an array of short integers. The first element is the lower
+     * limit of the range, the second element the upper limit.
+     * @throws IllegalStateException
+     * @throws IllegalArgumentException
+     * @throws UnsupportedOperationException
+     */
+    public short[] getBandLevelRange()
+    throws IllegalStateException, IllegalArgumentException, UnsupportedOperationException {
+        int[] param = new int[1];
+        int[] value = new int[2];
+        param[0] = PARAM_LEVEL_RANGE;
+        checkStatus(getParameter(param, value));
+
+        short[] result = new short[2];
+
+        result[0] = (short)value[0];
+        result[1] = (short)value[1];
+
+        return result;
+    }
+
+    /**
+     * Sets the given equalizer band to the given gain value.
+     * @param band Frequency band that will have the new gain. The numbering of the bands starts
+     * from 0 and ends at (number of bands - 1). See @see #getNumberOfBands().
+     * @param level New gain in millibels that will be set to the given band. getBandLevelRange()
+     * will define the maximum and minimum values.
+     * @throws IllegalStateException
+     * @throws IllegalArgumentException
+     * @throws UnsupportedOperationException
+     */
+    public void setBandLevel(int band, short level)
+    throws IllegalStateException, IllegalArgumentException, UnsupportedOperationException {
+        int[] param = new int[2];
+        int[] value = new int[1];
+
+        param[0] = PARAM_BAND_LEVEL;
+        param[1] = band;
+        value[0] = (int)level;
+        checkStatus(setParameter(param, value));
+    }
+
+    /**
+     * Gets the gain set for the given equalizer band.
+     * @param band Frequency band whose gain is requested. The numbering of the bands starts
+     * from 0 and ends at (number of bands - 1).
+     * @return Gain in millibels of the given band.
+     * @throws IllegalStateException
+     * @throws IllegalArgumentException
+     * @throws UnsupportedOperationException
+     */
+    public short getBandLevel(int band)
+    throws IllegalStateException, IllegalArgumentException, UnsupportedOperationException {
+        int[] param = new int[2];
+        int[] result = new int[1];
+
+        param[0] = PARAM_BAND_LEVEL;
+        param[1] = band;
+        checkStatus(getParameter(param, result));
+
+        return (short)result[0];
+    }
+
+
+    /**
+     * Gets the center frequency of the given band.
+     * @param band Frequency band whose center frequency is requested. The numbering of the bands
+     * starts from 0 and ends at (number of bands - 1).
+     * @return The center frequency in milliHertz
+     * @throws IllegalStateException
+     * @throws IllegalArgumentException
+     * @throws UnsupportedOperationException
+     */
+    public int getCenterFreq(int band)
+    throws IllegalStateException, IllegalArgumentException, UnsupportedOperationException {
+        int[] param = new int[2];
+        int[] result = new int[1];
+
+        param[0] = PARAM_CENTER_FREQ;
+        param[1] = band;
+        checkStatus(getParameter(param, result));
+
+        return result[0];
+    }
+
+    /**
+     * Gets the frequency range of the given frequency band.
+     * @param band Frequency band whose frequency range is requested. The numbering of the bands
+     * starts from 0 and ends at (number of bands - 1).
+     * @return The frequency range in millHertz in an array of integers. The first element is the
+     * lower limit of the range, the second element the upper limit.
+     * @throws IllegalStateException
+     * @throws IllegalArgumentException
+     * @throws UnsupportedOperationException
+     */
+    public int[] getBandFreqRange(int band)
+    throws IllegalStateException, IllegalArgumentException, UnsupportedOperationException {
+        int[] param = new int[2];
+        int[] result = new int[2];
+        param[0] = PARAM_BAND_FREQ_RANGE;
+        param[1] = band;
+        checkStatus(getParameter(param, result));
+
+        return result;
+    }
+
+    /**
+     * Gets the band that has the most effect on the given frequency.
+     * @param frequency Frequency in milliHertz which is to be equalized via the returned band.
+     * @return Frequency band that has most effect on the given frequency.
+     * @throws IllegalStateException
+     * @throws IllegalArgumentException
+     * @throws UnsupportedOperationException
+     */
+    public int getBand(int frequency)
+    throws IllegalStateException, IllegalArgumentException, UnsupportedOperationException {
+        int[] param = new int[2];
+        int[] result = new int[1];
+
+        param[0] = PARAM_GET_BAND;
+        param[1] = frequency;
+        checkStatus(getParameter(param, result));
+
+        return result[0];
+    }
+
+    /**
+     * Gets current preset.
+     * @return Preset that is set at the moment.
+     * @throws IllegalStateException
+     * @throws IllegalArgumentException
+     * @throws UnsupportedOperationException
+     */
+    public short getCurrentPreset()
+    throws IllegalStateException, IllegalArgumentException, UnsupportedOperationException {
+        int[] param = new int[1];
+        param[0] = PARAM_CURRENT_PRESET;
+        short[] value = new short[1];
+        checkStatus(getParameter(param, value));
+        return value[0];
+    }
+
+    /**
+     * Sets the equalizer according to the given preset.
+     * @param preset New preset that will be taken into use. The valid range is [0,
+     * number of presets-1]. See {@see #getNumberOfPresets()}.
+     * @throws IllegalStateException
+     * @throws IllegalArgumentException
+     * @throws UnsupportedOperationException
+     */
+    public void usePreset(short preset)
+    throws IllegalStateException, IllegalArgumentException, UnsupportedOperationException {
+        checkStatus(setParameter(PARAM_CURRENT_PRESET, preset));
+    }
+
+    /**
+     * Gets the total number of presets the equalizer supports. The presets will have indices
+     * [0, number of presets-1].
+     * @return The number of presets the equalizer supports.
+     * @throws IllegalStateException
+     * @throws IllegalArgumentException
+     * @throws UnsupportedOperationException
+     */
+    public short getNumberOfPresets()
+    throws IllegalStateException, IllegalArgumentException, UnsupportedOperationException {
+        int[] param = new int[1];
+        param[0] = PARAM_GET_NUM_OF_PRESETS;
+        short[] value = new short[1];
+        checkStatus(getParameter(param, value));
+        return value[0];
+    }
+
+    /**
+     * Gets the preset name based on the index.
+     * @param preset Index of the preset. The valid range is [0, number of presets-1].
+     * @return A string containing the name of the given preset.
+     * @throws IllegalStateException
+     * @throws IllegalArgumentException
+     * @throws UnsupportedOperationException
+     */
+    public String getPresetName(short preset)
+    {
+        if (preset >= 0 && preset < mNumPresets) {
+            return mPresetNames[preset];
+        } else {
+            return "";
+        }
+    }
+
+    /**
+     * The OnParameterChangeListener interface defines a method called by the Equalizer when a
+     * parameter value has changed.
+     */
+    public interface OnParameterChangeListener  {
+        /**
+         * Method called when a parameter value has changed. The method is called only if the
+         * parameter was changed by another application having the control of the same
+         * Equalizer engine.
+         * @param effect the Equalizer on which the interface is registered.
+         * @param status status of the set parameter operation.
+         // TODO when AudioEffect is unhidden
+         // See {_at_link android.media.AudioEffect#setParameter(byte[], byte[])}.
+         * @param param1 ID of the modified parameter. See {@link #PARAM_BAND_LEVEL} ...
+         * @param param2 additional parameter qualifier (e.g the band for band level parameter).
+         * @param value the new parameter value.
+         */
+        void onParameterChange(Equalizer effect, int status, int param1, int param2, int value);
+    }
+
+    /**
+     * Listener used internally to receive unformatted parameter change events from AudioEffect
+     * super class.
+     */
+    private class BaseParameterListener implements AudioEffect.OnParameterChangeListener {
+        private BaseParameterListener() {
+
+        }
+        public void onParameterChange(AudioEffect effect, int status, byte[] param, byte[] value) {
+            OnParameterChangeListener l = null;
+
+            synchronized (mParamListenerLock) {
+                if (mParamListener != null) {
+                    l = mParamListener;
+                }
+            }
+            if (l != null) {
+                int p1 = -1;
+                int p2 = -1;
+                int v = -1;
+
+                if (param.length >= 4) {
+                    p1 = byteArrayToInt(param, 0);
+                    if (param.length >= 8) {
+                        p2 = byteArrayToInt(param, 4);
+                    }
+                }
+                if (value.length == 2) {
+                    v = (int)byteArrayToShort(value, 0);;
+                } else if (value.length == 4) {
+                    v = byteArrayToInt(value, 0);
+                }
+
+                if (p1 != -1 && v != -1) {
+                    l.onParameterChange(Equalizer.this, status, p1, p2, v);
+                }
+            }
+        }
+    }
+
+    /**
+     * Registers an OnParameterChangeListener interface.
+     * @param listener OnParameterChangeListener interface registered
+     */
+    public void setParameterListener(OnParameterChangeListener listener) {
+        synchronized (mParamListenerLock) {
+            if (mParamListener == null) {
+                mParamListener = listener;
+                mBaseParamListener = new BaseParameterListener();
+                super.setParameterListener(mBaseParamListener);
+            }
+        }
+    }
+
+}
diff --git a/media/java/android/media/MediaFile.java b/media/java/android/media/MediaFile.java
index 6e527d9..a346ae4 100644
--- a/media/java/android/media/MediaFile.java
+++ b/media/java/android/media/MediaFile.java
@@ -20,6 +20,7 @@
 import android.provider.MediaStore.Audio;
 import android.provider.MediaStore.Images;
 import android.provider.MediaStore.Video;
+import android.provider.Mtp;
 import android.media.DecoderCapabilities;
 import android.media.DecoderCapabilities.VideoDecoder;
 import android.media.DecoderCapabilities.AudioDecoder;
@@ -96,15 +97,32 @@
         }
     }
     
-    private static HashMap<String, MediaFileType> sFileTypeMap 
+    private static HashMap<String, MediaFileType> sFileTypeMap
             = new HashMap<String, MediaFileType>();
-    private static HashMap<String, Integer> sMimeTypeMap 
-            = new HashMap<String, Integer>();            
+    private static HashMap<String, Integer> sMimeTypeMap
+            = new HashMap<String, Integer>();
+    // maps file extension to MTP format code
+    private static HashMap<String, Integer> sFileTypeToFormatMap
+            = new HashMap<String, Integer>();
+    // maps mime type to MTP format code
+    private static HashMap<String, Integer> sMimeTypeToFormatMap
+            = new HashMap<String, Integer>();
+    // maps MTP format code to mime type
+    private static HashMap<Integer, String> sFormatToMimeTypeMap
+            = new HashMap<Integer, String>();
+
     static void addFileType(String extension, int fileType, String mimeType) {
         sFileTypeMap.put(extension, new MediaFileType(fileType, mimeType));
         sMimeTypeMap.put(mimeType, Integer.valueOf(fileType));
     }
 
+    static void addFileType(String extension, int fileType, String mimeType, int mtpFormatCode) {
+        addFileType(extension, fileType, mimeType);
+        sFileTypeToFormatMap.put(extension, Integer.valueOf(mtpFormatCode));
+        sMimeTypeToFormatMap.put(mimeType, Integer.valueOf(mtpFormatCode));
+        sFormatToMimeTypeMap.put(mtpFormatCode, mimeType);
+    }
+
     private static boolean isWMAEnabled() {
         List<AudioDecoder> decoders = DecoderCapabilities.getAudioDecoders();
         for (AudioDecoder decoder: decoders) {
@@ -126,17 +144,17 @@
     }
 
     static {
-        addFileType("MP3", FILE_TYPE_MP3, "audio/mpeg");
-        addFileType("M4A", FILE_TYPE_M4A, "audio/mp4");
-        addFileType("WAV", FILE_TYPE_WAV, "audio/x-wav");
+        addFileType("MP3", FILE_TYPE_MP3, "audio/mpeg", Mtp.Object.FORMAT_MP3);
+        addFileType("M4A", FILE_TYPE_M4A, "audio/mp4", Mtp.Object.FORMAT_MPEG);
+        addFileType("WAV", FILE_TYPE_WAV, "audio/x-wav", Mtp.Object.FORMAT_WAV);
         addFileType("AMR", FILE_TYPE_AMR, "audio/amr");
         addFileType("AWB", FILE_TYPE_AWB, "audio/amr-wb");
         if (isWMAEnabled()) {
-            addFileType("WMA", FILE_TYPE_WMA, "audio/x-ms-wma");
+            addFileType("WMA", FILE_TYPE_WMA, "audio/x-ms-wma", Mtp.Object.FORMAT_WMA);
         }
-        addFileType("OGG", FILE_TYPE_OGG, "application/ogg");
-        addFileType("OGA", FILE_TYPE_OGG, "application/ogg");
-        addFileType("AAC", FILE_TYPE_AAC, "audio/aac");
+        addFileType("OGG", FILE_TYPE_OGG, "application/ogg", Mtp.Object.FORMAT_OGG);
+        addFileType("OGA", FILE_TYPE_OGG, "application/ogg", Mtp.Object.FORMAT_OGG);
+        addFileType("AAC", FILE_TYPE_AAC, "audio/aac", Mtp.Object.FORMAT_AAC);
         addFileType("MKA", FILE_TYPE_MKA, "audio/x-matroska");
  
         addFileType("MID", FILE_TYPE_MID, "audio/midi");
@@ -148,32 +166,32 @@
         addFileType("RTX", FILE_TYPE_MID, "audio/midi");
         addFileType("OTA", FILE_TYPE_MID, "audio/midi");
         
-        addFileType("MPEG", FILE_TYPE_MP4, "video/mpeg");
-        addFileType("MP4", FILE_TYPE_MP4, "video/mp4");
-        addFileType("M4V", FILE_TYPE_M4V, "video/mp4");
-        addFileType("3GP", FILE_TYPE_3GPP, "video/3gpp");
-        addFileType("3GPP", FILE_TYPE_3GPP, "video/3gpp");
-        addFileType("3G2", FILE_TYPE_3GPP2, "video/3gpp2");
-        addFileType("3GPP2", FILE_TYPE_3GPP2, "video/3gpp2");
+        addFileType("MPEG", FILE_TYPE_MP4, "video/mpeg", Mtp.Object.FORMAT_MPEG);
+        addFileType("MP4", FILE_TYPE_MP4, "video/mp4", Mtp.Object.FORMAT_MPEG);
+        addFileType("M4V", FILE_TYPE_M4V, "video/mp4", Mtp.Object.FORMAT_MPEG);
+        addFileType("3GP", FILE_TYPE_3GPP, "video/3gpp",  Mtp.Object.FORMAT_3GP_CONTAINER);
+        addFileType("3GPP", FILE_TYPE_3GPP, "video/3gpp", Mtp.Object.FORMAT_3GP_CONTAINER);
+        addFileType("3G2", FILE_TYPE_3GPP2, "video/3gpp2", Mtp.Object.FORMAT_3GP_CONTAINER);
+        addFileType("3GPP2", FILE_TYPE_3GPP2, "video/3gpp2", Mtp.Object.FORMAT_3GP_CONTAINER);
         addFileType("MKV", FILE_TYPE_MKV, "video/x-matroska");
         addFileType("WEBM", FILE_TYPE_MKV, "video/x-matroska");
         addFileType("TS", FILE_TYPE_MP2TS, "video/mp2ts");
 
         if (isWMVEnabled()) {
-            addFileType("WMV", FILE_TYPE_WMV, "video/x-ms-wmv");
+            addFileType("WMV", FILE_TYPE_WMV, "video/x-ms-wmv", Mtp.Object.FORMAT_WMV);
             addFileType("ASF", FILE_TYPE_ASF, "video/x-ms-asf");
         }
 
-        addFileType("JPG", FILE_TYPE_JPEG, "image/jpeg");
-        addFileType("JPEG", FILE_TYPE_JPEG, "image/jpeg");
-        addFileType("GIF", FILE_TYPE_GIF, "image/gif");
-        addFileType("PNG", FILE_TYPE_PNG, "image/png");
-        addFileType("BMP", FILE_TYPE_BMP, "image/x-ms-bmp");
+        addFileType("JPG", FILE_TYPE_JPEG, "image/jpeg", Mtp.Object.FORMAT_EXIF_JPEG);
+        addFileType("JPEG", FILE_TYPE_JPEG, "image/jpeg", Mtp.Object.FORMAT_EXIF_JPEG);
+        addFileType("GIF", FILE_TYPE_GIF, "image/gif", Mtp.Object.FORMAT_GIF);
+        addFileType("PNG", FILE_TYPE_PNG, "image/png", Mtp.Object.FORMAT_PNG);
+        addFileType("BMP", FILE_TYPE_BMP, "image/x-ms-bmp", Mtp.Object.FORMAT_BMP);
         addFileType("WBMP", FILE_TYPE_WBMP, "image/vnd.wap.wbmp");
  
-        addFileType("M3U", FILE_TYPE_M3U, "audio/x-mpegurl");
-        addFileType("PLS", FILE_TYPE_PLS, "audio/x-scpls");
-        addFileType("WPL", FILE_TYPE_WPL, "application/vnd.ms-wpl");
+        addFileType("M3U", FILE_TYPE_M3U, "audio/x-mpegurl", Mtp.Object.FORMAT_M3U_PLAYLIST);
+        addFileType("PLS", FILE_TYPE_PLS, "audio/x-scpls", Mtp.Object.FORMAT_PLS_PLAYLIST);
+        addFileType("WPL", FILE_TYPE_WPL, "application/vnd.ms-wpl", Mtp.Object.FORMAT_WPL_PLAYLIST);
 
         // compute file extensions list for native Media Scanner
         StringBuilder builder = new StringBuilder();
@@ -222,4 +240,25 @@
         return (value == null ? 0 : value.intValue());
     }
 
+    public static int getFormatCode(String fileName, String mimeType) {
+        if (mimeType != null) {
+            Integer value = sMimeTypeToFormatMap.get(mimeType);
+            if (value != null) {
+                return value.intValue();
+            }
+        }
+        int lastDot = fileName.lastIndexOf('.');
+        if (lastDot > 0) {
+            String extension = fileName.substring(lastDot + 1);
+            Integer value = sFileTypeToFormatMap.get(extension);
+            if (value != null) {
+                return value.intValue();
+            }
+        }
+        return Mtp.Object.FORMAT_UNDEFINED;
+    }
+
+    public static String getMimeTypeForFormatCode(int formatCode) {
+        return sFormatToMimeTypeMap.get(formatCode);
+    }
 }
diff --git a/media/java/android/media/MediaScanner.java b/media/java/android/media/MediaScanner.java
index 3333268..7cbe409 100644
--- a/media/java/android/media/MediaScanner.java
+++ b/media/java/android/media/MediaScanner.java
@@ -305,6 +305,7 @@
     private Uri mGenresUri;
     private Uri mPlaylistsUri;
     private boolean mProcessPlaylists, mProcessGenres;
+    private int mMtpObjectHandle;
 
     // used when scanning the image database so we know whether we have to prune
     // old thumbnail files
@@ -625,6 +626,9 @@
             map.put(MediaStore.MediaColumns.DATE_MODIFIED, mLastModified);
             map.put(MediaStore.MediaColumns.SIZE, mFileSize);
             map.put(MediaStore.MediaColumns.MIME_TYPE, mMimeType);
+            if (mMtpObjectHandle != 0) {
+                map.put(MediaStore.MediaColumns.MTP_OBJECT_HANDLE, mMtpObjectHandle);
+            }
 
             if (MediaFile.isVideoFileType(mFileType)) {
                 map.put(Video.Media.ARTIST, (mArtist != null && mArtist.length() > 0 ? mArtist : MediaStore.UNKNOWN_STRING));
@@ -1227,6 +1231,14 @@
         }
     }
 
+    public Uri scanMtpFile(String path, String volumeName, int objectHandle, int format) {
+        String mimeType = MediaFile.getMimeTypeForFormatCode(format);
+        mMtpObjectHandle = objectHandle;
+        Uri result = scanSingleFile(path, volumeName, mimeType);
+        mMtpObjectHandle = 0;
+        return result;
+    }
+
     // returns the number of matching file/directory names, starting from the right
     private int matchPaths(String path1, String path2) {
         int result = 0;
diff --git a/media/java/android/media/MtpDatabase.java b/media/java/android/media/MtpDatabase.java
new file mode 100644
index 0000000..2b311f5
--- /dev/null
+++ b/media/java/android/media/MtpDatabase.java
@@ -0,0 +1,313 @@
+/*
+ * 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.media;
+
+import android.content.Context;
+import android.content.ContentValues;
+import android.content.IContentProvider;
+import android.database.Cursor;
+import android.net.Uri;
+import android.os.RemoteException;
+import android.provider.MediaStore.MtpObjects;
+import android.util.Log;
+
+/**
+ * {@hide}
+ */
+public class MtpDatabase {
+
+    private static final String TAG = "MtpDatabase";
+
+    private final IContentProvider mMediaProvider;
+    private final String mVolumeName;
+    private final Uri mObjectsUri;
+
+    // FIXME - this should be passed in via the constructor
+    private final int mStorageID = 0x00010001;
+
+    private static final String[] ID_PROJECTION = new String[] {
+            MtpObjects.ObjectColumns._ID, // 0
+    };
+    private static final String[] PATH_SIZE_PROJECTION = new String[] {
+            MtpObjects.ObjectColumns._ID, // 0
+            MtpObjects.ObjectColumns.DATA, // 1
+            MtpObjects.ObjectColumns.SIZE, // 2
+    };
+    private static final String[] OBJECT_INFO_PROJECTION = new String[] {
+            MtpObjects.ObjectColumns._ID, // 0
+            MtpObjects.ObjectColumns.DATA, // 1
+            MtpObjects.ObjectColumns.FORMAT, // 2
+            MtpObjects.ObjectColumns.PARENT, // 3
+            MtpObjects.ObjectColumns.SIZE, // 4
+            MtpObjects.ObjectColumns.DATE_MODIFIED, // 5
+    };
+    private static final String ID_WHERE = MtpObjects.ObjectColumns._ID + "=?";
+    private static final String PATH_WHERE = MtpObjects.ObjectColumns.DATA + "=?";
+    private static final String PARENT_WHERE = MtpObjects.ObjectColumns.PARENT + "=?";
+    private static final String PARENT_FORMAT_WHERE = PARENT_WHERE + " AND "
+                                            + MtpObjects.ObjectColumns.FORMAT + "=?";
+
+    private final MediaScanner mMediaScanner;
+
+    // MTP property codes
+    private static final int MTP_PROPERTY_STORAGE_ID = 0xDC01;
+    private static final int MTP_PROPERTY_OBJECT_FORMAT = 0xDC02;
+    private static final int MTP_PROPERTY_OBJECT_SIZE = 0xDC04;
+    private static final int MTP_PROPERTY_OBJECT_FILE_NAME = 0xDC07;
+    private static final int MTP_PROPERTY_DATE_MODIFIED = 0xDC09;
+    private static final int MTP_PROPERTY_PARENT_OBJECT = 0xDC0B;
+
+    // MTP response codes
+    private static final int MTP_RESPONSE_OK = 0x2001;
+    private static final int MTP_RESPONSE_GENERAL_ERROR = 0x2002;
+    private static final int MTP_RESPONSE_INVALID_OBJECT_HANDLE = 0x2009;
+    private static final int MTP_RESPONSE_OBJECT_PROP_NOT_SUPPORTED = 0xA80A;
+
+    static {
+        System.loadLibrary("media_jni");
+    }
+
+    public MtpDatabase(Context context, String volumeName) {
+        native_setup();
+
+        mMediaProvider = context.getContentResolver().acquireProvider("media");
+        mVolumeName = volumeName;
+        mObjectsUri = MtpObjects.getContentUri(volumeName);
+        mMediaScanner = new MediaScanner(context);
+    }
+
+    @Override
+    protected void finalize() {
+        native_finalize();
+    }
+
+    private int beginSendObject(String path, int format, int parent,
+                         int storage, long size, long modified) {
+        ContentValues values = new ContentValues();
+        values.put(MtpObjects.ObjectColumns.DATA, path);
+        values.put(MtpObjects.ObjectColumns.FORMAT, format);
+        values.put(MtpObjects.ObjectColumns.PARENT, parent);
+        // storage is ignored for now
+        values.put(MtpObjects.ObjectColumns.SIZE, size);
+        values.put(MtpObjects.ObjectColumns.DATE_MODIFIED, modified);
+
+        try {
+            Uri uri = mMediaProvider.insert(mObjectsUri, values);
+            if (uri != null) {
+                return Integer.parseInt(uri.getPathSegments().get(2));
+            } else {
+                return -1;
+            }
+        } catch (RemoteException e) {
+            Log.e(TAG, "RemoteException in beginSendObject", e);
+            return -1;
+        }
+    }
+
+    private void endSendObject(String path, int handle, int format, boolean succeeded) {
+        if (succeeded) {
+            Uri uri = mMediaScanner.scanMtpFile(path, mVolumeName, handle, format);
+        } else {
+            deleteFile(handle);
+        }
+    }
+
+    private int[] getObjectList(int storageID, int format, int parent) {
+        // we can ignore storageID until we support multiple storages
+        Log.d(TAG, "getObjectList parent: " + parent);
+        Cursor c = null;
+        try {
+            if (format != 0) {
+                c = mMediaProvider.query(mObjectsUri, ID_PROJECTION,
+                            PARENT_FORMAT_WHERE,
+                            new String[] { Integer.toString(parent), Integer.toString(format) },
+                             null);
+            } else {
+                c = mMediaProvider.query(mObjectsUri, ID_PROJECTION,
+                            PARENT_WHERE, new String[] { Integer.toString(parent) }, null);
+            }
+            if (c == null) {
+                Log.d(TAG, "null cursor");
+                return null;
+            }
+            int count = c.getCount();
+            if (count > 0) {
+                int[] result = new int[count];
+                for (int i = 0; i < count; i++) {
+                    c.moveToNext();
+                    result[i] = c.getInt(0);
+                }
+                Log.d(TAG, "returning " + result);
+                return result;
+            }
+        } catch (RemoteException e) {
+            Log.e(TAG, "RemoteException in getObjectList", e);
+        } finally {
+            if (c != null) {
+                c.close();
+            }
+        }
+        return null;
+    }
+
+    private int getObjectProperty(int handle, int property,
+                            long[] outIntValue, char[] outStringValue) {
+        Log.d(TAG, "getObjectProperty: " + property);
+        String column = null;
+        boolean isString = false;
+
+        switch (property) {
+            case MTP_PROPERTY_STORAGE_ID:
+                outIntValue[0] = mStorageID;
+                return MTP_RESPONSE_OK;
+            case MTP_PROPERTY_OBJECT_FORMAT:
+                column = MtpObjects.ObjectColumns.FORMAT;
+                break;
+            case MTP_PROPERTY_OBJECT_SIZE:
+                column = MtpObjects.ObjectColumns.SIZE;
+                break;
+            case MTP_PROPERTY_OBJECT_FILE_NAME:
+                column = MtpObjects.ObjectColumns.DATA;
+                isString = true;
+                break;
+            case MTP_PROPERTY_DATE_MODIFIED:
+                column = MtpObjects.ObjectColumns.DATE_MODIFIED;
+                break;
+            case MTP_PROPERTY_PARENT_OBJECT:
+                column = MtpObjects.ObjectColumns.PARENT;
+                break;
+            default:
+                return MTP_RESPONSE_OBJECT_PROP_NOT_SUPPORTED;
+        }
+
+        Cursor c = null;
+        try {
+            // for now we are only reading properties from the "objects" table
+            c = mMediaProvider.query(mObjectsUri,
+                            new String [] { MtpObjects.ObjectColumns._ID, column },
+                            ID_WHERE, new String[] { Integer.toString(handle) }, null);
+            if (c != null && c.moveToNext()) {
+                if (isString) {
+                    String value = c.getString(1);
+                    int start = 0;
+
+                    if (property == MTP_PROPERTY_OBJECT_FILE_NAME) {
+                        // extract name from full path
+                        int lastSlash = value.lastIndexOf('/');
+                        if (lastSlash >= 0) {
+                            start = lastSlash + 1;
+                        }
+                    }
+                    int end = value.length();
+                    if (end - start > 255) {
+                        end = start + 255;
+                    }
+                    value.getChars(start, end, outStringValue, 0);
+                    outStringValue[end - start] = 0;
+                } else {
+                    outIntValue[0] = c.getLong(1);
+                }
+                return MTP_RESPONSE_OK;
+            }
+        } catch (Exception e) {
+            return MTP_RESPONSE_GENERAL_ERROR;
+        } finally {
+            if (c != null) {
+                c.close();
+            }
+        }
+        // query failed if we get here
+        return MTP_RESPONSE_INVALID_OBJECT_HANDLE;
+    }
+
+    private boolean getObjectInfo(int handle, int[] outStorageFormatParent,
+                        char[] outName, long[] outSizeModified) {
+        Log.d(TAG, "getObjectInfo: " + handle);
+        Cursor c = null;
+        try {
+            c = mMediaProvider.query(mObjectsUri, OBJECT_INFO_PROJECTION,
+                            ID_WHERE, new String[] {  Integer.toString(handle) }, null);
+            if (c != null && c.moveToNext()) {
+                outStorageFormatParent[0] = mStorageID;
+                outStorageFormatParent[1] = c.getInt(2);
+                outStorageFormatParent[2] = c.getInt(3);
+
+                // extract name from path
+                String path = c.getString(1);
+                int lastSlash = path.lastIndexOf('/');
+                int start = (lastSlash >= 0 ? lastSlash + 1 : 0);
+                int end = path.length();
+                if (end - start > 255) {
+                    end = start + 255;
+                }
+                path.getChars(start, end, outName, 0);
+                outName[end - start] = 0;
+
+                outSizeModified[0] = c.getLong(4);
+                outSizeModified[1] = c.getLong(5);
+                return true;
+            }
+        } catch (RemoteException e) {
+            Log.e(TAG, "RemoteException in getObjectProperty", e);
+        } finally {
+            if (c != null) {
+                c.close();
+            }
+        }
+        return false;
+    }
+
+    private boolean getObjectFilePath(int handle, char[] outFilePath, long[] outFileLength) {
+        Log.d(TAG, "getObjectFilePath: " + handle);
+        Cursor c = null;
+        try {
+            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);
+                path.getChars(0, path.length(), outFilePath, 0);
+                outFilePath[path.length()] = 0;
+                outFileLength[0] = c.getLong(2);
+                return true;
+            }
+        } catch (RemoteException e) {
+            Log.e(TAG, "RemoteException in getObjectFilePath", e);
+        } finally {
+            if (c != null) {
+                c.close();
+            }
+        }
+        return false;
+    }
+
+    private boolean deleteFile(int handle) {
+        Log.d(TAG, "deleteFile: " + handle);
+        Uri uri = MtpObjects.getContentUri(mVolumeName, handle);
+        try {
+            return (mMediaProvider.delete(uri, null, null) == 1);
+        } catch (RemoteException e) {
+            Log.e(TAG, "RemoteException in deleteFile", e);
+            return false;
+        }
+    }
+
+    // used by the JNI code
+    private int mNativeContext;
+
+    private native final void native_setup();
+    private native final void native_finalize();
+}
diff --git a/media/java/android/media/MtpServer.java b/media/java/android/media/MtpServer.java
index a9a54e7..b0945a5 100644
--- a/media/java/android/media/MtpServer.java
+++ b/media/java/android/media/MtpServer.java
@@ -30,8 +30,8 @@
         System.loadLibrary("media_jni");
     }
 
-    public MtpServer(String storagePath, String databasePath) {
-        native_setup(storagePath, databasePath);
+    public MtpServer(MtpDatabase database, String storagePath) {
+        native_setup(database, storagePath);
     }
 
     @Override
@@ -47,11 +47,21 @@
         native_stop();
     }
 
+    public void sendObjectAdded(int handle) {
+        native_send_object_added(handle);
+    }
+
+    public void sendObjectRemoved(int handle) {
+        native_send_object_removed(handle);
+    }
+
     // used by the JNI code
     private int mNativeContext;
 
-    private native final void native_setup(String storagePath, String databasePath);
+    private native final void native_setup(MtpDatabase database, String storagePath);
     private native final void native_finalize();
     private native final void native_start();
     private native final void native_stop();
+    private native final void native_send_object_added(int handle);
+    private native final void native_send_object_removed(int handle);
 }
diff --git a/media/java/android/media/PresetReverb.java b/media/java/android/media/PresetReverb.java
new file mode 100644
index 0000000..83a01a4
--- /dev/null
+++ b/media/java/android/media/PresetReverb.java
@@ -0,0 +1,219 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.media;
+
+import android.app.Activity;
+import android.content.Context;
+import android.content.Intent;
+import android.os.Bundle;
+import android.util.Log;
+import java.nio.ByteOrder;
+import java.nio.ByteBuffer;
+
+import android.media.AudioEffect;
+
+/**
+ * A sound generated within a room travels in many directions. The listener first hears the
+ * direct sound from the source itself. Later, he or she hears discrete echoes caused by sound
+ * bouncing off nearby walls, the ceiling and the floor. As sound waves arrive after
+ * undergoing more and more reflections, individual reflections become indistinguishable and
+ * the listener hears continuous reverberation that decays over time.
+ * Reverb is vital for modeling a listener's environment. It can be used in music applications
+ * to simulate music being played back in various environments, or in games to immerse the
+ * listener within the game's environment.
+ * The PresetReverb class allows an application to configure the global reverb using a reverb preset.
+ * This is primarily used for adding some reverb in a music playback context. Applications
+ * requiring control over a more advanced environmental reverb are advised to use the
+ // TODO when EnvironmentalReverb is unhidden
+ // {_at_link android.media.EnvironmentalReverb} class.
+ * <p>An application creates a PresetReverb object to instantiate and control a reverb engine in the
+ * audio framework.
+ * <p>The methods, parameter types and units exposed by the PresetReverb implementation are
+ * directly mapping those defined by the OpenSL ES 1.0.1 Specification
+ * (http://www.khronos.org/opensles/) for the SLPresetReverbItf interface.
+ * Please refer to this specification for more details.
+ * <p>The PresetReverb is an output mix auxiliary effect and should be created on
+ * Audio session 0. In order for a MediaPlayer or AudioTrack to be fed into this effect,
+ * they must be explicitely attached to it and a send level must be specified. Use the effect ID
+ * returned by getId() method to designate this particular effect when attaching it to the
+ * MediaPlayer or AudioTrack.
+ // TODO when AudioEffect is unhidden
+ // <p> See {_at_link android.media.AudioEffect} class for more details on controlling audio effects.
+ *
+ * {@hide Pending API council review}
+ */
+
+public class PresetReverb extends AudioEffect {
+
+    private final static String TAG = "PresetReverb";
+
+    // These constants must be synchronized with those in
+    // frameworks/base/include/media/EffectPresetReverbApi.h
+
+    /**
+     * Preset. Parameter ID for
+     * {@link android.media.PresetReverb.OnParameterChangeListener}
+     */
+    public static final int PARAM_PRESET = 0;
+
+    /**
+     * Room level. Parameter ID for
+     * {@link android.media.PresetReverb.OnParameterChangeListener}
+     */
+    public static final int PRESET_NONE        = 0;
+    public static final int PRESET_SMALLROOM   = 1;
+    public static final int PRESET_MEDIUMROOM  = 2;
+    public static final int PRESET_LARGEROOM   = 3;
+    public static final int PRESET_MEDIUMHALL  = 4;
+    public static final int PRESET_LARGEHALL   = 5;
+    public static final int PRESET_PLATE       = 6;
+
+    /**
+     * Registered listener for parameter changes.
+     */
+    private OnParameterChangeListener mParamListener = null;
+
+    /**
+     * Listener used internally to to receive raw parameter change event from AudioEffect super class
+     */
+    private BaseParameterListener mBaseParamListener = null;
+
+    /**
+     * Lock for access to mParamListener
+     */
+    private final Object mParamListenerLock = new Object();
+
+    /**
+     * Class constructor.
+     * @param priority the priority level requested by the application for controlling the
+     * PresetReverb engine. As the same engine can be shared by several applications, this
+     * parameter indicates how much the requesting application needs control of effect parameters.
+     * The normal priority is 0, above normal is a positive number, below normal a negative number.
+     * @param audioSession  System wide unique audio session identifier. If audioSession
+     *  is not 0, the PresetReverb will be attached to the MediaPlayer or AudioTrack in the
+     *  same audio session. Otherwise, the PresetReverb will apply to the output mix.
+     *  As the PresetReverb is an auxiliary effect it is recommended to instantiate it on
+     *  audio session 0 and to attach it to the MediaPLayer auxiliary output.
+     *
+     * @throws java.lang.IllegalArgumentException
+     * @throws java.lang.UnsupportedOperationException
+     * @throws java.lang.RuntimeException
+     */
+    public PresetReverb(int priority, int audioSession)
+    throws IllegalArgumentException, UnsupportedOperationException, RuntimeException {
+        super(EFFECT_TYPE_PRESET_REVERB, EFFECT_TYPE_NULL, priority, audioSession);
+        Log.e(TAG, "contructor");
+    }
+
+    /**
+     *  Enables a preset on the reverb.
+     *  <p>The reverb PRESET_NONE disables any reverb from the current output but does not free the
+     *  resources associated with the reverb. For an application to signal to the implementation
+     *  to free the resources, it must call the release() method.
+     * @param preset This must be one of the the preset constants defined in this class.
+     * e.g. {@link #PRESET_SMALLROOM}
+     * @throws IllegalStateException
+     * @throws IllegalArgumentException
+     * @throws UnsupportedOperationException
+     */
+    public void setPreset(short preset)
+    throws IllegalStateException, IllegalArgumentException, UnsupportedOperationException {
+        checkStatus(setParameter(PARAM_PRESET, preset));
+    }
+
+    /**
+     * Gets current reverb preset.
+     * @return Preset that is set at the moment.
+     * @throws IllegalStateException
+     * @throws IllegalArgumentException
+     * @throws UnsupportedOperationException
+     */
+    public short getPreset()
+    throws IllegalStateException, IllegalArgumentException, UnsupportedOperationException {
+        int[] param = new int[1];
+        param[0] = PARAM_PRESET;
+        short[] value = new short[1];
+        checkStatus(getParameter(param, value));
+        return value[0];
+    }
+
+    /**
+     * The OnParameterChangeListener interface defines a method called by the PresetReverb
+     * when a parameter value has changed.
+     */
+    public interface OnParameterChangeListener  {
+        /**
+         * Method called when a parameter value has changed. The method is called only if the
+         * parameter was changed by another application having the control of the same
+         * PresetReverb engine.
+         * @param effect the PresetReverb on which the interface is registered.
+         * @param status status of the set parameter operation.
+         // TODO when AudioEffect is unhidden
+         // See {_at_link android.media.AudioEffect#setParameter(byte[], byte[])}.
+         * @param param ID of the modified parameter. See {@link #PARAM_PRESET} ...
+         * @param value the new parameter value.
+         */
+        void onParameterChange(PresetReverb effect, int status, int param, short value);
+    }
+
+    /**
+     * Listener used internally to receive unformatted parameter change events from AudioEffect
+     * super class.
+     */
+    private class BaseParameterListener implements AudioEffect.OnParameterChangeListener {
+        private BaseParameterListener() {
+
+        }
+        public void onParameterChange(AudioEffect effect, int status, byte[] param, byte[] value) {
+            OnParameterChangeListener l = null;
+
+            synchronized (mParamListenerLock) {
+                if (mParamListener != null) {
+                    l = mParamListener;
+                }
+            }
+            if (l != null) {
+                int p = -1;
+                short v = -1;
+
+                if (param.length == 4) {
+                    p = byteArrayToInt(param, 0);
+                }
+                if (value.length == 2) {
+                    v = byteArrayToShort(value, 0);
+                }
+                if (p != -1 && v != -1) {
+                    l.onParameterChange(PresetReverb.this, status, p, v);
+                }
+            }
+        }
+    }
+
+    /**
+     * Registers an OnParameterChangeListener interface.
+     * @param listener OnParameterChangeListener interface registered
+     */
+    public void setParameterListener(OnParameterChangeListener listener) {
+        synchronized (mParamListenerLock) {
+            if (mParamListener == null) {
+                mParamListener = listener;
+                mBaseParamListener = new BaseParameterListener();
+                super.setParameterListener(mBaseParamListener);
+            }
+        }
+    }
+}
diff --git a/media/java/android/media/Virtualizer.java b/media/java/android/media/Virtualizer.java
new file mode 100644
index 0000000..9f71297
--- /dev/null
+++ b/media/java/android/media/Virtualizer.java
@@ -0,0 +1,214 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.media;
+
+import android.app.Activity;
+import android.content.Context;
+import android.content.Intent;
+import android.os.Bundle;
+import android.util.Log;
+import java.nio.ByteOrder;
+import java.nio.ByteBuffer;
+import java.nio.CharBuffer;
+
+import android.media.AudioEffect;
+
+/**
+ * An audio virtualizer is a general name for an effect to spatialize audio channels. The exact
+ * behavior of this effect is dependent on the number of audio input channels and the types and
+ * number of audio output channels of the device. For example, in the case of a stereo input and
+ * stereo headphone output, a stereo widening effect is used when this effect is turned on.
+ * <p>An application creates a Virtualizer object to instantiate and control a virtualizer engine
+ * in the audio framework.
+ * <p>The methods, parameter types and units exposed by the Virtualizer implementation are directly
+ * mapping those defined by the OpenSL ES 1.0.1 Specification (http://www.khronos.org/opensles/)
+ * for the SLVirtualizerItf interface. Please refer to this specification for more details.
+ * <p>To attach the Virtualizer to a particular AudioTrack or MediaPlayer, specify the audio session
+ * ID of this AudioTrack or MediaPlayer when constructing the Virtualizer. If the audio session ID 0
+ * is specified, the Virtualizer applies to the main audio output mix.
+ // TODO when AudioEffect is unhidden
+ // <p> See {_at_link android.media.AudioEffect} class for more details on controlling audio effects.
+ *
+ * {@hide Pending API council review}
+ */
+
+public class Virtualizer extends AudioEffect {
+
+    private final static String TAG = "Virtualizer";
+
+    // These constants must be synchronized with those in frameworks/base/include/media/EffectVirtualizerApi.h
+    /**
+     * Is strength parameter supported by virtualizer engine. Parameter ID for getParameter().
+     */
+    public static final int PARAM_STRENGTH_SUPPORTED = 0;
+    /**
+     * Virtualizer effect strength. Parameter ID for
+     * {@link android.media.Virtualizer.OnParameterChangeListener}
+     */
+    public static final int PARAM_STRENGTH = 1;
+
+    /**
+     * Indicates if strength parameter is supported by the virtualizer engine
+     */
+    private boolean mStrengthSupported = false;
+
+    /**
+     * Registered listener for parameter changes.
+     */
+    private OnParameterChangeListener mParamListener = null;
+
+    /**
+     * Listener used internally to to receive raw parameter change event from AudioEffect super class
+     */
+    private BaseParameterListener mBaseParamListener = null;
+
+    /**
+     * Lock for access to mParamListener
+     */
+    private final Object mParamListenerLock = new Object();
+
+    /**
+     * Class constructor.
+     * @param priority the priority level requested by the application for controlling the Virtualizer
+     * engine. As the same engine can be shared by several applications, this parameter indicates
+     * how much the requesting application needs control of effect parameters. The normal priority
+     * is 0, above normal is a positive number, below normal a negative number.
+     * @param audioSession  System wide unique audio session identifier. If audioSession
+     *  is not 0, the Virtualizer will be attached to the MediaPlayer or AudioTrack in the
+     *  same audio session. Otherwise, the Virtualizer will apply to the output mix.
+     *
+     * @throws java.lang.IllegalStateException
+     * @throws java.lang.IllegalArgumentException
+     * @throws java.lang.UnsupportedOperationException
+     * @throws java.lang.RuntimeException
+     */
+    public Virtualizer(int priority, int audioSession)
+    throws IllegalStateException, IllegalArgumentException,
+           UnsupportedOperationException, RuntimeException {
+        super(EFFECT_TYPE_VIRTUALIZER, EFFECT_TYPE_NULL, priority, audioSession);
+
+        short[] value = new short[1];
+        checkStatus(getParameter(PARAM_STRENGTH_SUPPORTED, value));
+        mStrengthSupported = (value[0] != 0);
+    }
+
+    /**
+     * Indicates whether setting strength is supported. If this method returns false, only one
+     * strength is supported and the setStrength() method always rounds to that value.
+     * @return true is strength parameter is supported, false otherwise
+     */
+    public boolean getStrengthSupported() {
+       return mStrengthSupported;
+    }
+
+    /**
+     * Sets the strength of the virtualizer effect. If the implementation does not support per mille
+     * accuracy for setting the strength, it is allowed to round the given strength to the nearest
+     * supported value. You can use the {@link #getRoundedStrength()} method to query the
+     * (possibly rounded) value that was actually set.
+     * @param strength Strength of the effect. The valid range for strength strength is [0, 1000],
+     * where 0 per mille designates the mildest effect and 1000 per mille designates the strongest.
+     * @throws IllegalStateException
+     * @throws IllegalArgumentException
+     * @throws UnsupportedOperationException
+     */
+    public void setStrength(short strength)
+    throws IllegalStateException, IllegalArgumentException, UnsupportedOperationException {
+        checkStatus(setParameter(PARAM_STRENGTH, strength));
+    }
+
+    /**
+     * Gets the current strength of the effect.
+     * @return The strength of the effect. The valid range for strength is [0, 1000], where 0 per
+     * mille designates the mildest effect and 1000 per mille the strongest
+     * @throws IllegalStateException
+     * @throws IllegalArgumentException
+     * @throws UnsupportedOperationException
+     */
+    public short getRoundedStrength()
+    throws IllegalStateException, IllegalArgumentException, UnsupportedOperationException {
+        short[] value = new short[1];
+        checkStatus(getParameter(PARAM_STRENGTH, value));
+        return value[0];
+    }
+
+    /**
+     * The OnParameterChangeListener interface defines a method called by the Virtualizer when a
+     * parameter value has changed.
+     */
+    public interface OnParameterChangeListener  {
+        /**
+         * Method called when a parameter value has changed. The method is called only if the
+         * parameter was changed by another application having the control of the same
+         * Virtualizer engine.
+         * @param effect the Virtualizer on which the interface is registered.
+         * @param status status of the set parameter operation.
+         // TODO when AudioEffect is unhidden
+         // See {_at_link android.media.AudioEffect#setParameter(byte[], byte[])}.
+         * @param param ID of the modified parameter. See {@link #PARAM_STRENGTH} ...
+         * @param value the new parameter value.
+         */
+        void onParameterChange(Virtualizer effect, int status, int param, short value);
+    }
+
+    /**
+     * Listener used internally to receive unformatted parameter change events from AudioEffect
+     * super class.
+     */
+    private class BaseParameterListener implements AudioEffect.OnParameterChangeListener {
+        private BaseParameterListener() {
+
+        }
+        public void onParameterChange(AudioEffect effect, int status, byte[] param, byte[] value) {
+            OnParameterChangeListener l = null;
+
+            synchronized (mParamListenerLock) {
+                if (mParamListener != null) {
+                    l = mParamListener;
+                }
+            }
+            if (l != null) {
+                int p = -1;
+                short v = -1;
+
+                if (param.length == 4) {
+                    p = byteArrayToInt(param, 0);
+                }
+                if (value.length == 2) {
+                    v = byteArrayToShort(value, 0);
+                }
+                if (p != -1 && v != -1) {
+                    l.onParameterChange(Virtualizer.this, status, p, v);
+                }
+            }
+        }
+    }
+
+    /**
+     * Registers an OnParameterChangeListener interface.
+     * @param listener OnParameterChangeListener interface registered
+     */
+    public void setParameterListener(OnParameterChangeListener listener) {
+        synchronized (mParamListenerLock) {
+            if (mParamListener == null) {
+                mParamListener = listener;
+                mBaseParamListener = new BaseParameterListener();
+                super.setParameterListener(mBaseParamListener);
+            }
+        }
+    }
+}
diff --git a/media/jni/Android.mk b/media/jni/Android.mk
index 3a7291f..653532c 100644
--- a/media/jni/Android.mk
+++ b/media/jni/Android.mk
@@ -15,6 +15,7 @@
     android_media_AmrInputStream.cpp \
 	android_media_MtpClient.cpp \
 	android_media_MtpCursor.cpp \
+	android_media_MtpDatabase.cpp \
 	android_media_MtpServer.cpp \
 
 LOCAL_SHARED_LIBRARIES := \
@@ -39,7 +40,9 @@
     LOCAL_CFLAGS += -DNO_OPENCORE
 endif
 
+ifneq ($(TARGET_SIMULATOR),true)
 LOCAL_STATIC_LIBRARIES := libmtp libusbhost
+endif
 
 LOCAL_C_INCLUDES += \
     external/tremor/Tremor \
diff --git a/media/jni/android_media_MediaPlayer.cpp b/media/jni/android_media_MediaPlayer.cpp
index 47f1974..5c2ec00 100644
--- a/media/jni/android_media_MediaPlayer.cpp
+++ b/media/jni/android_media_MediaPlayer.cpp
@@ -766,6 +766,7 @@
 extern int register_android_media_MediaProfiles(JNIEnv *env);
 extern int register_android_media_MtpClient(JNIEnv *env);
 extern int register_android_media_MtpCursor(JNIEnv *env);
+extern int register_android_media_MtpDatabase(JNIEnv *env);
 extern int register_android_media_MtpServer(JNIEnv *env);
 
 #ifndef NO_OPENCORE
@@ -830,6 +831,11 @@
         goto bail;
     }
 
+    if (register_android_media_MtpDatabase(env) < 0) {
+        LOGE("ERROR: MtpDatabase native registration failed");
+        goto bail;
+    }
+
     if (register_android_media_MtpServer(env) < 0) {
         LOGE("ERROR: MtpServer native registration failed");
         goto bail;
diff --git a/media/jni/android_media_MtpClient.cpp b/media/jni/android_media_MtpClient.cpp
index 5c397a6..f69053c 100644
--- a/media/jni/android_media_MtpClient.cpp
+++ b/media/jni/android_media_MtpClient.cpp
@@ -38,6 +38,8 @@
 static jmethodID method_deviceRemoved;
 static jfieldID field_context;
 
+#ifdef HAVE_ANDROID_OS
+
 static void checkAndClearExceptionFromCallback(JNIEnv* env, const char* methodName) {
     if (env->ExceptionCheck()) {
         LOGE("An exception was thrown by callback '%s'.", methodName);
@@ -94,52 +96,66 @@
     checkAndClearExceptionFromCallback(env, __FUNCTION__);
 }
 
+#endif // HAVE_ANDROID_OS
+
 // ----------------------------------------------------------------------------
 
 static void
 android_media_MtpClient_setup(JNIEnv *env, jobject thiz)
 {
+#ifdef HAVE_ANDROID_OS
     LOGD("setup\n");
     MyClient* client = new MyClient(env, thiz);
     client->start();
     env->SetIntField(thiz, field_context, (int)client);
+#endif
 }
 
 static void
 android_media_MtpClient_finalize(JNIEnv *env, jobject thiz)
 {
+#ifdef HAVE_ANDROID_OS
     LOGD("finalize\n");
     MyClient *client = (MyClient *)env->GetIntField(thiz, field_context);
     client->cleanup(env);
     delete client;
     env->SetIntField(thiz, field_context, 0);
+#endif
 }
 
 static jboolean
 android_media_MtpClient_start(JNIEnv *env, jobject thiz)
 {
+#ifdef HAVE_ANDROID_OS
     LOGD("start\n");
     MyClient *client = (MyClient *)env->GetIntField(thiz, field_context);
     return client->start();
+#else
+    return false;
+#endif
 }
 
 static void
 android_media_MtpClient_stop(JNIEnv *env, jobject thiz)
 {
+#ifdef HAVE_ANDROID_OS
     LOGD("stop\n");
     MyClient *client = (MyClient *)env->GetIntField(thiz, field_context);
     client->stop();
+#endif
 }
 
 static jboolean
 android_media_MtpClient_delete_object(JNIEnv *env, jobject thiz,
         jint device_id, jint object_id)
 {
+#ifdef HAVE_ANDROID_OS
     MyClient *client = (MyClient *)env->GetIntField(thiz, field_context);
     MtpDevice* device = client->getDevice(device_id);
     if (device)
         return device->deleteObject(object_id);
     else
+ #endif
         return NULL;
 }
 
@@ -147,11 +163,13 @@
 android_media_MtpClient_get_parent(JNIEnv *env, jobject thiz,
         jint device_id, jint object_id)
 {
+#ifdef HAVE_ANDROID_OS
     MyClient *client = (MyClient *)env->GetIntField(thiz, field_context);
     MtpDevice* device = client->getDevice(device_id);
     if (device)
         return device->getParent(object_id);
     else
+#endif
         return -1;
 }
 
@@ -159,11 +177,13 @@
 android_media_MtpClient_get_storage_id(JNIEnv *env, jobject thiz,
         jint device_id, jint object_id)
 {
+ #ifdef HAVE_ANDROID_OS
     MyClient *client = (MyClient *)env->GetIntField(thiz, field_context);
     MtpDevice* device = client->getDevice(device_id);
     if (device)
         return device->getStorageID(object_id);
     else
+#endif
         return -1;
 }
 
diff --git a/media/jni/android_media_MtpCursor.cpp b/media/jni/android_media_MtpCursor.cpp
index 470fa05..6228b5d 100644
--- a/media/jni/android_media_MtpCursor.cpp
+++ b/media/jni/android_media_MtpCursor.cpp
@@ -51,6 +51,7 @@
 android_media_MtpCursor_setup(JNIEnv *env, jobject thiz, jobject javaClient,
         jint queryType, jint deviceID, jint storageID, jint objectID, jintArray javaColumns)
 {
+#ifdef HAVE_ANDROID_OS
     LOGD("android_media_MtpCursor_setup queryType: %d deviceID: %d storageID: %d objectID: %d\n",
                 queryType, deviceID, storageID, objectID);
 
@@ -68,19 +69,23 @@
     if (columns)
         env->ReleaseIntArrayElements(javaColumns, columns, 0);
     env->SetIntField(thiz, field_context, (int)cursor);
+#endif
 }
 
 static void
 android_media_MtpCursor_finalize(JNIEnv *env, jobject thiz)
 {
+#ifdef HAVE_ANDROID_OS
     LOGD("finalize\n");
     MtpCursor *cursor = (MtpCursor *)env->GetIntField(thiz, field_context);
     delete cursor;
+#endif
 }
 
 static jint
 android_media_MtpCursor_fill_window(JNIEnv *env, jobject thiz, jobject javaWindow, jint startPos)
 {
+#ifdef HAVE_ANDROID_OS
     CursorWindow* window = get_window_from_object(env, javaWindow);
     if (!window) {
         LOGE("Invalid CursorWindow");
@@ -91,6 +96,9 @@
     MtpCursor *cursor = (MtpCursor *)env->GetIntField(thiz, field_context);
 
     return cursor->fillWindow(window, startPos);
+#else
+    return 0;
+#endif
 }
 
 // ----------------------------------------------------------------------------
diff --git a/media/jni/android_media_MtpDatabase.cpp b/media/jni/android_media_MtpDatabase.cpp
new file mode 100644
index 0000000..be59362
--- /dev/null
+++ b/media/jni/android_media_MtpDatabase.cpp
@@ -0,0 +1,463 @@
+/*
+ * 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.
+ */
+
+#define LOG_TAG "MtpDatabaseJNI"
+#include "utils/Log.h"
+
+#include <stdio.h>
+#include <assert.h>
+#include <limits.h>
+#include <unistd.h>
+#include <fcntl.h>
+
+#include "jni.h"
+#include "JNIHelp.h"
+#include "android_runtime/AndroidRuntime.h"
+
+#include "MtpDatabase.h"
+#include "MtpDataPacket.h"
+#include "MtpUtils.h"
+#include "mtp.h"
+
+using namespace android;
+
+// ----------------------------------------------------------------------------
+
+static jmethodID method_beginSendObject;
+static jmethodID method_endSendObject;
+static jmethodID method_getObjectList;
+static jmethodID method_getObjectProperty;
+static jmethodID method_getObjectInfo;
+static jmethodID method_getObjectFilePath;
+static jmethodID method_deleteFile;
+static jfieldID field_context;
+
+MtpDatabase* getMtpDatabase(JNIEnv *env, jobject database) {
+    return (MtpDatabase *)env->GetIntField(database, field_context);
+}
+
+#ifdef HAVE_ANDROID_OS
+// ----------------------------------------------------------------------------
+
+class MyMtpDatabase : public MtpDatabase {
+private:
+    jobject         mDatabase;
+    jintArray       mIntBuffer;
+    jlongArray      mLongBuffer;
+    jcharArray      mStringBuffer;
+
+public:
+                                    MyMtpDatabase(JNIEnv *env, jobject client);
+    virtual                         ~MyMtpDatabase();
+    void                            cleanup(JNIEnv *env);
+
+    virtual MtpObjectHandle         beginSendObject(const char* path,
+                                            MtpObjectFormat format,
+                                            MtpObjectHandle parent,
+                                            MtpStorageID storage,
+                                            uint64_t size,
+                                            time_t modified);
+
+    virtual void                    endSendObject(const char* path,
+                                            MtpObjectHandle handle,
+                                            MtpObjectFormat format,
+                                            bool succeeded);
+
+    virtual MtpObjectHandleList*    getObjectList(MtpStorageID storageID,
+                                    MtpObjectFormat format,
+                                    MtpObjectHandle parent);
+
+    virtual MtpResponseCode         getObjectProperty(MtpObjectHandle handle,
+                                            MtpObjectProperty property,
+                                            MtpDataPacket& packet);
+
+    virtual MtpResponseCode         getObjectInfo(MtpObjectHandle handle,
+                                            MtpDataPacket& packet);
+
+    virtual bool                    getObjectFilePath(MtpObjectHandle handle,
+                                            MtpString& filePath,
+                                            int64_t& fileLength);
+    virtual bool                    deleteFile(MtpObjectHandle handle);
+
+    // helper for media scanner
+    virtual MtpObjectHandle*        getFileList(int& outCount);
+
+    virtual void                    beginTransaction();
+    virtual void                    commitTransaction();
+    virtual void                    rollbackTransaction();
+
+    bool                            getPropertyInfo(MtpObjectProperty property, int& type);
+};
+
+MyMtpDatabase::MyMtpDatabase(JNIEnv *env, jobject client)
+    :   mDatabase(env->NewGlobalRef(client)),
+        mIntBuffer(NULL),
+        mLongBuffer(NULL),
+        mStringBuffer(NULL)
+{
+    jintArray intArray;
+    jlongArray longArray;
+    jcharArray charArray;
+
+    // create buffers for out arguments
+    // we don't need to be thread-safe so this is OK
+    intArray = env->NewIntArray(3);
+    if (!intArray)
+        goto out_of_memory;
+    mIntBuffer = (jintArray)env->NewGlobalRef(intArray);
+    longArray = env->NewLongArray(2);
+    if (!longArray)
+        goto out_of_memory;
+    mLongBuffer = (jlongArray)env->NewGlobalRef(longArray);
+    charArray = env->NewCharArray(256);
+    if (!charArray)
+        goto out_of_memory;
+    mStringBuffer = (jcharArray)env->NewGlobalRef(charArray);
+    return;
+
+out_of_memory:
+    env->ThrowNew(env->FindClass("java/lang/OutOfMemoryError"), NULL);
+}
+
+void MyMtpDatabase::cleanup(JNIEnv *env) {
+    env->DeleteGlobalRef(mDatabase);
+    env->DeleteGlobalRef(mIntBuffer);
+    env->DeleteGlobalRef(mLongBuffer);
+    env->DeleteGlobalRef(mStringBuffer);
+}
+
+MyMtpDatabase::~MyMtpDatabase() {
+}
+
+MtpObjectHandle MyMtpDatabase::beginSendObject(const char* path,
+                                            MtpObjectFormat format,
+                                            MtpObjectHandle parent,
+                                            MtpStorageID storage,
+                                            uint64_t size,
+                                            time_t modified) {
+    JNIEnv* env = AndroidRuntime::getJNIEnv();
+    return env->CallIntMethod(mDatabase, method_beginSendObject, env->NewStringUTF(path),
+                (jint)format, (jint)parent, (jint)storage, (jlong)size, (jlong)modified);
+}
+
+void MyMtpDatabase::endSendObject(const char* path, MtpObjectHandle handle,
+                                MtpObjectFormat format, bool succeeded) {
+    JNIEnv* env = AndroidRuntime::getJNIEnv();
+    env->CallVoidMethod(mDatabase, method_endSendObject, env->NewStringUTF(path),
+                        (jint)handle, (jint)format, (jboolean)succeeded);
+}
+
+MtpObjectHandleList* MyMtpDatabase::getObjectList(MtpStorageID storageID,
+                                    MtpObjectFormat format,
+                                    MtpObjectHandle parent) {
+    JNIEnv* env = AndroidRuntime::getJNIEnv();
+    jintArray array = (jintArray)env->CallObjectMethod(mDatabase, method_getObjectList,
+                (jint)storageID, (jint)format, (jint)parent);
+    if (!array)
+        return NULL;
+    MtpObjectHandleList* list = new MtpObjectHandleList();
+    jint* handles = env->GetIntArrayElements(array, 0);
+    jsize length = env->GetArrayLength(array);
+LOGD("getObjectList length: %d", length);
+    for (int i = 0; i < length; i++) {
+LOGD("push: %d", handles[i]);
+        list->push(handles[i]);
+    }
+   env->ReleaseIntArrayElements(array, handles, 0);
+   return list;
+}
+
+MtpResponseCode MyMtpDatabase::getObjectProperty(MtpObjectHandle handle,
+                                            MtpObjectProperty property,
+                                            MtpDataPacket& packet) {
+    int         type;
+
+    if (!getPropertyInfo(property, type))
+        return MTP_RESPONSE_INVALID_OBJECT_PROP_CODE;
+
+    JNIEnv* env = AndroidRuntime::getJNIEnv();
+    jint result = env->CallIntMethod(mDatabase, method_getObjectProperty,
+                (jint)handle, (jint)property, mLongBuffer, mStringBuffer);
+    if (result != MTP_RESPONSE_OK)
+        return result;
+
+    jlong* longValues = env->GetLongArrayElements(mLongBuffer, 0);
+    jlong longValue = longValues[0];
+    env->ReleaseLongArrayElements(mLongBuffer, longValues, 0);
+
+    switch (type) {
+        case MTP_TYPE_INT8:
+            packet.putInt8(longValue);
+            break;
+        case MTP_TYPE_UINT8:
+            packet.putUInt8(longValue);
+            break;
+        case MTP_TYPE_INT16:
+            packet.putInt16(longValue);
+            break;
+        case MTP_TYPE_UINT16:
+            packet.putUInt16(longValue);
+            break;
+        case MTP_TYPE_INT32:
+            packet.putInt32(longValue);
+            break;
+        case MTP_TYPE_UINT32:
+            packet.putUInt32(longValue);
+            break;
+        case MTP_TYPE_INT64:
+            packet.putInt64(longValue);
+            break;
+        case MTP_TYPE_UINT64:
+            packet.putUInt64(longValue);
+            break;
+        case MTP_TYPE_STR:
+        {
+            jchar* str = env->GetCharArrayElements(mStringBuffer, 0);
+            packet.putString(str);
+            env->ReleaseCharArrayElements(mStringBuffer, str, 0);
+            break;
+         }
+        default:
+            LOGE("unsupported object type\n");
+            return MTP_RESPONSE_INVALID_OBJECT_HANDLE;
+    }
+    return MTP_RESPONSE_OK;
+}
+
+MtpResponseCode MyMtpDatabase::getObjectInfo(MtpObjectHandle handle,
+                                            MtpDataPacket& packet) {
+    char    date[20];
+
+    JNIEnv* env = AndroidRuntime::getJNIEnv();
+    jboolean result = env->CallBooleanMethod(mDatabase, method_getObjectInfo,
+                (jint)handle, mIntBuffer, mStringBuffer, mLongBuffer);
+    if (!result)
+        return MTP_RESPONSE_INVALID_OBJECT_HANDLE;
+
+    jint* intValues = env->GetIntArrayElements(mIntBuffer, 0);
+    MtpStorageID storageID = intValues[0];
+    MtpObjectFormat format = intValues[1];
+    MtpObjectHandle parent = intValues[2];
+    env->ReleaseIntArrayElements(mIntBuffer, intValues, 0);
+
+    jlong* longValues = env->GetLongArrayElements(mLongBuffer, 0);
+    uint64_t size = longValues[0];
+    uint64_t modified = longValues[1];
+    env->ReleaseLongArrayElements(mLongBuffer, longValues, 0);
+
+    int associationType = (format == MTP_FORMAT_ASSOCIATION ?
+                            MTP_ASSOCIATION_TYPE_GENERIC_FOLDER :
+                            MTP_ASSOCIATION_TYPE_UNDEFINED);
+
+    packet.putUInt32(storageID);
+    packet.putUInt16(format);
+    packet.putUInt16(0);   // protection status
+    packet.putUInt32((size > 0xFFFFFFFFLL ? 0xFFFFFFFF : size));
+    packet.putUInt16(0);   // thumb format
+    packet.putUInt32(0);   // thumb compressed size
+    packet.putUInt32(0);   // thumb pix width
+    packet.putUInt32(0);   // thumb pix height
+    packet.putUInt32(0);   // image pix width
+    packet.putUInt32(0);   // image pix height
+    packet.putUInt32(0);   // image bit depth
+    packet.putUInt32(parent);
+    packet.putUInt16(associationType);
+    packet.putUInt32(0);   // association desc
+    packet.putUInt32(0);   // sequence number
+
+    jchar* str = env->GetCharArrayElements(mStringBuffer, 0);
+    packet.putString(str);   // file name
+    env->ReleaseCharArrayElements(mStringBuffer, str, 0);
+
+    packet.putEmptyString();
+    formatDateTime(modified, date, sizeof(date));
+    packet.putString(date);   // date modified
+    packet.putEmptyString();   // keywords
+
+    return MTP_RESPONSE_OK;
+}
+
+bool MyMtpDatabase::getObjectFilePath(MtpObjectHandle handle,
+                                            MtpString& filePath,
+                                            int64_t& fileLength) {
+    JNIEnv* env = AndroidRuntime::getJNIEnv();
+    jboolean result = env->CallBooleanMethod(mDatabase, method_getObjectFilePath,
+                (jint)handle, mStringBuffer, mLongBuffer);
+    if (!result)
+        return false;
+
+    jchar* str = env->GetCharArrayElements(mStringBuffer, 0);
+    filePath.setTo(str, strlen16(str));
+    env->ReleaseCharArrayElements(mStringBuffer, str, 0);
+
+    jlong* longValues = env->GetLongArrayElements(mLongBuffer, 0);
+    fileLength = longValues[0];
+    env->ReleaseLongArrayElements(mLongBuffer, longValues, 0);
+    
+    return true;
+}
+
+bool MyMtpDatabase::deleteFile(MtpObjectHandle handle) {
+    JNIEnv* env = AndroidRuntime::getJNIEnv();
+    return env->CallBooleanMethod(mDatabase, method_deleteFile, (jint)handle); 
+}
+
+    // helper for media scanner
+MtpObjectHandle* MyMtpDatabase::getFileList(int& outCount) {
+    // REMOVE ME
+    return NULL;
+}
+
+void MyMtpDatabase::beginTransaction() {
+    // REMOVE ME
+}
+
+void MyMtpDatabase::commitTransaction() {
+    // REMOVE ME
+}
+
+void MyMtpDatabase::rollbackTransaction() {
+    // REMOVE ME
+}
+
+struct PropertyTableEntry {
+    MtpObjectProperty   property;
+    int                 type;
+};
+
+static const PropertyTableEntry   kPropertyTable[] = {
+    {   MTP_PROPERTY_PARENT_OBJECT,     MTP_TYPE_UINT32 },
+    {   MTP_PROPERTY_STORAGE_ID,        MTP_TYPE_UINT32 },
+    {   MTP_PROPERTY_OBJECT_FORMAT,     MTP_TYPE_UINT32 },
+    {   MTP_PROPERTY_OBJECT_FILE_NAME,  MTP_TYPE_STR    },
+    {   MTP_PROPERTY_OBJECT_SIZE,       MTP_TYPE_UINT64 },
+    {   MTP_PROPERTY_DATE_MODIFIED,     MTP_TYPE_STR    },
+};
+
+bool MyMtpDatabase::getPropertyInfo(MtpObjectProperty property, int& type) {
+    int count = sizeof(kPropertyTable) / sizeof(kPropertyTable[0]);
+    const PropertyTableEntry* entry = kPropertyTable;
+    for (int i = 0; i < count; i++, entry++) {
+        if (entry->property == property) {
+            type = entry->type;
+            return true;
+        }
+    }
+    return false;
+}
+
+// ----------------------------------------------------------------------------
+
+static void checkAndClearExceptionFromCallback(JNIEnv* env, const char* methodName) {
+    if (env->ExceptionCheck()) {
+        LOGE("An exception was thrown by callback '%s'.", methodName);
+        LOGE_EX(env);
+        env->ExceptionClear();
+    }
+}
+
+#endif // HAVE_ANDROID_OS
+
+// ----------------------------------------------------------------------------
+
+static void
+android_media_MtpDatabase_setup(JNIEnv *env, jobject thiz)
+{
+#ifdef HAVE_ANDROID_OS
+    LOGD("setup\n");
+    MyMtpDatabase* database = new MyMtpDatabase(env, thiz);
+    env->SetIntField(thiz, field_context, (int)database);
+    checkAndClearExceptionFromCallback(env, __FUNCTION__);
+#endif
+}
+
+static void
+android_media_MtpDatabase_finalize(JNIEnv *env, jobject thiz)
+{
+#ifdef HAVE_ANDROID_OS
+    LOGD("finalize\n");
+    MyMtpDatabase* database = (MyMtpDatabase *)env->GetIntField(thiz, field_context);
+    database->cleanup(env);
+    delete database;
+    env->SetIntField(thiz, field_context, 0);
+    checkAndClearExceptionFromCallback(env, __FUNCTION__);
+#endif
+}
+
+// ----------------------------------------------------------------------------
+
+static JNINativeMethod gMethods[] = {
+    {"native_setup",            "()V",  (void *)android_media_MtpDatabase_setup},
+    {"native_finalize",         "()V",  (void *)android_media_MtpDatabase_finalize},
+};
+
+static const char* const kClassPathName = "android/media/MtpDatabase";
+
+int register_android_media_MtpDatabase(JNIEnv *env)
+{
+    jclass clazz;
+
+    LOGD("register_android_media_MtpDatabase\n");
+
+    clazz = env->FindClass("android/media/MtpDatabase");
+    if (clazz == NULL) {
+        LOGE("Can't find android/media/MtpDatabase");
+        return -1;
+    }
+    method_beginSendObject = env->GetMethodID(clazz, "beginSendObject", "(Ljava/lang/String;IIIJJ)I");
+    if (method_beginSendObject == NULL) {
+        LOGE("Can't find beginSendObject");
+        return -1;
+    }
+    method_endSendObject = env->GetMethodID(clazz, "endSendObject", "(Ljava/lang/String;IIZ)V");
+    if (method_endSendObject == NULL) {
+        LOGE("Can't find endSendObject");
+        return -1;
+    }
+    method_getObjectList = env->GetMethodID(clazz, "getObjectList", "(III)[I");
+    if (method_getObjectList == NULL) {
+        LOGE("Can't find getObjectList");
+        return -1;
+    }
+    method_getObjectProperty = env->GetMethodID(clazz, "getObjectProperty", "(II[J[C)I");
+    if (method_getObjectProperty == NULL) {
+        LOGE("Can't find getObjectProperty");
+        return -1;
+    }
+    method_getObjectInfo = env->GetMethodID(clazz, "getObjectInfo", "(I[I[C[J)Z");
+    if (method_getObjectInfo == NULL) {
+        LOGE("Can't find getObjectInfo");
+        return -1;
+    }
+    method_getObjectFilePath = env->GetMethodID(clazz, "getObjectFilePath", "(I[C[J)Z");
+    if (method_getObjectFilePath == NULL) {
+        LOGE("Can't find getObjectFilePath");
+        return -1;
+    }
+    method_deleteFile = env->GetMethodID(clazz, "deleteFile", "(I)Z");
+    if (method_deleteFile == NULL) {
+        LOGE("Can't find deleteFile");
+        return -1;
+    }
+    field_context = env->GetFieldID(clazz, "mNativeContext", "I");
+    if (field_context == NULL) {
+        LOGE("Can't find MtpDatabase.mNativeContext");
+        return -1;
+    }
+
+    return AndroidRuntime::registerNativeMethods(env,
+                "android/media/MtpDatabase", gMethods, NELEM(gMethods));
+}
diff --git a/media/jni/android_media_MtpServer.cpp b/media/jni/android_media_MtpServer.cpp
index e6a3835..eddad57 100644
--- a/media/jni/android_media_MtpServer.cpp
+++ b/media/jni/android_media_MtpServer.cpp
@@ -37,9 +37,13 @@
 
 static jfieldID field_context;
 
+// in android_media_MtpDatabase.cpp
+extern MtpDatabase* getMtpDatabase(JNIEnv *env, jobject database);
 
 // ----------------------------------------------------------------------------
 
+#ifdef HAVE_ANDROID_OS
+
 static bool ExceptionCheck(void* env)
 {
     return ((JNIEnv *)env)->ExceptionCheck();
@@ -47,14 +51,15 @@
 
 class MtpThread : public Thread {
 private:
+    MtpDatabase*    mDatabase;
+    MtpServer*      mServer;
     String8 mStoragePath;
-    String8 mDatabasePath;
     bool mDone;
-    bool mScannedOnce;
+    Mutex           mMutex;
 
 public:
-    MtpThread(const char* storagePath, const char* databasePath)
-        : mStoragePath(storagePath), mDatabasePath(databasePath), mDone(false), mScannedOnce(false)
+    MtpThread(MtpDatabase* database, const char* storagePath)
+        : mDatabase(database), mServer(NULL), mStoragePath(storagePath), mDone(false)
     {
     }
 
@@ -66,16 +71,19 @@
             return false;
         }
 
-        MtpServer* server = new MtpServer(fd, mDatabasePath, AID_SDCARD_RW, 0664, 0775);
-        server->addStorage(mStoragePath);
+        mMutex.lock();
+        mServer = new MtpServer(fd, mDatabase, AID_SDCARD_RW, 0664, 0775);
+        mServer->addStorage(mStoragePath);
+        mMutex.unlock();
 
-        // temporary
-        LOGD("MtpThread server->scanStorage");
-        server->scanStorage();
-        LOGD("MtpThread server->run");
-        server->run();
+        LOGD("MtpThread mServer->run");
+        mServer->run();
         close(fd);
-        delete server;
+
+        mMutex.lock();
+        delete mServer;
+        mServer = NULL;
+        mMutex.unlock();
 
         bool done = mDone;
         if (done)
@@ -85,21 +93,42 @@
     }
 
     void setDone() { mDone = true; }
+
+    void sendObjectAdded(MtpObjectHandle handle) {
+        mMutex.lock();
+        if (mServer)
+            mServer->sendObjectAdded(handle);
+        else
+            LOGE("sendObjectAdded called while disconnected\n");
+        mMutex.unlock();
+    }
+
+    void sendObjectRemoved(MtpObjectHandle handle) {
+        mMutex.lock();
+        if (mServer)
+            mServer->sendObjectRemoved(handle);
+        else
+            LOGE("sendObjectRemoved called while disconnected\n");
+        mMutex.unlock();
+    }
 };
 
+#endif // HAVE_ANDROID_OS
+
 static void
-android_media_MtpServer_setup(JNIEnv *env, jobject thiz, jstring storagePath, jstring databasePath)
+android_media_MtpServer_setup(JNIEnv *env, jobject thiz, jobject javaDatabase, jstring storagePath)
 {
+#ifdef HAVE_ANDROID_OS
     LOGD("setup\n");
 
+    MtpDatabase* database = getMtpDatabase(env, javaDatabase);
     const char *storagePathStr = env->GetStringUTFChars(storagePath, NULL);
-    const char *databasePathStr = env->GetStringUTFChars(databasePath, NULL);
 
-    MtpThread* thread = new MtpThread(storagePathStr, databasePathStr);
+    MtpThread* thread = new MtpThread(database, storagePathStr);
     env->SetIntField(thiz, field_context, (int)thread);
 
     env->ReleaseStringUTFChars(storagePath, storagePathStr);
-    env->ReleaseStringUTFChars(databasePath, databasePathStr);
+#endif
 }
 
 static void
@@ -112,29 +141,62 @@
 static void
 android_media_MtpServer_start(JNIEnv *env, jobject thiz)
 {
+#ifdef HAVE_ANDROID_OS
     LOGD("start\n");
     MtpThread *thread = (MtpThread *)env->GetIntField(thiz, field_context);
     thread->run("MtpThread");
+#endif // HAVE_ANDROID_OS
 }
 
 static void
 android_media_MtpServer_stop(JNIEnv *env, jobject thiz)
 {
+#ifdef HAVE_ANDROID_OS
     LOGD("stop\n");
     MtpThread *thread = (MtpThread *)env->GetIntField(thiz, field_context);
     if (thread) {
         thread->setDone();
         env->SetIntField(thiz, field_context, 0);
     }
+#endif
+}
+
+static void
+android_media_MtpServer_send_object_added(JNIEnv *env, jobject thiz, jint handle)
+{
+#ifdef HAVE_ANDROID_OS
+    LOGD("send_object_added %d\n", handle);
+    MtpThread *thread = (MtpThread *)env->GetIntField(thiz, field_context);
+    if (thread)
+        thread->sendObjectAdded(handle);
+    else
+        LOGE("sendObjectAdded called while disconnected\n");
+#endif
+}
+
+static void
+android_media_MtpServer_send_object_removed(JNIEnv *env, jobject thiz, jint handle)
+{
+#ifdef HAVE_ANDROID_OS
+    LOGD("send_object_removed %d\n", handle);
+    MtpThread *thread = (MtpThread *)env->GetIntField(thiz, field_context);
+    if (thread)
+        thread->sendObjectRemoved(handle);
+    else
+        LOGE("sendObjectRemoved called while disconnected\n");
+#endif
 }
 
 // ----------------------------------------------------------------------------
 
 static JNINativeMethod gMethods[] = {
-    {"native_setup",            "(Ljava/lang/String;Ljava/lang/String;)V",  (void *)android_media_MtpServer_setup},
-    {"native_finalize",         "()V",  (void *)android_media_MtpServer_finalize},
-    {"native_start",            "()V",  (void *)android_media_MtpServer_start},
-    {"native_stop",             "()V",  (void *)android_media_MtpServer_stop},
+    {"native_setup",                "(Landroid/media/MtpDatabase;Ljava/lang/String;)V",
+                                            (void *)android_media_MtpServer_setup},
+    {"native_finalize",             "()V",  (void *)android_media_MtpServer_finalize},
+    {"native_start",                "()V",  (void *)android_media_MtpServer_start},
+    {"native_stop",                 "()V",  (void *)android_media_MtpServer_stop},
+    {"native_send_object_added",    "(I)V", (void *)android_media_MtpServer_send_object_added},
+    {"native_send_object_removed",  "(I)V", (void *)android_media_MtpServer_send_object_removed},
 };
 
 static const char* const kClassPathName = "android/media/MtpServer";
diff --git a/media/jni/audioeffect/android_media_AudioEffect.cpp b/media/jni/audioeffect/android_media_AudioEffect.cpp
index 02474a4..beb3dfc 100644
--- a/media/jni/audioeffect/android_media_AudioEffect.cpp
+++ b/media/jni/audioeffect/android_media_AudioEffect.cpp
@@ -323,8 +323,8 @@
                                     priority,
                                     effectCallback,
                                     &lpJniStorage->mCallbackData,
-                                    0,
-                                    sessionId);
+                                    sessionId,
+                                    0);
     if (lpAudioEffect == NULL) {
         LOGE("Error creating AudioEffect");
         goto setup_failure;
diff --git a/media/libeffects/Android.mk b/media/libeffects/Android.mk
index 54e87f3..fc4ceb6 100644
--- a/media/libeffects/Android.mk
+++ b/media/libeffects/Android.mk
@@ -87,7 +87,8 @@
 endif
 
 LOCAL_C_INCLUDES := \
-	$(call include-path-for, graphics corecg)
+	$(call include-path-for, graphics corecg) \
+	system/media/opensles/include
 
 LOCAL_PRELINK_MODULE := false
 
diff --git a/media/libeffects/EffectEqualizer.cpp b/media/libeffects/EffectEqualizer.cpp
index d19c6b9..af0c411 100644
--- a/media/libeffects/EffectEqualizer.cpp
+++ b/media/libeffects/EffectEqualizer.cpp
@@ -30,6 +30,12 @@
 // effect_interface_t interface implementation for equalizer effect
 extern "C" const struct effect_interface_s gEqualizerInterface;
 
+enum equalizer_state_e {
+    EQUALIZER_STATE_UNINITIALIZED,
+    EQUALIZER_STATE_INITIALIZED,
+    EQUALIZER_STATE_ACTIVE,
+};
+
 namespace android {
 namespace {
 
@@ -100,6 +106,7 @@
     effect_config_t config;
     FormatAdapter adapter;
     AudioEqualizer * pEqualizer;
+    uint32_t state;
 };
 
 //--- local function prototypes
@@ -151,6 +158,7 @@
 
     pContext->itfe = &gEqualizerInterface;
     pContext->pEqualizer = NULL;
+    pContext->state = EQUALIZER_STATE_UNINITIALIZED;
 
     ret = Equalizer_init(pContext);
     if (ret < 0) {
@@ -160,6 +168,7 @@
     }
 
     *pInterface = (effect_interface_t)pContext;
+    pContext->state = EQUALIZER_STATE_INITIALIZED;
 
     LOGV("EffectLibCreateEffect %p, size %d", pContext, AudioEqualizer::GetInstanceSize(kNumBands)+sizeof(EqualizerContext));
 
@@ -175,6 +184,7 @@
         return -EINVAL;
     }
 
+    pContext->state = EQUALIZER_STATE_UNINITIALIZED;
     pContext->pEqualizer->free();
     delete pContext;
 
@@ -528,6 +538,13 @@
         return -EINVAL;
     }
 
+    if (pContext->state == EQUALIZER_STATE_UNINITIALIZED) {
+        return -EINVAL;
+    }
+    if (pContext->state == EQUALIZER_STATE_INITIALIZED) {
+        return -ENODATA;
+    }
+
     pContext->adapter.process(inBuffer->raw, outBuffer->raw, outBuffer->frameCount);
 
     return 0;
@@ -539,7 +556,7 @@
     android::EqualizerContext * pContext = (android::EqualizerContext *) self;
     int retsize;
 
-    if (pContext == NULL) {
+    if (pContext == NULL || pContext->state == EQUALIZER_STATE_UNINITIALIZED) {
         return -EINVAL;
     }
 
@@ -594,10 +611,25 @@
                 p->data + p->psize);
         } break;
     case EFFECT_CMD_ENABLE:
+        if (pReplyData == NULL || *replySize != sizeof(int)) {
+            return -EINVAL;
+        }
+        if (pContext->state != EQUALIZER_STATE_INITIALIZED) {
+            return -ENOSYS;
+        }
+        pContext->state = EQUALIZER_STATE_ACTIVE;
+        LOGV("EFFECT_CMD_ENABLE() OK");
+        *(int *)pReplyData = 0;
+        break;
     case EFFECT_CMD_DISABLE:
         if (pReplyData == NULL || *replySize != sizeof(int)) {
             return -EINVAL;
         }
+        if (pContext->state != EQUALIZER_STATE_ACTIVE) {
+            return -ENOSYS;
+        }
+        pContext->state = EQUALIZER_STATE_INITIALIZED;
+        LOGV("EFFECT_CMD_DISABLE() OK");
         *(int *)pReplyData = 0;
         break;
     case EFFECT_CMD_SET_DEVICE:
diff --git a/media/libeffects/EffectReverb.c b/media/libeffects/EffectReverb.c
index ada252c..2ce7558 100644
--- a/media/libeffects/EffectReverb.c
+++ b/media/libeffects/EffectReverb.c
@@ -15,8 +15,7 @@
  */
 
 #define LOG_TAG "EffectReverb"
-//
-#define LOG_NDEBUG 0
+//#define LOG_NDEBUG 0
 #include <cutils/log.h>
 #include <stdlib.h>
 #include <string.h>
@@ -57,7 +56,7 @@
 
 // Google auxiliary preset reverb UUID: 63909320-53a6-11df-bdbd-0002a5d5c51b
 static const effect_descriptor_t gAuxPresetReverbDescriptor = {
-        {0x47382d60, 0xddd8, 0x4763, 0x11db, {0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b}},
+        {0x47382d60, 0xddd8, 0x11db, 0xbf3a, {0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b}},
         {0x63909320, 0x53a6, 0x11df, 0xbdbd, {0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b}},
         EFFECT_API_VERSION,
         EFFECT_FLAG_TYPE_AUXILIARY,
@@ -69,7 +68,7 @@
 
 // Google insert preset reverb UUID: d93dc6a0-6342-11df-b128-0002a5d5c51b
 static const effect_descriptor_t gInsertPresetReverbDescriptor = {
-        {0x47382d60, 0xddd8, 0x4763, 0x11db, {0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b}},
+        {0x47382d60, 0xddd8, 0x11db, 0xbf3a, {0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b}},
         {0xd93dc6a0, 0x6342, 0x11df, 0xb128, {0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b}},
         EFFECT_API_VERSION,
         EFFECT_FLAG_TYPE_INSERT | EFFECT_FLAG_INSERT_FIRST,
@@ -143,6 +142,8 @@
 
     module->itfe = &gReverbInterface;
 
+    module->context.mState = REVERB_STATE_UNINITIALIZED;
+
     if (memcmp(&desc->type, SL_IID_PRESETREVERB, sizeof(effect_uuid_t)) == 0) {
         preset = 1;
     }
@@ -158,6 +159,8 @@
 
     *pInterface = (effect_interface_t) module;
 
+    module->context.mState = REVERB_STATE_INITIALIZED;
+
     LOGV("EffectLibCreateEffect %p ,size %d", module, sizeof(reverb_module_t));
 
     return 0;
@@ -171,6 +174,8 @@
         return -EINVAL;
     }
 
+    pRvbModule->context.mState = REVERB_STATE_UNINITIALIZED;
+
     free(pRvbModule);
     return 0;
 }
@@ -195,8 +200,15 @@
 
     pReverb = (reverb_object_t*) &pRvbModule->context;
 
+    if (pReverb->mState == REVERB_STATE_UNINITIALIZED) {
+        return -EINVAL;
+    }
+    if (pReverb->mState == REVERB_STATE_INITIALIZED) {
+        return -ENODATA;
+    }
+
     //if bypassed or the preset forces the signal to be completely dry
-    if (pReverb->m_bBypass) {
+    if (pReverb->m_bBypass != 0) {
         if (inBuffer->raw != outBuffer->raw) {
             int16_t smp;
             pSrc = inBuffer->s16;
@@ -257,13 +269,15 @@
     return 0;
 }
 
+
 static int Reverb_Command(effect_interface_t self, int cmdCode, int cmdSize,
         void *pCmdData, int *replySize, void *pReplyData) {
     reverb_module_t *pRvbModule = (reverb_module_t *) self;
     reverb_object_t *pReverb;
     int retsize;
 
-    if (pRvbModule == NULL) {
+    if (pRvbModule == NULL ||
+            pRvbModule->context.mState == REVERB_STATE_UNINITIALIZED) {
         return -EINVAL;
     }
 
@@ -277,6 +291,9 @@
             return -EINVAL;
         }
         *(int *) pReplyData = Reverb_Init(pRvbModule, pReverb->m_Aux, pReverb->m_Preset);
+        if (*(int *) pReplyData == 0) {
+            pRvbModule->context.mState = REVERB_STATE_INITIALIZED;
+        }
         break;
     case EFFECT_CMD_CONFIGURE:
         if (pCmdData == NULL || cmdSize != sizeof(effect_config_t)
@@ -315,10 +332,25 @@
                 cmd->vsize, cmd->data + sizeof(int32_t));
         break;
     case EFFECT_CMD_ENABLE:
+        if (pReplyData == NULL || *replySize != sizeof(int)) {
+            return -EINVAL;
+        }
+        if (pReverb->mState != REVERB_STATE_INITIALIZED) {
+            return -ENOSYS;
+        }
+        pReverb->mState = REVERB_STATE_ACTIVE;
+        LOGV("EFFECT_CMD_ENABLE() OK");
+        *(int *)pReplyData = 0;
+        break;
     case EFFECT_CMD_DISABLE:
         if (pReplyData == NULL || *replySize != sizeof(int)) {
             return -EINVAL;
         }
+        if (pReverb->mState != REVERB_STATE_ACTIVE) {
+            return -ENOSYS;
+        }
+        pReverb->mState = REVERB_STATE_INITIALIZED;
+        LOGV("EFFECT_CMD_DISABLE() OK");
         *(int *)pReplyData = 0;
         break;
     case EFFECT_CMD_SET_DEVICE:
@@ -520,7 +552,7 @@
         pReverb->m_bUseNoise = true;
 
         // for debugging purposes, allow bypass
-        pReverb->m_bBypass = false;
+        pReverb->m_bBypass = 0;
 
         pReverb->m_nNextRoom = 1;
 
@@ -662,248 +694,254 @@
     int32_t temp2;
     size_t size;
 
-    if (pReverb->m_Preset && param != REVERB_PARAM_PRESET) {
-        return -EINVAL;
-    }
-    if (!pReverb->m_Preset && param == REVERB_PARAM_PRESET) {
-        return -EINVAL;
-    }
-
-    switch (param) {
-    case REVERB_PARAM_ROOM_LEVEL:
-    case REVERB_PARAM_ROOM_HF_LEVEL:
-    case REVERB_PARAM_DECAY_HF_RATIO:
-    case REVERB_PARAM_REFLECTIONS_LEVEL:
-    case REVERB_PARAM_REVERB_LEVEL:
-    case REVERB_PARAM_DIFFUSION:
-    case REVERB_PARAM_DENSITY:
+    if (pReverb->m_Preset) {
+        if (param != REVERB_PARAM_PRESET || *pSize < sizeof(int16_t)) {
+            return -EINVAL;
+        }
         size = sizeof(int16_t);
-        break;
-
-    case REVERB_PARAM_BYPASS:
-    case REVERB_PARAM_PRESET:
-    case REVERB_PARAM_DECAY_TIME:
-    case REVERB_PARAM_REFLECTIONS_DELAY:
-    case REVERB_PARAM_REVERB_DELAY:
-        size = sizeof(int32_t);
-        break;
-
-    case REVERB_PARAM_PROPERTIES:
-        size = sizeof(t_reverb_properties);
-        break;
-
-    default:
-        return -EINVAL;
-    }
-
-    if (*pSize < size) {
-        return -EINVAL;
-    }
-    *pSize = size;
-    pValue32 = (int32_t *) pValue;
-    pValue16 = (int16_t *) pValue;
-    pProperties = (t_reverb_properties *) pValue;
-
-    switch (param) {
-    case REVERB_PARAM_BYPASS:
-        *(int32_t *) pValue = (int32_t) pReverb->m_bBypass;
-        break;
-    case REVERB_PARAM_PRESET:
-        *(int32_t *) pValue = (int8_t) pReverb->m_nCurrentRoom;
-        break;
-
-    case REVERB_PARAM_PROPERTIES:
-        pValue16 = &pProperties->roomLevel;
-        /* FALL THROUGH */
-
-    case REVERB_PARAM_ROOM_LEVEL:
-        // Convert m_nRoomLpfFwd to millibels
-        temp = (pReverb->m_nRoomLpfFwd << 15)
-                / (32767 - pReverb->m_nRoomLpfFbk);
-        *pValue16 = Effects_Linear16ToMillibels(temp);
-
-        LOGV("get REVERB_PARAM_ROOM_LEVEL %d, gain %d, m_nRoomLpfFwd %d, m_nRoomLpfFbk %d", *pValue16, temp, pReverb->m_nRoomLpfFwd, pReverb->m_nRoomLpfFbk);
-
-        if (param == REVERB_PARAM_ROOM_LEVEL) {
-            break;
-        }
-        pValue16 = &pProperties->roomHFLevel;
-        /* FALL THROUGH */
-
-    case REVERB_PARAM_ROOM_HF_LEVEL:
-        // The ratio between linear gain at 0Hz and at 5000Hz for the room low pass is:
-        // (1 + a1) / sqrt(a1^2 + 2*C*a1 + 1) where:
-        // - a1 is minus the LP feedback gain: -pReverb->m_nRoomLpfFbk
-        // - C is cos(2piWT) @ 5000Hz: pReverb->m_nCosWT_5KHz
-
-        temp = MULT_EG1_EG1(pReverb->m_nRoomLpfFbk, pReverb->m_nRoomLpfFbk);
-        LOGV("get REVERB_PARAM_ROOM_HF_LEVEL, a1^2 %d", temp);
-        temp2 = MULT_EG1_EG1(pReverb->m_nRoomLpfFbk, pReverb->m_nCosWT_5KHz)
-                << 1;
-        LOGV("get REVERB_PARAM_ROOM_HF_LEVEL, 2 Cos a1 %d", temp2);
-        temp = 32767 + temp - temp2;
-        LOGV("get REVERB_PARAM_ROOM_HF_LEVEL, a1^2 + 2 Cos a1 + 1 %d", temp);
-        temp = Effects_Sqrt(temp) * 181;
-        LOGV("get REVERB_PARAM_ROOM_HF_LEVEL, SQRT(a1^2 + 2 Cos a1 + 1) %d", temp);
-        temp = ((32767 - pReverb->m_nRoomLpfFbk) << 15) / temp;
-
-        LOGV("get REVERB_PARAM_ROOM_HF_LEVEL, gain %d, m_nRoomLpfFwd %d, m_nRoomLpfFbk %d", temp, pReverb->m_nRoomLpfFwd, pReverb->m_nRoomLpfFbk);
-
-        *pValue16 = Effects_Linear16ToMillibels(temp);
-
-        if (param == REVERB_PARAM_ROOM_HF_LEVEL) {
-            break;
-        }
-        pValue32 = &pProperties->decayTime;
-        /* FALL THROUGH */
-
-    case REVERB_PARAM_DECAY_TIME:
-        // Calculate reverb feedback path gain
-        temp = (pReverb->m_nRvbLpfFwd << 15) / (32767 - pReverb->m_nRvbLpfFbk);
-        temp = Effects_Linear16ToMillibels(temp);
-
-        // Calculate decay time: g = -6000 d/DT , g gain in millibels, d reverb delay, DT decay time
-        temp = (-6000 * pReverb->m_nLateDelay) / temp;
-
-        // Convert samples to ms
-        *pValue32 = (temp * 1000) / pReverb->m_nSamplingRate;
-
-        LOGV("get REVERB_PARAM_DECAY_TIME, samples %d, ms %d", temp, *pValue32);
-
-        if (param == REVERB_PARAM_DECAY_TIME) {
-            break;
-        }
-        pValue16 = &pProperties->decayHFRatio;
-        /* FALL THROUGH */
-
-    case REVERB_PARAM_DECAY_HF_RATIO:
-        // If r is the decay HF ratio  (r = REVERB_PARAM_DECAY_HF_RATIO/1000) we have:
-        //       DT_5000Hz = DT_0Hz * r
-        //  and  G_5000Hz = -6000 * d / DT_5000Hz and G_0Hz = -6000 * d / DT_0Hz in millibels so :
-        // r = G_0Hz/G_5000Hz in millibels
-        // The linear gain at 5000Hz is b0 / sqrt(a1^2 + 2*C*a1 + 1) where:
-        // - a1 is minus the LP feedback gain: -pReverb->m_nRvbLpfFbk
-        // - b0 is the LP forward gain: pReverb->m_nRvbLpfFwd
-        // - C is cos(2piWT) @ 5000Hz: pReverb->m_nCosWT_5KHz
-        if (pReverb->m_nRvbLpfFbk == 0) {
-            *pValue16 = 1000;
-            LOGV("get REVERB_PARAM_DECAY_HF_RATIO, pReverb->m_nRvbLpfFbk == 0, ratio %d", *pValue16);
+        pValue16 = (int16_t *)pValue;
+        // REVERB_PRESET_NONE is mapped to bypass
+        if (pReverb->m_bBypass != 0) {
+            *pValue16 = (int16_t)REVERB_PRESET_NONE;
         } else {
-            temp = MULT_EG1_EG1(pReverb->m_nRvbLpfFbk, pReverb->m_nRvbLpfFbk);
-            temp2 = MULT_EG1_EG1(pReverb->m_nRvbLpfFbk, pReverb->m_nCosWT_5KHz)
+            *pValue16 = (int16_t)(pReverb->m_nNextRoom + 1);
+        }
+        LOGV("get REVERB_PARAM_PRESET, preset %d", *pValue16);
+    } else {
+        switch (param) {
+        case REVERB_PARAM_ROOM_LEVEL:
+        case REVERB_PARAM_ROOM_HF_LEVEL:
+        case REVERB_PARAM_DECAY_HF_RATIO:
+        case REVERB_PARAM_REFLECTIONS_LEVEL:
+        case REVERB_PARAM_REVERB_LEVEL:
+        case REVERB_PARAM_DIFFUSION:
+        case REVERB_PARAM_DENSITY:
+            size = sizeof(int16_t);
+            break;
+
+        case REVERB_PARAM_BYPASS:
+        case REVERB_PARAM_DECAY_TIME:
+        case REVERB_PARAM_REFLECTIONS_DELAY:
+        case REVERB_PARAM_REVERB_DELAY:
+            size = sizeof(int32_t);
+            break;
+
+        case REVERB_PARAM_PROPERTIES:
+            size = sizeof(t_reverb_properties);
+            break;
+
+        default:
+            return -EINVAL;
+        }
+
+        if (*pSize < size) {
+            return -EINVAL;
+        }
+
+        pValue32 = (int32_t *) pValue;
+        pValue16 = (int16_t *) pValue;
+        pProperties = (t_reverb_properties *) pValue;
+
+        switch (param) {
+        case REVERB_PARAM_BYPASS:
+            *pValue32 = (int32_t) pReverb->m_bBypass;
+            break;
+
+        case REVERB_PARAM_PROPERTIES:
+            pValue16 = &pProperties->roomLevel;
+            /* FALL THROUGH */
+
+        case REVERB_PARAM_ROOM_LEVEL:
+            // Convert m_nRoomLpfFwd to millibels
+            temp = (pReverb->m_nRoomLpfFwd << 15)
+                    / (32767 - pReverb->m_nRoomLpfFbk);
+            *pValue16 = Effects_Linear16ToMillibels(temp);
+
+            LOGV("get REVERB_PARAM_ROOM_LEVEL %d, gain %d, m_nRoomLpfFwd %d, m_nRoomLpfFbk %d", *pValue16, temp, pReverb->m_nRoomLpfFwd, pReverb->m_nRoomLpfFbk);
+
+            if (param == REVERB_PARAM_ROOM_LEVEL) {
+                break;
+            }
+            pValue16 = &pProperties->roomHFLevel;
+            /* FALL THROUGH */
+
+        case REVERB_PARAM_ROOM_HF_LEVEL:
+            // The ratio between linear gain at 0Hz and at 5000Hz for the room low pass is:
+            // (1 + a1) / sqrt(a1^2 + 2*C*a1 + 1) where:
+            // - a1 is minus the LP feedback gain: -pReverb->m_nRoomLpfFbk
+            // - C is cos(2piWT) @ 5000Hz: pReverb->m_nCosWT_5KHz
+
+            temp = MULT_EG1_EG1(pReverb->m_nRoomLpfFbk, pReverb->m_nRoomLpfFbk);
+            LOGV("get REVERB_PARAM_ROOM_HF_LEVEL, a1^2 %d", temp);
+            temp2 = MULT_EG1_EG1(pReverb->m_nRoomLpfFbk, pReverb->m_nCosWT_5KHz)
                     << 1;
+            LOGV("get REVERB_PARAM_ROOM_HF_LEVEL, 2 Cos a1 %d", temp2);
             temp = 32767 + temp - temp2;
+            LOGV("get REVERB_PARAM_ROOM_HF_LEVEL, a1^2 + 2 Cos a1 + 1 %d", temp);
             temp = Effects_Sqrt(temp) * 181;
-            temp = (pReverb->m_nRvbLpfFwd << 15) / temp;
-            // The linear gain at 0Hz is b0 / (a1 + 1)
-            temp2 = (pReverb->m_nRvbLpfFwd << 15) / (32767
-                    - pReverb->m_nRvbLpfFbk);
+            LOGV("get REVERB_PARAM_ROOM_HF_LEVEL, SQRT(a1^2 + 2 Cos a1 + 1) %d", temp);
+            temp = ((32767 - pReverb->m_nRoomLpfFbk) << 15) / temp;
 
+            LOGV("get REVERB_PARAM_ROOM_HF_LEVEL, gain %d, m_nRoomLpfFwd %d, m_nRoomLpfFbk %d", temp, pReverb->m_nRoomLpfFwd, pReverb->m_nRoomLpfFbk);
+
+            *pValue16 = Effects_Linear16ToMillibels(temp);
+
+            if (param == REVERB_PARAM_ROOM_HF_LEVEL) {
+                break;
+            }
+            pValue32 = &pProperties->decayTime;
+            /* FALL THROUGH */
+
+        case REVERB_PARAM_DECAY_TIME:
+            // Calculate reverb feedback path gain
+            temp = (pReverb->m_nRvbLpfFwd << 15) / (32767 - pReverb->m_nRvbLpfFbk);
             temp = Effects_Linear16ToMillibels(temp);
-            temp2 = Effects_Linear16ToMillibels(temp2);
-            LOGV("get REVERB_PARAM_DECAY_HF_RATIO, gain 5KHz %d mB, gain DC %d mB", temp, temp2);
 
-            if (temp == 0)
-                temp = 1;
-            temp = (int16_t) ((1000 * temp2) / temp);
+            // Calculate decay time: g = -6000 d/DT , g gain in millibels, d reverb delay, DT decay time
+            temp = (-6000 * pReverb->m_nLateDelay) / temp;
+
+            // Convert samples to ms
+            *pValue32 = (temp * 1000) / pReverb->m_nSamplingRate;
+
+            LOGV("get REVERB_PARAM_DECAY_TIME, samples %d, ms %d", temp, *pValue32);
+
+            if (param == REVERB_PARAM_DECAY_TIME) {
+                break;
+            }
+            pValue16 = &pProperties->decayHFRatio;
+            /* FALL THROUGH */
+
+        case REVERB_PARAM_DECAY_HF_RATIO:
+            // If r is the decay HF ratio  (r = REVERB_PARAM_DECAY_HF_RATIO/1000) we have:
+            //       DT_5000Hz = DT_0Hz * r
+            //  and  G_5000Hz = -6000 * d / DT_5000Hz and G_0Hz = -6000 * d / DT_0Hz in millibels so :
+            // r = G_0Hz/G_5000Hz in millibels
+            // The linear gain at 5000Hz is b0 / sqrt(a1^2 + 2*C*a1 + 1) where:
+            // - a1 is minus the LP feedback gain: -pReverb->m_nRvbLpfFbk
+            // - b0 is the LP forward gain: pReverb->m_nRvbLpfFwd
+            // - C is cos(2piWT) @ 5000Hz: pReverb->m_nCosWT_5KHz
+            if (pReverb->m_nRvbLpfFbk == 0) {
+                *pValue16 = 1000;
+                LOGV("get REVERB_PARAM_DECAY_HF_RATIO, pReverb->m_nRvbLpfFbk == 0, ratio %d", *pValue16);
+            } else {
+                temp = MULT_EG1_EG1(pReverb->m_nRvbLpfFbk, pReverb->m_nRvbLpfFbk);
+                temp2 = MULT_EG1_EG1(pReverb->m_nRvbLpfFbk, pReverb->m_nCosWT_5KHz)
+                        << 1;
+                temp = 32767 + temp - temp2;
+                temp = Effects_Sqrt(temp) * 181;
+                temp = (pReverb->m_nRvbLpfFwd << 15) / temp;
+                // The linear gain at 0Hz is b0 / (a1 + 1)
+                temp2 = (pReverb->m_nRvbLpfFwd << 15) / (32767
+                        - pReverb->m_nRvbLpfFbk);
+
+                temp = Effects_Linear16ToMillibels(temp);
+                temp2 = Effects_Linear16ToMillibels(temp2);
+                LOGV("get REVERB_PARAM_DECAY_HF_RATIO, gain 5KHz %d mB, gain DC %d mB", temp, temp2);
+
+                if (temp == 0)
+                    temp = 1;
+                temp = (int16_t) ((1000 * temp2) / temp);
+                if (temp > 1000)
+                    temp = 1000;
+
+                *pValue16 = temp;
+                LOGV("get REVERB_PARAM_DECAY_HF_RATIO, ratio %d", *pValue16);
+            }
+
+            if (param == REVERB_PARAM_DECAY_HF_RATIO) {
+                break;
+            }
+            pValue16 = &pProperties->reflectionsLevel;
+            /* FALL THROUGH */
+
+        case REVERB_PARAM_REFLECTIONS_LEVEL:
+            *pValue16 = Effects_Linear16ToMillibels(pReverb->m_nEarlyGain);
+
+            LOGV("get REVERB_PARAM_REFLECTIONS_LEVEL, %d", *pValue16);
+            if (param == REVERB_PARAM_REFLECTIONS_LEVEL) {
+                break;
+            }
+            pValue32 = &pProperties->reflectionsDelay;
+            /* FALL THROUGH */
+
+        case REVERB_PARAM_REFLECTIONS_DELAY:
+            // convert samples to ms
+            *pValue32 = (pReverb->m_nEarlyDelay * 1000) / pReverb->m_nSamplingRate;
+
+            LOGV("get REVERB_PARAM_REFLECTIONS_DELAY, samples %d, ms %d", pReverb->m_nEarlyDelay, *pValue32);
+
+            if (param == REVERB_PARAM_REFLECTIONS_DELAY) {
+                break;
+            }
+            pValue16 = &pProperties->reverbLevel;
+            /* FALL THROUGH */
+
+        case REVERB_PARAM_REVERB_LEVEL:
+            // Convert linear gain to millibels
+            *pValue16 = Effects_Linear16ToMillibels(pReverb->m_nLateGain << 2);
+
+            LOGV("get REVERB_PARAM_REVERB_LEVEL %d", *pValue16);
+
+            if (param == REVERB_PARAM_REVERB_LEVEL) {
+                break;
+            }
+            pValue32 = &pProperties->reverbDelay;
+            /* FALL THROUGH */
+
+        case REVERB_PARAM_REVERB_DELAY:
+            // convert samples to ms
+            *pValue32 = (pReverb->m_nLateDelay * 1000) / pReverb->m_nSamplingRate;
+
+            LOGV("get REVERB_PARAM_REVERB_DELAY, samples %d, ms %d", pReverb->m_nLateDelay, *pValue32);
+
+            if (param == REVERB_PARAM_REVERB_DELAY) {
+                break;
+            }
+            pValue16 = &pProperties->diffusion;
+            /* FALL THROUGH */
+
+        case REVERB_PARAM_DIFFUSION:
+            temp = (int16_t) ((1000 * (pReverb->m_sAp0.m_nApGain - AP0_GAIN_BASE))
+                    / AP0_GAIN_RANGE);
+
+            if (temp < 0)
+                temp = 0;
             if (temp > 1000)
                 temp = 1000;
 
             *pValue16 = temp;
-            LOGV("get REVERB_PARAM_DECAY_HF_RATIO, ratio %d", *pValue16);
-        }
+            LOGV("get REVERB_PARAM_DIFFUSION, %d, AP0 gain %d", *pValue16, pReverb->m_sAp0.m_nApGain);
 
-        if (param == REVERB_PARAM_DECAY_HF_RATIO) {
+            if (param == REVERB_PARAM_DIFFUSION) {
+                break;
+            }
+            pValue16 = &pProperties->density;
+            /* FALL THROUGH */
+
+        case REVERB_PARAM_DENSITY:
+            // Calculate AP delay in time units
+            temp = ((pReverb->m_sAp0.m_zApOut - pReverb->m_sAp0.m_zApIn) << 16)
+                    / pReverb->m_nSamplingRate;
+
+            temp = (int16_t) ((1000 * (temp - AP0_TIME_BASE)) / AP0_TIME_RANGE);
+
+            if (temp < 0)
+                temp = 0;
+            if (temp > 1000)
+                temp = 1000;
+
+            *pValue16 = temp;
+
+            LOGV("get REVERB_PARAM_DENSITY, %d, AP0 delay smps %d", *pValue16, pReverb->m_sAp0.m_zApOut - pReverb->m_sAp0.m_zApIn);
+            break;
+
+        default:
             break;
         }
-        pValue16 = &pProperties->reflectionsLevel;
-        /* FALL THROUGH */
-
-    case REVERB_PARAM_REFLECTIONS_LEVEL:
-        *pValue16 = Effects_Linear16ToMillibels(pReverb->m_nEarlyGain);
-
-        LOGV("get REVERB_PARAM_REFLECTIONS_LEVEL, %d", *pValue16);
-        if (param == REVERB_PARAM_REFLECTIONS_LEVEL) {
-            break;
-        }
-        pValue32 = &pProperties->reflectionsDelay;
-        /* FALL THROUGH */
-
-    case REVERB_PARAM_REFLECTIONS_DELAY:
-        // convert samples to ms
-        *pValue32 = (pReverb->m_nEarlyDelay * 1000) / pReverb->m_nSamplingRate;
-
-        LOGV("get REVERB_PARAM_REFLECTIONS_DELAY, samples %d, ms %d", pReverb->m_nEarlyDelay, *pValue32);
-
-        if (param == REVERB_PARAM_REFLECTIONS_DELAY) {
-            break;
-        }
-        pValue16 = &pProperties->reverbLevel;
-        /* FALL THROUGH */
-
-    case REVERB_PARAM_REVERB_LEVEL:
-        // Convert linear gain to millibels
-        *pValue16 = Effects_Linear16ToMillibels(pReverb->m_nLateGain << 2);
-
-        LOGV("get REVERB_PARAM_REVERB_LEVEL %d", *pValue16);
-
-        if (param == REVERB_PARAM_REVERB_LEVEL) {
-            break;
-        }
-        pValue32 = &pProperties->reverbDelay;
-        /* FALL THROUGH */
-
-    case REVERB_PARAM_REVERB_DELAY:
-        // convert samples to ms
-        *pValue32 = (pReverb->m_nLateDelay * 1000) / pReverb->m_nSamplingRate;
-
-        LOGV("get REVERB_PARAM_REVERB_DELAY, samples %d, ms %d", pReverb->m_nLateDelay, *pValue32);
-
-        if (param == REVERB_PARAM_REVERB_DELAY) {
-            break;
-        }
-        pValue16 = &pProperties->diffusion;
-        /* FALL THROUGH */
-
-    case REVERB_PARAM_DIFFUSION:
-        temp = (int16_t) ((1000 * (pReverb->m_sAp0.m_nApGain - AP0_GAIN_BASE))
-                / AP0_GAIN_RANGE);
-
-        if (temp < 0)
-            temp = 0;
-        if (temp > 1000)
-            temp = 1000;
-
-        *pValue16 = temp;
-        LOGV("get REVERB_PARAM_DIFFUSION, %d, AP0 gain %d", *pValue16, pReverb->m_sAp0.m_nApGain);
-
-        if (param == REVERB_PARAM_DIFFUSION) {
-            break;
-        }
-        pValue16 = &pProperties->density;
-        /* FALL THROUGH */
-
-    case REVERB_PARAM_DENSITY:
-        // Calculate AP delay in time units
-        temp = ((pReverb->m_sAp0.m_zApOut - pReverb->m_sAp0.m_zApIn) << 16)
-                / pReverb->m_nSamplingRate;
-
-        temp = (int16_t) ((1000 * (temp - AP0_TIME_BASE)) / AP0_TIME_RANGE);
-
-        if (temp < 0)
-            temp = 0;
-        if (temp > 1000)
-            temp = 1000;
-
-        *pValue16 = temp;
-
-        LOGV("get REVERB_PARAM_DENSITY, %d, AP0 delay smps %d", *pValue16, pReverb->m_sAp0.m_zApOut - pReverb->m_sAp0.m_zApIn);
-        break;
-
-    default:
-        break;
     }
 
+    *pSize = size;
+
     LOGV("Reverb_getParameter, context %p, param %d, value %d",
             pReverb, param, *(int *)pValue);
 
@@ -945,382 +983,386 @@
     LOGV("Reverb_setParameter, context %p, param %d, value16 %d, value32 %d",
             pReverb, param, *(int16_t *)pValue, *(int32_t *)pValue);
 
-    if (pReverb->m_Preset && param != REVERB_PARAM_PRESET) {
-        return -EINVAL;
-    }
-    if (!pReverb->m_Preset && param == REVERB_PARAM_PRESET) {
-        return -EINVAL;
-    }
-
-    switch (param) {
-    case REVERB_PARAM_ROOM_LEVEL:
-    case REVERB_PARAM_ROOM_HF_LEVEL:
-    case REVERB_PARAM_DECAY_HF_RATIO:
-    case REVERB_PARAM_REFLECTIONS_LEVEL:
-    case REVERB_PARAM_REVERB_LEVEL:
-    case REVERB_PARAM_DIFFUSION:
-    case REVERB_PARAM_DENSITY:
-        paramSize = sizeof(int16_t);
-        break;
-
-    case REVERB_PARAM_BYPASS:
-    case REVERB_PARAM_PRESET:
-    case REVERB_PARAM_DECAY_TIME:
-    case REVERB_PARAM_REFLECTIONS_DELAY:
-    case REVERB_PARAM_REVERB_DELAY:
-        paramSize = sizeof(int32_t);
-        break;
-
-    case REVERB_PARAM_PROPERTIES:
-        paramSize = sizeof(t_reverb_properties);
-        break;
-
-    default:
-        return -EINVAL;
-    }
-
-    if (size != paramSize) {
-        return -EINVAL;
-    }
-
-    if (paramSize == sizeof(int16_t)) {
-        value16 = *(int16_t *) pValue;
-    } else if (paramSize == sizeof(int32_t)) {
-        value32 = *(int32_t *) pValue;
-    } else {
-        pProperties = (t_reverb_properties *) pValue;
-    }
-
-    pPreset = &pReverb->m_sPreset.m_sPreset[pReverb->m_nCurrentRoom];
-
-    switch (param) {
-    case REVERB_PARAM_BYPASS:
-        pReverb->m_bBypass = (uint16_t)value32;
-        break;
-    case REVERB_PARAM_PRESET:
-        if (value32 != REVERB_PRESET_LARGE_HALL && value32
-                != REVERB_PRESET_HALL && value32 != REVERB_PRESET_CHAMBER
-                && value32 != REVERB_PRESET_ROOM)
+    if (pReverb->m_Preset) {
+        if (param != REVERB_PARAM_PRESET || size != sizeof(int16_t)) {
             return -EINVAL;
-        pReverb->m_nNextRoom = (int16_t) value32;
-        break;
-
-    case REVERB_PARAM_PROPERTIES:
-        value16 = pProperties->roomLevel;
-        /* FALL THROUGH */
-
-    case REVERB_PARAM_ROOM_LEVEL:
-        // Convert millibels to linear 16 bit signed => m_nRoomLpfFwd
-        if (value16 > 0)
-            return -EINVAL;
-
-        temp = Effects_MillibelsToLinear16(value16);
-
-        pReverb->m_nRoomLpfFwd
-                = MULT_EG1_EG1(temp, (32767 - pReverb->m_nRoomLpfFbk));
-
-        LOGV("REVERB_PARAM_ROOM_LEVEL, gain %d, new m_nRoomLpfFwd %d, m_nRoomLpfFbk %d", temp, pReverb->m_nRoomLpfFwd, pReverb->m_nRoomLpfFbk);
-        if (param == REVERB_PARAM_ROOM_LEVEL)
-            break;
-        value16 = pProperties->roomHFLevel;
-        /* FALL THROUGH */
-
-    case REVERB_PARAM_ROOM_HF_LEVEL:
-
-        // Limit to 0 , -40dB range because of low pass implementation
-        if (value16 > 0 || value16 < -4000)
-            return -EINVAL;
-        // Convert attenuation @ 5000H expressed in millibels to => m_nRoomLpfFbk
-        // m_nRoomLpfFbk is -a1 where a1 is the solution of:
-        // a1^2 + 2*(C-dG^2)/(1-dG^2)*a1 + 1 = 0 where:
-        // - C is cos(2*pi*5000/Fs) (pReverb->m_nCosWT_5KHz)
-        // - dG is G0/Gf (G0 is the linear gain at DC and Gf is the wanted gain at 5000Hz)
-
-        // Save current DC gain m_nRoomLpfFwd / (32767 - m_nRoomLpfFbk) to keep it unchanged
-        // while changing HF level
-        temp2 = (pReverb->m_nRoomLpfFwd << 15) / (32767
-                - pReverb->m_nRoomLpfFbk);
-        if (value16 == 0) {
-            pReverb->m_nRoomLpfFbk = 0;
-        } else {
-            int32_t dG2, b, delta;
-
-            // dG^2
-            temp = Effects_MillibelsToLinear16(value16);
-            LOGV("REVERB_PARAM_ROOM_HF_LEVEL, HF gain %d", temp);
-            temp = (1 << 30) / temp;
-            LOGV("REVERB_PARAM_ROOM_HF_LEVEL, 1/ HF gain %d", temp);
-            dG2 = (int32_t) (((int64_t) temp * (int64_t) temp) >> 15);
-            LOGV("REVERB_PARAM_ROOM_HF_LEVEL, 1/ HF gain ^ 2 %d", dG2);
-            // b = 2*(C-dG^2)/(1-dG^2)
-            b = (int32_t) ((((int64_t) 1 << (15 + 1))
-                    * ((int64_t) pReverb->m_nCosWT_5KHz - (int64_t) dG2))
-                    / ((int64_t) 32767 - (int64_t) dG2));
-
-            // delta = b^2 - 4
-            delta = (int32_t) ((((int64_t) b * (int64_t) b) >> 15) - (1 << (15
-                    + 2)));
-
-            LOGV_IF(delta > (1<<30), " delta overflow %d", delta);
-
-            LOGV("REVERB_PARAM_ROOM_HF_LEVEL, dG2 %d, b %d, delta %d, m_nCosWT_5KHz %d", dG2, b, delta, pReverb->m_nCosWT_5KHz);
-            // m_nRoomLpfFbk = -a1 = - (- b + sqrt(delta)) / 2
-            pReverb->m_nRoomLpfFbk = (b - Effects_Sqrt(delta) * 181) >> 1;
         }
-        LOGV("REVERB_PARAM_ROOM_HF_LEVEL, olg DC gain %d new m_nRoomLpfFbk %d, old m_nRoomLpfFwd %d",
-                temp2, pReverb->m_nRoomLpfFbk, pReverb->m_nRoomLpfFwd);
-
-        pReverb->m_nRoomLpfFwd
-                = MULT_EG1_EG1(temp2, (32767 - pReverb->m_nRoomLpfFbk));
-        LOGV("REVERB_PARAM_ROOM_HF_LEVEL, new m_nRoomLpfFwd %d", pReverb->m_nRoomLpfFwd);
-
-        if (param == REVERB_PARAM_ROOM_HF_LEVEL)
-            break;
-        value32 = pProperties->decayTime;
-        /* FALL THROUGH */
-
-    case REVERB_PARAM_DECAY_TIME:
-
-        // Convert milliseconds to => m_nRvbLpfFwd (function of m_nRvbLpfFbk)
-        // convert ms to samples
-        value32 = (value32 * pReverb->m_nSamplingRate) / 1000;
-
-        // calculate valid decay time range as a function of current reverb delay and
-        // max feed back gain. Min value <=> -40dB in one pass, Max value <=> feedback gain = -1 dB
-        // Calculate attenuation for each round in late reverb given a total attenuation of -6000 millibels.
-        // g = -6000 d/DT , g gain in millibels, d reverb delay, DT decay time
-        averageDelay = pReverb->m_nLateDelay - pReverb->m_nMaxExcursion;
-        averageDelay += ((pReverb->m_sAp0.m_zApOut - pReverb->m_sAp0.m_zApIn)
-                + (pReverb->m_sAp1.m_zApOut - pReverb->m_sAp1.m_zApIn)) >> 1;
-
-        temp = (-6000 * averageDelay) / value32;
-        LOGV("REVERB_PARAM_DECAY_TIME, delay smps %d, DT smps %d, gain mB %d",averageDelay, value32, temp);
-        if (temp < -4000 || temp > -100)
+        value16 = *(int16_t *)pValue;
+        LOGV("set REVERB_PARAM_PRESET, preset %d", value16);
+        if (value16 < REVERB_PRESET_NONE || value16 > REVERB_PRESET_PLATE) {
             return -EINVAL;
-
-        // calculate low pass gain by adding reverb input attenuation (pReverb->m_nLateGain) and substrating output
-        // xfade and sum gain (max +9dB)
-        temp -= Effects_Linear16ToMillibels(pReverb->m_nLateGain) + 900;
-        temp = Effects_MillibelsToLinear16(temp);
-
-        // DC gain (temp) = b0 / (1 + a1) = pReverb->m_nRvbLpfFwd / (32767 - pReverb->m_nRvbLpfFbk)
-        pReverb->m_nRvbLpfFwd
-                = MULT_EG1_EG1(temp, (32767 - pReverb->m_nRvbLpfFbk));
-
-        LOGV("REVERB_PARAM_DECAY_TIME, gain %d, new m_nRvbLpfFwd %d, old m_nRvbLpfFbk %d, reverb gain %d", temp, pReverb->m_nRvbLpfFwd, pReverb->m_nRvbLpfFbk, Effects_Linear16ToMillibels(pReverb->m_nLateGain));
-
-        if (param == REVERB_PARAM_DECAY_TIME)
-            break;
-        value16 = pProperties->decayHFRatio;
-        /* FALL THROUGH */
-
-    case REVERB_PARAM_DECAY_HF_RATIO:
-
-        // We limit max value to 1000 because reverb filter is lowpass only
-        if (value16 < 100 || value16 > 1000)
-            return -EINVAL;
-        // Convert per mille to => m_nLpfFwd, m_nLpfFbk
-
-        // Save current DC gain m_nRoomLpfFwd / (32767 - m_nRoomLpfFbk) to keep it unchanged
-        // while changing HF level
-        temp2 = (pReverb->m_nRvbLpfFwd << 15) / (32767 - pReverb->m_nRvbLpfFbk);
-
-        if (value16 == 1000) {
-            pReverb->m_nRvbLpfFbk = 0;
+        }
+        // REVERB_PRESET_NONE is mapped to bypass
+        if (value16 == REVERB_PRESET_NONE) {
+            pReverb->m_bBypass = 1;
         } else {
-            int32_t dG2, b, delta;
+            pReverb->m_bBypass = 0;
+            pReverb->m_nNextRoom = value16 - 1;
+        }
+    } else {
+        switch (param) {
+        case REVERB_PARAM_ROOM_LEVEL:
+        case REVERB_PARAM_ROOM_HF_LEVEL:
+        case REVERB_PARAM_DECAY_HF_RATIO:
+        case REVERB_PARAM_REFLECTIONS_LEVEL:
+        case REVERB_PARAM_REVERB_LEVEL:
+        case REVERB_PARAM_DIFFUSION:
+        case REVERB_PARAM_DENSITY:
+            paramSize = sizeof(int16_t);
+            break;
 
-            temp = Effects_Linear16ToMillibels(temp2);
-            // G_5000Hz = G_DC * (1000/REVERB_PARAM_DECAY_HF_RATIO) in millibels
+        case REVERB_PARAM_BYPASS:
+        case REVERB_PARAM_DECAY_TIME:
+        case REVERB_PARAM_REFLECTIONS_DELAY:
+        case REVERB_PARAM_REVERB_DELAY:
+            paramSize = sizeof(int32_t);
+            break;
 
-            value32 = ((int32_t) 1000 << 15) / (int32_t) value16;
-            LOGV("REVERB_PARAM_DECAY_HF_RATIO, DC gain %d, DC gain mB %d, 1000/R %d", temp2, temp, value32);
+        case REVERB_PARAM_PROPERTIES:
+            paramSize = sizeof(t_reverb_properties);
+            break;
 
-            temp = (int32_t) (((int64_t) temp * (int64_t) value32) >> 15);
+        default:
+            return -EINVAL;
+        }
 
-            if (temp < -4000) {
-                LOGV("REVERB_PARAM_DECAY_HF_RATIO HF gain overflow %d mB", temp);
-                temp = -4000;
+        if (size != paramSize) {
+            return -EINVAL;
+        }
+
+        if (paramSize == sizeof(int16_t)) {
+            value16 = *(int16_t *) pValue;
+        } else if (paramSize == sizeof(int32_t)) {
+            value32 = *(int32_t *) pValue;
+        } else {
+            pProperties = (t_reverb_properties *) pValue;
+        }
+
+        pPreset = &pReverb->m_sPreset.m_sPreset[pReverb->m_nNextRoom];
+
+        switch (param) {
+        case REVERB_PARAM_BYPASS:
+            pReverb->m_bBypass = (uint16_t)value32;
+            break;
+
+        case REVERB_PARAM_PROPERTIES:
+            value16 = pProperties->roomLevel;
+            /* FALL THROUGH */
+
+        case REVERB_PARAM_ROOM_LEVEL:
+            // Convert millibels to linear 16 bit signed => m_nRoomLpfFwd
+            if (value16 > 0)
+                return -EINVAL;
+
+            temp = Effects_MillibelsToLinear16(value16);
+
+            pReverb->m_nRoomLpfFwd
+                    = MULT_EG1_EG1(temp, (32767 - pReverb->m_nRoomLpfFbk));
+
+            LOGV("REVERB_PARAM_ROOM_LEVEL, gain %d, new m_nRoomLpfFwd %d, m_nRoomLpfFbk %d", temp, pReverb->m_nRoomLpfFwd, pReverb->m_nRoomLpfFbk);
+            if (param == REVERB_PARAM_ROOM_LEVEL)
+                break;
+            value16 = pProperties->roomHFLevel;
+            /* FALL THROUGH */
+
+        case REVERB_PARAM_ROOM_HF_LEVEL:
+
+            // Limit to 0 , -40dB range because of low pass implementation
+            if (value16 > 0 || value16 < -4000)
+                return -EINVAL;
+            // Convert attenuation @ 5000H expressed in millibels to => m_nRoomLpfFbk
+            // m_nRoomLpfFbk is -a1 where a1 is the solution of:
+            // a1^2 + 2*(C-dG^2)/(1-dG^2)*a1 + 1 = 0 where:
+            // - C is cos(2*pi*5000/Fs) (pReverb->m_nCosWT_5KHz)
+            // - dG is G0/Gf (G0 is the linear gain at DC and Gf is the wanted gain at 5000Hz)
+
+            // Save current DC gain m_nRoomLpfFwd / (32767 - m_nRoomLpfFbk) to keep it unchanged
+            // while changing HF level
+            temp2 = (pReverb->m_nRoomLpfFwd << 15) / (32767
+                    - pReverb->m_nRoomLpfFbk);
+            if (value16 == 0) {
+                pReverb->m_nRoomLpfFbk = 0;
+            } else {
+                int32_t dG2, b, delta;
+
+                // dG^2
+                temp = Effects_MillibelsToLinear16(value16);
+                LOGV("REVERB_PARAM_ROOM_HF_LEVEL, HF gain %d", temp);
+                temp = (1 << 30) / temp;
+                LOGV("REVERB_PARAM_ROOM_HF_LEVEL, 1/ HF gain %d", temp);
+                dG2 = (int32_t) (((int64_t) temp * (int64_t) temp) >> 15);
+                LOGV("REVERB_PARAM_ROOM_HF_LEVEL, 1/ HF gain ^ 2 %d", dG2);
+                // b = 2*(C-dG^2)/(1-dG^2)
+                b = (int32_t) ((((int64_t) 1 << (15 + 1))
+                        * ((int64_t) pReverb->m_nCosWT_5KHz - (int64_t) dG2))
+                        / ((int64_t) 32767 - (int64_t) dG2));
+
+                // delta = b^2 - 4
+                delta = (int32_t) ((((int64_t) b * (int64_t) b) >> 15) - (1 << (15
+                        + 2)));
+
+                LOGV_IF(delta > (1<<30), " delta overflow %d", delta);
+
+                LOGV("REVERB_PARAM_ROOM_HF_LEVEL, dG2 %d, b %d, delta %d, m_nCosWT_5KHz %d", dG2, b, delta, pReverb->m_nCosWT_5KHz);
+                // m_nRoomLpfFbk = -a1 = - (- b + sqrt(delta)) / 2
+                pReverb->m_nRoomLpfFbk = (b - Effects_Sqrt(delta) * 181) >> 1;
+            }
+            LOGV("REVERB_PARAM_ROOM_HF_LEVEL, olg DC gain %d new m_nRoomLpfFbk %d, old m_nRoomLpfFwd %d",
+                    temp2, pReverb->m_nRoomLpfFbk, pReverb->m_nRoomLpfFwd);
+
+            pReverb->m_nRoomLpfFwd
+                    = MULT_EG1_EG1(temp2, (32767 - pReverb->m_nRoomLpfFbk));
+            LOGV("REVERB_PARAM_ROOM_HF_LEVEL, new m_nRoomLpfFwd %d", pReverb->m_nRoomLpfFwd);
+
+            if (param == REVERB_PARAM_ROOM_HF_LEVEL)
+                break;
+            value32 = pProperties->decayTime;
+            /* FALL THROUGH */
+
+        case REVERB_PARAM_DECAY_TIME:
+
+            // Convert milliseconds to => m_nRvbLpfFwd (function of m_nRvbLpfFbk)
+            // convert ms to samples
+            value32 = (value32 * pReverb->m_nSamplingRate) / 1000;
+
+            // calculate valid decay time range as a function of current reverb delay and
+            // max feed back gain. Min value <=> -40dB in one pass, Max value <=> feedback gain = -1 dB
+            // Calculate attenuation for each round in late reverb given a total attenuation of -6000 millibels.
+            // g = -6000 d/DT , g gain in millibels, d reverb delay, DT decay time
+            averageDelay = pReverb->m_nLateDelay - pReverb->m_nMaxExcursion;
+            averageDelay += ((pReverb->m_sAp0.m_zApOut - pReverb->m_sAp0.m_zApIn)
+                    + (pReverb->m_sAp1.m_zApOut - pReverb->m_sAp1.m_zApIn)) >> 1;
+
+            temp = (-6000 * averageDelay) / value32;
+            LOGV("REVERB_PARAM_DECAY_TIME, delay smps %d, DT smps %d, gain mB %d",averageDelay, value32, temp);
+            if (temp < -4000 || temp > -100)
+                return -EINVAL;
+
+            // calculate low pass gain by adding reverb input attenuation (pReverb->m_nLateGain) and substrating output
+            // xfade and sum gain (max +9dB)
+            temp -= Effects_Linear16ToMillibels(pReverb->m_nLateGain) + 900;
+            temp = Effects_MillibelsToLinear16(temp);
+
+            // DC gain (temp) = b0 / (1 + a1) = pReverb->m_nRvbLpfFwd / (32767 - pReverb->m_nRvbLpfFbk)
+            pReverb->m_nRvbLpfFwd
+                    = MULT_EG1_EG1(temp, (32767 - pReverb->m_nRvbLpfFbk));
+
+            LOGV("REVERB_PARAM_DECAY_TIME, gain %d, new m_nRvbLpfFwd %d, old m_nRvbLpfFbk %d, reverb gain %d", temp, pReverb->m_nRvbLpfFwd, pReverb->m_nRvbLpfFbk, Effects_Linear16ToMillibels(pReverb->m_nLateGain));
+
+            if (param == REVERB_PARAM_DECAY_TIME)
+                break;
+            value16 = pProperties->decayHFRatio;
+            /* FALL THROUGH */
+
+        case REVERB_PARAM_DECAY_HF_RATIO:
+
+            // We limit max value to 1000 because reverb filter is lowpass only
+            if (value16 < 100 || value16 > 1000)
+                return -EINVAL;
+            // Convert per mille to => m_nLpfFwd, m_nLpfFbk
+
+            // Save current DC gain m_nRoomLpfFwd / (32767 - m_nRoomLpfFbk) to keep it unchanged
+            // while changing HF level
+            temp2 = (pReverb->m_nRvbLpfFwd << 15) / (32767 - pReverb->m_nRvbLpfFbk);
+
+            if (value16 == 1000) {
+                pReverb->m_nRvbLpfFbk = 0;
+            } else {
+                int32_t dG2, b, delta;
+
+                temp = Effects_Linear16ToMillibels(temp2);
+                // G_5000Hz = G_DC * (1000/REVERB_PARAM_DECAY_HF_RATIO) in millibels
+
+                value32 = ((int32_t) 1000 << 15) / (int32_t) value16;
+                LOGV("REVERB_PARAM_DECAY_HF_RATIO, DC gain %d, DC gain mB %d, 1000/R %d", temp2, temp, value32);
+
+                temp = (int32_t) (((int64_t) temp * (int64_t) value32) >> 15);
+
+                if (temp < -4000) {
+                    LOGV("REVERB_PARAM_DECAY_HF_RATIO HF gain overflow %d mB", temp);
+                    temp = -4000;
+                }
+
+                temp = Effects_MillibelsToLinear16(temp);
+                LOGV("REVERB_PARAM_DECAY_HF_RATIO, HF gain %d", temp);
+                // dG^2
+                temp = (temp2 << 15) / temp;
+                dG2 = (int32_t) (((int64_t) temp * (int64_t) temp) >> 15);
+
+                // b = 2*(C-dG^2)/(1-dG^2)
+                b = (int32_t) ((((int64_t) 1 << (15 + 1))
+                        * ((int64_t) pReverb->m_nCosWT_5KHz - (int64_t) dG2))
+                        / ((int64_t) 32767 - (int64_t) dG2));
+
+                // delta = b^2 - 4
+                delta = (int32_t) ((((int64_t) b * (int64_t) b) >> 15) - (1 << (15
+                        + 2)));
+
+                // m_nRoomLpfFbk = -a1 = - (- b + sqrt(delta)) / 2
+                pReverb->m_nRvbLpfFbk = (b - Effects_Sqrt(delta) * 181) >> 1;
+
+                LOGV("REVERB_PARAM_DECAY_HF_RATIO, dG2 %d, b %d, delta %d", dG2, b, delta);
+
             }
 
-            temp = Effects_MillibelsToLinear16(temp);
-            LOGV("REVERB_PARAM_DECAY_HF_RATIO, HF gain %d", temp);
-            // dG^2
-            temp = (temp2 << 15) / temp;
-            dG2 = (int32_t) (((int64_t) temp * (int64_t) temp) >> 15);
+            LOGV("REVERB_PARAM_DECAY_HF_RATIO, gain %d, m_nRvbLpfFbk %d, m_nRvbLpfFwd %d", temp2, pReverb->m_nRvbLpfFbk, pReverb->m_nRvbLpfFwd);
 
-            // b = 2*(C-dG^2)/(1-dG^2)
-            b = (int32_t) ((((int64_t) 1 << (15 + 1))
-                    * ((int64_t) pReverb->m_nCosWT_5KHz - (int64_t) dG2))
-                    / ((int64_t) 32767 - (int64_t) dG2));
+            pReverb->m_nRvbLpfFwd
+                    = MULT_EG1_EG1(temp2, (32767 - pReverb->m_nRvbLpfFbk));
 
-            // delta = b^2 - 4
-            delta = (int32_t) ((((int64_t) b * (int64_t) b) >> 15) - (1 << (15
-                    + 2)));
+            if (param == REVERB_PARAM_DECAY_HF_RATIO)
+                break;
+            value16 = pProperties->reflectionsLevel;
+            /* FALL THROUGH */
 
-            // m_nRoomLpfFbk = -a1 = - (- b + sqrt(delta)) / 2
-            pReverb->m_nRvbLpfFbk = (b - Effects_Sqrt(delta) * 181) >> 1;
+        case REVERB_PARAM_REFLECTIONS_LEVEL:
+            // We limit max value to 0 because gain is limited to 0dB
+            if (value16 > 0 || value16 < -6000)
+                return -EINVAL;
 
-            LOGV("REVERB_PARAM_DECAY_HF_RATIO, dG2 %d, b %d, delta %d", dG2, b, delta);
+            // Convert millibels to linear 16 bit signed and recompute m_sEarlyL.m_nGain[i] and m_sEarlyR.m_nGain[i].
+            value16 = Effects_MillibelsToLinear16(value16);
+            for (i = 0; i < REVERB_MAX_NUM_REFLECTIONS; i++) {
+                pReverb->m_sEarlyL.m_nGain[i]
+                        = MULT_EG1_EG1(pPreset->m_sEarlyL.m_nGain[i],value16);
+                pReverb->m_sEarlyR.m_nGain[i]
+                        = MULT_EG1_EG1(pPreset->m_sEarlyR.m_nGain[i],value16);
+            }
+            pReverb->m_nEarlyGain = value16;
+            LOGV("REVERB_PARAM_REFLECTIONS_LEVEL, m_nEarlyGain %d", pReverb->m_nEarlyGain);
 
+            if (param == REVERB_PARAM_REFLECTIONS_LEVEL)
+                break;
+            value32 = pProperties->reflectionsDelay;
+            /* FALL THROUGH */
+
+        case REVERB_PARAM_REFLECTIONS_DELAY:
+            // We limit max value MAX_EARLY_TIME
+            // convert ms to time units
+            temp = (value32 * 65536) / 1000;
+            if (temp < 0 || temp > MAX_EARLY_TIME)
+                return -EINVAL;
+
+            maxSamples = (int32_t) (MAX_EARLY_TIME * pReverb->m_nSamplingRate)
+                    >> 16;
+            temp = (temp * pReverb->m_nSamplingRate) >> 16;
+            for (i = 0; i < REVERB_MAX_NUM_REFLECTIONS; i++) {
+                temp2 = temp + (((int32_t) pPreset->m_sEarlyL.m_zDelay[i]
+                        * pReverb->m_nSamplingRate) >> 16);
+                if (temp2 > maxSamples)
+                    temp2 = maxSamples;
+                pReverb->m_sEarlyL.m_zDelay[i] = pReverb->m_nEarly0in + temp2;
+                temp2 = temp + (((int32_t) pPreset->m_sEarlyR.m_zDelay[i]
+                        * pReverb->m_nSamplingRate) >> 16);
+                if (temp2 > maxSamples)
+                    temp2 = maxSamples;
+                pReverb->m_sEarlyR.m_zDelay[i] = pReverb->m_nEarly1in + temp2;
+            }
+            pReverb->m_nEarlyDelay = temp;
+
+            LOGV("REVERB_PARAM_REFLECTIONS_DELAY, m_nEarlyDelay smps %d max smp delay %d", pReverb->m_nEarlyDelay, maxSamples);
+
+            // Convert milliseconds to sample count => m_nEarlyDelay
+            if (param == REVERB_PARAM_REFLECTIONS_DELAY)
+                break;
+            value16 = pProperties->reverbLevel;
+            /* FALL THROUGH */
+
+        case REVERB_PARAM_REVERB_LEVEL:
+            // We limit max value to 0 because gain is limited to 0dB
+            if (value16 > 0 || value16 < -6000)
+                return -EINVAL;
+            // Convert millibels to linear 16 bits (gange 0 - 8191) => m_nLateGain.
+            pReverb->m_nLateGain = Effects_MillibelsToLinear16(value16) >> 2;
+
+            LOGV("REVERB_PARAM_REVERB_LEVEL, m_nLateGain %d", pReverb->m_nLateGain);
+
+            if (param == REVERB_PARAM_REVERB_LEVEL)
+                break;
+            value32 = pProperties->reverbDelay;
+            /* FALL THROUGH */
+
+        case REVERB_PARAM_REVERB_DELAY:
+            // We limit max value to MAX_DELAY_TIME
+            // convert ms to time units
+            temp = (value32 * 65536) / 1000;
+            if (temp < 0 || temp > MAX_DELAY_TIME)
+                return -EINVAL;
+
+            maxSamples = (int32_t) (MAX_DELAY_TIME * pReverb->m_nSamplingRate)
+                    >> 16;
+            temp = (temp * pReverb->m_nSamplingRate) >> 16;
+            if ((temp + pReverb->m_nMaxExcursion) > maxSamples) {
+                temp = maxSamples - pReverb->m_nMaxExcursion;
+            }
+            if (temp < pReverb->m_nMaxExcursion) {
+                temp = pReverb->m_nMaxExcursion;
+            }
+
+            temp -= pReverb->m_nLateDelay;
+            pReverb->m_nDelay0Out += temp;
+            pReverb->m_nDelay1Out += temp;
+            pReverb->m_nLateDelay += temp;
+
+            LOGV("REVERB_PARAM_REVERB_DELAY, m_nLateDelay smps %d max smp delay %d", pReverb->m_nLateDelay, maxSamples);
+
+            // Convert milliseconds to sample count => m_nDelay1Out + m_nMaxExcursion
+            if (param == REVERB_PARAM_REVERB_DELAY)
+                break;
+
+            value16 = pProperties->diffusion;
+            /* FALL THROUGH */
+
+        case REVERB_PARAM_DIFFUSION:
+            if (value16 < 0 || value16 > 1000)
+                return -EINVAL;
+
+            // Convert per mille to m_sAp0.m_nApGain, m_sAp1.m_nApGain
+            pReverb->m_sAp0.m_nApGain = AP0_GAIN_BASE + ((int32_t) value16
+                    * AP0_GAIN_RANGE) / 1000;
+            pReverb->m_sAp1.m_nApGain = AP1_GAIN_BASE + ((int32_t) value16
+                    * AP1_GAIN_RANGE) / 1000;
+
+            LOGV("REVERB_PARAM_DIFFUSION, m_sAp0.m_nApGain %d m_sAp1.m_nApGain %d", pReverb->m_sAp0.m_nApGain, pReverb->m_sAp1.m_nApGain);
+
+            if (param == REVERB_PARAM_DIFFUSION)
+                break;
+
+            value16 = pProperties->density;
+            /* FALL THROUGH */
+
+        case REVERB_PARAM_DENSITY:
+            if (value16 < 0 || value16 > 1000)
+                return -EINVAL;
+
+            // Convert per mille to m_sAp0.m_zApOut, m_sAp1.m_zApOut
+            maxSamples = (int32_t) (MAX_AP_TIME * pReverb->m_nSamplingRate) >> 16;
+
+            temp = AP0_TIME_BASE + ((int32_t) value16 * AP0_TIME_RANGE) / 1000;
+            /*lint -e{702} shift for performance */
+            temp = (temp * pReverb->m_nSamplingRate) >> 16;
+            if (temp > maxSamples)
+                temp = maxSamples;
+            pReverb->m_sAp0.m_zApOut = (uint16_t) (pReverb->m_sAp0.m_zApIn + temp);
+
+            LOGV("REVERB_PARAM_DENSITY, Ap0 delay smps %d", temp);
+
+            temp = AP1_TIME_BASE + ((int32_t) value16 * AP1_TIME_RANGE) / 1000;
+            /*lint -e{702} shift for performance */
+            temp = (temp * pReverb->m_nSamplingRate) >> 16;
+            if (temp > maxSamples)
+                temp = maxSamples;
+            pReverb->m_sAp1.m_zApOut = (uint16_t) (pReverb->m_sAp1.m_zApIn + temp);
+
+            LOGV("Ap1 delay smps %d", temp);
+
+            break;
+
+        default:
+            break;
         }
-
-        LOGV("REVERB_PARAM_DECAY_HF_RATIO, gain %d, m_nRvbLpfFbk %d, m_nRvbLpfFwd %d", temp2, pReverb->m_nRvbLpfFbk, pReverb->m_nRvbLpfFwd);
-
-        pReverb->m_nRvbLpfFwd
-                = MULT_EG1_EG1(temp2, (32767 - pReverb->m_nRvbLpfFbk));
-
-        if (param == REVERB_PARAM_DECAY_HF_RATIO)
-            break;
-        value16 = pProperties->reflectionsLevel;
-        /* FALL THROUGH */
-
-    case REVERB_PARAM_REFLECTIONS_LEVEL:
-        // We limit max value to 0 because gain is limited to 0dB
-        if (value16 > 0 || value16 < -6000)
-            return -EINVAL;
-
-        // Convert millibels to linear 16 bit signed and recompute m_sEarlyL.m_nGain[i] and m_sEarlyR.m_nGain[i].
-        value16 = Effects_MillibelsToLinear16(value16);
-        for (i = 0; i < REVERB_MAX_NUM_REFLECTIONS; i++) {
-            pReverb->m_sEarlyL.m_nGain[i]
-                    = MULT_EG1_EG1(pPreset->m_sEarlyL.m_nGain[i],value16);
-            pReverb->m_sEarlyR.m_nGain[i]
-                    = MULT_EG1_EG1(pPreset->m_sEarlyR.m_nGain[i],value16);
-        }
-        pReverb->m_nEarlyGain = value16;
-        LOGV("REVERB_PARAM_REFLECTIONS_LEVEL, m_nEarlyGain %d", pReverb->m_nEarlyGain);
-
-        if (param == REVERB_PARAM_REFLECTIONS_LEVEL)
-            break;
-        value32 = pProperties->reflectionsDelay;
-        /* FALL THROUGH */
-
-    case REVERB_PARAM_REFLECTIONS_DELAY:
-        // We limit max value MAX_EARLY_TIME
-        // convert ms to time units
-        temp = (value32 * 65536) / 1000;
-        if (temp < 0 || temp > MAX_EARLY_TIME)
-            return -EINVAL;
-
-        maxSamples = (int32_t) (MAX_EARLY_TIME * pReverb->m_nSamplingRate)
-                >> 16;
-        temp = (temp * pReverb->m_nSamplingRate) >> 16;
-        for (i = 0; i < REVERB_MAX_NUM_REFLECTIONS; i++) {
-            temp2 = temp + (((int32_t) pPreset->m_sEarlyL.m_zDelay[i]
-                    * pReverb->m_nSamplingRate) >> 16);
-            if (temp2 > maxSamples)
-                temp2 = maxSamples;
-            pReverb->m_sEarlyL.m_zDelay[i] = pReverb->m_nEarly0in + temp2;
-            temp2 = temp + (((int32_t) pPreset->m_sEarlyR.m_zDelay[i]
-                    * pReverb->m_nSamplingRate) >> 16);
-            if (temp2 > maxSamples)
-                temp2 = maxSamples;
-            pReverb->m_sEarlyR.m_zDelay[i] = pReverb->m_nEarly1in + temp2;
-        }
-        pReverb->m_nEarlyDelay = temp;
-
-        LOGV("REVERB_PARAM_REFLECTIONS_DELAY, m_nEarlyDelay smps %d max smp delay %d", pReverb->m_nEarlyDelay, maxSamples);
-
-        // Convert milliseconds to sample count => m_nEarlyDelay
-        if (param == REVERB_PARAM_REFLECTIONS_DELAY)
-            break;
-        value16 = pProperties->reverbLevel;
-        /* FALL THROUGH */
-
-    case REVERB_PARAM_REVERB_LEVEL:
-        // We limit max value to 0 because gain is limited to 0dB
-        if (value16 > 0 || value16 < -6000)
-            return -EINVAL;
-        // Convert millibels to linear 16 bits (gange 0 - 8191) => m_nLateGain.
-        pReverb->m_nLateGain = Effects_MillibelsToLinear16(value16) >> 2;
-
-        LOGV("REVERB_PARAM_REVERB_LEVEL, m_nLateGain %d", pReverb->m_nLateGain);
-
-        if (param == REVERB_PARAM_REVERB_LEVEL)
-            break;
-        value32 = pProperties->reverbDelay;
-        /* FALL THROUGH */
-
-    case REVERB_PARAM_REVERB_DELAY:
-        // We limit max value to MAX_DELAY_TIME
-        // convert ms to time units
-        temp = (value32 * 65536) / 1000;
-        if (temp < 0 || temp > MAX_DELAY_TIME)
-            return -EINVAL;
-
-        maxSamples = (int32_t) (MAX_DELAY_TIME * pReverb->m_nSamplingRate)
-                >> 16;
-        temp = (temp * pReverb->m_nSamplingRate) >> 16;
-        if ((temp + pReverb->m_nMaxExcursion) > maxSamples) {
-            temp = maxSamples - pReverb->m_nMaxExcursion;
-        }
-        if (temp < pReverb->m_nMaxExcursion) {
-            temp = pReverb->m_nMaxExcursion;
-        }
-
-        temp -= pReverb->m_nLateDelay;
-        pReverb->m_nDelay0Out += temp;
-        pReverb->m_nDelay1Out += temp;
-        pReverb->m_nLateDelay += temp;
-
-        LOGV("REVERB_PARAM_REVERB_DELAY, m_nLateDelay smps %d max smp delay %d", pReverb->m_nLateDelay, maxSamples);
-
-        // Convert milliseconds to sample count => m_nDelay1Out + m_nMaxExcursion
-        if (param == REVERB_PARAM_REVERB_DELAY)
-            break;
-
-        value16 = pProperties->diffusion;
-        /* FALL THROUGH */
-
-    case REVERB_PARAM_DIFFUSION:
-        if (value16 < 0 || value16 > 1000)
-            return -EINVAL;
-
-        // Convert per mille to m_sAp0.m_nApGain, m_sAp1.m_nApGain
-        pReverb->m_sAp0.m_nApGain = AP0_GAIN_BASE + ((int32_t) value16
-                * AP0_GAIN_RANGE) / 1000;
-        pReverb->m_sAp1.m_nApGain = AP1_GAIN_BASE + ((int32_t) value16
-                * AP1_GAIN_RANGE) / 1000;
-
-        LOGV("REVERB_PARAM_DIFFUSION, m_sAp0.m_nApGain %d m_sAp1.m_nApGain %d", pReverb->m_sAp0.m_nApGain, pReverb->m_sAp1.m_nApGain);
-
-        if (param == REVERB_PARAM_DIFFUSION)
-            break;
-
-        value16 = pProperties->density;
-        /* FALL THROUGH */
-
-    case REVERB_PARAM_DENSITY:
-        if (value16 < 0 || value16 > 1000)
-            return -EINVAL;
-
-        // Convert per mille to m_sAp0.m_zApOut, m_sAp1.m_zApOut
-        maxSamples = (int32_t) (MAX_AP_TIME * pReverb->m_nSamplingRate) >> 16;
-
-        temp = AP0_TIME_BASE + ((int32_t) value16 * AP0_TIME_RANGE) / 1000;
-        /*lint -e{702} shift for performance */
-        temp = (temp * pReverb->m_nSamplingRate) >> 16;
-        if (temp > maxSamples)
-            temp = maxSamples;
-        pReverb->m_sAp0.m_zApOut = (uint16_t) (pReverb->m_sAp0.m_zApIn + temp);
-
-        LOGV("REVERB_PARAM_DENSITY, Ap0 delay smps %d", temp);
-
-        temp = AP1_TIME_BASE + ((int32_t) value16 * AP1_TIME_RANGE) / 1000;
-        /*lint -e{702} shift for performance */
-        temp = (temp * pReverb->m_nSamplingRate) >> 16;
-        if (temp > maxSamples)
-            temp = maxSamples;
-        pReverb->m_sAp1.m_zApOut = (uint16_t) (pReverb->m_sAp1.m_zApIn + temp);
-
-        LOGV("Ap1 delay smps %d", temp);
-
-        break;
-
-    default:
-        break;
     }
+
     return 0;
 } /* end Reverb_setParameter */
 
@@ -1905,139 +1947,15 @@
  */
 static int ReverbReadInPresets(reverb_object_t *pReverb) {
 
-    int preset = 0;
-    int defaultPreset = 0;
+    int preset;
 
-    //now init any remaining presets to defaults
-    for (defaultPreset = preset; defaultPreset < REVERB_MAX_ROOM_TYPE; defaultPreset++) {
-        reverb_preset_t *pPreset = &pReverb->m_sPreset.m_sPreset[defaultPreset];
-        if (defaultPreset == 0 || defaultPreset > REVERB_MAX_ROOM_TYPE - 1) {
-            pPreset->m_nRvbLpfFbk = 8307;
-            pPreset->m_nRvbLpfFwd = 14768;
-            pPreset->m_nEarlyGain = 27690;
-            pPreset->m_nEarlyDelay = 1311;
-            pPreset->m_nLateGain = 8191;
-            pPreset->m_nLateDelay = 3932;
-            pPreset->m_nRoomLpfFbk = 3692;
-            pPreset->m_nRoomLpfFwd = 24569;
-            pPreset->m_sEarlyL.m_zDelay[0] = 1376;
-            pPreset->m_sEarlyL.m_nGain[0] = 22152;
-            pPreset->m_sEarlyL.m_zDelay[1] = 2163;
-            pPreset->m_sEarlyL.m_nGain[1] = 17537;
-            pPreset->m_sEarlyL.m_zDelay[2] = 0;
-            pPreset->m_sEarlyL.m_nGain[2] = 14768;
-            pPreset->m_sEarlyL.m_zDelay[3] = 1835;
-            pPreset->m_sEarlyL.m_nGain[3] = 14307;
-            pPreset->m_sEarlyL.m_zDelay[4] = 0;
-            pPreset->m_sEarlyL.m_nGain[4] = 13384;
-            pPreset->m_sEarlyR.m_zDelay[0] = 721;
-            pPreset->m_sEarlyR.m_nGain[0] = 20306;
-            pPreset->m_sEarlyR.m_zDelay[1] = 2621;
-            pPreset->m_sEarlyR.m_nGain[1] = 17537;
-            pPreset->m_sEarlyR.m_zDelay[2] = 0;
-            pPreset->m_sEarlyR.m_nGain[2] = 14768;
-            pPreset->m_sEarlyR.m_zDelay[3] = 0;
-            pPreset->m_sEarlyR.m_nGain[3] = 16153;
-            pPreset->m_sEarlyR.m_zDelay[4] = 0;
-            pPreset->m_sEarlyR.m_nGain[4] = 13384;
-            pPreset->m_nMaxExcursion = 127;
-            pPreset->m_nXfadeInterval = 6388;
-            pPreset->m_nAp0_ApGain = 15691;
-            pPreset->m_nAp0_ApOut = 711;
-            pPreset->m_nAp1_ApGain = 16317;
-            pPreset->m_nAp1_ApOut = 1029;
-            pPreset->m_rfu4 = 0;
-            pPreset->m_rfu5 = 0;
-            pPreset->m_rfu6 = 0;
-            pPreset->m_rfu7 = 0;
-            pPreset->m_rfu8 = 0;
-            pPreset->m_rfu9 = 0;
-            pPreset->m_rfu10 = 0;
-        } else if (defaultPreset == 1) {
-            pPreset->m_nRvbLpfFbk = 6461;
-            pPreset->m_nRvbLpfFwd = 14307;
-            pPreset->m_nEarlyGain = 27690;
-            pPreset->m_nEarlyDelay = 1311;
-            pPreset->m_nLateGain = 8191;
-            pPreset->m_nLateDelay = 3932;
-            pPreset->m_nRoomLpfFbk = 3692;
-            pPreset->m_nRoomLpfFwd = 24569;
-            pPreset->m_sEarlyL.m_zDelay[0] = 1376;
-            pPreset->m_sEarlyL.m_nGain[0] = 22152;
-            pPreset->m_sEarlyL.m_zDelay[1] = 1462;
-            pPreset->m_sEarlyL.m_nGain[1] = 17537;
-            pPreset->m_sEarlyL.m_zDelay[2] = 0;
-            pPreset->m_sEarlyL.m_nGain[2] = 14768;
-            pPreset->m_sEarlyL.m_zDelay[3] = 1835;
-            pPreset->m_sEarlyL.m_nGain[3] = 14307;
-            pPreset->m_sEarlyL.m_zDelay[4] = 0;
-            pPreset->m_sEarlyL.m_nGain[4] = 13384;
-            pPreset->m_sEarlyR.m_zDelay[0] = 721;
-            pPreset->m_sEarlyR.m_nGain[0] = 20306;
-            pPreset->m_sEarlyR.m_zDelay[1] = 2621;
-            pPreset->m_sEarlyR.m_nGain[1] = 17537;
-            pPreset->m_sEarlyR.m_zDelay[2] = 0;
-            pPreset->m_sEarlyR.m_nGain[2] = 14768;
-            pPreset->m_sEarlyR.m_zDelay[3] = 0;
-            pPreset->m_sEarlyR.m_nGain[3] = 16153;
-            pPreset->m_sEarlyR.m_zDelay[4] = 0;
-            pPreset->m_sEarlyR.m_nGain[4] = 13384;
-            pPreset->m_nMaxExcursion = 127;
-            pPreset->m_nXfadeInterval = 6391;
-            pPreset->m_nAp0_ApGain = 15230;
-            pPreset->m_nAp0_ApOut = 708;
-            pPreset->m_nAp1_ApGain = 15547;
-            pPreset->m_nAp1_ApOut = 1023;
-            pPreset->m_rfu4 = 0;
-            pPreset->m_rfu5 = 0;
-            pPreset->m_rfu6 = 0;
-            pPreset->m_rfu7 = 0;
-            pPreset->m_rfu8 = 0;
-            pPreset->m_rfu9 = 0;
-            pPreset->m_rfu10 = 0;
-        } else if (defaultPreset == 2) {
-            pPreset->m_nRvbLpfFbk = 5077;
-            pPreset->m_nRvbLpfFwd = 12922;
-            pPreset->m_nEarlyGain = 27690;
-            pPreset->m_nEarlyDelay = 1311;
-            pPreset->m_nLateGain = 8191;
-            pPreset->m_nLateDelay = 3932;
-            pPreset->m_nRoomLpfFbk = 3692;
-            pPreset->m_nRoomLpfFwd = 21703;
-            pPreset->m_sEarlyL.m_zDelay[0] = 1376;
-            pPreset->m_sEarlyL.m_nGain[0] = 22152;
-            pPreset->m_sEarlyL.m_zDelay[1] = 1462;
-            pPreset->m_sEarlyL.m_nGain[1] = 17537;
-            pPreset->m_sEarlyL.m_zDelay[2] = 0;
-            pPreset->m_sEarlyL.m_nGain[2] = 14768;
-            pPreset->m_sEarlyL.m_zDelay[3] = 1835;
-            pPreset->m_sEarlyL.m_nGain[3] = 14307;
-            pPreset->m_sEarlyL.m_zDelay[4] = 0;
-            pPreset->m_sEarlyL.m_nGain[4] = 13384;
-            pPreset->m_sEarlyR.m_zDelay[0] = 721;
-            pPreset->m_sEarlyR.m_nGain[0] = 20306;
-            pPreset->m_sEarlyR.m_zDelay[1] = 2621;
-            pPreset->m_sEarlyR.m_nGain[1] = 17537;
-            pPreset->m_sEarlyR.m_zDelay[2] = 0;
-            pPreset->m_sEarlyR.m_nGain[2] = 14768;
-            pPreset->m_sEarlyR.m_zDelay[3] = 0;
-            pPreset->m_sEarlyR.m_nGain[3] = 16153;
-            pPreset->m_sEarlyR.m_zDelay[4] = 0;
-            pPreset->m_sEarlyR.m_nGain[4] = 13384;
-            pPreset->m_nMaxExcursion = 127;
-            pPreset->m_nXfadeInterval = 6449;
-            pPreset->m_nAp0_ApGain = 15691;
-            pPreset->m_nAp0_ApOut = 774;
-            pPreset->m_nAp1_ApGain = 16317;
-            pPreset->m_nAp1_ApOut = 1155;
-            pPreset->m_rfu4 = 0;
-            pPreset->m_rfu5 = 0;
-            pPreset->m_rfu6 = 0;
-            pPreset->m_rfu7 = 0;
-            pPreset->m_rfu8 = 0;
-            pPreset->m_rfu9 = 0;
-            pPreset->m_rfu10 = 0;
-        } else if (defaultPreset == 3) {
+    // this is for test only. OpenSL ES presets are mapped to 4 presets.
+    // REVERB_PRESET_NONE is mapped to bypass
+    for (preset = 0; preset < REVERB_NUM_PRESETS; preset++) {
+        reverb_preset_t *pPreset = &pReverb->m_sPreset.m_sPreset[preset];
+        switch (preset + 1) {
+        case REVERB_PRESET_PLATE:
+        case REVERB_PRESET_SMALLROOM:
             pPreset->m_nRvbLpfFbk = 5077;
             pPreset->m_nRvbLpfFwd = 11076;
             pPreset->m_nEarlyGain = 27690;
@@ -2079,6 +1997,137 @@
             pPreset->m_rfu8 = 0;
             pPreset->m_rfu9 = 0;
             pPreset->m_rfu10 = 0;
+            break;
+        case REVERB_PRESET_MEDIUMROOM:
+        case REVERB_PRESET_LARGEROOM:
+            pPreset->m_nRvbLpfFbk = 5077;
+            pPreset->m_nRvbLpfFwd = 12922;
+            pPreset->m_nEarlyGain = 27690;
+            pPreset->m_nEarlyDelay = 1311;
+            pPreset->m_nLateGain = 8191;
+            pPreset->m_nLateDelay = 3932;
+            pPreset->m_nRoomLpfFbk = 3692;
+            pPreset->m_nRoomLpfFwd = 21703;
+            pPreset->m_sEarlyL.m_zDelay[0] = 1376;
+            pPreset->m_sEarlyL.m_nGain[0] = 22152;
+            pPreset->m_sEarlyL.m_zDelay[1] = 1462;
+            pPreset->m_sEarlyL.m_nGain[1] = 17537;
+            pPreset->m_sEarlyL.m_zDelay[2] = 0;
+            pPreset->m_sEarlyL.m_nGain[2] = 14768;
+            pPreset->m_sEarlyL.m_zDelay[3] = 1835;
+            pPreset->m_sEarlyL.m_nGain[3] = 14307;
+            pPreset->m_sEarlyL.m_zDelay[4] = 0;
+            pPreset->m_sEarlyL.m_nGain[4] = 13384;
+            pPreset->m_sEarlyR.m_zDelay[0] = 721;
+            pPreset->m_sEarlyR.m_nGain[0] = 20306;
+            pPreset->m_sEarlyR.m_zDelay[1] = 2621;
+            pPreset->m_sEarlyR.m_nGain[1] = 17537;
+            pPreset->m_sEarlyR.m_zDelay[2] = 0;
+            pPreset->m_sEarlyR.m_nGain[2] = 14768;
+            pPreset->m_sEarlyR.m_zDelay[3] = 0;
+            pPreset->m_sEarlyR.m_nGain[3] = 16153;
+            pPreset->m_sEarlyR.m_zDelay[4] = 0;
+            pPreset->m_sEarlyR.m_nGain[4] = 13384;
+            pPreset->m_nMaxExcursion = 127;
+            pPreset->m_nXfadeInterval = 6449;
+            pPreset->m_nAp0_ApGain = 15691;
+            pPreset->m_nAp0_ApOut = 774;
+            pPreset->m_nAp1_ApGain = 16317;
+            pPreset->m_nAp1_ApOut = 1155;
+            pPreset->m_rfu4 = 0;
+            pPreset->m_rfu5 = 0;
+            pPreset->m_rfu6 = 0;
+            pPreset->m_rfu7 = 0;
+            pPreset->m_rfu8 = 0;
+            pPreset->m_rfu9 = 0;
+            pPreset->m_rfu10 = 0;
+            break;
+        case REVERB_PRESET_MEDIUMHALL:
+            pPreset->m_nRvbLpfFbk = 6461;
+            pPreset->m_nRvbLpfFwd = 14307;
+            pPreset->m_nEarlyGain = 27690;
+            pPreset->m_nEarlyDelay = 1311;
+            pPreset->m_nLateGain = 8191;
+            pPreset->m_nLateDelay = 3932;
+            pPreset->m_nRoomLpfFbk = 3692;
+            pPreset->m_nRoomLpfFwd = 24569;
+            pPreset->m_sEarlyL.m_zDelay[0] = 1376;
+            pPreset->m_sEarlyL.m_nGain[0] = 22152;
+            pPreset->m_sEarlyL.m_zDelay[1] = 1462;
+            pPreset->m_sEarlyL.m_nGain[1] = 17537;
+            pPreset->m_sEarlyL.m_zDelay[2] = 0;
+            pPreset->m_sEarlyL.m_nGain[2] = 14768;
+            pPreset->m_sEarlyL.m_zDelay[3] = 1835;
+            pPreset->m_sEarlyL.m_nGain[3] = 14307;
+            pPreset->m_sEarlyL.m_zDelay[4] = 0;
+            pPreset->m_sEarlyL.m_nGain[4] = 13384;
+            pPreset->m_sEarlyR.m_zDelay[0] = 721;
+            pPreset->m_sEarlyR.m_nGain[0] = 20306;
+            pPreset->m_sEarlyR.m_zDelay[1] = 2621;
+            pPreset->m_sEarlyR.m_nGain[1] = 17537;
+            pPreset->m_sEarlyR.m_zDelay[2] = 0;
+            pPreset->m_sEarlyR.m_nGain[2] = 14768;
+            pPreset->m_sEarlyR.m_zDelay[3] = 0;
+            pPreset->m_sEarlyR.m_nGain[3] = 16153;
+            pPreset->m_sEarlyR.m_zDelay[4] = 0;
+            pPreset->m_sEarlyR.m_nGain[4] = 13384;
+            pPreset->m_nMaxExcursion = 127;
+            pPreset->m_nXfadeInterval = 6391;
+            pPreset->m_nAp0_ApGain = 15230;
+            pPreset->m_nAp0_ApOut = 708;
+            pPreset->m_nAp1_ApGain = 15547;
+            pPreset->m_nAp1_ApOut = 1023;
+            pPreset->m_rfu4 = 0;
+            pPreset->m_rfu5 = 0;
+            pPreset->m_rfu6 = 0;
+            pPreset->m_rfu7 = 0;
+            pPreset->m_rfu8 = 0;
+            pPreset->m_rfu9 = 0;
+            pPreset->m_rfu10 = 0;
+            break;
+        case REVERB_PRESET_LARGEHALL:
+            pPreset->m_nRvbLpfFbk = 8307;
+            pPreset->m_nRvbLpfFwd = 14768;
+            pPreset->m_nEarlyGain = 27690;
+            pPreset->m_nEarlyDelay = 1311;
+            pPreset->m_nLateGain = 8191;
+            pPreset->m_nLateDelay = 3932;
+            pPreset->m_nRoomLpfFbk = 3692;
+            pPreset->m_nRoomLpfFwd = 24569;
+            pPreset->m_sEarlyL.m_zDelay[0] = 1376;
+            pPreset->m_sEarlyL.m_nGain[0] = 22152;
+            pPreset->m_sEarlyL.m_zDelay[1] = 2163;
+            pPreset->m_sEarlyL.m_nGain[1] = 17537;
+            pPreset->m_sEarlyL.m_zDelay[2] = 0;
+            pPreset->m_sEarlyL.m_nGain[2] = 14768;
+            pPreset->m_sEarlyL.m_zDelay[3] = 1835;
+            pPreset->m_sEarlyL.m_nGain[3] = 14307;
+            pPreset->m_sEarlyL.m_zDelay[4] = 0;
+            pPreset->m_sEarlyL.m_nGain[4] = 13384;
+            pPreset->m_sEarlyR.m_zDelay[0] = 721;
+            pPreset->m_sEarlyR.m_nGain[0] = 20306;
+            pPreset->m_sEarlyR.m_zDelay[1] = 2621;
+            pPreset->m_sEarlyR.m_nGain[1] = 17537;
+            pPreset->m_sEarlyR.m_zDelay[2] = 0;
+            pPreset->m_sEarlyR.m_nGain[2] = 14768;
+            pPreset->m_sEarlyR.m_zDelay[3] = 0;
+            pPreset->m_sEarlyR.m_nGain[3] = 16153;
+            pPreset->m_sEarlyR.m_zDelay[4] = 0;
+            pPreset->m_sEarlyR.m_nGain[4] = 13384;
+            pPreset->m_nMaxExcursion = 127;
+            pPreset->m_nXfadeInterval = 6388;
+            pPreset->m_nAp0_ApGain = 15691;
+            pPreset->m_nAp0_ApOut = 711;
+            pPreset->m_nAp1_ApGain = 16317;
+            pPreset->m_nAp1_ApOut = 1029;
+            pPreset->m_rfu4 = 0;
+            pPreset->m_rfu5 = 0;
+            pPreset->m_rfu6 = 0;
+            pPreset->m_rfu7 = 0;
+            pPreset->m_rfu8 = 0;
+            pPreset->m_rfu9 = 0;
+            pPreset->m_rfu10 = 0;
+            break;
         }
     }
 
diff --git a/media/libeffects/EffectReverb.h b/media/libeffects/EffectReverb.h
index f5aadfa..ee8e390 100644
--- a/media/libeffects/EffectReverb.h
+++ b/media/libeffects/EffectReverb.h
@@ -17,7 +17,8 @@
 #ifndef ANDROID_EFFECTREVERB_H_
 #define ANDROID_EFFECTREVERB_H_
 
-#include <media/EffectReverbApi.h>
+#include <media/EffectEnvironmentalReverbApi.h>
+#include <media/EffectPresetReverbApi.h>
 
 
 /*------------------------------------
@@ -43,7 +44,7 @@
 
 #define REVERB_BUFFER_SIZE_IN_SAMPLES_MAX   16384
 
-#define REVERB_MAX_ROOM_TYPE            4   // any room numbers larger than this are invalid
+#define REVERB_NUM_PRESETS  REVERB_PRESET_PLATE   // REVERB_PRESET_NONE is not included
 #define REVERB_MAX_NUM_REFLECTIONS      5   // max num reflections per channel
 
 
@@ -113,6 +114,12 @@
 #define AP1_GAIN_RANGE (int)(22936-6553)
 
 
+enum reverb_state_e {
+    REVERB_STATE_UNINITIALIZED,
+    REVERB_STATE_INITIALIZED,
+    REVERB_STATE_ACTIVE,
+};
+
 /* parameters for each allpass */
 typedef struct
 {
@@ -171,7 +178,7 @@
 
 typedef struct
 {
-    reverb_preset_t     m_sPreset[REVERB_MAX_ROOM_TYPE];    //array of presets
+    reverb_preset_t     m_sPreset[REVERB_NUM_PRESETS]; // array of presets(does not include REVERB_PRESET_NONE)
 
 } reverb_preset_bank_t;
 
@@ -278,6 +285,7 @@
     uint16_t            m_Aux;                // if TRUE, is connected as auxiliary effect
     uint16_t            m_Preset;             // if TRUE, expose preset revert interface
 
+    uint32_t            mState;
 } reverb_object_t;
 
 
diff --git a/media/libeffects/EffectVisualizer.cpp b/media/libeffects/EffectVisualizer.cpp
index f27e296..bcda06e 100644
--- a/media/libeffects/EffectVisualizer.cpp
+++ b/media/libeffects/EffectVisualizer.cpp
@@ -231,7 +231,7 @@
         return -EINVAL;
     }
     if (pContext->mState != VISUALIZER_STATE_ACTIVE) {
-        return -ENOSYS;
+        return -ENODATA;
     }
 
     if (inBuffer == NULL || inBuffer->raw == NULL ||
diff --git a/media/libmedia/AudioEffect.cpp b/media/libmedia/AudioEffect.cpp
index 783249d..df0f73b 100644
--- a/media/libmedia/AudioEffect.cpp
+++ b/media/libmedia/AudioEffect.cpp
@@ -52,7 +52,7 @@
                 )
     : mStatus(NO_INIT)
 {
-    mStatus = set(type, uuid, priority, cbf, user, output, sessionId);
+    mStatus = set(type, uuid, priority, cbf, user, sessionId, output);
 }
 
 AudioEffect::AudioEffect(const char *typeStr,
@@ -84,7 +84,7 @@
         }
     }
 
-    mStatus = set(pType, pUuid, priority, cbf, user, output, sessionId);
+    mStatus = set(pType, pUuid, priority, cbf, user, sessionId, output);
 }
 
 status_t AudioEffect::set(const effect_uuid_t *type,
diff --git a/media/libmedia/MediaScanner.cpp b/media/libmedia/MediaScanner.cpp
index 24426ff..ba98f04 100644
--- a/media/libmedia/MediaScanner.cpp
+++ b/media/libmedia/MediaScanner.cpp
@@ -81,13 +81,13 @@
 }
 
 static bool fileMatchesExtension(const char* path, const char* extensions) {
-    char* extension = strrchr(path, '.');
+    const char* extension = strrchr(path, '.');
     if (!extension) return false;
     ++extension;    // skip the dot
     if (extension[0] == 0) return false;
 
     while (extensions[0]) {
-        char* comma = strchr(extensions, ',');
+        const char* comma = strchr(extensions, ',');
         size_t length = (comma ? comma - extensions : strlen(extensions));
         if (length == strlen(extension) && strncasecmp(extension, extensions, length) == 0) return true;
         extensions += length;
diff --git a/media/libmediaplayerservice/MediaPlayerService.cpp b/media/libmediaplayerservice/MediaPlayerService.cpp
index 4872047..5401ec0 100644
--- a/media/libmediaplayerservice/MediaPlayerService.cpp
+++ b/media/libmediaplayerservice/MediaPlayerService.cpp
@@ -511,11 +511,17 @@
             sp<Client> c = mClients[i].promote();
             if (c != 0) c->dump(fd, args);
         }
-        for (int i = 0, n = mMediaRecorderClients.size(); i < n; ++i) {
-            result.append(" MediaRecorderClient\n");
-            sp<MediaRecorderClient> c = mMediaRecorderClients[i].promote();
-            snprintf(buffer, 255, "  pid(%d)\n\n", c->mPid);
-            result.append(buffer);
+        if (mMediaRecorderClients.size() == 0) {
+                result.append(" No media recorder client\n\n");
+        } else {
+            for (int i = 0, n = mMediaRecorderClients.size(); i < n; ++i) {
+                sp<MediaRecorderClient> c = mMediaRecorderClients[i].promote();
+                snprintf(buffer, 255, " MediaRecorderClient pid(%d)\n", c->mPid);
+                result.append(buffer);
+                write(fd, result.string(), result.size());
+                result = "\n";
+                c->dump(fd, args);
+            }
         }
 
         result.append(" Files opened and/or mapped:\n");
diff --git a/media/libmediaplayerservice/MediaRecorderClient.cpp b/media/libmediaplayerservice/MediaRecorderClient.cpp
index 80b1cfd..fef3e6e 100644
--- a/media/libmediaplayerservice/MediaRecorderClient.cpp
+++ b/media/libmediaplayerservice/MediaRecorderClient.cpp
@@ -329,5 +329,12 @@
     return mRecorder->setListener(listener);
 }
 
+status_t MediaRecorderClient::dump(int fd, const Vector<String16>& args) const {
+    if (mRecorder != NULL) {
+        return mRecorder->dump(fd, args);
+    }
+    return OK;
+}
+
 }; // namespace android
 
diff --git a/media/libmediaplayerservice/MediaRecorderClient.h b/media/libmediaplayerservice/MediaRecorderClient.h
index b53d950..d12e558 100644
--- a/media/libmediaplayerservice/MediaRecorderClient.h
+++ b/media/libmediaplayerservice/MediaRecorderClient.h
@@ -28,7 +28,7 @@
 class MediaRecorderClient : public BnMediaRecorder
 {
 public:
-    virtual	    status_t		setCamera(const sp<ICamera>& camera);
+    virtual     status_t        setCamera(const sp<ICamera>& camera);
     virtual     status_t        setPreviewSurface(const sp<ISurface>& surface);
     virtual     status_t        setVideoSource(int vs);
     virtual     status_t        setAudioSource(int as);
@@ -45,21 +45,22 @@
     virtual     status_t        getMaxAmplitude(int* max);
     virtual     status_t        start();
     virtual     status_t        stop();
-    virtual	    status_t        reset();
+    virtual     status_t        reset();
     virtual     status_t        init();
     virtual     status_t        close();
     virtual     status_t        release();
 
+    virtual     status_t        dump(int fd, const Vector<String16>& args) const;
 private:
-    friend class                 MediaPlayerService;  // for accessing private constructor
+    friend class                MediaPlayerService;  // for accessing private constructor
 
-                                 MediaRecorderClient(const sp<MediaPlayerService>& service, pid_t pid);
-    virtual 		         ~MediaRecorderClient();
+                                MediaRecorderClient(const sp<MediaPlayerService>& service, pid_t pid);
+    virtual                     ~MediaRecorderClient();
 
-    pid_t			 mPid;
-    Mutex			 mLock;
-    MediaRecorderBase            *mRecorder;
-    sp<MediaPlayerService>       mMediaPlayerService;
+    pid_t                       mPid;
+    Mutex                       mLock;
+    MediaRecorderBase           *mRecorder;
+    sp<MediaPlayerService>      mMediaPlayerService;
 };
 
 }; // namespace android
diff --git a/media/libmediaplayerservice/StagefrightRecorder.cpp b/media/libmediaplayerservice/StagefrightRecorder.cpp
index 509c6fd..24b0e7b 100644
--- a/media/libmediaplayerservice/StagefrightRecorder.cpp
+++ b/media/libmediaplayerservice/StagefrightRecorder.cpp
@@ -381,12 +381,12 @@
     return OK;
 }
 
-// If interval <  0, only the first frame is I frame, and rest are all P frames
-// If interval == 0, all frames are encoded as I frames. No P frames
-// If interval >  0, it is the time spacing (seconds) between 2 neighboring I frames
-status_t StagefrightRecorder::setParamVideoIFramesInterval(int32_t interval) {
-    LOGV("setParamVideoIFramesInterval: %d seconds", interval);
-    mIFramesInterval = interval;
+// If seconds <  0, only the first frame is I frame, and rest are all P frames
+// If seconds == 0, all frames are encoded as I frames. No P frames
+// If seconds >  0, it is the time spacing (seconds) between 2 neighboring I frames
+status_t StagefrightRecorder::setParamVideoIFramesInterval(int32_t seconds) {
+    LOGV("setParamVideoIFramesInterval: %d seconds", seconds);
+    mIFramesIntervalSec = seconds;
     return OK;
 }
 
@@ -444,6 +444,44 @@
     return OK;
 }
 
+status_t StagefrightRecorder::setParamMovieTimeScale(int32_t timeScale) {
+    LOGV("setParamMovieTimeScale: %d", timeScale);
+
+    // The range is set to be the same as the audio's time scale range
+    // since audio's time scale has a wider range.
+    if (timeScale < 600 || timeScale > 96000) {
+        LOGE("Time scale (%d) for movie is out of range [600, 96000]", timeScale);
+        return BAD_VALUE;
+    }
+    mMovieTimeScale = timeScale;
+    return OK;
+}
+
+status_t StagefrightRecorder::setParamVideoTimeScale(int32_t timeScale) {
+    LOGV("setParamVideoTimeScale: %d", timeScale);
+
+    // 60000 is chosen to make sure that each video frame from a 60-fps
+    // video has 1000 ticks.
+    if (timeScale < 600 || timeScale > 60000) {
+        LOGE("Time scale (%d) for video is out of range [600, 60000]", timeScale);
+        return BAD_VALUE;
+    }
+    mVideoTimeScale = timeScale;
+    return OK;
+}
+
+status_t StagefrightRecorder::setParamAudioTimeScale(int32_t timeScale) {
+    LOGV("setParamAudioTimeScale: %d", timeScale);
+
+    // 96000 Hz is the highest sampling rate support in AAC.
+    if (timeScale < 600 || timeScale > 96000) {
+        LOGE("Time scale (%d) for audio is out of range [600, 96000]", timeScale);
+        return BAD_VALUE;
+    }
+    mAudioTimeScale = timeScale;
+    return OK;
+}
+
 status_t StagefrightRecorder::setParameter(
         const String8 &key, const String8 &value) {
     LOGV("setParameter: key (%s) => value (%s)", key.string(), value.string());
@@ -462,6 +500,11 @@
         if (safe_strtoi32(value.string(), &durationUs)) {
             return setParamInterleaveDuration(durationUs);
         }
+    } else if (key == "param-movie-time-scale") {
+        int32_t timeScale;
+        if (safe_strtoi32(value.string(), &timeScale)) {
+            return setParamMovieTimeScale(timeScale);
+        }
     } else if (key == "param-use-64bit-offset") {
         int32_t use64BitOffset;
         if (safe_strtoi32(value.string(), &use64BitOffset)) {
@@ -492,15 +535,20 @@
         if (safe_strtoi32(value.string(), &audio_bitrate)) {
             return setParamAudioEncodingBitRate(audio_bitrate);
         }
+    } else if (key == "audio-param-time-scale") {
+        int32_t timeScale;
+        if (safe_strtoi32(value.string(), &timeScale)) {
+            return setParamAudioTimeScale(timeScale);
+        }
     } else if (key == "video-param-encoding-bitrate") {
         int32_t video_bitrate;
         if (safe_strtoi32(value.string(), &video_bitrate)) {
             return setParamVideoEncodingBitRate(video_bitrate);
         }
     } else if (key == "video-param-i-frames-interval") {
-        int32_t interval;
-        if (safe_strtoi32(value.string(), &interval)) {
-            return setParamVideoIFramesInterval(interval);
+        int32_t seconds;
+        if (safe_strtoi32(value.string(), &seconds)) {
+            return setParamVideoIFramesInterval(seconds);
         }
     } else if (key == "video-param-encoder-profile") {
         int32_t profile;
@@ -517,6 +565,11 @@
         if (safe_strtoi32(value.string(), &cameraId)) {
             return setParamVideoCameraId(cameraId);
         }
+    } else if (key == "video-param-time-scale") {
+        int32_t timeScale;
+        if (safe_strtoi32(value.string(), &timeScale)) {
+            return setParamVideoTimeScale(timeScale);
+        }
     } else {
         LOGE("setParameter: failed to find key %s", key.string());
     }
@@ -637,6 +690,7 @@
     encMeta->setInt32(kKeyChannelCount, mAudioChannels);
     encMeta->setInt32(kKeySampleRate, mSampleRate);
     encMeta->setInt32(kKeyBitRate, mAudioBitRate);
+    encMeta->setInt32(kKeyTimeScale, mAudioTimeScale);
 
     OMXClient client;
     CHECK_EQ(client.connect(), OK);
@@ -871,17 +925,20 @@
 
     sp<MetaData> meta = cameraSource->getFormat();
 
-    int32_t width, height, stride, sliceHeight;
+    int32_t width, height, stride, sliceHeight, colorFormat;
     CHECK(meta->findInt32(kKeyWidth, &width));
     CHECK(meta->findInt32(kKeyHeight, &height));
     CHECK(meta->findInt32(kKeyStride, &stride));
     CHECK(meta->findInt32(kKeySliceHeight, &sliceHeight));
+    CHECK(meta->findInt32(kKeyColorFormat, &colorFormat));
 
     enc_meta->setInt32(kKeyWidth, width);
     enc_meta->setInt32(kKeyHeight, height);
-    enc_meta->setInt32(kKeyIFramesInterval, mIFramesInterval);
+    enc_meta->setInt32(kKeyIFramesInterval, mIFramesIntervalSec);
     enc_meta->setInt32(kKeyStride, stride);
     enc_meta->setInt32(kKeySliceHeight, sliceHeight);
+    enc_meta->setInt32(kKeyColorFormat, colorFormat);
+    enc_meta->setInt32(kKeyTimeScale, mVideoTimeScale);
     if (mVideoEncoderProfile != -1) {
         enc_meta->setInt32(kKeyVideoProfile, mVideoEncoderProfile);
     }
@@ -919,6 +976,7 @@
     if (audioEncoder == NULL) {
         return UNKNOWN_ERROR;
     }
+
     writer->addSource(audioEncoder);
     return OK;
 }
@@ -955,6 +1013,7 @@
     meta->setInt32(kKeyFileType, mOutputFormat);
     meta->setInt32(kKeyBitRate, totalBitRate);
     meta->setInt32(kKey64BitFileOffset, mUse64BitFileOffset);
+    meta->setInt32(kKeyTimeScale, mMovieTimeScale);
     if (mTrackEveryNumberOfFrames > 0) {
         meta->setInt32(kKeyTrackFrameStatus, mTrackEveryNumberOfFrames);
     }
@@ -1025,9 +1084,12 @@
     mAudioChannels = 1;
     mAudioBitRate  = 12200;
     mInterleaveDurationUs = 0;
-    mIFramesInterval = 1;
+    mIFramesIntervalSec = 1;
     mAudioSourceNode = 0;
     mUse64BitFileOffset = false;
+    mMovieTimeScale  = 1000;
+    mAudioTimeScale  = 1000;
+    mVideoTimeScale  = 1000;
     mCameraId        = 0;
     mVideoEncoderProfile = -1;
     mVideoEncoderLevel   = -1;
@@ -1061,4 +1123,64 @@
     return OK;
 }
 
+status_t StagefrightRecorder::dump(int fd, const Vector<String16>& args) const {
+    const size_t SIZE = 256;
+    char buffer[SIZE];
+    String8 result;
+    snprintf(buffer, SIZE, "   Recorder: %p", this);
+    snprintf(buffer, SIZE, "   Output file (fd %d):\n", mOutputFd);
+    result.append(buffer);
+    snprintf(buffer, SIZE, "     File format: %d\n", mOutputFormat);
+    result.append(buffer);
+    snprintf(buffer, SIZE, "     Max file size (bytes): %lld\n", mMaxFileSizeBytes);
+    result.append(buffer);
+    snprintf(buffer, SIZE, "     Max file duration (us): %lld\n", mMaxFileDurationUs);
+    result.append(buffer);
+    snprintf(buffer, SIZE, "     File offset length (bits): %d\n", mUse64BitFileOffset? 64: 32);
+    result.append(buffer);
+    snprintf(buffer, SIZE, "     Interleave duration (us): %d\n", mInterleaveDurationUs);
+    result.append(buffer);
+    snprintf(buffer, SIZE, "     Progress notification: %d frames\n", mTrackEveryNumberOfFrames);
+    result.append(buffer);
+    snprintf(buffer, SIZE, "     Progress notification: %lld us\n", mTrackEveryTimeDurationUs);
+    result.append(buffer);
+    snprintf(buffer, SIZE, "   Audio\n");
+    result.append(buffer);
+    snprintf(buffer, SIZE, "     Source: %d\n", mAudioSource);
+    result.append(buffer);
+    snprintf(buffer, SIZE, "     Encoder: %d\n", mAudioEncoder);
+    result.append(buffer);
+    snprintf(buffer, SIZE, "     Bit rate (bps): %d\n", mAudioBitRate);
+    result.append(buffer);
+    snprintf(buffer, SIZE, "     Sampling rate (hz): %d\n", mSampleRate);
+    result.append(buffer);
+    snprintf(buffer, SIZE, "     Number of channels: %d\n", mAudioChannels);
+    result.append(buffer);
+    snprintf(buffer, SIZE, "     Max amplitude: %d\n", mAudioSourceNode == 0? 0: mAudioSourceNode->getMaxAmplitude());
+    result.append(buffer);
+    snprintf(buffer, SIZE, "   Video\n");
+    result.append(buffer);
+    snprintf(buffer, SIZE, "     Source: %d\n", mVideoSource);
+    result.append(buffer);
+    snprintf(buffer, SIZE, "     Camera Id: %d\n", mCameraId);
+    result.append(buffer);
+    snprintf(buffer, SIZE, "     Camera flags: %d\n", mFlags);
+    result.append(buffer);
+    snprintf(buffer, SIZE, "     Encoder: %d\n", mVideoEncoder);
+    result.append(buffer);
+    snprintf(buffer, SIZE, "     Encoder profile: %d\n", mVideoEncoderProfile);
+    result.append(buffer);
+    snprintf(buffer, SIZE, "     Encoder level: %d\n", mVideoEncoderLevel);
+    result.append(buffer);
+    snprintf(buffer, SIZE, "     I frames interval (s): %d\n", mIFramesIntervalSec);
+    result.append(buffer);
+    snprintf(buffer, SIZE, "     Frame size (pixels): %dx%d\n", mVideoWidth, mVideoHeight);
+    result.append(buffer);
+    snprintf(buffer, SIZE, "     Frame rate (fps): %d\n", mFrameRate);
+    result.append(buffer);
+    snprintf(buffer, SIZE, "     Bit rate (bps): %d\n", mVideoBitRate);
+    result.append(buffer);
+    ::write(fd, result.string(), result.size());
+    return OK;
+}
 }  // namespace android
diff --git a/media/libmediaplayerservice/StagefrightRecorder.h b/media/libmediaplayerservice/StagefrightRecorder.h
index 2090666..f51d7f8 100644
--- a/media/libmediaplayerservice/StagefrightRecorder.h
+++ b/media/libmediaplayerservice/StagefrightRecorder.h
@@ -54,6 +54,7 @@
     virtual status_t close();
     virtual status_t reset();
     virtual status_t getMaxAmplitude(int *max);
+    virtual status_t dump(int fd, const Vector<String16>& args) const;
 
 private:
     enum CameraFlags {
@@ -80,10 +81,13 @@
     int32_t mAudioChannels;
     int32_t mSampleRate;
     int32_t mInterleaveDurationUs;
-    int32_t mIFramesInterval;
+    int32_t mIFramesIntervalSec;
     int32_t mCameraId;
     int32_t mVideoEncoderProfile;
     int32_t mVideoEncoderLevel;
+    int32_t mMovieTimeScale;
+    int32_t mVideoTimeScale;
+    int32_t mAudioTimeScale;
     int64_t mMaxFileSizeBytes;
     int64_t mMaxFileDurationUs;
     int32_t mTrackEveryNumberOfFrames;
@@ -110,17 +114,20 @@
     status_t setParamAudioEncodingBitRate(int32_t bitRate);
     status_t setParamAudioNumberOfChannels(int32_t channles);
     status_t setParamAudioSamplingRate(int32_t sampleRate);
+    status_t setParamAudioTimeScale(int32_t timeScale);
     status_t setParamVideoEncodingBitRate(int32_t bitRate);
-    status_t setParamVideoIFramesInterval(int32_t interval);
+    status_t setParamVideoIFramesInterval(int32_t seconds);
     status_t setParamVideoEncoderProfile(int32_t profile);
     status_t setParamVideoEncoderLevel(int32_t level);
     status_t setParamVideoCameraId(int32_t cameraId);
+    status_t setParamVideoTimeScale(int32_t timeScale);
     status_t setParamTrackTimeStatus(int64_t timeDurationUs);
     status_t setParamTrackFrameStatus(int32_t nFrames);
     status_t setParamInterleaveDuration(int32_t durationUs);
     status_t setParam64BitFileOffset(bool use64BitFileOffset);
     status_t setParamMaxFileDurationUs(int64_t timeUs);
     status_t setParamMaxFileSizeBytes(int64_t bytes);
+    status_t setParamMovieTimeScale(int32_t timeScale);
     void clipVideoBitRate();
     void clipVideoFrameRate();
     void clipVideoFrameWidth();
diff --git a/media/libstagefright/Android.mk b/media/libstagefright/Android.mk
index 60d0233..49cf647 100644
--- a/media/libstagefright/Android.mk
+++ b/media/libstagefright/Android.mk
@@ -66,6 +66,7 @@
         libstagefright_amrwbdec \
         libstagefright_amrwbenc \
         libstagefright_avcdec \
+        libstagefright_avcenc \
         libstagefright_m4vh263dec \
         libstagefright_mp3dec \
         libstagefright_vorbisdec \
diff --git a/media/libstagefright/MPEG4Writer.cpp b/media/libstagefright/MPEG4Writer.cpp
index 6a4a131..b7388bb 100644
--- a/media/libstagefright/MPEG4Writer.cpp
+++ b/media/libstagefright/MPEG4Writer.cpp
@@ -41,6 +41,7 @@
 class MPEG4Writer::Track {
 public:
     Track(MPEG4Writer *owner, const sp<MediaSource> &source);
+
     ~Track();
 
     status_t start(MetaData *params);
@@ -61,12 +62,13 @@
     volatile bool mResumed;
     int64_t mMaxTimeStampUs;
     int64_t mEstimatedTrackSizeBytes;
+    int32_t mTimeScale;
 
     pthread_t mThread;
 
     struct SampleInfo {
         size_t size;
-        int64_t timestamp;
+        int64_t timestampUs;
     };
     List<SampleInfo>    mSampleInfos;
     bool                mSamplesHaveSameSize;
@@ -92,11 +94,11 @@
 
     struct SttsTableEntry {
 
-        SttsTableEntry(uint32_t count, uint32_t duration)
-            : sampleCount(count), sampleDuration(duration) {}
+        SttsTableEntry(uint32_t count, uint32_t durationUs)
+            : sampleCount(count), sampleDurationUs(durationUs) {}
 
         uint32_t sampleCount;
-        uint32_t sampleDuration;
+        uint32_t sampleDurationUs;
     };
     List<SttsTableEntry> mSttsTableEntries;
 
@@ -270,6 +272,13 @@
         return OK;
     }
 
+    if (!param ||
+        !param->findInt32(kKeyTimeScale, &mTimeScale)) {
+        mTimeScale = 1000;
+    }
+    CHECK(mTimeScale > 0);
+    LOGV("movie time scale: %d", mTimeScale);
+
     mStreamableFile = true;
     mWriteMoovBoxToMemory = false;
     mMoovBoxBuffer = NULL;
@@ -336,14 +345,14 @@
         return;
     }
 
-    int64_t max_duration = 0;
+    int64_t maxDurationUs = 0;
     for (List<Track *>::iterator it = mTracks.begin();
          it != mTracks.end(); ++it) {
         (*it)->stop();
 
-        int64_t duration = (*it)->getDurationUs();
-        if (duration > max_duration) {
-            max_duration = duration;
+        int64_t durationUs = (*it)->getDurationUs();
+        if (durationUs > maxDurationUs) {
+            maxDurationUs = durationUs;
         }
     }
 
@@ -367,8 +376,7 @@
     mMoovBoxBuffer = (uint8_t *) malloc(mEstimatedMoovBoxSize);
     mMoovBoxBufferOffset = 0;
     CHECK(mMoovBoxBuffer != NULL);
-    int32_t timeScale = 1000;
-    int32_t duration = max_duration / timeScale;
+    int32_t duration = (maxDurationUs * mTimeScale) / 1E6;
 
     beginBox("moov");
 
@@ -376,7 +384,7 @@
         writeInt32(0);             // version=0, flags=0
         writeInt32(now);           // creation time
         writeInt32(now);           // modification time
-        writeInt32(timeScale);          // timescale
+        writeInt32(mTimeScale);    // mvhd timescale
         writeInt32(duration);
         writeInt32(0x10000);       // rate: 1.0
         writeInt16(0x100);         // volume
@@ -655,7 +663,6 @@
 }
 
 int64_t MPEG4Writer::getStartTimestampUs() {
-    LOGI("getStartTimestampUs: %lld", mStartTimestampUs);
     Mutex::Autolock autoLock(mLock);
     return mStartTimestampUs;
 }
@@ -683,6 +690,11 @@
       mGotAllCodecSpecificData(false),
       mReachedEOS(false) {
     getCodecSpecificDataFromInputFormatIfPossible();
+
+    if (!mMeta->findInt32(kKeyTimeScale, &mTimeScale)) {
+        mTimeScale = 1000;
+    }
+    CHECK(mTimeScale > 0);
 }
 
 void MPEG4Writer::Track::getCodecSpecificDataFromInputFormatIfPossible() {
@@ -927,9 +939,9 @@
     int64_t chunkTimestampUs = 0;
     int32_t nChunks = 0;
     int32_t nZeroLengthFrames = 0;
-    int64_t lastTimestamp = 0;  // Timestamp of the previous sample
-    int64_t lastDuration = 0;   // Time spacing between the previous two samples
-    int32_t sampleCount = 1;    // Sample count in the current stts table entry
+    int64_t lastTimestampUs = 0;  // Previous sample time stamp in ms
+    int64_t lastDurationUs = 0;   // Between the previous two samples in ms
+    int32_t sampleCount = 1;      // Sample count in the current stts table entry
     uint32_t previousSampleSize = 0;  // Size of the previous sample
     int64_t previousPausedDurationUs = 0;
     sp<MetaData> meta_data;
@@ -1113,7 +1125,7 @@
         }
 
         if (mResumed) {
-            previousPausedDurationUs += (timestampUs - mMaxTimeStampUs - 1000 * lastDuration);
+            previousPausedDurationUs += (timestampUs - mMaxTimeStampUs - lastDurationUs);
             mResumed = false;
         }
 
@@ -1124,12 +1136,11 @@
             mMaxTimeStampUs = timestampUs;
         }
 
-        // Our timestamp is in ms.
-        info.timestamp = (timestampUs + 500) / 1000;
+        info.timestampUs = timestampUs;
         mSampleInfos.push_back(info);
         if (mSampleInfos.size() > 2) {
-            if (lastDuration != info.timestamp - lastTimestamp) {
-                SttsTableEntry sttsEntry(sampleCount, lastDuration);
+            if (lastDurationUs != info.timestampUs - lastTimestampUs) {
+                SttsTableEntry sttsEntry(sampleCount, lastDurationUs);
                 mSttsTableEntries.push_back(sttsEntry);
                 sampleCount = 1;
             } else {
@@ -1142,8 +1153,8 @@
             }
             previousSampleSize = info.size;
         }
-        lastDuration = info.timestamp - lastTimestamp;
-        lastTimestamp = info.timestamp;
+        lastDurationUs = info.timestampUs - lastTimestampUs;
+        lastTimestampUs = info.timestampUs;
 
         if (isSync != 0) {
             mStssTableEntries.push_back(mSampleInfos.size());
@@ -1213,11 +1224,11 @@
     // there is no frame time after it, just repeat the previous
     // frame's duration.
     if (mSampleInfos.size() == 1) {
-        lastDuration = 0;  // A single sample's duration
+        lastDurationUs = 0;  // A single sample's duration
     } else {
         ++sampleCount;  // Count for the last sample
     }
-    SttsTableEntry sttsEntry(sampleCount, lastDuration);
+    SttsTableEntry sttsEntry(sampleCount, lastDurationUs);
     mSttsTableEntries.push_back(sttsEntry);
     mReachedEOS = true;
     LOGI("Received total/0-length (%d/%d) buffers and encoded %d frames - %s",
@@ -1249,12 +1260,13 @@
 void MPEG4Writer::Track::findMinAvgMaxSampleDurationMs(
         int32_t *min, int32_t *avg, int32_t *max) {
     CHECK(!mSampleInfos.empty());
-    int32_t avgSampleDurationMs = mMaxTimeStampUs / 1000/ mSampleInfos.size();
+    int32_t avgSampleDurationMs = mMaxTimeStampUs / 1000 / mSampleInfos.size();
     int32_t minSampleDurationMs = 0x7FFFFFFF;
     int32_t maxSampleDurationMs = 0;
     for (List<SttsTableEntry>::iterator it = mSttsTableEntries.begin();
         it != mSttsTableEntries.end(); ++it) {
-        int32_t sampleDurationMs = static_cast<int32_t>(it->sampleDuration);
+        int32_t sampleDurationMs =
+            (static_cast<int32_t>(it->sampleDurationUs) + 500) / 1000;
         if (sampleDurationMs > maxSampleDurationMs) {
             maxSampleDurationMs = sampleDurationMs;
         } else if (sampleDurationMs < minSampleDurationMs) {
@@ -1370,10 +1382,13 @@
     CHECK(success);
 
     bool is_audio = !strncasecmp(mime, "audio/", 6);
-    int32_t timeScale = 1000;
-    int32_t duration = getDurationUs() / timeScale;
+    LOGV("%s track time scale: %d",
+        is_audio? "Audio": "Video", mTimeScale);
+
 
     time_t now = time(NULL);
+    int32_t mvhdTimeScale = mOwner->getTimeScale();
+    int64_t trakDurationUs = getDurationUs();
 
     mOwner->beginBox("trak");
 
@@ -1385,7 +1400,9 @@
         mOwner->writeInt32(now);           // modification time
         mOwner->writeInt32(trackID);
         mOwner->writeInt32(0);             // reserved
-        mOwner->writeInt32(duration);
+        int32_t tkhdDuration =
+            (trakDurationUs * mvhdTimeScale + 5E5) / 1E6;
+        mOwner->writeInt32(tkhdDuration);  // in mvhd timescale
         mOwner->writeInt32(0);             // reserved
         mOwner->writeInt32(0);             // reserved
         mOwner->writeInt16(0);             // layer
@@ -1423,12 +1440,17 @@
           mOwner->beginBox("elst");
             mOwner->writeInt32(0);           // version=0, flags=0: 32-bit time
             mOwner->writeInt32(2);           // never ends with an empty list
-            int64_t durationMs =
-                (mStartTimestampUs - moovStartTimeUs) / 1000;
-            mOwner->writeInt32(durationMs);  // edit duration
-            mOwner->writeInt32(-1);          // empty edit box to signal starting time offset
-            mOwner->writeInt32(1 << 16);     // x1 rate
-            mOwner->writeInt32(duration);
+
+            // First elst entry: specify the starting time offset
+            int64_t offsetUs = mStartTimestampUs - moovStartTimeUs;
+            int32_t seg = (offsetUs * mvhdTimeScale + 5E5) / 1E6;
+            mOwner->writeInt32(seg);         // in mvhd timecale
+            mOwner->writeInt32(-1);          // starting time offset
+            mOwner->writeInt32(1 << 16);     // rate = 1.0
+
+            // Second elst entry: specify the track duration
+            seg = (trakDurationUs * mvhdTimeScale + 5E5) / 1E6;
+            mOwner->writeInt32(seg);         // in mvhd timescale
             mOwner->writeInt32(0);
             mOwner->writeInt32(1 << 16);
           mOwner->endBox();
@@ -1441,8 +1463,9 @@
           mOwner->writeInt32(0);             // version=0, flags=0
           mOwner->writeInt32(now);           // creation time
           mOwner->writeInt32(now);           // modification time
-          mOwner->writeInt32(timeScale);     // timescale
-          mOwner->writeInt32(duration);      // duration
+          mOwner->writeInt32(mTimeScale);    // media timescale
+          int32_t mdhdDuration = (trakDurationUs * mTimeScale + 5E5) / 1E6;
+          mOwner->writeInt32(mdhdDuration);  // use media timescale
           // Language follows the three letter standard ISO-639-2/T
           // 'e', 'n', 'g' for "English", for instance.
           // Each character is packed as the difference between its ASCII value and 0x60.
@@ -1664,7 +1687,8 @@
             for (List<SttsTableEntry>::iterator it = mSttsTableEntries.begin();
                  it != mSttsTableEntries.end(); ++it) {
                 mOwner->writeInt32(it->sampleCount);
-                mOwner->writeInt32(it->sampleDuration);
+                int32_t dur = (it->sampleDurationUs * mTimeScale + 5E5) / 1E6;
+                mOwner->writeInt32(dur);
             }
           mOwner->endBox();  // stts
 
@@ -1717,7 +1741,7 @@
                     mOwner->writeInt64((*it));
                 }
             }
-          mOwner->endBox();  // co64
+          mOwner->endBox();  // stco or co64
 
         mOwner->endBox();  // stbl
        mOwner->endBox();  // minf
diff --git a/media/libstagefright/NuHTTPDataSource.cpp b/media/libstagefright/NuHTTPDataSource.cpp
index ab9285d..332bab3 100644
--- a/media/libstagefright/NuHTTPDataSource.cpp
+++ b/media/libstagefright/NuHTTPDataSource.cpp
@@ -42,7 +42,7 @@
         path->setTo(slashPos);
     }
 
-    char *colonPos = strchr(host->string(), ':');
+    const char *colonPos = strchr(host->string(), ':');
 
     if (colonPos != NULL) {
         unsigned long x;
diff --git a/media/libstagefright/OMXCodec.cpp b/media/libstagefright/OMXCodec.cpp
index 83f7040..157897b 100644
--- a/media/libstagefright/OMXCodec.cpp
+++ b/media/libstagefright/OMXCodec.cpp
@@ -25,6 +25,7 @@
 #include "include/AMRWBDecoder.h"
 #include "include/AMRWBEncoder.h"
 #include "include/AVCDecoder.h"
+#include "include/AVCEncoder.h"
 #include "include/M4vH263Decoder.h"
 #include "include/MP3Decoder.h"
 #include "include/VorbisDecoder.h"
@@ -81,6 +82,7 @@
 FACTORY_CREATE_ENCODER(AMRNBEncoder)
 FACTORY_CREATE_ENCODER(AMRWBEncoder)
 FACTORY_CREATE_ENCODER(AACEncoder)
+FACTORY_CREATE_ENCODER(AVCEncoder)
 
 static sp<MediaSource> InstantiateSoftwareEncoder(
         const char *name, const sp<MediaSource> &source,
@@ -94,6 +96,7 @@
         FACTORY_REF(AMRNBEncoder)
         FACTORY_REF(AMRWBEncoder)
         FACTORY_REF(AACEncoder)
+        FACTORY_REF(AVCEncoder)
     };
     for (size_t i = 0;
          i < sizeof(kFactoryInfo) / sizeof(kFactoryInfo[0]); ++i) {
@@ -186,6 +189,7 @@
     { MEDIA_MIMETYPE_VIDEO_AVC, "OMX.qcom.7x30.video.encoder.avc" },
     { MEDIA_MIMETYPE_VIDEO_AVC, "OMX.qcom.video.encoder.avc" },
     { MEDIA_MIMETYPE_VIDEO_AVC, "OMX.TI.Video.encoder" },
+    { MEDIA_MIMETYPE_VIDEO_AVC, "AVCEncoder" },
 //    { MEDIA_MIMETYPE_VIDEO_AVC, "OMX.PV.avcenc" },
 };
 
@@ -948,7 +952,7 @@
 
         int32_t supportedProfile = static_cast<int32_t>(param.eProfile);
         int32_t supportedLevel = static_cast<int32_t>(param.eLevel);
-        CODEC_LOGV("Supported profile: %ld, level %ld",
+        CODEC_LOGV("Supported profile: %d, level %d",
             supportedProfile, supportedLevel);
 
         if (profile == supportedProfile &&
@@ -3208,6 +3212,12 @@
 void OMXCodec::initOutputFormat(const sp<MetaData> &inputFormat) {
     mOutputFormat = new MetaData;
     mOutputFormat->setCString(kKeyDecoderComponent, mComponentName);
+    if (mIsEncoder) {
+        int32_t timeScale;
+        if (inputFormat->findInt32(kKeyTimeScale, &timeScale)) {
+            mOutputFormat->setInt32(kKeyTimeScale, timeScale);
+        }
+    }
 
     OMX_PARAM_PORTDEFINITIONTYPE def;
     InitOMXParams(&def);
diff --git a/media/libstagefright/codecs/aacdec/AACDecoder.cpp b/media/libstagefright/codecs/aacdec/AACDecoder.cpp
index 2bc4448..f3b281f 100644
--- a/media/libstagefright/codecs/aacdec/AACDecoder.cpp
+++ b/media/libstagefright/codecs/aacdec/AACDecoder.cpp
@@ -15,6 +15,7 @@
  */
 
 #include "AACDecoder.h"
+#define LOG_TAG "AACDecoder"
 
 #include "../../include/ESDS.h"
 
@@ -36,26 +37,33 @@
       mAnchorTimeUs(0),
       mNumSamplesOutput(0),
       mInputBuffer(NULL) {
-}
 
-AACDecoder::~AACDecoder() {
-    if (mStarted) {
-        stop();
+    sp<MetaData> srcFormat = mSource->getFormat();
+
+    int32_t sampleRate;
+    CHECK(srcFormat->findInt32(kKeySampleRate, &sampleRate));
+
+    mMeta = new MetaData;
+    mMeta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_RAW);
+
+    // We'll always output stereo, regardless of how many channels are
+    // present in the input due to decoder limitations.
+    mMeta->setInt32(kKeyChannelCount, 2);
+    mMeta->setInt32(kKeySampleRate, sampleRate);
+
+    int64_t durationUs;
+    if (srcFormat->findInt64(kKeyDuration, &durationUs)) {
+        mMeta->setInt64(kKeyDuration, durationUs);
     }
+    mMeta->setCString(kKeyDecoderComponent, "AACDecoder");
 
-    delete mConfig;
-    mConfig = NULL;
+    mInitCheck = initCheck();
 }
 
-status_t AACDecoder::start(MetaData *params) {
-    CHECK(!mStarted);
-
-    mBufferGroup = new MediaBufferGroup;
-    mBufferGroup->add_buffer(new MediaBuffer(2048 * 2));
-
+status_t AACDecoder::initCheck() {
+    memset(mConfig, 0, sizeof(tPVMP4AudioDecoderExternal));
     mConfig->outputFormat = OUTPUTFORMAT_16PCM_INTERLEAVED;
-    mConfig->aacPlusUpsamplingFactor = 0;
-    mConfig->aacPlusEnabled = false;
+    mConfig->aacPlusEnabled = 1;
 
     // The software decoder doesn't properly support mono output on
     // AACplus files. Always output stereo.
@@ -64,8 +72,11 @@
     UInt32 memRequirements = PVMP4AudioDecoderGetMemRequirements();
     mDecoderBuf = malloc(memRequirements);
 
-    CHECK_EQ(PVMP4AudioDecoderInitLibrary(mConfig, mDecoderBuf),
-             MP4AUDEC_SUCCESS);
+    status_t err = PVMP4AudioDecoderInitLibrary(mConfig, mDecoderBuf);
+    if (err != MP4AUDEC_SUCCESS) {
+        LOGE("Failed to initialize MP4 audio decoder");
+        return UNKNOWN_ERROR;
+    }
 
     uint32_t type;
     const void *data;
@@ -83,18 +94,38 @@
         mConfig->pInputBuffer = (UChar *)codec_specific_data;
         mConfig->inputBufferCurrentLength = codec_specific_data_size;
         mConfig->inputBufferMaxLength = 0;
-        mConfig->inputBufferUsedLength = 0;
-        mConfig->remainderBits = 0;
-
-        mConfig->pOutputBuffer = NULL;
-        mConfig->pOutputBuffer_plus = NULL;
-        mConfig->repositionFlag = false;
 
         if (PVMP4AudioDecoderConfig(mConfig, mDecoderBuf)
                 != MP4AUDEC_SUCCESS) {
             return ERROR_UNSUPPORTED;
         }
+
+        // Check on the sampling rate to see whether it is changed.
+        int32_t sampleRate;
+        CHECK(mMeta->findInt32(kKeySampleRate, &sampleRate));
+        if (mConfig->samplingRate != sampleRate) {
+            mMeta->setInt32(kKeySampleRate, mConfig->samplingRate);
+            LOGW("Sample rate was %d, but now is %d",
+                    sampleRate, mConfig->samplingRate);
+        }
     }
+    return OK;
+}
+
+AACDecoder::~AACDecoder() {
+    if (mStarted) {
+        stop();
+    }
+
+    delete mConfig;
+    mConfig = NULL;
+}
+
+status_t AACDecoder::start(MetaData *params) {
+    CHECK(!mStarted);
+
+    mBufferGroup = new MediaBufferGroup;
+    mBufferGroup->add_buffer(new MediaBuffer(4096 * 2));
 
     mSource->start();
 
@@ -127,28 +158,7 @@
 }
 
 sp<MetaData> AACDecoder::getFormat() {
-    sp<MetaData> srcFormat = mSource->getFormat();
-
-    int32_t sampleRate;
-    CHECK(srcFormat->findInt32(kKeySampleRate, &sampleRate));
-
-    sp<MetaData> meta = new MetaData;
-    meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_RAW);
-
-    // We'll always output stereo, regardless of how many channels are
-    // present in the input due to decoder limitations.
-    meta->setInt32(kKeyChannelCount, 2);
-
-    meta->setInt32(kKeySampleRate, sampleRate);
-
-    int64_t durationUs;
-    if (srcFormat->findInt64(kKeyDuration, &durationUs)) {
-        meta->setInt64(kKeyDuration, durationUs);
-    }
-
-    meta->setCString(kKeyDecoderComponent, "AACDecoder");
-
-    return meta;
+    return mMeta;
 }
 
 status_t AACDecoder::read(
@@ -200,13 +210,19 @@
     mConfig->remainderBits = 0;
 
     mConfig->pOutputBuffer = static_cast<Int16 *>(buffer->data());
-    mConfig->pOutputBuffer_plus = NULL;
+    mConfig->pOutputBuffer_plus = &mConfig->pOutputBuffer[2048];
     mConfig->repositionFlag = false;
 
     Int decoderErr = PVMP4AudioDecodeFrame(mConfig, mDecoderBuf);
 
     size_t numOutBytes =
         mConfig->frameLength * sizeof(int16_t) * mConfig->desiredChannels;
+    if (mConfig->aacPlusUpsamplingFactor == 2) {
+        if (mConfig->desiredChannels == 1) {
+            memcpy(&mConfig->pOutputBuffer[1024], &mConfig->pOutputBuffer[2048], numOutBytes * 2);
+        }
+        numOutBytes *= 2;
+    }
 
     if (decoderErr != MP4AUDEC_SUCCESS) {
         LOGW("AAC decoder returned error %d, substituting silence", decoderErr);
diff --git a/media/libstagefright/codecs/avc/enc/AVCEncoder.cpp b/media/libstagefright/codecs/avc/enc/AVCEncoder.cpp
new file mode 100644
index 0000000..d5eb156
--- /dev/null
+++ b/media/libstagefright/codecs/avc/enc/AVCEncoder.cpp
@@ -0,0 +1,492 @@
+/*
+ * 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.
+ */
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "AVCEncoder"
+#include <utils/Log.h>
+
+#include "AVCEncoder.h"
+
+#include "avcenc_api.h"
+#include "avcenc_int.h"
+#include "OMX_Video.h"
+
+#include <media/stagefright/MediaBufferGroup.h>
+#include <media/stagefright/MediaDebug.h>
+#include <media/stagefright/MediaDefs.h>
+#include <media/stagefright/MediaErrors.h>
+#include <media/stagefright/MetaData.h>
+#include <media/stagefright/Utils.h>
+
+namespace android {
+
+inline static void ConvertYUV420SemiPlanarToYUV420Planar(
+        uint8_t *inyuv, uint8_t* outyuv,
+        int32_t width, int32_t height) {
+
+    int32_t outYsize = width * height;
+    uint32_t *outy =  (uint32_t *) outyuv;
+    uint16_t *outcb = (uint16_t *) (outyuv + outYsize);
+    uint16_t *outcr = (uint16_t *) (outyuv + outYsize + (outYsize >> 2));
+
+    /* Y copying */
+    memcpy(outy, inyuv, outYsize);
+
+    /* U & V copying */
+    uint32_t *inyuv_4 = (uint32_t *) (inyuv + outYsize);
+    for (int32_t i = height >> 1; i > 0; --i) {
+        for (int32_t j = width >> 2; j > 0; --j) {
+            uint32_t temp = *inyuv_4++;
+            uint32_t tempU = temp & 0xFF;
+            tempU = tempU | ((temp >> 8) & 0xFF00);
+
+            uint32_t tempV = (temp >> 8) & 0xFF;
+            tempV = tempV | ((temp >> 16) & 0xFF00);
+
+            // Flip U and V
+            *outcb++ = tempV;
+            *outcr++ = tempU;
+        }
+    }
+}
+
+static int32_t MallocWrapper(
+        void *userData, int32_t size, int32_t attrs) {
+    return reinterpret_cast<int32_t>(malloc(size));
+}
+
+static void FreeWrapper(void *userData, int32_t ptr) {
+    free(reinterpret_cast<void *>(ptr));
+}
+
+static int32_t DpbAllocWrapper(void *userData,
+        unsigned int sizeInMbs, unsigned int numBuffers) {
+    AVCEncoder *encoder = static_cast<AVCEncoder *>(userData);
+    CHECK(encoder != NULL);
+    return encoder->allocOutputBuffers(sizeInMbs, numBuffers);
+}
+
+static int32_t BindFrameWrapper(
+        void *userData, int32_t index, uint8_t **yuv) {
+    AVCEncoder *encoder = static_cast<AVCEncoder *>(userData);
+    CHECK(encoder != NULL);
+    return encoder->bindOutputBuffer(index, yuv);
+}
+
+static void UnbindFrameWrapper(void *userData, int32_t index) {
+    AVCEncoder *encoder = static_cast<AVCEncoder *>(userData);
+    CHECK(encoder != NULL);
+    return encoder->unbindOutputBuffer(index);
+}
+
+AVCEncoder::AVCEncoder(
+        const sp<MediaSource>& source,
+        const sp<MetaData>& meta)
+    : mSource(source),
+      mMeta(meta),
+      mNumInputFrames(-1),
+      mStarted(false),
+      mInputBuffer(NULL),
+      mInputFrameData(NULL),
+      mGroup(NULL) {
+
+    LOGV("Construct software AVCEncoder");
+
+    mHandle = new tagAVCHandle;
+    memset(mHandle, 0, sizeof(tagAVCHandle));
+    mHandle->AVCObject = NULL;
+    mHandle->userData = this;
+    mHandle->CBAVC_DPBAlloc = DpbAllocWrapper;
+    mHandle->CBAVC_FrameBind = BindFrameWrapper;
+    mHandle->CBAVC_FrameUnbind = UnbindFrameWrapper;
+    mHandle->CBAVC_Malloc = MallocWrapper;
+    mHandle->CBAVC_Free = FreeWrapper;
+
+    mInitCheck = initCheck(meta);
+}
+
+AVCEncoder::~AVCEncoder() {
+    LOGV("Destruct software AVCEncoder");
+    if (mStarted) {
+        stop();
+    }
+
+    delete mEncParams;
+    delete mHandle;
+}
+
+status_t AVCEncoder::initCheck(const sp<MetaData>& meta) {
+    LOGV("initCheck");
+    CHECK(meta->findInt32(kKeyWidth, &mVideoWidth));
+    CHECK(meta->findInt32(kKeyHeight, &mVideoHeight));
+    CHECK(meta->findInt32(kKeySampleRate, &mVideoFrameRate));
+    CHECK(meta->findInt32(kKeyBitRate, &mVideoBitRate));
+
+    // XXX: Add more color format support
+    CHECK(meta->findInt32(kKeyColorFormat, &mVideoColorFormat));
+    if (mVideoColorFormat != OMX_COLOR_FormatYUV420Planar) {
+        if (mVideoColorFormat != OMX_COLOR_FormatYUV420SemiPlanar) {
+            LOGE("Color format %d is not supported", mVideoColorFormat);
+            return BAD_VALUE;
+        }
+        // Allocate spare buffer only when color conversion is needed.
+        // Assume the color format is OMX_COLOR_FormatYUV420SemiPlanar.
+        mInputFrameData =
+            (uint8_t *) malloc((mVideoWidth * mVideoHeight * 3 ) >> 1);
+        CHECK(mInputFrameData);
+    }
+
+    // XXX: Remove this restriction
+    if (mVideoWidth % 16 != 0 || mVideoHeight % 16 != 0) {
+        LOGE("Video frame size %dx%d must be a multiple of 16",
+            mVideoWidth, mVideoHeight);
+        return BAD_VALUE;
+    }
+
+    mEncParams = new tagAVCEncParam;
+    memset(mEncParams, 0, sizeof(mEncParams));
+    mEncParams->width = mVideoWidth;
+    mEncParams->height = mVideoHeight;
+    mEncParams->frame_rate = 1000 * mVideoFrameRate;  // In frames/ms!
+    mEncParams->rate_control = AVC_ON;
+    mEncParams->bitrate = mVideoBitRate;
+    mEncParams->initQP = 0;
+    mEncParams->init_CBP_removal_delay = 1600;
+    mEncParams->CPB_size = (uint32_t) (mVideoBitRate >> 1);
+
+    mEncParams->intramb_refresh = 0;
+    mEncParams->auto_scd = AVC_ON;
+    mEncParams->out_of_band_param_set = AVC_ON;
+    mEncParams->poc_type = 2;
+    mEncParams->log2_max_poc_lsb_minus_4 = 12;
+    mEncParams->delta_poc_zero_flag = 0;
+    mEncParams->offset_poc_non_ref = 0;
+    mEncParams->offset_top_bottom = 0;
+    mEncParams->num_ref_in_cycle = 0;
+    mEncParams->offset_poc_ref = NULL;
+
+    mEncParams->num_ref_frame = 1;
+    mEncParams->num_slice_group = 1;
+    mEncParams->fmo_type = 0;
+
+    mEncParams->db_filter = AVC_ON;
+    mEncParams->disable_db_idc = 0;
+
+    mEncParams->alpha_offset = 0;
+    mEncParams->beta_offset = 0;
+    mEncParams->constrained_intra_pred = AVC_OFF;
+
+    mEncParams->data_par = AVC_OFF;
+    mEncParams->fullsearch = AVC_OFF;
+    mEncParams->search_range = 16;
+    mEncParams->sub_pel = AVC_OFF;
+    mEncParams->submb_pred = AVC_OFF;
+    mEncParams->rdopt_mode = AVC_OFF;
+    mEncParams->bidir_pred = AVC_OFF;
+    int32_t nMacroBlocks = ((((mVideoWidth + 15) >> 4) << 4) *
+            (((mVideoHeight + 15) >> 4) << 4)) >> 8;
+    uint32_t *sliceGroup = (uint32_t *) malloc(sizeof(uint32_t) * nMacroBlocks);
+    for (int ii = 0, idx = 0; ii < nMacroBlocks; ++ii) {
+        sliceGroup[ii] = idx++;
+        if (idx >= mEncParams->num_slice_group) {
+            idx = 0;
+        }
+    }
+    mEncParams->slice_group = sliceGroup;
+
+    mEncParams->use_overrun_buffer = AVC_OFF;
+
+    // Set IDR frame refresh interval
+    int32_t iFramesIntervalSec;
+    CHECK(meta->findInt32(kKeyIFramesInterval, &iFramesIntervalSec));
+    if (iFramesIntervalSec < 0) {
+        mEncParams->idr_period = -1;
+    } else if (iFramesIntervalSec == 0) {
+        mEncParams->idr_period = 1;  // All I frames
+    } else {
+        mEncParams->idr_period =
+            (iFramesIntervalSec * mVideoFrameRate);
+    }
+    LOGV("idr_period: %d, I-frames interval: %d seconds, and frame rate: %d",
+        mEncParams->idr_period, iFramesIntervalSec, mVideoFrameRate);
+
+    // Set profile and level
+    // If profile and level setting is not correct, failure
+    // is reported when the encoder is initialized.
+    mEncParams->profile = AVC_BASELINE;
+    mEncParams->level = AVC_LEVEL3_2;
+    int32_t profile, level;
+    if (meta->findInt32(kKeyVideoProfile, &profile)) {
+        mEncParams->profile = (AVCProfile) profile;
+    }
+    if (meta->findInt32(kKeyVideoLevel, &level)) {
+        mEncParams->level = (AVCLevel) level;
+    }
+
+
+    mFormat = new MetaData;
+    mFormat->setInt32(kKeyWidth, mVideoWidth);
+    mFormat->setInt32(kKeyHeight, mVideoHeight);
+    mFormat->setInt32(kKeyBitRate, mVideoBitRate);
+    mFormat->setInt32(kKeySampleRate, mVideoFrameRate);
+    mFormat->setInt32(kKeyColorFormat, mVideoColorFormat);
+    mFormat->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_AVC);
+    mFormat->setCString(kKeyDecoderComponent, "AVCEncoder");
+    return OK;
+}
+
+status_t AVCEncoder::start(MetaData *params) {
+    LOGV("start");
+    if (mInitCheck != OK) {
+        return mInitCheck;
+    }
+
+    if (mStarted) {
+        LOGW("Call start() when encoder already started");
+        return OK;
+    }
+
+    AVCEnc_Status err;
+    err = PVAVCEncInitialize(mHandle, mEncParams, NULL, NULL);
+    if (err != AVCENC_SUCCESS) {
+        LOGE("Failed to initialize the encoder: %d", err);
+        return UNKNOWN_ERROR;
+    }
+
+    mGroup = new MediaBufferGroup();
+    int32_t maxSize;
+    if (AVCENC_SUCCESS !=
+        PVAVCEncGetMaxOutputBufferSize(mHandle, &maxSize)) {
+        maxSize = 31584;  // Magic #
+    }
+    mGroup->add_buffer(new MediaBuffer(maxSize));
+
+    mSource->start(params);
+    mNumInputFrames = -2;  // 1st two buffers contain SPS and PPS
+    mStarted = true;
+    mSpsPpsHeaderReceived = false;
+    mReadyForNextFrame = true;
+    mIsIDRFrame = 0;
+
+    return OK;
+}
+
+status_t AVCEncoder::stop() {
+    LOGV("stop");
+    if (!mStarted) {
+        LOGW("Call stop() when encoder has not started");
+        return OK;
+    }
+
+    if (mInputBuffer) {
+        mInputBuffer->release();
+        mInputBuffer = NULL;
+    }
+
+    if (mGroup) {
+        delete mGroup;
+        mGroup = NULL;
+    }
+
+    if (mInputFrameData) {
+        delete mInputFrameData;
+        mInputFrameData = NULL;
+    }
+
+    PVAVCCleanUpEncoder(mHandle);
+    mSource->stop();
+    releaseOutputBuffers();
+    mStarted = false;
+
+    return OK;
+}
+
+void AVCEncoder::releaseOutputBuffers() {
+    LOGV("releaseOutputBuffers");
+    for (size_t i = 0; i < mOutputBuffers.size(); ++i) {
+        MediaBuffer *buffer = mOutputBuffers.editItemAt(i);
+        buffer->setObserver(NULL);
+        buffer->release();
+    }
+    mOutputBuffers.clear();
+}
+
+sp<MetaData> AVCEncoder::getFormat() {
+    LOGV("getFormat");
+    return mFormat;
+}
+
+status_t AVCEncoder::read(
+        MediaBuffer **out, const ReadOptions *options) {
+
+    CHECK(!options);
+    *out = NULL;
+
+    MediaBuffer *outputBuffer;
+    CHECK_EQ(OK, mGroup->acquire_buffer(&outputBuffer));
+    uint8_t *outPtr = (uint8_t *) outputBuffer->data();
+    uint32_t dataLength = outputBuffer->size();
+
+    int32_t type;
+    AVCEnc_Status encoderStatus = AVCENC_SUCCESS;
+
+    // Return SPS and PPS for the first two buffers
+    if (!mSpsPpsHeaderReceived) {
+        encoderStatus = PVAVCEncodeNAL(mHandle, outPtr, &dataLength, &type);
+        if (encoderStatus == AVCENC_WRONG_STATE) {
+            mSpsPpsHeaderReceived = true;
+            CHECK_EQ(0, mNumInputFrames);  // 1st video frame is 0
+        } else {
+            switch (type) {
+                case AVC_NALTYPE_SPS:
+                case AVC_NALTYPE_PPS:
+                    LOGV("%s received",
+                            (type == AVC_NALTYPE_SPS)? "SPS": "PPS");
+                    ++mNumInputFrames;
+                    outputBuffer->set_range(0, dataLength);
+                    *out = outputBuffer;
+                    return OK;
+                default:
+                    LOGE("Nal type (%d) other than SPS/PPS is unexpected", type);
+                    return UNKNOWN_ERROR;
+            }
+        }
+    }
+
+    // Get next input video frame
+    if (mReadyForNextFrame) {
+        if (mInputBuffer) {
+            mInputBuffer->release();
+            mInputBuffer = NULL;
+        }
+        status_t err = mSource->read(&mInputBuffer, options);
+        if (err != OK) {
+            LOGE("Failed to read input video frame: %d", err);
+            outputBuffer->release();
+            return err;
+        }
+        int64_t timeUs;
+        CHECK(mInputBuffer->meta_data()->findInt64(kKeyTime, &timeUs));
+        outputBuffer->meta_data()->setInt64(kKeyTime, timeUs);
+
+        AVCFrameIO videoInput;
+        memset(&videoInput, 0, sizeof(videoInput));
+        videoInput.height = ((mVideoHeight  + 15) >> 4) << 4;
+        videoInput.pitch = ((mVideoWidth + 15) >> 4) << 4;
+        videoInput.coding_timestamp = (timeUs + 500) / 1000;  // in ms
+        uint8_t *inputData = (uint8_t *) mInputBuffer->data();
+
+        if (mVideoColorFormat != OMX_COLOR_FormatYUV420Planar) {
+            CHECK(mInputFrameData);
+            CHECK(mVideoColorFormat == OMX_COLOR_FormatYUV420SemiPlanar);
+            ConvertYUV420SemiPlanarToYUV420Planar(
+                inputData, mInputFrameData, mVideoWidth, mVideoHeight);
+            inputData = mInputFrameData;
+        }
+        CHECK(inputData != NULL);
+        videoInput.YCbCr[0] = inputData;
+        videoInput.YCbCr[1] = videoInput.YCbCr[0] + videoInput.height * videoInput.pitch;
+        videoInput.YCbCr[2] = videoInput.YCbCr[1] +
+            ((videoInput.height * videoInput.pitch) >> 2);
+        videoInput.disp_order = mNumInputFrames;
+
+        encoderStatus = PVAVCEncSetInput(mHandle, &videoInput);
+        if (encoderStatus == AVCENC_SUCCESS ||
+            encoderStatus == AVCENC_NEW_IDR) {
+            mReadyForNextFrame = false;
+            ++mNumInputFrames;
+            if (encoderStatus == AVCENC_NEW_IDR) {
+                mIsIDRFrame = 1;
+            }
+        } else {
+            if (encoderStatus < AVCENC_SUCCESS) {
+                outputBuffer->release();
+                return UNKNOWN_ERROR;
+            } else {
+                outputBuffer->set_range(0, 0);
+                *out = outputBuffer;
+                return OK;
+            }
+        }
+    }
+
+    // Encode an input video frame
+    CHECK(encoderStatus == AVCENC_SUCCESS ||
+          encoderStatus == AVCENC_NEW_IDR);
+    dataLength = outputBuffer->size();  // Reset the output buffer length
+    encoderStatus = PVAVCEncodeNAL(mHandle, outPtr, &dataLength, &type);
+    if (encoderStatus == AVCENC_SUCCESS) {
+        outputBuffer->meta_data()->setInt32(kKeyIsSyncFrame, mIsIDRFrame);
+        CHECK_EQ(NULL, PVAVCEncGetOverrunBuffer(mHandle));
+    } else if (encoderStatus == AVCENC_PICTURE_READY) {
+        CHECK_EQ(NULL, PVAVCEncGetOverrunBuffer(mHandle));
+        if (mIsIDRFrame) {
+            outputBuffer->meta_data()->setInt32(kKeyIsSyncFrame, mIsIDRFrame);
+            mIsIDRFrame = 0;
+            LOGV("Output an IDR frame");
+        }
+        mReadyForNextFrame = true;
+        AVCFrameIO recon;
+        if (PVAVCEncGetRecon(mHandle, &recon) == AVCENC_SUCCESS) {
+            PVAVCEncReleaseRecon(mHandle, &recon);
+        }
+    } else {
+        dataLength = 0;
+        mReadyForNextFrame = true;
+    }
+    if (encoderStatus < AVCENC_SUCCESS) {
+        outputBuffer->release();
+        return UNKNOWN_ERROR;
+    }
+
+    outputBuffer->set_range(0, dataLength);
+    *out = outputBuffer;
+    return OK;
+}
+
+int32_t AVCEncoder::allocOutputBuffers(
+        unsigned int sizeInMbs, unsigned int numBuffers) {
+    CHECK(mOutputBuffers.isEmpty());
+    size_t frameSize = (sizeInMbs << 7) * 3;
+    for (unsigned int i = 0; i <  numBuffers; ++i) {
+        MediaBuffer *buffer = new MediaBuffer(frameSize);
+        buffer->setObserver(this);
+        mOutputBuffers.push(buffer);
+    }
+
+    return 1;
+}
+
+void AVCEncoder::unbindOutputBuffer(int32_t index) {
+    CHECK(index >= 0);
+}
+
+int32_t AVCEncoder::bindOutputBuffer(int32_t index, uint8_t **yuv) {
+    CHECK(index >= 0);
+    CHECK(index < (int32_t) mOutputBuffers.size());
+    int64_t timeUs;
+    CHECK(mInputBuffer->meta_data()->findInt64(kKeyTime, &timeUs));
+    mOutputBuffers[index]->meta_data()->setInt64(kKeyTime, timeUs);
+
+    *yuv = (uint8_t *) mOutputBuffers[index]->data();
+
+    return 1;
+}
+
+void AVCEncoder::signalBufferReturned(MediaBuffer *buffer) {
+}
+
+}  // namespace android
diff --git a/media/libstagefright/codecs/avc/enc/Android.mk b/media/libstagefright/codecs/avc/enc/Android.mk
new file mode 100644
index 0000000..100f239
--- /dev/null
+++ b/media/libstagefright/codecs/avc/enc/Android.mk
@@ -0,0 +1,35 @@
+LOCAL_PATH := $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := \
+    AVCEncoder.cpp \
+    src/avcenc_api.cpp \
+    src/bitstream_io.cpp \
+    src/block.cpp \
+    src/findhalfpel.cpp \
+    src/header.cpp \
+    src/init.cpp \
+    src/intra_est.cpp \
+    src/motion_comp.cpp \
+    src/motion_est.cpp \
+    src/rate_control.cpp \
+    src/residual.cpp \
+    src/sad.cpp \
+    src/sad_halfpel.cpp \
+    src/slice.cpp \
+    src/vlc_encode.cpp
+
+
+LOCAL_MODULE := libstagefright_avcenc
+
+LOCAL_C_INCLUDES := \
+    $(LOCAL_PATH)/src \
+    $(LOCAL_PATH)/../common/include \
+    $(TOP)/external/opencore/extern_libs_v2/khronos/openmax/include \
+    $(TOP)/frameworks/base/media/libstagefright/include
+
+LOCAL_CFLAGS := \
+    -D__arm__ \
+    -DOSCL_IMPORT_REF= -DOSCL_UNUSED_ARG= -DOSCL_EXPORT_REF=
+
+include $(BUILD_STATIC_LIBRARY)
diff --git a/media/libstagefright/codecs/avc/enc/src/avcenc_api.cpp b/media/libstagefright/codecs/avc/enc/src/avcenc_api.cpp
new file mode 100644
index 0000000..d39885d
--- /dev/null
+++ b/media/libstagefright/codecs/avc/enc/src/avcenc_api.cpp
@@ -0,0 +1,744 @@
+/* ------------------------------------------------------------------
+ * Copyright (C) 1998-2009 PacketVideo
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
+ * express or implied.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ * -------------------------------------------------------------------
+ */
+#include "avcenc_api.h"
+#include "avcenc_lib.h"
+
+/* ======================================================================== */
+/*  Function : PVAVCGetNALType()                                            */
+/*  Date     : 11/4/2003                                                    */
+/*  Purpose  : Sniff NAL type from the bitstream                            */
+/*  In/out   :                                                              */
+/*  Return   : AVCENC_SUCCESS if succeed, AVCENC_FAIL if fail.              */
+/*  Modified :                                                              */
+/* ======================================================================== */
+OSCL_EXPORT_REF AVCEnc_Status PVAVCEncGetNALType(unsigned char *bitstream, int size,
+        int *nal_type, int *nal_ref_idc)
+{
+    int forbidden_zero_bit;
+    if (size > 0)
+    {
+        forbidden_zero_bit = bitstream[0] >> 7;
+        if (forbidden_zero_bit != 0)
+            return AVCENC_FAIL;
+        *nal_ref_idc = (bitstream[0] & 0x60) >> 5;
+        *nal_type = bitstream[0] & 0x1F;
+        return AVCENC_SUCCESS;
+    }
+
+    return AVCENC_FAIL;
+}
+
+
+/* ======================================================================== */
+/*  Function : PVAVCEncInitialize()                                         */
+/*  Date     : 3/18/2004                                                    */
+/*  Purpose  : Initialize the encoder library, allocate memory and verify   */
+/*              the profile/level support/settings.                         */
+/*  In/out   : Encoding parameters.                                         */
+/*  Return   : AVCENC_SUCCESS for success.                                  */
+/*  Modified :                                                              */
+/* ======================================================================== */
+OSCL_EXPORT_REF AVCEnc_Status PVAVCEncInitialize(AVCHandle *avcHandle, AVCEncParams *encParam,
+        void* extSPS, void* extPPS)
+{
+    AVCEnc_Status status;
+    AVCEncObject *encvid;
+    AVCCommonObj *video;
+    uint32 *userData = (uint32*) avcHandle->userData;
+    int framesize;
+
+    if (avcHandle->AVCObject != NULL)
+    {
+        return AVCENC_ALREADY_INITIALIZED; /* It's already initialized, need to cleanup first */
+    }
+
+    /* not initialized */
+
+    /* allocate videoObject */
+    avcHandle->AVCObject = (void*)avcHandle->CBAVC_Malloc(userData, sizeof(AVCEncObject), DEFAULT_ATTR);
+    if (avcHandle->AVCObject == NULL)
+    {
+        return AVCENC_MEMORY_FAIL;
+    }
+
+    encvid = (AVCEncObject*) avcHandle->AVCObject;
+    memset(encvid, 0, sizeof(AVCEncObject)); /* reset everything */
+
+    encvid->enc_state = AVCEnc_Initializing;
+
+    encvid->avcHandle = avcHandle;
+
+    encvid->common = (AVCCommonObj*) avcHandle->CBAVC_Malloc(userData, sizeof(AVCCommonObj), DEFAULT_ATTR);
+    if (encvid->common == NULL)
+    {
+        return AVCENC_MEMORY_FAIL;
+    }
+
+    video = encvid->common;
+    memset(video, 0, sizeof(AVCCommonObj));
+
+    /* allocate bitstream structure */
+    encvid->bitstream = (AVCEncBitstream*) avcHandle->CBAVC_Malloc(userData, sizeof(AVCEncBitstream), DEFAULT_ATTR);
+    if (encvid->bitstream == NULL)
+    {
+        return AVCENC_MEMORY_FAIL;
+    }
+    encvid->bitstream->encvid = encvid; /* to point back for reallocation */
+
+    /* allocate sequence parameter set structure */
+    video->currSeqParams = (AVCSeqParamSet*) avcHandle->CBAVC_Malloc(userData, sizeof(AVCSeqParamSet), DEFAULT_ATTR);
+    if (video->currSeqParams == NULL)
+    {
+        return AVCENC_MEMORY_FAIL;
+    }
+    memset(video->currSeqParams, 0, sizeof(AVCSeqParamSet));
+
+    /* allocate picture parameter set structure */
+    video->currPicParams = (AVCPicParamSet*) avcHandle->CBAVC_Malloc(userData, sizeof(AVCPicParamSet), DEFAULT_ATTR);
+    if (video->currPicParams == NULL)
+    {
+        return AVCENC_MEMORY_FAIL;
+    }
+    memset(video->currPicParams, 0, sizeof(AVCPicParamSet));
+
+    /* allocate slice header structure */
+    video->sliceHdr = (AVCSliceHeader*) avcHandle->CBAVC_Malloc(userData, sizeof(AVCSliceHeader), DEFAULT_ATTR);
+    if (video->sliceHdr == NULL)
+    {
+        return AVCENC_MEMORY_FAIL;
+    }
+    memset(video->sliceHdr, 0, sizeof(AVCSliceHeader));
+
+    /* allocate encoded picture buffer structure*/
+    video->decPicBuf = (AVCDecPicBuffer*) avcHandle->CBAVC_Malloc(userData, sizeof(AVCDecPicBuffer), DEFAULT_ATTR);
+    if (video->decPicBuf == NULL)
+    {
+        return AVCENC_MEMORY_FAIL;
+    }
+    memset(video->decPicBuf, 0, sizeof(AVCDecPicBuffer));
+
+    /* allocate rate control structure */
+    encvid->rateCtrl = (AVCRateControl*) avcHandle->CBAVC_Malloc(userData, sizeof(AVCRateControl), DEFAULT_ATTR);
+    if (encvid->rateCtrl == NULL)
+    {
+        return AVCENC_MEMORY_FAIL;
+    }
+    memset(encvid->rateCtrl, 0, sizeof(AVCRateControl));
+
+    /* reset frame list, not really needed */
+    video->currPic = NULL;
+    video->currFS = NULL;
+    encvid->currInput = NULL;
+    video->prevRefPic = NULL;
+
+    /* now read encParams, and allocate dimension-dependent variables */
+    /* such as mblock */
+    status = SetEncodeParam(avcHandle, encParam, extSPS, extPPS); /* initialized variables to be used in SPS*/
+    if (status != AVCENC_SUCCESS)
+    {
+        return status;
+    }
+
+    if (encParam->use_overrun_buffer == AVC_ON)
+    {
+        /* allocate overrun buffer */
+        encvid->oBSize = encvid->rateCtrl->cpbSize;
+        if (encvid->oBSize > DEFAULT_OVERRUN_BUFFER_SIZE)
+        {
+            encvid->oBSize = DEFAULT_OVERRUN_BUFFER_SIZE;
+        }
+        encvid->overrunBuffer = (uint8*) avcHandle->CBAVC_Malloc(userData, encvid->oBSize, DEFAULT_ATTR);
+        if (encvid->overrunBuffer == NULL)
+        {
+            return AVCENC_MEMORY_FAIL;
+        }
+    }
+    else
+    {
+        encvid->oBSize = 0;
+        encvid->overrunBuffer = NULL;
+    }
+
+    /* allocate frame size dependent structures */
+    framesize = video->FrameHeightInMbs * video->PicWidthInMbs;
+
+    video->mblock = (AVCMacroblock*) avcHandle->CBAVC_Malloc(userData, sizeof(AVCMacroblock) * framesize, DEFAULT_ATTR);
+    if (video->mblock == NULL)
+    {
+        return AVCENC_MEMORY_FAIL;
+    }
+
+    video->MbToSliceGroupMap = (int*) avcHandle->CBAVC_Malloc(userData, sizeof(uint) * video->PicSizeInMapUnits * 2, DEFAULT_ATTR);
+    if (video->MbToSliceGroupMap == NULL)
+    {
+        return AVCENC_MEMORY_FAIL;
+    }
+
+    encvid->mot16x16 = (AVCMV*) avcHandle->CBAVC_Malloc(userData, sizeof(AVCMV) * framesize, DEFAULT_ATTR);
+    if (encvid->mot16x16 == NULL)
+    {
+        return AVCENC_MEMORY_FAIL;
+    }
+    memset(encvid->mot16x16, 0, sizeof(AVCMV)*framesize);
+
+    encvid->intraSearch = (uint8*) avcHandle->CBAVC_Malloc(userData, sizeof(uint8) * framesize, DEFAULT_ATTR);
+    if (encvid->intraSearch == NULL)
+    {
+        return AVCENC_MEMORY_FAIL;
+    }
+
+    encvid->min_cost = (int*) avcHandle->CBAVC_Malloc(userData, sizeof(int) * framesize, DEFAULT_ATTR);
+    if (encvid->min_cost == NULL)
+    {
+        return AVCENC_MEMORY_FAIL;
+    }
+
+    /* initialize motion search related memory */
+    if (AVCENC_SUCCESS != InitMotionSearchModule(avcHandle))
+    {
+        return AVCENC_MEMORY_FAIL;
+    }
+
+    if (AVCENC_SUCCESS != InitRateControlModule(avcHandle))
+    {
+        return AVCENC_MEMORY_FAIL;
+    }
+
+    /* intialize function pointers */
+    encvid->functionPointer = (AVCEncFuncPtr*) avcHandle->CBAVC_Malloc(userData, sizeof(AVCEncFuncPtr), DEFAULT_ATTR);
+    if (encvid->functionPointer == NULL)
+    {
+        return AVCENC_MEMORY_FAIL;
+    }
+    encvid->functionPointer->SAD_Macroblock = &AVCSAD_Macroblock_C;
+    encvid->functionPointer->SAD_MB_HalfPel[0] = NULL;
+    encvid->functionPointer->SAD_MB_HalfPel[1] = &AVCSAD_MB_HalfPel_Cxh;
+    encvid->functionPointer->SAD_MB_HalfPel[2] = &AVCSAD_MB_HalfPel_Cyh;
+    encvid->functionPointer->SAD_MB_HalfPel[3] = &AVCSAD_MB_HalfPel_Cxhyh;
+
+    /* initialize timing control */
+    encvid->modTimeRef = 0;     /* ALWAYS ASSUME THAT TIMESTAMP START FROM 0 !!!*/
+    video->prevFrameNum = 0;
+    encvid->prevCodedFrameNum = 0;
+    encvid->dispOrdPOCRef = 0;
+
+    if (encvid->outOfBandParamSet == TRUE)
+    {
+        encvid->enc_state = AVCEnc_Encoding_SPS;
+    }
+    else
+    {
+        encvid->enc_state = AVCEnc_Analyzing_Frame;
+    }
+
+    return AVCENC_SUCCESS;
+}
+
+/* ======================================================================== */
+/*  Function : PVAVCEncGetMaxOutputSize()                                   */
+/*  Date     : 11/29/2008                                                   */
+/*  Purpose  : Return max output buffer size that apps should allocate for  */
+/*              output buffer.                                              */
+/*  In/out   :                                                              */
+/*  Return   : AVCENC_SUCCESS for success.                                  */
+/*  Modified :   size                                                       */
+/* ======================================================================== */
+
+OSCL_EXPORT_REF AVCEnc_Status PVAVCEncGetMaxOutputBufferSize(AVCHandle *avcHandle, int* size)
+{
+    AVCEncObject *encvid = (AVCEncObject*)avcHandle->AVCObject;
+
+    if (encvid == NULL)
+    {
+        return AVCENC_UNINITIALIZED;
+    }
+
+    *size = encvid->rateCtrl->cpbSize;
+
+    return AVCENC_SUCCESS;
+}
+
+/* ======================================================================== */
+/*  Function : PVAVCEncSetInput()                                           */
+/*  Date     : 4/18/2004                                                    */
+/*  Purpose  : To feed an unencoded original frame to the encoder library.  */
+/*  In/out   :                                                              */
+/*  Return   : AVCENC_SUCCESS for success.                                  */
+/*  Modified :                                                              */
+/* ======================================================================== */
+OSCL_EXPORT_REF AVCEnc_Status PVAVCEncSetInput(AVCHandle *avcHandle, AVCFrameIO *input)
+{
+    AVCEncObject *encvid = (AVCEncObject*)avcHandle->AVCObject;
+    AVCCommonObj *video = encvid->common;
+    AVCRateControl *rateCtrl = encvid->rateCtrl;
+
+    AVCEnc_Status status;
+    uint frameNum;
+
+    if (encvid == NULL)
+    {
+        return AVCENC_UNINITIALIZED;
+    }
+
+    if (encvid->enc_state == AVCEnc_WaitingForBuffer)
+    {
+        goto RECALL_INITFRAME;
+    }
+    else if (encvid->enc_state != AVCEnc_Analyzing_Frame)
+    {
+        return AVCENC_FAIL;
+    }
+
+    if (input->pitch > 0xFFFF)
+    {
+        return AVCENC_NOT_SUPPORTED; // we use 2-bytes for pitch
+    }
+
+    /***********************************/
+
+    /* Let's rate control decide whether to encode this frame or not */
+    /* Also set video->nal_unit_type, sliceHdr->slice_type, video->slice_type */
+    if (AVCENC_SUCCESS != RCDetermineFrameNum(encvid, rateCtrl, input->coding_timestamp, &frameNum))
+    {
+        return AVCENC_SKIPPED_PICTURE; /* not time to encode, thus skipping */
+    }
+
+    /* we may not need this line */
+    //nextFrmModTime = (uint32)((((frameNum+1)*1000)/rateCtrl->frame_rate) + modTimeRef); /* rec. time */
+    //encvid->nextModTime = nextFrmModTime - (encvid->frameInterval>>1) - 1; /* between current and next frame */
+
+    encvid->currInput = input;
+    encvid->currInput->coding_order = frameNum;
+
+RECALL_INITFRAME:
+    /* initialize and analyze the frame */
+    status = InitFrame(encvid);
+
+    if (status == AVCENC_SUCCESS)
+    {
+        encvid->enc_state = AVCEnc_Encoding_Frame;
+    }
+    else if (status == AVCENC_NEW_IDR)
+    {
+        if (encvid->outOfBandParamSet == TRUE)
+        {
+            encvid->enc_state = AVCEnc_Encoding_Frame;
+        }
+        else // assuming that in-band paramset keeps sending new SPS and PPS.
+        {
+            encvid->enc_state = AVCEnc_Encoding_SPS;
+            //video->currSeqParams->seq_parameter_set_id++;
+            //if(video->currSeqParams->seq_parameter_set_id > 31) // range check
+            {
+                video->currSeqParams->seq_parameter_set_id = 0;  // reset
+            }
+        }
+
+        video->sliceHdr->idr_pic_id++;
+        if (video->sliceHdr->idr_pic_id > 65535) // range check
+        {
+            video->sliceHdr->idr_pic_id = 0;  // reset
+        }
+    }
+    /* the following logics need to be revisited */
+    else if (status == AVCENC_PICTURE_READY) // no buffers returned back to the encoder
+    {
+        encvid->enc_state = AVCEnc_WaitingForBuffer; // Input accepted but can't continue
+        // need to free up some memory before proceeding with Encode
+    }
+
+    return status; // return status, including the AVCENC_FAIL case and all 3 above.
+}
+
+/* ======================================================================== */
+/*  Function : PVAVCEncodeNAL()                                             */
+/*  Date     : 4/29/2004                                                    */
+/*  Purpose  : To encode one NAL/slice.                                     */
+/*  In/out   :                                                              */
+/*  Return   : AVCENC_SUCCESS for success.                                  */
+/*  Modified :                                                              */
+/* ======================================================================== */
+OSCL_EXPORT_REF AVCEnc_Status PVAVCEncodeNAL(AVCHandle *avcHandle, unsigned char *buffer, unsigned int *buf_nal_size, int *nal_type)
+{
+    AVCEncObject *encvid = (AVCEncObject*)avcHandle->AVCObject;
+    AVCCommonObj *video = encvid->common;
+    AVCEncBitstream *bitstream = encvid->bitstream;
+    AVCEnc_Status status;
+
+    if (encvid == NULL)
+    {
+        return AVCENC_UNINITIALIZED;
+    }
+
+    switch (encvid->enc_state)
+    {
+        case AVCEnc_Initializing:
+            return AVCENC_UNINITIALIZED;
+        case AVCEnc_Encoding_SPS:
+            /* initialized the structure */
+            BitstreamEncInit(bitstream, buffer, *buf_nal_size, NULL, 0);
+            BitstreamWriteBits(bitstream, 8, (1 << 5) | AVC_NALTYPE_SPS);
+
+            /* encode SPS */
+            status = EncodeSPS(encvid, bitstream);
+            if (status != AVCENC_SUCCESS)
+            {
+                return status;
+            }
+
+            /* closing the NAL with trailing bits */
+            status = BitstreamTrailingBits(bitstream, buf_nal_size);
+            if (status == AVCENC_SUCCESS)
+            {
+                encvid->enc_state = AVCEnc_Encoding_PPS;
+                video->currPicParams->seq_parameter_set_id = video->currSeqParams->seq_parameter_set_id;
+                video->currPicParams->pic_parameter_set_id++;
+                *nal_type = AVC_NALTYPE_SPS;
+                *buf_nal_size = bitstream->write_pos;
+            }
+            break;
+        case AVCEnc_Encoding_PPS:
+            /* initialized the structure */
+            BitstreamEncInit(bitstream, buffer, *buf_nal_size, NULL, 0);
+            BitstreamWriteBits(bitstream, 8, (1 << 5) | AVC_NALTYPE_PPS);
+
+            /* encode PPS */
+            status = EncodePPS(encvid, bitstream);
+            if (status != AVCENC_SUCCESS)
+            {
+                return status;
+            }
+
+            /* closing the NAL with trailing bits */
+            status = BitstreamTrailingBits(bitstream, buf_nal_size);
+            if (status == AVCENC_SUCCESS)
+            {
+                if (encvid->outOfBandParamSet == TRUE) // already extract PPS, SPS
+                {
+                    encvid->enc_state = AVCEnc_Analyzing_Frame;
+                }
+                else    // SetInput has been called before SPS and PPS.
+                {
+                    encvid->enc_state = AVCEnc_Encoding_Frame;
+                }
+
+                *nal_type = AVC_NALTYPE_PPS;
+                *buf_nal_size = bitstream->write_pos;
+            }
+            break;
+
+        case AVCEnc_Encoding_Frame:
+            /* initialized the structure */
+            BitstreamEncInit(bitstream, buffer, *buf_nal_size, encvid->overrunBuffer, encvid->oBSize);
+            BitstreamWriteBits(bitstream, 8, (video->nal_ref_idc << 5) | (video->nal_unit_type));
+
+            /* Re-order the reference list according to the ref_pic_list_reordering() */
+            /* We don't have to reorder the list for the encoder here. This can only be done
+            after we encode this slice. We can run thru a second-pass to see if new ordering
+            would save more bits. Too much delay !! */
+            /* status = ReOrderList(video);*/
+            status = InitSlice(encvid);
+            if (status != AVCENC_SUCCESS)
+            {
+                return status;
+            }
+
+            /* when we have everything, we encode the slice header */
+            status = EncodeSliceHeader(encvid, bitstream);
+            if (status != AVCENC_SUCCESS)
+            {
+                return status;
+            }
+
+            status = AVCEncodeSlice(encvid);
+
+            video->slice_id++;
+
+            /* closing the NAL with trailing bits */
+            BitstreamTrailingBits(bitstream, buf_nal_size);
+
+            *buf_nal_size = bitstream->write_pos;
+
+            encvid->rateCtrl->numFrameBits += ((*buf_nal_size) << 3);
+
+            *nal_type = video->nal_unit_type;
+
+            if (status == AVCENC_PICTURE_READY)
+            {
+                status = RCUpdateFrame(encvid);
+                if (status == AVCENC_SKIPPED_PICTURE) /* skip current frame */
+                {
+                    DPBReleaseCurrentFrame(avcHandle, video);
+                    encvid->enc_state = AVCEnc_Analyzing_Frame;
+
+                    return status;
+                }
+
+                /* perform loop-filtering on the entire frame */
+                DeblockPicture(video);
+
+                /* update the original frame array */
+                encvid->prevCodedFrameNum = encvid->currInput->coding_order;
+
+                /* store the encoded picture in the DPB buffer */
+                StorePictureInDPB(avcHandle, video);
+
+                if (video->currPic->isReference)
+                {
+                    video->PrevRefFrameNum = video->sliceHdr->frame_num;
+                }
+
+                /* update POC related variables */
+                PostPOC(video);
+
+                encvid->enc_state = AVCEnc_Analyzing_Frame;
+                status = AVCENC_PICTURE_READY;
+
+            }
+            break;
+        default:
+            status = AVCENC_WRONG_STATE;
+    }
+
+    return status;
+}
+
+/* ======================================================================== */
+/*  Function : PVAVCEncGetOverrunBuffer()                                   */
+/*  Purpose  : To retrieve the overrun buffer. Check whether overrun buffer */
+/*              is used or not before returning                             */
+/*  In/out   :                                                              */
+/*  Return   : Pointer to the internal overrun buffer.                      */
+/*  Modified :                                                              */
+/* ======================================================================== */
+OSCL_EXPORT_REF uint8* PVAVCEncGetOverrunBuffer(AVCHandle* avcHandle)
+{
+    AVCEncObject *encvid = (AVCEncObject*)avcHandle->AVCObject;
+    AVCEncBitstream *bitstream = encvid->bitstream;
+
+    if (bitstream->overrunBuffer == bitstream->bitstreamBuffer) /* OB is used */
+    {
+        return encvid->overrunBuffer;
+    }
+    else
+    {
+        return NULL;
+    }
+}
+
+
+/* ======================================================================== */
+/*  Function : PVAVCEncGetRecon()                                           */
+/*  Date     : 4/29/2004                                                    */
+/*  Purpose  : To retrieve the most recently encoded frame.                 */
+/*              assume that user will make a copy if they want to hold on   */
+/*              to it. Otherwise, it is not guaranteed to be reserved.      */
+/*              Most applications prefer to see original frame rather than  */
+/*              reconstructed frame. So, we are staying aware from complex  */
+/*              buffering mechanism. If needed, can be added later.         */
+/*  In/out   :                                                              */
+/*  Return   : AVCENC_SUCCESS for success.                                  */
+/*  Modified :                                                              */
+/* ======================================================================== */
+OSCL_EXPORT_REF AVCEnc_Status PVAVCEncGetRecon(AVCHandle *avcHandle, AVCFrameIO *recon)
+{
+    AVCEncObject *encvid = (AVCEncObject*)avcHandle->AVCObject;
+    AVCCommonObj *video = encvid->common;
+    AVCFrameStore *currFS = video->currFS;
+
+    if (encvid == NULL)
+    {
+        return AVCENC_UNINITIALIZED;
+    }
+
+    recon->YCbCr[0] = currFS->frame.Sl;
+    recon->YCbCr[1] = currFS->frame.Scb;
+    recon->YCbCr[2] = currFS->frame.Scr;
+    recon->height = currFS->frame.height;
+    recon->pitch = currFS->frame.pitch;
+    recon->disp_order = currFS->PicOrderCnt;
+    recon->coding_order = currFS->FrameNum;
+    recon->id = (uint32) currFS->base_dpb; /* use the pointer as the id */
+
+    currFS->IsOutputted |= 1;
+
+    return AVCENC_SUCCESS;
+}
+
+OSCL_EXPORT_REF AVCEnc_Status PVAVCEncReleaseRecon(AVCHandle *avcHandle, AVCFrameIO *recon)
+{
+    OSCL_UNUSED_ARG(avcHandle);
+    OSCL_UNUSED_ARG(recon);
+
+    return AVCENC_SUCCESS; //for now
+}
+
+/* ======================================================================== */
+/*  Function : PVAVCCleanUpEncoder()                                        */
+/*  Date     : 4/18/2004                                                    */
+/*  Purpose  : To clean up memories allocated by PVAVCEncInitialize()       */
+/*  In/out   :                                                              */
+/*  Return   : AVCENC_SUCCESS for success.                                  */
+/*  Modified :                                                              */
+/* ======================================================================== */
+OSCL_EXPORT_REF void    PVAVCCleanUpEncoder(AVCHandle *avcHandle)
+{
+    AVCEncObject *encvid = (AVCEncObject*) avcHandle->AVCObject;
+    AVCCommonObj *video;
+    uint32 *userData = (uint32*) avcHandle->userData;
+
+    if (encvid != NULL)
+    {
+        CleanMotionSearchModule(avcHandle);
+
+        CleanupRateControlModule(avcHandle);
+
+        if (encvid->functionPointer != NULL)
+        {
+            avcHandle->CBAVC_Free(userData, (int)encvid->functionPointer);
+        }
+
+        if (encvid->min_cost)
+        {
+            avcHandle->CBAVC_Free(userData, (int)encvid->min_cost);
+        }
+
+        if (encvid->intraSearch)
+        {
+            avcHandle->CBAVC_Free(userData, (int)encvid->intraSearch);
+        }
+
+        if (encvid->mot16x16)
+        {
+            avcHandle->CBAVC_Free(userData, (int)encvid->mot16x16);
+        }
+
+        if (encvid->rateCtrl)
+        {
+            avcHandle->CBAVC_Free(userData, (int)encvid->rateCtrl);
+        }
+
+        if (encvid->overrunBuffer)
+        {
+            avcHandle->CBAVC_Free(userData, (int)encvid->overrunBuffer);
+        }
+
+        video = encvid->common;
+        if (video != NULL)
+        {
+            if (video->MbToSliceGroupMap)
+            {
+                avcHandle->CBAVC_Free(userData, (int)video->MbToSliceGroupMap);
+            }
+            if (video->mblock != NULL)
+            {
+                avcHandle->CBAVC_Free(userData, (int)video->mblock);
+            }
+            if (video->decPicBuf != NULL)
+            {
+                CleanUpDPB(avcHandle, video);
+                avcHandle->CBAVC_Free(userData, (int)video->decPicBuf);
+            }
+            if (video->sliceHdr != NULL)
+            {
+                avcHandle->CBAVC_Free(userData, (int)video->sliceHdr);
+            }
+            if (video->currPicParams != NULL)
+            {
+                if (video->currPicParams->slice_group_id)
+                {
+                    avcHandle->CBAVC_Free(userData, (int)video->currPicParams->slice_group_id);
+                }
+
+                avcHandle->CBAVC_Free(userData, (int)video->currPicParams);
+            }
+            if (video->currSeqParams != NULL)
+            {
+                avcHandle->CBAVC_Free(userData, (int)video->currSeqParams);
+            }
+            if (encvid->bitstream != NULL)
+            {
+                avcHandle->CBAVC_Free(userData, (int)encvid->bitstream);
+            }
+            if (video != NULL)
+            {
+                avcHandle->CBAVC_Free(userData, (int)video);
+            }
+        }
+
+        avcHandle->CBAVC_Free(userData, (int)encvid);
+
+        avcHandle->AVCObject = NULL;
+    }
+
+    return ;
+}
+
+OSCL_EXPORT_REF AVCEnc_Status PVAVCEncUpdateBitRate(AVCHandle *avcHandle, uint32 bitrate)
+{
+    OSCL_UNUSED_ARG(avcHandle);
+    OSCL_UNUSED_ARG(bitrate);
+
+    return AVCENC_FAIL;
+}
+
+OSCL_EXPORT_REF AVCEnc_Status PVAVCEncUpdateFrameRate(AVCHandle *avcHandle, uint32 num, uint32 denom)
+{
+    OSCL_UNUSED_ARG(avcHandle);
+    OSCL_UNUSED_ARG(num);
+    OSCL_UNUSED_ARG(denom);
+
+    return AVCENC_FAIL;
+}
+
+OSCL_EXPORT_REF AVCEnc_Status PVAVCEncUpdateIDRInterval(AVCHandle *avcHandle, int IDRInterval)
+{
+    OSCL_UNUSED_ARG(avcHandle);
+    OSCL_UNUSED_ARG(IDRInterval);
+
+    return AVCENC_FAIL;
+}
+
+OSCL_EXPORT_REF AVCEnc_Status PVAVCEncIDRRequest(AVCHandle *avcHandle)
+{
+    OSCL_UNUSED_ARG(avcHandle);
+
+    return AVCENC_FAIL;
+}
+
+OSCL_EXPORT_REF AVCEnc_Status PVAVCEncUpdateIMBRefresh(AVCHandle *avcHandle, int numMB)
+{
+    OSCL_UNUSED_ARG(avcHandle);
+    OSCL_UNUSED_ARG(numMB);
+
+    return AVCENC_FAIL;
+}
+
+void PVAVCEncGetFrameStats(AVCHandle *avcHandle, AVCEncFrameStats *avcStats)
+{
+    AVCEncObject *encvid = (AVCEncObject*) avcHandle->AVCObject;
+    AVCRateControl *rateCtrl = encvid->rateCtrl;
+
+    avcStats->avgFrameQP = GetAvgFrameQP(rateCtrl);
+    avcStats->numIntraMBs = encvid->numIntraMB;
+
+    return ;
+}
+
+
+
diff --git a/media/libstagefright/codecs/avc/enc/src/avcenc_api.h b/media/libstagefright/codecs/avc/enc/src/avcenc_api.h
new file mode 100644
index 0000000..6841ec3
--- /dev/null
+++ b/media/libstagefright/codecs/avc/enc/src/avcenc_api.h
@@ -0,0 +1,323 @@
+/* ------------------------------------------------------------------
+ * Copyright (C) 1998-2009 PacketVideo
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
+ * express or implied.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ * -------------------------------------------------------------------
+ */
+/**
+This file contains application function interfaces to the AVC encoder library
+and necessary type defitionitions and enumerations.
+@publishedAll
+*/
+
+#ifndef AVCENC_API_H_INCLUDED
+#define AVCENC_API_H_INCLUDED
+
+#ifndef AVCAPI_COMMON_H_INCLUDED
+#include "avcapi_common.h"
+#endif
+
+// For memset, etc
+#include <string.h>
+
+/**
+ This enumeration is used for the status returned from the library interface.
+*/
+typedef enum
+{
+    /**
+    Fail information, need to add more error code for more specific info
+    */
+    AVCENC_TRAILINGONES_FAIL = -35,
+    AVCENC_SLICE_EMPTY = -34,
+    AVCENC_POC_FAIL = -33,
+    AVCENC_CONSECUTIVE_NONREF = -32,
+    AVCENC_CABAC_FAIL = -31,
+    AVCENC_PRED_WEIGHT_TAB_FAIL = -30,
+    AVCENC_DEC_REF_PIC_MARK_FAIL = -29,
+    AVCENC_SPS_FAIL = -28,
+    AVCENC_BITSTREAM_BUFFER_FULL    = -27,
+    AVCENC_BITSTREAM_INIT_FAIL = -26,
+    AVCENC_CHROMA_QP_FAIL = -25,
+    AVCENC_INIT_QS_FAIL = -24,
+    AVCENC_INIT_QP_FAIL = -23,
+    AVCENC_WEIGHTED_BIPRED_FAIL = -22,
+    AVCENC_INVALID_INTRA_PERIOD = -21,
+    AVCENC_INVALID_CHANGE_RATE = -20,
+    AVCENC_INVALID_BETA_OFFSET = -19,
+    AVCENC_INVALID_ALPHA_OFFSET = -18,
+    AVCENC_INVALID_DEBLOCK_IDC = -17,
+    AVCENC_INVALID_REDUNDANT_PIC = -16,
+    AVCENC_INVALID_FRAMERATE = -15,
+    AVCENC_INVALID_NUM_SLICEGROUP = -14,
+    AVCENC_INVALID_POC_LSB = -13,
+    AVCENC_INVALID_NUM_REF = -12,
+    AVCENC_INVALID_FMO_TYPE = -11,
+    AVCENC_ENCPARAM_MEM_FAIL = -10,
+    AVCENC_LEVEL_NOT_SUPPORTED = -9,
+    AVCENC_LEVEL_FAIL = -8,
+    AVCENC_PROFILE_NOT_SUPPORTED = -7,
+    AVCENC_TOOLS_NOT_SUPPORTED = -6,
+    AVCENC_WRONG_STATE = -5,
+    AVCENC_UNINITIALIZED = -4,
+    AVCENC_ALREADY_INITIALIZED = -3,
+    AVCENC_NOT_SUPPORTED = -2,
+    AVCENC_MEMORY_FAIL = AVC_MEMORY_FAIL,
+    AVCENC_FAIL = AVC_FAIL,
+    /**
+    Generic success value
+    */
+    AVCENC_SUCCESS = AVC_SUCCESS,
+    AVCENC_PICTURE_READY = 2,
+    AVCENC_NEW_IDR = 3, /* upon getting this, users have to call PVAVCEncodeSPS and PVAVCEncodePPS to get a new SPS and PPS*/
+    AVCENC_SKIPPED_PICTURE = 4 /* continuable error message */
+
+} AVCEnc_Status;
+
+#define MAX_NUM_SLICE_GROUP  8      /* maximum for all the profiles */
+
+/**
+This structure contains the encoding parameters.
+*/
+typedef struct tagAVCEncParam
+{
+    /* if profile/level is set to zero, encoder will choose the closest one for you */
+    AVCProfile profile; /* profile of the bitstream to be compliant with*/
+    AVCLevel   level;   /* level of the bitstream to be compliant with*/
+
+    int width;      /* width of an input frame in pixel */
+    int height;     /* height of an input frame in pixel */
+
+    int poc_type; /* picture order count mode, 0,1 or 2 */
+    /* for poc_type == 0 */
+    uint log2_max_poc_lsb_minus_4; /* specify maximum value of POC Lsb, range 0..12*/
+    /* for poc_type == 1 */
+    uint delta_poc_zero_flag; /* delta POC always zero */
+    int offset_poc_non_ref; /* offset for non-reference pic */
+    int offset_top_bottom; /* offset between top and bottom field */
+    uint num_ref_in_cycle; /* number of reference frame in one cycle */
+    int *offset_poc_ref; /* array of offset for ref pic, dimension [num_ref_in_cycle] */
+
+    int num_ref_frame;  /* number of reference frame used */
+    int num_slice_group;  /* number of slice group */
+    int fmo_type;   /* 0: interleave, 1: dispersed, 2: foreground with left-over
+                    3: box-out, 4:raster scan, 5:wipe, 6:explicit */
+    /* for fmo_type == 0 */
+    uint run_length_minus1[MAX_NUM_SLICE_GROUP];   /* array of size num_slice_group, in round robin fasion */
+    /* fmo_type == 2*/
+    uint top_left[MAX_NUM_SLICE_GROUP-1];           /* array of co-ordinates of each slice_group */
+    uint bottom_right[MAX_NUM_SLICE_GROUP-1];       /* except the last one which is the background. */
+    /* fmo_type == 3,4,5 */
+    AVCFlag change_dir_flag;  /* slice group change direction flag */
+    uint change_rate_minus1;
+    /* fmo_type == 6 */
+    uint *slice_group; /* array of size MBWidth*MBHeight */
+
+    AVCFlag db_filter;  /* enable deblocking loop filter */
+    int disable_db_idc;  /* 0: filter everywhere, 1: no filter, 2: no filter across slice boundary */
+    int alpha_offset;   /* alpha offset range -6,...,6 */
+    int beta_offset;    /* beta offset range -6,...,6 */
+
+    AVCFlag constrained_intra_pred; /* constrained intra prediction flag */
+
+    AVCFlag auto_scd;   /* scene change detection on or off */
+    int idr_period; /* idr frame refresh rate in number of target encoded frame (no concept of actual time).*/
+    int intramb_refresh;    /* minimum number of intra MB per frame */
+    AVCFlag data_par;   /* enable data partitioning */
+
+    AVCFlag fullsearch; /* enable full-pel full-search mode */
+    int search_range;   /* search range for motion vector in (-search_range,+search_range) pixels */
+    AVCFlag sub_pel;    /* enable sub pel prediction */
+    AVCFlag submb_pred; /* enable sub MB partition mode */
+    AVCFlag rdopt_mode; /* RD optimal mode selection */
+    AVCFlag bidir_pred; /* enable bi-directional for B-slice, this flag forces the encoder to encode
+                        any frame with POC less than the previously encoded frame as a B-frame.
+                        If it's off, then such frames will remain P-frame. */
+
+    AVCFlag rate_control; /* rate control enable, on: RC on, off: constant QP */
+    int initQP;     /* initial QP */
+    uint32 bitrate;    /* target encoding bit rate in bits/second */
+    uint32 CPB_size;  /* coded picture buffer in number of bits */
+    uint32 init_CBP_removal_delay; /* initial CBP removal delay in msec */
+
+    uint32 frame_rate;  /* frame rate in the unit of frames per 1000 second */
+    /* note, frame rate is only needed by the rate control, AVC is timestamp agnostic. */
+
+    AVCFlag out_of_band_param_set; /* flag to set whether param sets are to be retrieved up front or not */
+
+    AVCFlag use_overrun_buffer;  /* do not throw away the frame if output buffer is not big enough.
+                                    copy excess bits to the overrun buffer */
+} AVCEncParams;
+
+
+/**
+This structure contains current frame encoding statistics for debugging purpose.
+*/
+typedef struct tagAVCEncFrameStats
+{
+    int avgFrameQP;   /* average frame QP */
+    int numIntraMBs;  /* number of intra MBs */
+    int numFalseAlarm;
+    int numMisDetected;
+    int numDetected;
+
+} AVCEncFrameStats;
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+    /** THE FOLLOWINGS ARE APIS */
+    /**
+    This function initializes the encoder library. It verifies the validity of the
+    encoding parameters against the specified profile/level and the list of supported
+    tools by this library. It allocates necessary memories required to perform encoding.
+    For re-encoding application, if users want to setup encoder in a more precise way,
+    users can give the external SPS and PPS to the encoder to follow.
+    \param "avcHandle"  "Handle to the AVC encoder library object."
+    \param "encParam"   "Pointer to the encoding parameter structure."
+    \param "extSPS"     "External SPS used for re-encoding purpose. NULL if not present"
+    \param "extPPS"     "External PPS used for re-encoding purpose. NULL if not present"
+    \return "AVCENC_SUCCESS for success,
+             AVCENC_NOT_SUPPORTED for the use of unsupported tools,
+             AVCENC_MEMORY_FAIL for memory allocation failure,
+             AVCENC_FAIL for generic failure."
+    */
+    OSCL_IMPORT_REF AVCEnc_Status PVAVCEncInitialize(AVCHandle *avcHandle, AVCEncParams *encParam, void* extSPS, void* extPPS);
+
+
+    /**
+    Since the output buffer size is not known prior to encoding a frame, users need to
+    allocate big enough buffer otherwise, that frame will be dropped. This function returns
+    the size of the output buffer to be allocated by the users that guarantees to hold one frame.
+    It follows the CPB spec for a particular level.  However, when the users set use_overrun_buffer
+    flag, this API is useless as excess output bits are saved in the overrun buffer waiting to be
+    copied out in small chunks, i.e. users can allocate any size of output buffer.
+    \param "avcHandle"  "Handle to the AVC encoder library object."
+    \param "size"   "Pointer to the size to be modified."
+    \return "AVCENC_SUCCESS for success, AVCENC_UNINITIALIZED when level is not known.
+    */
+
+    OSCL_IMPORT_REF AVCEnc_Status PVAVCEncGetMaxOutputBufferSize(AVCHandle *avcHandle, int* size);
+
+    /**
+    Users call this function to provide an input structure to the encoder library which will keep
+    a list of input structures it receives in case the users call this function many time before
+    calling PVAVCEncodeSlice. The encoder library will encode them according to the frame_num order.
+    Users should not modify the content of a particular frame until this frame is encoded and
+    returned thru CBAVCEnc_ReturnInput() callback function.
+    \param "avcHandle"  "Handle to the AVC encoder library object."
+    \param "input"      "Pointer to the input structure."
+    \return "AVCENC_SUCCESS for success,
+            AVCENC_FAIL if the encoder is not in the right state to take a new input frame.
+            AVCENC_NEW_IDR for the detection or determination of a new IDR, with this status,
+            the returned NAL is an SPS NAL,
+            AVCENC_NO_PICTURE if the input frame coding timestamp is too early, users must
+            get next frame or adjust the coding timestamp."
+    */
+    OSCL_IMPORT_REF AVCEnc_Status PVAVCEncSetInput(AVCHandle *avcHandle, AVCFrameIO *input);
+
+    /**
+    This function is called to encode a NAL unit which can be an SPS NAL, a PPS NAL or
+    a VCL (video coding layer) NAL which contains one slice of data. It could be a
+    fixed number of macroblocks, as specified in the encoder parameters set, or the
+    maximum number of macroblocks fitted into the given input argument "buffer". The
+    input frame is taken from the oldest unencoded input frame retrieved by users by
+    PVAVCEncGetInput API.
+    \param "avcHandle"  "Handle to the AVC encoder library object."
+    \param "buffer"     "Pointer to the output AVC bitstream buffer, the format will be EBSP,
+                         not RBSP."
+    \param "buf_nal_size"   "As input, the size of the buffer in bytes.
+                        This is the physical limitation of the buffer. As output, the size of the EBSP."
+    \param "nal_type"   "Pointer to the NAL type of the returned buffer."
+    \return "AVCENC_SUCCESS for success of encoding one slice,
+             AVCENC_PICTURE_READY for the completion of a frame encoding,
+             AVCENC_FAIL for failure (this should not occur, though)."
+    */
+    OSCL_IMPORT_REF AVCEnc_Status PVAVCEncodeNAL(AVCHandle *avcHandle, uint8 *buffer, uint *buf_nal_size, int *nal_type);
+
+    /**
+    This function sniffs the nal_unit_type such that users can call corresponding APIs.
+    This function is identical to PVAVCDecGetNALType() in the decoder.
+    \param "bitstream"  "Pointer to the beginning of a NAL unit (start with forbidden_zero_bit, etc.)."
+    \param "size"       "size of the bitstream (NumBytesInNALunit + 1)."
+    \param "nal_unit_type" "Pointer to the return value of nal unit type."
+    \return "AVCENC_SUCCESS if success, AVCENC_FAIL otherwise."
+    */
+    OSCL_IMPORT_REF AVCEnc_Status PVAVCEncGetNALType(uint8 *bitstream, int size, int *nal_type, int *nal_ref_idc);
+
+    /**
+    This function returns the pointer to internal overrun buffer. Users can call this to query
+    whether the overrun buffer has been used to encode the current NAL.
+    \param "avcHandle"  "Pointer to the handle."
+    \return "Pointer to overrun buffer if it is used, otherwise, NULL."
+    */
+    OSCL_IMPORT_REF uint8* PVAVCEncGetOverrunBuffer(AVCHandle* avcHandle);
+
+    /**
+    This function returns the reconstructed frame of the most recently encoded frame.
+    Note that this frame is not returned to the users yet. Users should only read the
+    content of this frame.
+    \param "avcHandle"  "Handle to the AVC encoder library object."
+    \param "output"     "Pointer to the input structure."
+    \return "AVCENC_SUCCESS for success, AVCENC_NO_PICTURE if no picture to be outputted."
+    */
+    OSCL_IMPORT_REF AVCEnc_Status PVAVCEncGetRecon(AVCHandle *avcHandle, AVCFrameIO *recon);
+
+    /**
+    This function is used to return the recontructed frame back to the AVC encoder library
+    in order to be re-used for encoding operation. If users want the content of it to remain
+    unchanged for a long time, they should make a copy of it and release the memory back to
+    the encoder. The encoder relies on the id element in the AVCFrameIO structure,
+    thus users should not change the id value.
+    \param "avcHandle"  "Handle to the AVC decoder library object."
+    \param "output"      "Pointer to the AVCFrameIO structure."
+    \return "AVCENC_SUCCESS for success, AVCENC_FAIL for fail for id not found."
+    */
+    OSCL_IMPORT_REF AVCEnc_Status PVAVCEncReleaseRecon(AVCHandle *avcHandle, AVCFrameIO *recon);
+
+    /**
+    This function performs clean up operation including memory deallocation.
+    The encoder will also clear the list of input structures it has not released.
+    This implies that users must keep track of the number of input structure they have allocated
+    and free them accordingly.
+    \param "avcHandle"  "Handle to the AVC encoder library object."
+    */
+    OSCL_IMPORT_REF void    PVAVCCleanUpEncoder(AVCHandle *avcHandle);
+
+    /**
+    This function extracts statistics of the current frame. If the encoder has not finished
+    with the current frame, the result is not accurate.
+    \param "avcHandle"  "Handle to the AVC encoder library object."
+    \param "avcStats"   "Pointer to AVCEncFrameStats structure."
+    \return "void."
+    */
+    void PVAVCEncGetFrameStats(AVCHandle *avcHandle, AVCEncFrameStats *avcStats);
+
+    /**
+    These functions are used for the modification of encoding parameters.
+    To be polished.
+    */
+    OSCL_IMPORT_REF AVCEnc_Status PVAVCEncUpdateBitRate(AVCHandle *avcHandle, uint32 bitrate);
+    OSCL_IMPORT_REF AVCEnc_Status PVAVCEncUpdateFrameRate(AVCHandle *avcHandle, uint32 num, uint32 denom);
+    OSCL_IMPORT_REF AVCEnc_Status PVAVCEncUpdateIDRInterval(AVCHandle *avcHandle, int IDRInterval);
+    OSCL_IMPORT_REF AVCEnc_Status PVAVCEncIDRRequest(AVCHandle *avcHandle);
+    OSCL_IMPORT_REF AVCEnc_Status PVAVCEncUpdateIMBRefresh(AVCHandle *avcHandle, int numMB);
+
+
+#ifdef __cplusplus
+}
+#endif
+#endif  /* _AVCENC_API_H_ */
+
diff --git a/media/libstagefright/codecs/avc/enc/src/avcenc_int.h b/media/libstagefright/codecs/avc/enc/src/avcenc_int.h
new file mode 100644
index 0000000..3fe08a1
--- /dev/null
+++ b/media/libstagefright/codecs/avc/enc/src/avcenc_int.h
@@ -0,0 +1,471 @@
+/* ------------------------------------------------------------------
+ * Copyright (C) 1998-2009 PacketVideo
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
+ * express or implied.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ * -------------------------------------------------------------------
+ */
+/**
+This file contains application function interfaces to the AVC encoder library
+and necessary type defitionitions and enumerations.
+@publishedAll
+*/
+
+#ifndef AVCENC_INT_H_INCLUDED
+#define AVCENC_INT_H_INCLUDED
+
+#ifndef AVCINT_COMMON_H_INCLUDED
+#include "avcint_common.h"
+#endif
+#ifndef AVCENC_API_H_INCLUDED
+#include "avcenc_api.h"
+#endif
+
+typedef float OsclFloat;
+
+/* Definition for the structures below */
+#define DEFAULT_ATTR    0 /* default memory attribute */
+#define MAX_INPUT_FRAME 30 /* some arbitrary number, it can be much higher than this. */
+#define MAX_REF_FRAME  16 /* max size of the RefPicList0 and RefPicList1 */
+#define MAX_REF_PIC_LIST 33
+
+#define MIN_QP          0
+#define MAX_QP          51
+#define SHIFT_QP        12
+#define  LAMBDA_ACCURACY_BITS         16
+#define  LAMBDA_FACTOR(lambda)        ((int)((double)(1<<LAMBDA_ACCURACY_BITS)*lambda+0.5))
+
+
+#define DISABLE_THRESHOLDING  0
+// for better R-D performance
+#define _LUMA_COEFF_COST_       4 //!< threshold for luma coeffs
+#define _CHROMA_COEFF_COST_     4 //!< threshold for chroma coeffs, used to be 7
+#define _LUMA_MB_COEFF_COST_    5 //!< threshold for luma coeffs of inter Macroblocks
+#define _LUMA_8x8_COEFF_COST_   5 //!< threshold for luma coeffs of 8x8 Inter Partition
+#define MAX_VALUE       999999   //!< used for start value for some variables
+
+#define  WEIGHTED_COST(factor,bits)   (((factor)*(bits))>>LAMBDA_ACCURACY_BITS)
+#define  MV_COST(f,s,cx,cy,px,py)     (WEIGHTED_COST(f,mvbits[((cx)<<(s))-px]+mvbits[((cy)<<(s))-py]))
+#define  MV_COST_S(f,cx,cy,px,py)     (WEIGHTED_COST(f,mvbits[cx-px]+mvbits[cy-py]))
+
+/* for sub-pel search and interpolation */
+#define SUBPEL_PRED_BLK_SIZE 576 // 24x24
+#define REF_CENTER 75
+#define V2Q_H0Q 1
+#define V0Q_H2Q 2
+#define V2Q_H2Q 3
+
+/*
+#define V3Q_H0Q 1
+#define V3Q_H1Q 2
+#define V0Q_H1Q 3
+#define V1Q_H1Q 4
+#define V1Q_H0Q 5
+#define V1Q_H3Q 6
+#define V0Q_H3Q 7
+#define V3Q_H3Q 8
+#define V2Q_H3Q 9
+#define V2Q_H0Q 10
+#define V2Q_H1Q 11
+#define V2Q_H2Q 12
+#define V3Q_H2Q 13
+#define V0Q_H2Q 14
+#define V1Q_H2Q 15
+*/
+
+
+#define DEFAULT_OVERRUN_BUFFER_SIZE 1000
+
+// associated with the above cost model
+const uint8 COEFF_COST[2][16] =
+{
+    {3, 2, 2, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+    {9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9}
+};
+
+
+
+//! convert from H.263 QP to H.264 quant given by: quant=pow(2,QP/6)
+const int QP2QUANT[40] =
+{
+    1, 1, 1, 1, 2, 2, 2, 2,
+    3, 3, 3, 4, 4, 4, 5, 6,
+    6, 7, 8, 9, 10, 11, 13, 14,
+    16, 18, 20, 23, 25, 29, 32, 36,
+    40, 45, 51, 57, 64, 72, 81, 91
+};
+
+
+/**
+This enumeration keeps track of the internal status of the encoder whether it is doing
+something. The encoding flow follows the order in which these states are.
+@publishedAll
+*/
+typedef enum
+{
+    AVCEnc_Initializing = 0,
+    AVCEnc_Encoding_SPS,
+    AVCEnc_Encoding_PPS,
+    AVCEnc_Analyzing_Frame,
+    AVCEnc_WaitingForBuffer,  // pending state
+    AVCEnc_Encoding_Frame,
+} AVCEnc_State ;
+
+/**
+Bitstream structure contains bitstream related parameters such as the pointer
+to the buffer, the current byte position and bit position. The content of the
+bitstreamBuffer will be in EBSP format as the emulation prevention codes are
+automatically inserted as the RBSP is recorded.
+@publishedAll
+*/
+typedef struct tagEncBitstream
+{
+    uint8 *bitstreamBuffer; /* pointer to buffer memory   */
+    int buf_size;       /* size of the buffer memory */
+    int write_pos;      /* next position to write to bitstreamBuffer  */
+    int count_zeros;   /* count number of consecutive zero */
+    uint current_word;  /* byte-swapped (MSB left) current word to write to buffer */
+    int bit_left;      /* number of bit left in current_word */
+    uint8   *overrunBuffer;  /* extra output buffer to prevent current skip due to output buffer overrun*/
+    int     oBSize;     /* size of allocated overrun buffer */
+    void   *encvid; /* pointer to the main object */
+
+} AVCEncBitstream;
+
+/**
+This structure is used for rate control purpose and other performance related control
+variables such as, RD cost, statistics, motion search stuffs, etc.
+should be in this structure.
+@publishedAll
+*/
+
+
+typedef struct tagRDInfo
+{
+    int QP;
+    int actual_bits;
+    OsclFloat mad;
+    OsclFloat R_D;
+} RDInfo;
+
+typedef struct tagMultiPass
+{
+    /* multipass rate control data */
+    int target_bits;    /* target bits for current frame, = rc->T */
+    int actual_bits;    /* actual bits for current frame obtained after encoding, = rc->Rc*/
+    int QP;             /* quantization level for current frame, = rc->Qc*/
+    int prev_QP;        /* quantization level for previous frame */
+    int prev_prev_QP;   /* quantization level for previous frame before last*/
+    OsclFloat mad;          /* mad for current frame, = video->avgMAD*/
+    int bitrate;        /* bitrate for current frame */
+    OsclFloat framerate;    /* framerate for current frame*/
+
+    int nRe_Quantized;  /* control variable for multipass encoding, */
+    /* 0 : first pass */
+    /* 1 : intermediate pass(quantization and VLC loop only) */
+    /* 2 : final pass(de-quantization, idct, etc) */
+    /* 3 : macroblock level rate control */
+
+    int encoded_frames;     /* counter for all encoded frames */
+    int re_encoded_frames;  /* counter for all multipass encoded frames*/
+    int re_encoded_times;   /* counter for all times of multipass frame encoding */
+
+    /* Multiple frame prediction*/
+    RDInfo **pRDSamples;        /* pRDSamples[30][32], 30->30fps, 32 -> 5 bit quantizer, 32 candidates*/
+    int framePos;               /* specific position in previous multiple frames*/
+    int frameRange;             /* number of overall previous multiple frames */
+    int samplesPerFrame[30];    /* number of samples per frame, 30->30fps */
+
+    /* Bit allocation for scene change frames and high motion frames */
+    OsclFloat sum_mad;
+    int counter_BTsrc;  /* BT = Bit Transfer, bit transfer from low motion frames or less complicatedly compressed frames */
+    int counter_BTdst;  /* BT = Bit Transfer, bit transfer to scene change frames or high motion frames or more complicatedly compressed frames */
+    OsclFloat sum_QP;
+    int diff_counter;   /* diff_counter = -diff_counter_BTdst, or diff_counter_BTsrc */
+
+    /* For target bitrate or framerate update */
+    OsclFloat target_bits_per_frame;        /* = C = bitrate/framerate */
+    OsclFloat target_bits_per_frame_prev;   /* previous C */
+    OsclFloat aver_mad;                     /* so-far average mad could replace sum_mad */
+    OsclFloat aver_mad_prev;                /* previous average mad */
+    int   overlapped_win_size;          /* transition period of time */
+    int   encoded_frames_prev;          /* previous encoded_frames */
+} MultiPass;
+
+
+typedef struct tagdataPointArray
+{
+    int Qp;
+    int Rp;
+    OsclFloat Mp;   /* for MB-based RC */
+    struct tagdataPointArray *next;
+    struct tagdataPointArray *prev;
+} dataPointArray;
+
+typedef struct tagAVCRateControl
+{
+
+    /* these parameters are initialized by the users AVCEncParams */
+    /* bitrate-robustness tradeoff */
+    uint scdEnable; /* enable scene change detection */
+    int idrPeriod;  /* IDR period in number of frames */
+    int intraMBRate;   /* intra MB refresh rate per frame */
+    uint dpEnable;  /* enable data partitioning */
+
+    /* quality-complexity tradeoff */
+    uint subPelEnable;  /* enable quarter pel search */
+    int mvRange;    /* motion vector search range in +/- pixel */
+    uint subMBEnable;  /* enable sub MB prediction mode (4x4, 4x8, 8x4) */
+    uint rdOptEnable;  /* enable RD-opt mode selection */
+    uint twoPass; /* flag for 2 pass encoding ( for future )*/
+    uint bidirPred; /* bi-directional prediction for B-frame. */
+
+    uint rcEnable;  /* enable rate control, '1' on, '0' const QP */
+    int initQP; /* initial QP */
+
+    /* note the following 3 params are for HRD, these triplets can be a series
+    of triplets as the generalized HRD allows. SEI message must be generated in this case. */
+    /* We no longer have to differentiate between CBR and VBR. The users to the
+    AVC encoder lib will do the mapping from CBR/VBR to these parameters. */
+    int32 bitRate;  /* target bit rate for the overall clip in bits/second*/
+    int32 cpbSize;  /* coded picture buffer size in bytes */
+    int32 initDelayOffset; /* initial CBP removal delay in bits */
+
+    OsclFloat frame_rate; /* frame rate */
+    int srcInterval; /* source frame rate in msec */
+    int basicUnit;  /* number of macroblocks per BU */
+
+    /* Then internal parameters for the operation */
+    uint first_frame; /* a flag for the first frame */
+    int lambda_mf; /* for example */
+    int totalSAD;    /* SAD of current frame */
+
+    /*******************************************/
+    /* this part comes from MPEG4 rate control */
+    int alpha;  /* weight for I frame */
+    int Rs;     /*bit rate for the sequence (or segment) e.g., 24000 bits/sec */
+    int Rc;     /*bits used for the current frame. It is the bit count obtained after encoding. */
+    int Rp;     /*bits to be removed from the buffer per picture. */
+    /*? is this the average one, or just the bits coded for the previous frame */
+    int Rps;    /*bit to be removed from buffer per src frame */
+    OsclFloat Ts;   /*number of seconds for the sequence  (or segment). e.g., 10 sec */
+    OsclFloat Ep;
+    OsclFloat Ec;   /*mean absolute difference for the current frame after motion compensation.*/
+    /*If the macroblock is intra coded, the original spatial pixel values are summed.*/
+    int Qc;     /*quantization level used for the current frame. */
+    int Nr;     /*number of P frames remaining for encoding.*/
+    int Rr; /*number of bits remaining for encoding this sequence (or segment).*/
+    int Rr_Old;
+    int T;      /*target bit to be used for the current frame.*/
+    int S;      /*number of bits used for encoding the previous frame.*/
+    int Hc; /*header and motion vector bits used in the current frame. It includes all the  information except to the residual information.*/
+    int Hp; /*header and motion vector bits used in the previous frame. It includes all the     information except to the residual information.*/
+    int Ql; /*quantization level used in the previous frame */
+    int Bs; /*buffer size e.g., R/2 */
+    int B;      /*current buffer level e.g., R/4 - start from the middle of the buffer */
+    OsclFloat X1;
+    OsclFloat X2;
+    OsclFloat X11;
+    OsclFloat M;            /*safe margin for the buffer */
+    OsclFloat smTick;    /*ratio of src versus enc frame rate */
+    double remnant;  /*remainder frame of src/enc frame for fine frame skipping */
+    int timeIncRes; /* vol->timeIncrementResolution */
+
+    dataPointArray   *end; /*quantization levels for the past (20) frames */
+
+    int     frameNumber; /* ranging from 0 to 20 nodes*/
+    int     w;
+    int     Nr_Original;
+    int     Nr_Old, Nr_Old2;
+    int     skip_next_frame;
+    int     Qdep;       /* smooth Q adjustment */
+    int     VBR_Enabled;
+
+    int totalFrameNumber; /* total coded frames, for debugging!!*/
+
+    char    oFirstTime;
+
+    int numFrameBits; /* keep track of number of bits of the current frame */
+    int NumberofHeaderBits;
+    int NumberofTextureBits;
+    int numMBHeaderBits;
+    int numMBTextureBits;
+    double *MADofMB;
+    int32 bitsPerFrame;
+
+    /* BX rate control, something like TMN8 rate control*/
+
+    MultiPass *pMP;
+
+    int     TMN_W;
+    int     TMN_TH;
+    int     VBV_fullness;
+    int     max_BitVariance_num; /* the number of the maximum bit variance within the given buffer with the unit of 10% of bitrate/framerate*/
+    int     encoded_frames; /* counter for all encoded frames */
+    int     low_bound;              /* bound for underflow detection, usually low_bound=-Bs/2, but could be changed in H.263 mode */
+    int     VBV_fullness_offset;    /* offset of VBV_fullness, usually is zero, but can be changed in H.263 mode*/
+    /* End BX */
+
+} AVCRateControl;
+
+
+/**
+This structure is for the motion vector information. */
+typedef struct tagMV
+{
+    int x;
+    int y;
+    uint sad;
+} AVCMV;
+
+/**
+This structure contains function pointers for different platform dependent implementation of
+functions. */
+typedef struct tagAVCEncFuncPtr
+{
+
+    int (*SAD_MB_HalfPel[4])(uint8*, uint8*, int, void *);
+    int (*SAD_Macroblock)(uint8 *ref, uint8 *blk, int dmin_lx, void *extra_info);
+
+} AVCEncFuncPtr;
+
+/**
+This structure contains information necessary for correct padding.
+*/
+typedef struct tagPadInfo
+{
+    int i;
+    int width;
+    int j;
+    int height;
+} AVCPadInfo;
+
+
+#ifdef HTFM
+typedef struct tagHTFM_Stat
+{
+    int abs_dif_mad_avg;
+    uint countbreak;
+    int offsetArray[16];
+    int offsetRef[16];
+} HTFM_Stat;
+#endif
+
+
+/**
+This structure is the main object for AVC encoder library providing access to all
+global variables. It is allocated at PVAVCInitEncoder and freed at PVAVCCleanUpEncoder.
+@publishedAll
+*/
+typedef struct tagEncObject
+{
+
+    AVCCommonObj *common;
+
+    AVCEncBitstream     *bitstream; /* for current NAL */
+    uint8   *overrunBuffer;  /* extra output buffer to prevent current skip due to output buffer overrun*/
+    int     oBSize;     /* size of allocated overrun buffer */
+
+    /* rate control */
+    AVCRateControl      *rateCtrl; /* pointer to the rate control structure */
+
+    /* encoding operation */
+    AVCEnc_State        enc_state; /* encoding state */
+
+    AVCFrameIO          *currInput; /* pointer to the current input frame */
+
+    int                 currSliceGroup; /* currently encoded slice group id */
+
+    int     level[24][16], run[24][16]; /* scratch memory */
+    int     leveldc[16], rundc[16]; /* for DC component */
+    int     levelcdc[16], runcdc[16]; /* for chroma DC component */
+    int     numcoefcdc[2]; /* number of coefficient for chroma DC */
+    int     numcoefdc;      /* number of coefficients for DC component */
+
+    int     qp_const;
+    int     qp_const_c;
+    /********* intra prediction scratch memory **********************/
+    uint8   pred_i16[AVCNumI16PredMode][256]; /* save prediction for MB */
+    uint8   pred_i4[AVCNumI4PredMode][16];  /* save prediction for blk */
+    uint8   pred_ic[AVCNumIChromaMode][128];  /* for 2 chroma */
+
+    int     mostProbableI4Mode[16]; /* in raster scan order */
+    /********* motion compensation related variables ****************/
+    AVCMV   *mot16x16;          /* Saved motion vectors for 16x16 block*/
+    AVCMV(*mot16x8)[2];     /* Saved motion vectors for 16x8 block*/
+    AVCMV(*mot8x16)[2];     /* Saved motion vectors for 8x16 block*/
+    AVCMV(*mot8x8)[4];      /* Saved motion vectors for 8x8 block*/
+
+    /********* subpel position **************************************/
+    uint32  subpel_pred[SUBPEL_PRED_BLK_SIZE/*<<2*/]; /* all 16 sub-pel positions  */
+    uint8   *hpel_cand[9];      /* pointer to half-pel position */
+    int     best_hpel_pos;          /* best position */
+    uint8   qpel_cand[8][24*16];        /* pointer to quarter-pel position */
+    int     best_qpel_pos;
+    uint8   *bilin_base[9][4];    /* pointer to 4 position at top left of bilinear quarter-pel */
+
+    /* need for intra refresh rate */
+    uint8   *intraSearch;       /* Intra Array for MBs to be intra searched */
+    uint    firstIntraRefreshMBIndx; /* keep track for intra refresh */
+
+    int     i4_sad;             /* temporary for i4 mode SAD */
+    int     *min_cost;          /* Minimum cost for the all MBs */
+    int     lambda_mode;        /* Lagrange parameter for mode selection */
+    int     lambda_motion;      /* Lagrange parameter for MV selection */
+
+    uint8   *mvbits_array;      /* Table for bits spent in the cost funciton */
+    uint8   *mvbits;            /* An offset to the above array. */
+
+    /* to speedup the SAD calculation */
+    void *sad_extra_info;
+    uint8 currYMB[256];     /* interleaved current macroblock in HTFM order */
+
+#ifdef HTFM
+    int nrmlz_th[48];       /* Threshold for fast SAD calculation using HTFM */
+    HTFM_Stat htfm_stat;    /* For statistics collection */
+#endif
+
+    /* statistics */
+    int numIntraMB;         /* keep track of number of intra MB */
+
+    /* encoding complexity control */
+    uint fullsearch_enable; /* flag to enable full-pel full-search */
+
+    /* misc.*/
+    bool outOfBandParamSet; /* flag to enable out-of-band param set */
+
+    AVCSeqParamSet extSPS; /* for external SPS */
+    AVCPicParamSet extPPS; /* for external PPS */
+
+    /* time control */
+    uint32  prevFrameNum;   /* previous frame number starting from modTimeRef */
+    uint32  modTimeRef;     /* Reference modTime update every I-Vop*/
+    uint32  wrapModTime;    /* Offset to modTime Ref, rarely used */
+
+    uint    prevProcFrameNum;  /* previously processed frame number, could be skipped */
+    uint    prevCodedFrameNum;  /* previously encoded frame number */
+    /* POC related variables */
+    uint32  dispOrdPOCRef;      /* reference POC is displayer order unit. */
+
+    /* Function pointers */
+    AVCEncFuncPtr *functionPointer; /* store pointers to platform specific functions */
+
+    /* Application control data */
+    AVCHandle *avcHandle;
+
+
+} AVCEncObject;
+
+
+#endif /*AVCENC_INT_H_INCLUDED*/
+
diff --git a/media/libstagefright/codecs/avc/enc/src/avcenc_lib.h b/media/libstagefright/codecs/avc/enc/src/avcenc_lib.h
new file mode 100644
index 0000000..17e28ef
--- /dev/null
+++ b/media/libstagefright/codecs/avc/enc/src/avcenc_lib.h
@@ -0,0 +1,1020 @@
+/* ------------------------------------------------------------------
+ * Copyright (C) 1998-2009 PacketVideo
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
+ * express or implied.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ * -------------------------------------------------------------------
+ */
+/**
+This file contains declarations of internal functions for AVC decoder library.
+@publishedAll
+*/
+#ifndef AVCENC_LIB_H_INCLUDED
+#define AVCENC_LIB_H_INCLUDED
+
+#ifndef AVCLIB_COMMON_H_INCLUDED
+#include "avclib_common.h"
+#endif
+#ifndef AVCENC_INT_H_INCLUDED
+#include "avcenc_int.h"
+#endif
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+    /*------------- block.c -------------------------*/
+
+    /**
+    This function perform residue calculation, transform, quantize, inverse quantize,
+    inverse transform and residue compensation on a 4x4 block.
+    \param "encvid" "Pointer to AVCEncObject."
+    \param "blkidx"  "raster scan block index of the current 4x4 block."
+    \param "cur"    "Pointer to the reconstructed block."
+    \param "org"    "Pointer to the original block."
+    \param "coef_cost"  "Pointer to the coefficient cost to be filled in and returned."
+    \return "Number of non-zero coefficients."
+    */
+    int dct_luma(AVCEncObject *encvid, int blkidx, uint8 *cur, uint8 *org, int *coef_cost);
+
+    /**
+    This function performs IDCT on an INTER macroblock.
+    \param "video"  "Pointer to AVCCommonObj."
+    \param "curL"   "Pointer to the origin of the macroblock on the current frame."
+    \param "currMB" "Pointer to the AVCMacroblock structure."
+    \param "picPitch" "Pitch of the current frame."
+    \return "void".
+    */
+    void MBInterIdct(AVCCommonObj *video, uint8 *curL, AVCMacroblock *currMB, int picPitch);
+
+    /**
+    This function perform residue calculation, transform, quantize, inverse quantize,
+    inverse transform and residue compensation on a macroblock.
+    \param "encvid" "Pointer to AVCEncObject."
+    \param "curL"   "Pointer to the reconstructed MB."
+    \param "orgL"    "Pointer to the original MB."
+    \return "void"
+    */
+    void dct_luma_16x16(AVCEncObject *encvid, uint8 *curL, uint8 *orgL);
+
+    /**
+    This function perform residue calculation, transform, quantize, inverse quantize,
+    inverse transform and residue compensation for chroma components of an MB.
+    \param "encvid" "Pointer to AVCEncObject."
+    \param "curC"   "Pointer to the reconstructed MB."
+    \param "orgC"    "Pointer to the original MB."
+    \param "cr"     "Flag whether it is Cr or not."
+    \return "void"
+    */
+    void dct_chroma(AVCEncObject *encvid, uint8 *curC, uint8 *orgC, int cr);
+
+    /*----------- init.c ------------------*/
+    /**
+    This function interprets the encoding parameters provided by users in encParam.
+    The results are kept in AVCEncObject, AVCSeqParamSet, AVCPicParamSet and AVCSliceHeader.
+    \param "encvid"     "Pointer to AVCEncObject."
+    \param "encParam"   "Pointer to AVCEncParam."
+    \param "extSPS"     "External SPS template to be followed. NULL if not present."
+    \param "extPPS"     "External PPS template to be followed. NULL if not present."
+    \return "see AVCEnc_Status."
+    */
+    AVCEnc_Status  SetEncodeParam(AVCHandle *avcHandle, AVCEncParams *encParam,
+                                  void *extSPS, void *extPPS);
+
+    /**
+    This function verifies the encoding parameters whether they meet the set of supported
+    tool by a specific profile. If the profile is not set, it will just find the closest
+    profile instead of verifying it.
+    \param "video"  "Pointer to AVCEncObject."
+    \param "seqParam"   "Pointer to AVCSeqParamSet."
+    \param "picParam"   "Pointer to AVCPicParamSet."
+    \return "AVCENC_SUCCESS if success,
+            AVCENC_PROFILE_NOT_SUPPORTED if the specified profile
+                is not supported by this version of the library,
+            AVCENC_TOOLS_NOT_SUPPORTED if any of the specified encoding tools are
+            not supported by the user-selected profile."
+    */
+    AVCEnc_Status VerifyProfile(AVCEncObject *video, AVCSeqParamSet *seqParam, AVCPicParamSet *picParam);
+
+    /**
+    This function verifies the encoding parameters whether they meet the requirement
+    for a specific level. If the level is not set, it will just find the closest
+    level instead of verifying it.
+    \param "video"  "Pointer to AVCEncObject."
+    \param "seqParam"   "Pointer to AVCSeqParamSet."
+    \param "picParam"   "Pointer to AVCPicParamSet."
+    \return "AVCENC_SUCCESS if success,
+            AVCENC_LEVEL_NOT_SUPPORTED if the specified level
+                is not supported by this version of the library,
+            AVCENC_LEVEL_FAIL if any of the encoding parameters exceed
+            the range of the user-selected level."
+    */
+    AVCEnc_Status VerifyLevel(AVCEncObject *video, AVCSeqParamSet *seqParam, AVCPicParamSet *picParam);
+
+    /**
+    This funciton initializes the frame encoding by setting poc/frame_num related parameters. it
+    also performs motion estimation.
+    \param "encvid" "Pointer to the AVCEncObject."
+    \return "AVCENC_SUCCESS if success, AVCENC_NO_PICTURE if there is no input picture
+            in the queue to encode, AVCENC_POC_FAIL or AVCENC_CONSECUTIVE_NONREF for POC
+            related errors, AVCENC_NEW_IDR if new IDR is detected."
+    */
+    AVCEnc_Status InitFrame(AVCEncObject *encvid);
+
+    /**
+    This function initializes slice header related variables and other variables necessary
+    for decoding one slice.
+    \param "encvid" "Pointer to the AVCEncObject."
+    \return "AVCENC_SUCCESS if success."
+    */
+    AVCEnc_Status InitSlice(AVCEncObject *encvid);
+
+    /*----------- header.c ----------------*/
+    /**
+    This function performs bitstream encoding of the sequence parameter set NAL.
+    \param "encvid" "Pointer to the AVCEncObject."
+    \param "stream" "Pointer to AVCEncBitstream."
+    \return "AVCENC_SUCCESS if success or AVCENC_SPS_FAIL or others for unexpected failure which
+    should not occur. The SPS parameters should all be verified before this function is called."
+    */
+    AVCEnc_Status EncodeSPS(AVCEncObject *encvid, AVCEncBitstream *stream);
+
+    /**
+    This function encodes the VUI parameters into the sequence parameter set bitstream.
+    \param "stream" "Pointer to AVCEncBitstream."
+    \param "vui"    "Pointer to AVCVUIParams."
+    \return "nothing."
+    */
+    void EncodeVUI(AVCEncBitstream* stream, AVCVUIParams* vui);
+
+    /**
+    This function encodes HRD parameters into the sequence parameter set bitstream
+    \param "stream" "Pointer to AVCEncBitstream."
+    \param "hrd"    "Pointer to AVCHRDParams."
+    \return "nothing."
+    */
+    void EncodeHRD(AVCEncBitstream* stream, AVCHRDParams* hrd);
+
+
+    /**
+    This function performs bitstream encoding of the picture parameter set NAL.
+    \param "encvid" "Pointer to the AVCEncObject."
+    \param "stream" "Pointer to AVCEncBitstream."
+    \return "AVCENC_SUCCESS if success or AVCENC_PPS_FAIL or others for unexpected failure which
+    should not occur. The SPS parameters should all be verified before this function is called."
+    */
+    AVCEnc_Status EncodePPS(AVCEncObject *encvid, AVCEncBitstream *stream);
+
+    /**
+    This function encodes slice header information which has been initialized or fabricated
+    prior to entering this funciton.
+    \param "encvid" "Pointer to the AVCEncObject."
+    \param "stream" "Pointer to AVCEncBitstream."
+    \return "AVCENC_SUCCESS if success or bitstream fail statuses."
+    */
+    AVCEnc_Status EncodeSliceHeader(AVCEncObject *encvid, AVCEncBitstream *stream);
+
+    /**
+    This function encodes reference picture list reordering relted syntax.
+    \param "video" "Pointer to AVCCommonObj."
+    \param "stream" "Pointer to AVCEncBitstream."
+    \param "sliceHdr" "Pointer to AVCSliceHdr."
+    \param "slice_type" "Value of slice_type - 5 if greater than 5."
+    \return "AVCENC_SUCCESS for success and AVCENC_FAIL otherwise."
+    */
+    AVCEnc_Status ref_pic_list_reordering(AVCCommonObj *video, AVCEncBitstream *stream, AVCSliceHeader *sliceHdr, int slice_type);
+
+    /**
+    This function encodes dec_ref_pic_marking related syntax.
+    \param "video" "Pointer to AVCCommonObj."
+    \param "stream" "Pointer to AVCEncBitstream."
+    \param "sliceHdr" "Pointer to AVCSliceHdr."
+    \return "AVCENC_SUCCESS for success and AVCENC_FAIL otherwise."
+    */
+    AVCEnc_Status dec_ref_pic_marking(AVCCommonObj *video, AVCEncBitstream *stream, AVCSliceHeader *sliceHdr);
+
+    /**
+    This function initializes the POC related variables and the POC syntax to be encoded
+    to the slice header derived from the disp_order and is_reference flag of the original
+    input frame to be encoded.
+    \param "video"  "Pointer to the AVCEncObject."
+    \return "AVCENC_SUCCESS if success,
+            AVCENC_POC_FAIL if the poc type is undefined or
+            AVCENC_CONSECUTIVE_NONREF if there are consecutive non-reference frame for POC type 2."
+    */
+    AVCEnc_Status InitPOC(AVCEncObject *video);
+
+    /**
+    This function performs POC related operation after a picture is decoded.
+    \param "video" "Pointer to AVCCommonObj."
+    \return "AVCENC_SUCCESS"
+    */
+    AVCEnc_Status PostPOC(AVCCommonObj *video);
+
+    /*----------- bitstream_io.c ----------------*/
+    /**
+    This function initializes the bitstream structure with the information given by
+    the users.
+    \param "bitstream"  "Pointer to the AVCEncBitstream structure."
+    \param "buffer"     "Pointer to the unsigned char buffer for output."
+    \param "buf_size"   "The size of the buffer in bytes."
+    \param "overrunBuffer"  "Pointer to extra overrun buffer."
+    \param "oBSize"     "Size of overrun buffer in bytes."
+    \return "AVCENC_SUCCESS if success, AVCENC_BITSTREAM_INIT_FAIL if fail"
+    */
+    AVCEnc_Status BitstreamEncInit(AVCEncBitstream *bitstream, uint8 *buffer, int buf_size,
+                                   uint8 *overrunBuffer, int oBSize);
+
+    /**
+    This function writes the data from the cache into the bitstream buffer. It also adds the
+    emulation prevention code if necessary.
+    \param "stream"     "Pointer to the AVCEncBitstream structure."
+    \return "AVCENC_SUCCESS if success or AVCENC_BITSTREAM_BUFFER_FULL if fail."
+    */
+    AVCEnc_Status AVCBitstreamSaveWord(AVCEncBitstream *stream);
+
+    /**
+    This function writes the codeword into the cache which will eventually be written to
+    the bitstream buffer.
+    \param "stream"     "Pointer to the AVCEncBitstream structure."
+    \param "nBits"      "Number of bits in the codeword."
+    \param "code"       "The codeword."
+    \return "AVCENC_SUCCESS if success or AVCENC_BITSTREAM_BUFFER_FULL if fail."
+    */
+    AVCEnc_Status BitstreamWriteBits(AVCEncBitstream *stream, int nBits, uint code);
+
+    /**
+    This function writes one bit of data into the cache which will eventually be written
+    to the bitstream buffer.
+    \param "stream"     "Pointer to the AVCEncBitstream structure."
+    \param "code"       "The codeword."
+    \return "AVCENC_SUCCESS if success or AVCENC_BITSTREAM_BUFFER_FULL if fail."
+    */
+    AVCEnc_Status BitstreamWrite1Bit(AVCEncBitstream *stream, uint code);
+
+    /**
+    This function adds trailing bits to the bitstream and reports back the final EBSP size.
+    \param "stream"     "Pointer to the AVCEncBitstream structure."
+    \param "nal_size"   "Output the final NAL size."
+    \return "AVCENC_SUCCESS if success or AVCENC_BITSTREAM_BUFFER_FULL if fail."
+    */
+    AVCEnc_Status BitstreamTrailingBits(AVCEncBitstream *bitstream, uint *nal_size);
+
+    /**
+    This function checks whether the current bit position is byte-aligned or not.
+    \param "stream" "Pointer to the bitstream structure."
+    \return "true if byte-aligned, false otherwise."
+    */
+    bool byte_aligned(AVCEncBitstream *stream);
+
+
+    /**
+    This function checks the availability of overrun buffer and switches to use it when
+    normal bufffer is not big enough.
+    \param "stream" "Pointer to the bitstream structure."
+    \param "numExtraBytes" "Number of extra byte needed."
+    \return "AVCENC_SUCCESS or AVCENC_FAIL."
+    */
+    AVCEnc_Status AVCBitstreamUseOverrunBuffer(AVCEncBitstream* stream, int numExtraBytes);
+
+
+    /*-------------- intra_est.c ---------------*/
+
+    /** This function performs intra/inter decision based on ABE.
+    \param "encvid" "Pointer to AVCEncObject."
+    \param "min_cost"   "Best inter cost."
+    \param "curL"   "Pointer to the current MB origin in reconstructed frame."
+    \param "picPitch" "Pitch of the reconstructed frame."
+    \return "Boolean for intra mode."
+    */
+
+//bool IntraDecisionABE(AVCEncObject *encvid, int min_cost, uint8 *curL, int picPitch);
+    bool IntraDecision(int *min_cost, uint8 *cur, int pitch, bool ave);
+
+    /**
+    This function performs intra prediction mode search.
+    \param "encvid" "Pointer to AVCEncObject."
+    \param "mbnum"  "Current MB number."
+    \param "curL"   "Pointer to the current MB origin in reconstructed frame."
+    \param "picPitch" "Pitch of the reconstructed frame."
+    \return "void."
+    */
+    void MBIntraSearch(AVCEncObject *encvid, int mbnum, uint8 *curL, int picPitch);
+
+    /**
+    This function generates all the I16 prediction modes for an MB and keep it in
+    encvid->pred_i16.
+    \param "encvid" "Pointer to AVCEncObject."
+    \return "void"
+    */
+    void intrapred_luma_16x16(AVCEncObject *encvid);
+
+    /**
+    This function calculate the cost of all I16 modes and compare them to get the minimum.
+    \param "encvid" "Pointer to AVCEncObject."
+    \param "orgY"   "Pointer to the original luma MB."
+    \param "min_cost" "Pointer to the minimal cost so-far."
+    \return "void"
+    */
+    void find_cost_16x16(AVCEncObject *encvid, uint8 *orgY, int *min_cost);
+
+    /**
+    This function calculates the cost of each I16 mode.
+    \param "org"    "Pointer to the original luma MB."
+    \param "org_pitch" "Stride size of the original frame."
+    \param "pred"   "Pointer to the prediction values."
+    \param "min_cost" "Minimal cost so-far."
+    \return "Cost"
+    */
+
+    int cost_i16(uint8 *org, int org_pitch, uint8 *pred, int min_cost);
+
+    /**
+    This function generates all the I4 prediction modes and select the best one
+    for all the blocks inside a macroblock.It also calls dct_luma to generate the reconstructed
+    MB, and transform coefficients to be encoded.
+    \param "encvid" "Pointer to AVCEncObject."
+    \param "min_cost" "Pointer to the minimal cost so-far."
+    \return "void"
+    */
+    void mb_intra4x4_search(AVCEncObject *encvid, int *min_cost);
+
+    /**
+    This function calculates the most probable I4 mode of a given 4x4 block
+    from neighboring informationaccording to AVC/H.264 standard.
+    \param "video"  "Pointer to AVCCommonObj."
+    \param "blkidx" "The current block index."
+    \return "Most probable mode."
+    */
+    int FindMostProbableI4Mode(AVCCommonObj *video, int blkidx);
+
+    /**
+    This function is where a lot of actions take place in the 4x4 block level inside
+    mb_intra4x4_search.
+    \param "encvid" "Pointer to AVCEncObject."
+    \param "blkidx" "The current 4x4 block index."
+    \param "cur"    "Pointer to the reconstructed block."
+    \param "org"    "Pointer to the original block."
+    \return "Minimal cost, also set currMB->i4Mode"
+    */
+    int blk_intra4x4_search(AVCEncObject *encvid, int blkidx, uint8 *cur, uint8 *org);
+
+    /**
+    This function calculates the cost of a given I4 prediction mode.
+    \param "org"    "Pointer to the original block."
+    \param "org_pitch"  "Stride size of the original frame."
+    \param "pred"   "Pointer to the prediction block. (encvid->pred_i4)"
+    \param "cost"   "Pointer to the minimal cost (to be updated)."
+    \return "void"
+    */
+    void cost_i4(uint8 *org, int org_pitch, uint8 *pred, uint16 *cost);
+
+    /**
+    This function performs chroma intra search. Each mode is saved in encvid->pred_ic.
+    \param "encvid" "Pointer to AVCEncObject."
+    \return "void"
+    */
+    void chroma_intra_search(AVCEncObject *encvid);
+
+    /**
+    This function calculates the cost of a chroma prediction mode.
+    \param "orgCb"  "Pointer to the original Cb block."
+    \param "orgCr"  "Pointer to the original Cr block."
+    \param "org_pitch"  "Stride size of the original frame."
+    \param "pred"   "Pointer to the prediction block (encvid->pred_ic)"
+    \param "mincost"    "Minimal cost so far."
+    \return "Cost."
+    */
+
+    int SATDChroma(uint8 *orgCb, uint8 *orgCr, int org_pitch, uint8 *pred, int mincost);
+
+    /*-------------- motion_comp.c ---------------*/
+
+    /**
+    This is a main function to peform inter prediction.
+    \param "encvid"     "Pointer to AVCEncObject."
+    \param "video"      "Pointer to AVCCommonObj."
+    \return "void".
+    */
+    void AVCMBMotionComp(AVCEncObject *encvid, AVCCommonObj *video);
+
+
+    /**
+    This function is called for luma motion compensation.
+    \param "ref"    "Pointer to the origin of a reference luma."
+    \param "picwidth"   "Width of the picture."
+    \param "picheight"  "Height of the picture."
+    \param "x_pos"  "X-coordinate of the predicted block in quarter pel resolution."
+    \param "y_pos"  "Y-coordinate of the predicted block in quarter pel resolution."
+    \param "pred"   "Pointer to the output predicted block."
+    \param "pred_pitch" "Width of pred."
+    \param "blkwidth"   "Width of the current partition."
+    \param "blkheight"  "Height of the current partition."
+    \return "void"
+    */
+    void eLumaMotionComp(uint8 *ref, int picwidth, int picheight,
+                         int x_pos, int y_pos,
+                         uint8 *pred, int pred_pitch,
+                         int blkwidth, int blkheight);
+
+    void eFullPelMC(uint8 *in, int inwidth, uint8 *out, int outpitch,
+                    int blkwidth, int blkheight);
+
+    void eHorzInterp1MC(uint8 *in, int inpitch, uint8 *out, int outpitch,
+                        int blkwidth, int blkheight, int dx);
+
+    void eHorzInterp2MC(int *in, int inpitch, uint8 *out, int outpitch,
+                        int blkwidth, int blkheight, int dx);
+
+    void eHorzInterp3MC(uint8 *in, int inpitch, int *out, int outpitch,
+                        int blkwidth, int blkheight);
+
+    void eVertInterp1MC(uint8 *in, int inpitch, uint8 *out, int outpitch,
+                        int blkwidth, int blkheight, int dy);
+
+    void eVertInterp2MC(uint8 *in, int inpitch, int *out, int outpitch,
+                        int blkwidth, int blkheight);
+
+    void eVertInterp3MC(int *in, int inpitch, uint8 *out, int outpitch,
+                        int blkwidth, int blkheight, int dy);
+
+    void eDiagonalInterpMC(uint8 *in1, uint8 *in2, int inpitch,
+                           uint8 *out, int outpitch,
+                           int blkwidth, int blkheight);
+
+    void eChromaMotionComp(uint8 *ref, int picwidth, int picheight,
+                           int x_pos, int y_pos, uint8 *pred, int pred_pitch,
+                           int blkwidth, int blkheight);
+
+    void eChromaDiagonalMC_SIMD(uint8 *pRef, int srcPitch, int dx, int dy,
+                                uint8 *pOut, int predPitch, int blkwidth, int blkheight);
+
+    void eChromaHorizontalMC_SIMD(uint8 *pRef, int srcPitch, int dx, int dy,
+                                  uint8 *pOut, int predPitch, int blkwidth, int blkheight);
+
+    void eChromaVerticalMC_SIMD(uint8 *pRef, int srcPitch, int dx, int dy,
+                                uint8 *pOut, int predPitch, int blkwidth, int blkheight);
+
+    void eChromaFullMC_SIMD(uint8 *pRef, int srcPitch, int dx, int dy,
+                            uint8 *pOut, int predPitch, int blkwidth, int blkheight);
+
+    void eChromaVerticalMC2_SIMD(uint8 *pRef, int srcPitch, int dx, int dy,
+                                 uint8 *pOut, int predPitch, int blkwidth, int blkheight);
+
+    void eChromaHorizontalMC2_SIMD(uint8 *pRef, int srcPitch, int dx, int dy,
+                                   uint8 *pOut, int predPitch, int blkwidth, int blkheight);
+
+    void eChromaDiagonalMC2_SIMD(uint8 *pRef, int srcPitch, int dx, int dy,
+                                 uint8 *pOut, int predPitch, int blkwidth, int blkheight);
+
+
+    /*-------------- motion_est.c ---------------*/
+
+    /**
+    Allocate and initialize arrays necessary for motion search algorithm.
+    \param "envid" "Pointer to AVCEncObject."
+    \return "AVC_SUCCESS or AVC_MEMORY_FAIL."
+    */
+    AVCEnc_Status InitMotionSearchModule(AVCHandle *avcHandle);
+
+    /**
+    Clean up memory allocated in InitMotionSearchModule.
+    \param "envid" "Pointer to AVCEncObject."
+    \return "void."
+    */
+    void CleanMotionSearchModule(AVCHandle *avcHandle);
+
+
+    /**
+    This function performs motion estimation of all macroblocks in a frame during the InitFrame.
+    The goal is to find the best MB partition for inter and find out if intra search is needed for
+    any MBs. This intra MB tendency can be used for scene change detection.
+    \param "encvid" "Pointer to AVCEncObject."
+    \return "void"
+    */
+    void AVCMotionEstimation(AVCEncObject *encvid);
+
+    /**
+    This function performs repetitive edge padding to the reference picture by adding 16 pixels
+    around the luma and 8 pixels around the chromas.
+    \param "refPic" "Pointer to the reference picture."
+    \return "void"
+    */
+    void  AVCPaddingEdge(AVCPictureData *refPic);
+
+    /**
+    This function keeps track of intra refresh macroblock locations.
+    \param "encvid" "Pointer to the global array structure AVCEncObject."
+    \param "mblock" "Pointer to the array of AVCMacroblock structures."
+    \param "totalMB" "Total number of MBs in a frame."
+    \param "numRefresh" "Number of MB to be intra refresh in a single frame."
+    \return "void"
+    */
+    void AVCRasterIntraUpdate(AVCEncObject *encvid, AVCMacroblock *mblock, int totalMB, int numRefresh);
+
+#ifdef HTFM
+    void InitHTFM(VideoEncData *encvid, HTFM_Stat *htfm_stat, double *newvar, int *collect);
+    void UpdateHTFM(AVCEncObject *encvid, double *newvar, double *exp_lamda, HTFM_Stat *htfm_stat);
+    void CalcThreshold(double pf, double exp_lamda[], int nrmlz_th[]);
+    void    HTFMPrepareCurMB_AVC(AVCEncObject *encvid, HTFM_Stat *htfm_stat, uint8 *cur, int pitch);
+#endif
+
+    /**
+    This function reads the input MB into a smaller faster memory space to minimize the cache miss.
+    \param "encvid" "Pointer to the global AVCEncObject."
+    \param "cur"    "Pointer to the original input macroblock."
+    \param "pitch"  "Stride size of the input frame (luma)."
+    \return "void"
+    */
+    void    AVCPrepareCurMB(AVCEncObject *encvid, uint8 *cur, int pitch);
+
+    /**
+    Performs motion vector search for a macroblock.
+    \param "encvid" "Pointer to AVCEncObject structure."
+    \param "cur"    "Pointer to the current macroblock in the input frame."
+    \param "best_cand" "Array of best candidates (to be filled in and returned)."
+    \param "i0"     "X-coordinate of the macroblock."
+    \param "j0"     "Y-coordinate of the macroblock."
+    \param "type_pred" "Indicates the type of operations."
+    \param "FS_en"      "Flag for fullsearch enable."
+    \param "hp_guess"   "Guess for half-pel search."
+    \return "void"
+    */
+    void AVCMBMotionSearch(AVCEncObject *encvid, uint8 *cur, uint8 *best_cand[],
+                           int i0, int j0, int type_pred, int FS_en, int *hp_guess);
+
+//AVCEnc_Status AVCMBMotionSearch(AVCEncObject *encvid, AVCMacroblock *currMB, int mbNum,
+//                           int num_pass);
+
+    /**
+    Perform full-pel exhaustive search around the predicted MV.
+    \param "encvid" "Pointer to AVCEncObject structure."
+    \param "prev"   "Pointer to the reference frame."
+    \param "cur"    "Pointer to the input macroblock."
+    \param "imin"   "Pointer to minimal mv (x)."
+    \param "jmin"   "Pointer to minimal mv (y)."
+    \param "ilow, ihigh, jlow, jhigh"   "Lower bound on search range."
+    \param "cmvx, cmvy" "Predicted MV value."
+
+    \return "The cost function of the best candidate."
+    */
+    int AVCFullSearch(AVCEncObject *encvid, uint8 *prev, uint8 *cur,
+                      int *imin, int *jmin, int ilow, int ihigh, int jlow, int jhigh,
+                      int cmvx, int cmvy);
+
+    /**
+    Select candidates from neighboring blocks according to the type of the
+    prediction selection.
+    \param "mvx"    "Pointer to the candidate, x-coordinate."
+    \param "mvy"    "Pointer to the candidate, y-coordinate."
+    \param "num_can"    "Pointer to the number of candidates returned."
+    \param "imb"    "The MB index x-coordinate."
+    \param "jmb"    "The MB index y-coordinate."
+    \param "type_pred"  "Type of the prediction."
+    \param "cmvx, cmvy" "Pointer to predicted MV (modified version)."
+    \return "void."
+    */
+    void AVCCandidateSelection(int *mvx, int *mvy, int *num_can, int imb, int jmb,
+                               AVCEncObject *encvid, int type_pred, int *cmvx, int *cmvy);
+
+    /**
+    Utility function to move the values in the array dn according to the new
+    location to avoid redundant calculation.
+    \param "dn" "Array of integer of size 9."
+    \param "new_loc"    "New location index."
+    \return "void."
+    */
+    void AVCMoveNeighborSAD(int dn[], int new_loc);
+
+    /**
+    Find minimum index of dn.
+    \param "dn" "Array of integer of size 9."
+    \return "The index of dn with the smallest dn[] value."
+    */
+    int AVCFindMin(int dn[]);
+
+
+    /*------------- findhalfpel.c -------------------*/
+
+    /**
+    Search for the best half-pel resolution MV around the full-pel MV.
+    \param "encvid" "Pointer to the global AVCEncObject structure."
+    \param "cur"    "Pointer to the current macroblock."
+    \param "mot"    "Pointer to the AVCMV array of the frame."
+    \param "ncand"  "Pointer to the origin of the fullsearch result."
+    \param "xpos"   "The current MB position in x."
+    \param "ypos"   "The current MB position in y."
+    \param "hp_guess"   "Input to help speedup the search."
+    \param "cmvx, cmvy" "Predicted motion vector use for mvcost."
+    \return "Minimal cost (SATD) without MV cost. (for rate control purpose)"
+    */
+    int AVCFindHalfPelMB(AVCEncObject *encvid, uint8 *cur, AVCMV *mot, uint8 *ncand,
+                         int xpos, int ypos, int hp_guess, int cmvx, int cmvy);
+
+    /**
+    This function generates sub-pel pixels required to do subpel MV search.
+    \param "subpel_pred" "Pointer to 2-D array, each array for each position."
+    \param "ncand" "Pointer to the full-pel center position in ref frame."
+    \param "lx" "Pitch of the ref frame."
+    \return "void"
+     */
+    void GenerateHalfPelPred(uint8 *subpel_pred, uint8 *ncand, int lx);
+
+    /**
+    This function calculate vertical interpolation at half-point of size 4x17.
+    \param "dst" "Pointer to destination."
+    \param "ref" "Pointer to the starting reference pixel."
+    \return "void."
+    */
+    void VertInterpWClip(uint8 *dst, uint8 *ref);
+
+    /**
+    This function generates quarter-pel pixels around the best half-pel result
+    during the sub-pel MV search.
+    \param "bilin_base"  "Array of pointers to be used as basis for q-pel interp."
+    \param "qpel_pred"  "Array of pointers pointing to quarter-pel candidates."
+    \param "hpel_pos" "Best half-pel position at the center."
+    \return "void"
+    */
+    void GenerateQuartPelPred(uint8 **bilin_base, uint8 *qpel_pred, int hpel_pos);
+
+    /**
+    This function calculates the SATD of a subpel candidate.
+    \param "cand"   "Pointer to a candidate."
+    \param "cur"    "Pointer to the current block."
+    \param "dmin"   "Min-so-far SATD."
+    \return "Sum of Absolute Transformed Difference."
+    */
+    int SATD_MB(uint8 *cand, uint8 *cur, int dmin);
+
+    /*------------- rate_control.c -------------------*/
+
+    /** This function is a utility function. It returns average QP of the previously encoded frame.
+    \param "rateCtrl" "Pointer to AVCRateControl structure."
+    \return "Average QP."
+    */
+    int GetAvgFrameQP(AVCRateControl *rateCtrl);
+
+    /**
+    This function takes the timestamp of the input and determine whether it should be encoded
+    or skipped.
+    \param "encvid" "Pointer to the AVCEncObject structure."
+    \param "rateCtrl"   "Pointer to the AVCRateControl structure."
+    \param "modTime"    "The 32 bit timestamp of the input frame."
+    \param "frameNum"   "Pointer to the frame number if to be encoded."
+    \return "AVC_SUCCESS or else."
+    */
+    AVCEnc_Status RCDetermineFrameNum(AVCEncObject *encvid, AVCRateControl *rateCtrl, uint32 modTime, uint *frameNum);
+
+    /**
+    This function updates the buffer fullness when frames are dropped either by the
+    rate control algorithm or by the users to make sure that target bit rate is still met.
+    \param "video" "Pointer to the common object structure."
+    \param "rateCtrl" "Pointer to rate control structure."
+    \param "frameInc" "Difference of the current frame number and previous frame number."
+    \return "void."
+    */
+    void RCUpdateBuffer(AVCCommonObj *video, AVCRateControl *rateCtrl, int frameInc);
+
+    /**
+    This function initializes rate control module and allocates necessary bufferes to do the job.
+    \param "avcHandle" "Pointer to the encoder handle."
+    \return "AVCENC_SUCCESS or AVCENC_MEMORY_FAIL."
+    */
+    AVCEnc_Status InitRateControlModule(AVCHandle *avcHandle);
+
+    /**
+    This function frees buffers allocated in InitRateControlModule.
+    \param "avcHandle" "Pointer to the encoder handle."
+    \return "void."
+    */
+    void CleanupRateControlModule(AVCHandle *avcHandle);
+
+    /**
+    This function is called at the beginning of each GOP or the first IDR frame. It calculates
+    target bits for a GOP.
+    \param "encvid" "Pointer to the encoder object."
+    \return "void."
+    */
+    void RCInitGOP(AVCEncObject *encvid);
+
+    /**
+    This function calculates target bits for a particular frame.
+    \param "video"  "Pointer to the AVCEncObject structure."
+    \return "void"
+    */
+    void RCInitFrameQP(AVCEncObject *video);
+
+    /**
+    This function calculates QP for the upcoming frame or basic unit.
+    \param "encvid" "Pointer to the encoder object."
+    \param "rateCtrl" "Pointer to the rate control object."
+    \return "QP value ranging from 0-51."
+    */
+    int  RCCalculateQP(AVCEncObject *encvid, AVCRateControl *rateCtrl);
+
+    /**
+    This function translates the luma QP to chroma QP and calculates lambda based on QP.
+    \param "video"  "Pointer to the AVCEncObject structure."
+    \return "void"
+    */
+    void RCInitChromaQP(AVCEncObject *encvid);
+
+    /**
+    This function is called before encoding each macroblock.
+    \param "encvid" "Pointer to the encoder object."
+    \return "void."
+    */
+    void RCInitMBQP(AVCEncObject *encvid);
+
+    /**
+    This function updates bits usage stats after encoding an macroblock.
+    \param "video" "Pointer to AVCCommonObj."
+    \param "rateCtrl" "Pointer to AVCRateControl."
+    \param "num_header_bits" "Number of bits used for MB header."
+    \param "num_texture_bits" "Number of bits used for MB texture."
+    \return "void"
+    */
+    void RCPostMB(AVCCommonObj *video, AVCRateControl *rateCtrl, int num_header_bits, int num_texture_bits);
+
+    /**
+    This function calculates the difference between prediction and original MB.
+    \param "encvid" "Pointer to the encoder object."
+    \param "currMB" "Pointer to the current macroblock structure."
+    \param "orgL" "Pointer to the original MB."
+    \param "orgPitch" "Pointer to the original picture pitch."
+    \return "void."
+    */
+    void RCCalculateMAD(AVCEncObject *encvid, AVCMacroblock *currMB, uint8 *orgL, int orgPitch);
+
+    /**
+    Restore QP related parameters of previous MB when current MB is skipped.
+    \param "currMB" "Pointer to the current macroblock."
+    \param "video"  "Pointer to the common video structure."
+    \param "encvid" "Pointer to the global encoding structure."
+    \return "void"
+    */
+    void RCRestoreQP(AVCMacroblock *currMB, AVCCommonObj *video, AVCEncObject *encvid);
+
+    /**
+    This function is called after done with a frame.
+    \param "encvid" "Pointer to the encoder object."
+    \return "AVCENC_SUCCESS or AVCENC_SKIPPED_PICTURE when bufer overflow (need to discard current frame)."
+    */
+    AVCEnc_Status RCUpdateFrame(AVCEncObject *encvid);
+
+    /*--------- residual.c -------------------*/
+
+    /**
+    This function encodes the intra pcm data and fill it in the corresponding location
+    on the current picture.
+    \param "video"  "Pointer to AVCEncObject."
+    \return "AVCENC_SUCCESS if success, or else for bitstream errors."
+    */
+    AVCEnc_Status EncodeIntraPCM(AVCEncObject *video);
+
+    /**
+    This function performs CAVLC syntax encoding on the run and level information of the coefficients.
+    The level and run arrays are elements in AVCEncObject structure, populated by TransQuantZZ,
+    TransQuantIntraDC and TransQuantChromaDC functions.
+    \param "video"  "Pointer to AVCEncObject."
+    \param "type"   "One of AVCResidualType for a particular 4x4 block."
+    \param "bindx"  "Block index or number of nonzero coefficients for AVC_Intra16DC and AVC_ChromaDC mode."
+    \param "currMB" "Pointer to the current macroblock structure."
+    \return "AVCENC_SUCCESS for success."
+    \Note   "This function has 32-bit machine specific instruction!!!!"
+    */
+    AVCEnc_Status enc_residual_block(AVCEncObject *encvid, AVCResidualType type, int bindx, AVCMacroblock *currMB);
+
+
+    /*------------- sad.c ---------------------------*/
+
+
+    int AVCSAD_MB_HalfPel_Cxhyh(uint8 *ref, uint8 *blk, int dmin_lx, void *extra_info);
+    int AVCSAD_MB_HalfPel_Cyh(uint8 *ref, uint8 *blk, int dmin_lx, void *extra_info);
+    int AVCSAD_MB_HalfPel_Cxh(uint8 *ref, uint8 *blk, int dmin_lx, void *extra_info);
+    int AVCSAD_Macroblock_C(uint8 *ref, uint8 *blk, int dmin_lx, void *extra_info);
+
+#ifdef HTFM /*  3/2/1, Hypothesis Testing Fast Matching */
+    int AVCSAD_MB_HP_HTFM_Collectxhyh(uint8 *ref, uint8 *blk, int dmin_x, void *extra_info);
+    int AVCSAD_MB_HP_HTFM_Collectyh(uint8 *ref, uint8 *blk, int dmin_x, void *extra_info);
+    int AVCSAD_MB_HP_HTFM_Collectxh(uint8 *ref, uint8 *blk, int dmin_x, void *extra_info);
+    int AVCSAD_MB_HP_HTFMxhyh(uint8 *ref, uint8 *blk, int dmin_lx, void *extra_info);
+    int AVCSAD_MB_HP_HTFMyh(uint8 *ref, uint8 *blk, int dmin_lx, void *extra_info);
+    int AVCSAD_MB_HP_HTFMxh(uint8 *ref, uint8 *blk, int dmin_lx, void *extra_info);
+    int AVCSAD_MB_HTFM_Collect(uint8 *ref, uint8 *blk, int dmin_lx, void *extra_info);
+    int AVCSAD_MB_HTFM(uint8 *ref, uint8 *blk, int dmin_lx, void *extra_info);
+#endif
+
+
+    /*------------- slice.c -------------------------*/
+
+    /**
+    This function performs the main encoding loop for a slice.
+    \param "encvid" "Pointer to AVCEncObject."
+    \return "AVCENC_SUCCESS for success, AVCENC_PICTURE_READY for end-of-picture and
+             AVCENC_FAIL or AVCENC_SLICE_EMPTY otherwise."
+    */
+    AVCEnc_Status AVCEncodeSlice(AVCEncObject *encvid);
+
+    /**
+    This function performs the main encoding operation for one macroblock.
+    \param "video" "pointer to AVCEncObject."
+    \return "AVCENC_SUCCESS for success, or other bitstream related failure status."
+    */
+    AVCEnc_Status EncodeMB(AVCEncObject *video);
+
+    /**
+    This function calls prediction INTRA/INTER functions, transform,
+    quantization and zigzag scanning to get the run-level symbols.
+    \param "encvid" "pointer to AVCEncObject."
+    \param "curL"   "pointer to Luma component of the current frame.
+    \param "curCb"  "pointer to Cb component of the current frame.
+    \param "curCr"  "pointer to Cr component of the current frame.
+    \return "void for now."
+     */
+    void MBPredTransQuantZZ(AVCEncObject *encvid, uint8 *curL, uint8 *curCb, uint8 *curCr);
+
+    /**
+    This function copies the content of the prediction MB into the reconstructed YUV
+    frame directly.
+    \param "curL"   "Pointer to the destination Y component."
+    \param "curCb"  "Pointer to the destination Cb component."
+    \param "curCr"  "Pointer to the destination Cr component."
+    \param "predBlock"  "Pointer to the prediction MB."
+    \param "picWidth"   "The width of the frame."
+    \return "None."
+    */
+    void Copy_MB(uint8 *curL, uint8 *curCb, uint8 *curCr, uint8 *predBlock, int picWidth);
+
+    /**
+    This function encodes the mb_type, CBP, prediction mode, ref idx and MV.
+    \param "currMB" "Pointer to the current macroblock structure."
+    \param "video" "Pointer to the AVCEncObject structure."
+    \return "AVCENC_SUCCESS for success or else for fail."
+    */
+    AVCEnc_Status EncodeMBHeader(AVCMacroblock *currMB, AVCEncObject *video);
+
+    /**
+    This function finds the right mb_type for a macroblock given the mbMode, CBP,
+    NumPart, PredPartMode.
+    \param "currMB" "Pointer to the current macroblock structure."
+    \param "slice_type" "Value of the slice_type."
+    \return "mb_type."
+    */
+    uint InterpretMBType(AVCMacroblock *currMB, int slice_type);
+
+    /**
+    This function encodes the mb_pred part of the macroblock data.
+    \param "video"  "Pointer to the AVCCommonObj structure."
+    \param "currMB" "Pointer to the current macroblock structure."
+    \param "stream" "Pointer to the AVCEncBitstream structure."
+    \return "AVCENC_SUCCESS for success or bitstream fail status."
+    */
+    AVCEnc_Status mb_pred(AVCCommonObj *video, AVCMacroblock *currMB, AVCEncBitstream *stream);
+
+    /**
+    This function encodes the sub_mb_pred part of the macroblock data.
+    \param "video"  "Pointer to the AVCCommonObj structure."
+    \param "currMB" "Pointer to the current macroblock structure."
+    \param "stream" "Pointer to the AVCEncBitstream structure."
+    \return "AVCENC_SUCCESS for success or bitstream fail status."
+    */
+    AVCEnc_Status sub_mb_pred(AVCCommonObj *video, AVCMacroblock *currMB, AVCEncBitstream *stream);
+
+    /**
+    This function interprets the sub_mb_type and sets necessary information
+    when the slice type is AVC_P_SLICE.
+    in the macroblock structure.
+    \param "mblock" "Pointer to current AVCMacroblock."
+    \param "sub_mb_type" "From the syntax bitstream."
+    \return "void"
+    */
+    void InterpretSubMBTypeP(AVCMacroblock *mblock, uint *sub_mb_type);
+
+    /**
+    This function interprets the sub_mb_type and sets necessary information
+    when the slice type is AVC_B_SLICE.
+    in the macroblock structure.
+    \param "mblock" "Pointer to current AVCMacroblock."
+    \param "sub_mb_type" "From the syntax bitstream."
+    \return "void"
+    */
+    void InterpretSubMBTypeB(AVCMacroblock *mblock, uint *sub_mb_type);
+
+    /**
+    This function encodes intra 4x4 mode. It calculates the predicted I4x4 mode and the
+    remnant to be encoded.
+    \param "video"  "Pointer to AVCEncObject structure."
+    \param "currMB" "Pointer to the AVCMacroblock structure."
+    \param "stream" "Pointer to AVCEncBitstream sructure."
+    \return "AVCENC_SUCCESS for success."
+    */
+    AVCEnc_Status EncodeIntra4x4Mode(AVCCommonObj *video, AVCMacroblock *currMB, AVCEncBitstream *stream);
+
+    /*------------- vlc_encode.c -----------------------*/
+    /**
+    This function encodes and writes a value into an Exp-Golomb codeword.
+    \param "bitstream" "Pointer to AVCEncBitstream."
+    \param "codeNum" "Pointer to the value of the codeNum."
+    \return "AVCENC_SUCCESS for success or bitstream error messages for fail."
+    */
+    AVCEnc_Status ue_v(AVCEncBitstream *bitstream, uint codeNum);
+
+    /**
+    This function maps and encodes signed Exp-Golomb codes.
+    \param "bitstream" "Pointer to AVCEncBitstream."
+    \param "value"  "Pointer to syntax element value."
+    \return "AVCENC_SUCCESS or AVCENC_FAIL."
+    */
+    AVCEnc_Status  se_v(AVCEncBitstream *bitstream, int value);
+
+    /**
+    This function maps and encodes truncated Exp-Golomb codes.
+    \param "bitstream" "Pointer to AVCEncBitstream."
+    \param "value"  "Pointer to syntax element value."
+    \param "range"  "Range of the value as input to determine the algorithm."
+    \return "AVCENC_SUCCESS or AVCENC_FAIL."
+    */
+    AVCEnc_Status te_v(AVCEncBitstream *bitstream, uint value, uint range);
+
+    /**
+    This function creates Exp-Golomb codeword from codeNum.
+    \param "bitstream" "Pointer to AVCEncBitstream."
+    \param "codeNum" "Pointer to the codeNum value."
+    \return "AVCENC_SUCCESS for success or bitstream error messages for fail."
+    */
+    AVCEnc_Status SetEGBitstring(AVCEncBitstream *bitstream, uint codeNum);
+
+    /**
+    This function performs CAVLC encoding of the CBP (coded block pattern) of a macroblock
+    by calling ue_v() and then mapping the CBP to the corresponding VLC codeNum.
+    \param "currMB"  "Pointer to the current AVCMacroblock structure."
+    \param "stream"  "Pointer to the AVCEncBitstream."
+    \return "void"
+    */
+    AVCEnc_Status EncodeCBP(AVCMacroblock *currMB, AVCEncBitstream *stream);
+
+    /**
+    This function encodes trailing ones and total coefficient.
+    \param "stream" "Pointer to the AVCEncBitstream."
+    \param "TrailingOnes"   "The trailing one variable output."
+    \param "TotalCoeff" "The total coefficient variable output."
+    \param "nC" "Context for number of nonzero coefficient (prediction context)."
+    \return "AVCENC_SUCCESS for success or else for bitstream failure."
+    */
+    AVCEnc_Status ce_TotalCoeffTrailingOnes(AVCEncBitstream *stream, int TrailingOnes, int TotalCoeff, int nC);
+
+    /**
+    This function encodes trailing ones and total coefficient for chroma DC block.
+    \param "stream" "Pointer to the AVCEncBitstream."
+    \param "TrailingOnes"   "The trailing one variable output."
+    \param "TotalCoeff" "The total coefficient variable output."
+    \return "AVCENC_SUCCESS for success or else for bitstream failure."
+    */
+    AVCEnc_Status ce_TotalCoeffTrailingOnesChromaDC(AVCEncBitstream *stream, int TrailingOnes, int TotalCoeff);
+
+    /**
+    This function encodes total_zeros value as in Table 9-7 and 9-8.
+    \param "stream" "Pointer to the AVCEncBitstream."
+    \param "TotalZeros" "The total_zeros value."
+    \param "TotalCoeff" "The total coefficient variable output."
+    \return "AVCENC_SUCCESS for success or else for bitstream failure."
+    */
+    AVCEnc_Status ce_TotalZeros(AVCEncBitstream *stream, int total_zeros, int TotalCoeff);
+
+    /**
+    This function encodes total_zeros VLC syntax for chroma DC as in Table 9-9.
+    \param "stream" "Pointer to the AVCEncBitstream."
+    \param "TotalZeros" "The total_zeros value."
+    \param "TotalCoeff" "The total coefficient variable output."
+    \return "AVCENC_SUCCESS for success or else for bitstream failure."
+    */
+    AVCEnc_Status ce_TotalZerosChromaDC(AVCEncBitstream *stream, int total_zeros, int TotalCoeff);
+
+    /**
+    This function encodes run_before VLC syntax as in Table 9-10.
+    \param "stream" "Pointer to the AVCEncBitstream."
+    \param "run_before" "The run_before value."
+    \param "zerosLeft"  "The context for number of zeros left."
+    \return "AVCENC_SUCCESS for success or else for bitstream failure."
+    */
+    AVCEnc_Status ce_RunBefore(AVCEncBitstream *stream, int run_before, int zerosLeft);
+
+#ifdef __cplusplus
+}
+#endif
+
+
+#endif /* _AVCENC_LIB_H_ */
+
diff --git a/media/libstagefright/codecs/avc/enc/src/bitstream_io.cpp b/media/libstagefright/codecs/avc/enc/src/bitstream_io.cpp
new file mode 100644
index 0000000..75ab514
--- /dev/null
+++ b/media/libstagefright/codecs/avc/enc/src/bitstream_io.cpp
@@ -0,0 +1,336 @@
+/* ------------------------------------------------------------------
+ * Copyright (C) 1998-2009 PacketVideo
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
+ * express or implied.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ * -------------------------------------------------------------------
+ */
+#include "avcenc_lib.h"
+
+#define WORD_SIZE 32
+
+/* array for trailing bit pattern as function of number of bits */
+/* the first one is unused. */
+const static uint8 trailing_bits[9] = {0, 0x1, 0x2, 0x4, 0x8, 0x10, 0x20, 0x40, 0x80};
+
+/* ======================================================================== */
+/*  Function : BitstreamInit()                                              */
+/*  Date     : 11/4/2003                                                    */
+/*  Purpose  : Populate bitstream structure with bitstream buffer and size  */
+/*             it also initializes internal data                            */
+/*  In/out   :                                                              */
+/*  Return   : AVCENC_SUCCESS if successed, AVCENC_FAIL if failed.              */
+/*  Modified :                                                              */
+/* ======================================================================== */
+/* |--------|--------|----~~~~~-----|---------|---------|---------|
+   ^                                          ^write_pos          ^buf_size
+   bitstreamBuffer                  <--------->
+                                    current_word
+
+   |-----xxxxxxxxxxxxx|  = current_word 32 or 16 bits
+    <---->
+     bit_left
+ ======================================================================== */
+
+AVCEnc_Status BitstreamEncInit(AVCEncBitstream *stream, uint8 *buffer, int buf_size,
+                               uint8 *overrunBuffer, int oBSize)
+{
+    if (stream == NULL || buffer == NULL || buf_size <= 0)
+    {
+        return AVCENC_BITSTREAM_INIT_FAIL;
+    }
+
+    stream->bitstreamBuffer = buffer;
+
+    stream->buf_size = buf_size;
+
+    stream->write_pos = 0;
+
+    stream->count_zeros = 0;
+
+    stream->current_word = 0;
+
+    stream->bit_left = WORD_SIZE;
+
+    stream->overrunBuffer = overrunBuffer;
+
+    stream->oBSize = oBSize;
+
+    return AVCENC_SUCCESS;
+}
+
+/* ======================================================================== */
+/*  Function : AVCBitstreamSaveWord()                                           */
+/*  Date     : 3/29/2004                                                    */
+/*  Purpose  : Save the current_word into the buffer, byte-swap, and        */
+/*              add emulation prevention insertion.                         */
+/*  In/out   :                                                              */
+/*  Return   : AVCENC_SUCCESS if successed, AVCENC_WRITE_FAIL if buffer is  */
+/*              full.                                                       */
+/*  Modified :                                                              */
+/* ======================================================================== */
+AVCEnc_Status AVCBitstreamSaveWord(AVCEncBitstream *stream)
+{
+    int num_bits;
+    uint8 *write_pnt, byte;
+    uint current_word;
+
+    /* check number of bytes in current_word, must always be byte-aligned!!!! */
+    num_bits = WORD_SIZE - stream->bit_left; /* must be multiple of 8 !!*/
+
+    if (stream->buf_size - stream->write_pos <= (num_bits >> 3) + 2) /* 2 more bytes for possible EPBS */
+    {
+        if (AVCENC_SUCCESS != AVCBitstreamUseOverrunBuffer(stream, (num_bits >> 3) + 2))
+        {
+            return AVCENC_BITSTREAM_BUFFER_FULL;
+        }
+    }
+
+    /* write word, byte-by-byte */
+    write_pnt = stream->bitstreamBuffer + stream->write_pos;
+    current_word = stream->current_word;
+    while (num_bits) /* no need to check stream->buf_size and stream->write_pos, taken care already */
+    {
+        num_bits -= 8;
+        byte = (current_word >> num_bits) & 0xFF;
+        if (byte != 0)
+        {
+            *write_pnt++ = byte;
+            stream->write_pos++;
+            stream->count_zeros = 0;
+        }
+        else
+        {
+            stream->count_zeros++;
+            *write_pnt++ = byte;
+            stream->write_pos++;
+            if (stream->count_zeros == 2)
+            {   /* for num_bits = 32, this can add 2 more bytes extra for EPBS */
+                *write_pnt++ = 0x3;
+                stream->write_pos++;
+                stream->count_zeros = 0;
+            }
+        }
+    }
+
+    /* reset current_word and bit_left */
+    stream->current_word = 0;
+    stream->bit_left = WORD_SIZE;
+
+    return AVCENC_SUCCESS;
+}
+
+/* ======================================================================== */
+/*  Function : BitstreamWriteBits()                                         */
+/*  Date     : 3/29/2004                                                    */
+/*  Purpose  : Write up to machine word.                                    */
+/*  In/out   : Unused bits in 'code' must be all zeros.                     */
+/*  Return   : AVCENC_SUCCESS if successed, AVCENC_WRITE_FAIL if buffer is  */
+/*              full.                                                       */
+/*  Modified :                                                              */
+/* ======================================================================== */
+AVCEnc_Status BitstreamWriteBits(AVCEncBitstream *stream, int nBits, uint code)
+{
+    AVCEnc_Status status = AVCENC_SUCCESS;
+    int bit_left = stream->bit_left;
+    uint current_word = stream->current_word;
+
+    //DEBUG_LOG(userData,AVC_LOGTYPE_INFO,"BitstreamWriteBits",nBits,-1);
+
+    if (nBits > WORD_SIZE) /* has to be taken care of specially */
+    {
+        return AVCENC_FAIL; /* for now */
+        /* otherwise, break it down to 2 write of less than 16 bits at a time. */
+    }
+
+    if (nBits <= bit_left) /* more bits left in current_word */
+    {
+        stream->current_word = (current_word << nBits) | code;
+        stream->bit_left -= nBits;
+        if (stream->bit_left == 0) /* prepare for the next word */
+        {
+            status = AVCBitstreamSaveWord(stream);
+            return status;
+        }
+    }
+    else
+    {
+        stream->current_word = (current_word << bit_left) | (code >> (nBits - bit_left));
+
+        nBits -= bit_left;
+
+        stream->bit_left = 0;
+
+        status = AVCBitstreamSaveWord(stream); /* save current word */
+
+        stream->bit_left = WORD_SIZE - nBits;
+
+        stream->current_word = code; /* no extra masking for code, must be handled before saving */
+    }
+
+    return status;
+}
+
+
+/* ======================================================================== */
+/*  Function : BitstreamWrite1Bit()                                         */
+/*  Date     : 3/30/2004                                                    */
+/*  Purpose  : Write 1 bit                                                  */
+/*  In/out   : Unused bits in 'code' must be all zeros.                     */
+/*  Return   : AVCENC_SUCCESS if successed, AVCENC_WRITE_FAIL if buffer is  */
+/*              full.                                                       */
+/*  Modified :                                                              */
+/* ======================================================================== */
+AVCEnc_Status BitstreamWrite1Bit(AVCEncBitstream *stream, uint code)
+{
+    AVCEnc_Status status;
+    uint current_word = stream->current_word;
+
+    //DEBUG_LOG(userData,AVC_LOGTYPE_INFO,"BitstreamWrite1Bit",code,-1);
+
+    //if(1 <= bit_left) /* more bits left in current_word */
+    /* we can assume that there always be positive bit_left in the current word */
+    stream->current_word = (current_word << 1) | code;
+    stream->bit_left--;
+    if (stream->bit_left == 0) /* prepare for the next word */
+    {
+        status = AVCBitstreamSaveWord(stream);
+        return status;
+    }
+
+    return AVCENC_SUCCESS;
+}
+
+
+/* ======================================================================== */
+/*  Function : BitstreamTrailingBits()                                      */
+/*  Date     : 3/31/2004                                                    */
+/*  Purpose  : Add trailing bits and report the final EBSP size.            */
+/*  In/out   :                                                              */
+/*  Return   : AVCENC_SUCCESS if successed, AVCENC_WRITE_FAIL if buffer is  */
+/*              full.                                                       */
+/*  Modified :                                                              */
+/* ======================================================================== */
+AVCEnc_Status BitstreamTrailingBits(AVCEncBitstream *bitstream, uint *nal_size)
+{
+    (void)(nal_size);
+
+    AVCEnc_Status status;
+    int bit_left = bitstream->bit_left;
+
+    bit_left &= 0x7; /* modulo by 8 */
+    if (bit_left == 0) bit_left = 8;
+    /* bitstream->bit_left == 0 cannot happen here since it would have been Saved already */
+
+    status = BitstreamWriteBits(bitstream, bit_left, trailing_bits[bit_left]);
+
+    if (status != AVCENC_SUCCESS)
+    {
+        return status;
+    }
+
+    /* if it's not saved, save it. */
+    //if(bitstream->bit_left<(WORD_SIZE<<3)) /* in fact, no need to check */
+    {
+        status = AVCBitstreamSaveWord(bitstream);
+    }
+
+    return status;
+}
+
+/* check whether it's byte-aligned */
+bool byte_aligned(AVCEncBitstream *stream)
+{
+    if (stream->bit_left % 8)
+        return false;
+    else
+        return true;
+}
+
+
+/* determine whether overrun buffer can be used or not */
+AVCEnc_Status AVCBitstreamUseOverrunBuffer(AVCEncBitstream* stream, int numExtraBytes)
+{
+    AVCEncObject *encvid = (AVCEncObject*)stream->encvid;
+
+    if (stream->overrunBuffer != NULL) // overrunBuffer is set
+    {
+        if (stream->bitstreamBuffer != stream->overrunBuffer) // not already used
+        {
+            if (stream->write_pos + numExtraBytes >= stream->oBSize)
+            {
+                stream->oBSize = stream->write_pos + numExtraBytes + 100;
+                stream->oBSize &= (~0x3); // make it multiple of 4
+
+                // allocate new overrun Buffer
+                if (encvid->overrunBuffer)
+                {
+                    encvid->avcHandle->CBAVC_Free((uint32*)encvid->avcHandle->userData,
+                                                  (int)encvid->overrunBuffer);
+                }
+
+                encvid->oBSize = stream->oBSize;
+                encvid->overrunBuffer = (uint8*) encvid->avcHandle->CBAVC_Malloc(encvid->avcHandle->userData,
+                                        stream->oBSize, DEFAULT_ATTR);
+
+                stream->overrunBuffer = encvid->overrunBuffer;
+                if (stream->overrunBuffer == NULL)
+                {
+                    return AVCENC_FAIL;
+                }
+            }
+
+            // copy everything to overrun buffer and start using it.
+            memcpy(stream->overrunBuffer, stream->bitstreamBuffer, stream->write_pos);
+            stream->bitstreamBuffer = stream->overrunBuffer;
+            stream->buf_size = stream->oBSize;
+        }
+        else // overrun buffer is already used
+        {
+            stream->oBSize = stream->write_pos + numExtraBytes + 100;
+            stream->oBSize &= (~0x3); // make it multiple of 4
+
+            // allocate new overrun buffer
+            encvid->oBSize = stream->oBSize;
+            encvid->overrunBuffer = (uint8*) encvid->avcHandle->CBAVC_Malloc(encvid->avcHandle->userData,
+                                    stream->oBSize, DEFAULT_ATTR);
+
+            if (encvid->overrunBuffer == NULL)
+            {
+                return AVCENC_FAIL;
+            }
+
+
+            // copy from the old buffer to new buffer
+            memcpy(encvid->overrunBuffer, stream->overrunBuffer, stream->write_pos);
+            // free old buffer
+            encvid->avcHandle->CBAVC_Free((uint32*)encvid->avcHandle->userData,
+                                          (int)stream->overrunBuffer);
+
+            // assign pointer to new buffer
+            stream->overrunBuffer = encvid->overrunBuffer;
+            stream->bitstreamBuffer = stream->overrunBuffer;
+            stream->buf_size = stream->oBSize;
+        }
+
+        return AVCENC_SUCCESS;
+    }
+    else // overrunBuffer is not enable.
+    {
+        return AVCENC_FAIL;
+    }
+
+}
+
+
+
diff --git a/media/libstagefright/codecs/avc/enc/src/block.cpp b/media/libstagefright/codecs/avc/enc/src/block.cpp
new file mode 100644
index 0000000..01e26a6
--- /dev/null
+++ b/media/libstagefright/codecs/avc/enc/src/block.cpp
@@ -0,0 +1,1283 @@
+/* ------------------------------------------------------------------
+ * Copyright (C) 1998-2009 PacketVideo
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
+ * express or implied.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ * -------------------------------------------------------------------
+ */
+#include "avcenc_lib.h"
+
+/* subtract with the prediction and do transformation */
+void trans(uint8 *cur, int pitch, uint8 *predBlock, int16 *dataBlock)
+{
+    int16 *ptr = dataBlock;
+    int r0, r1, r2, r3, j;
+    int curpitch = (uint)pitch >> 16;
+    int predpitch = (pitch & 0xFFFF);
+
+    /* horizontal */
+    j = 4;
+    while (j > 0)
+    {
+        /* calculate the residue first */
+        r0 = cur[0] - predBlock[0];
+        r1 = cur[1] - predBlock[1];
+        r2 = cur[2] - predBlock[2];
+        r3 = cur[3] - predBlock[3];
+
+        r0 += r3;           //ptr[0] + ptr[3];
+        r3 = r0 - (r3 << 1);    //ptr[0] - ptr[3];
+        r1 += r2;           //ptr[1] + ptr[2];
+        r2 = r1 - (r2 << 1);    //ptr[1] - ptr[2];
+
+        ptr[0] = r0 + r1;
+        ptr[2] = r0 - r1;
+        ptr[1] = (r3 << 1) + r2;
+        ptr[3] = r3 - (r2 << 1);
+
+        ptr += 16;
+        predBlock += predpitch;
+        cur += curpitch;
+        j--;
+    }
+    /* vertical */
+    ptr = dataBlock;
+    j = 4;
+    while (j > 0)
+    {
+        r0 = ptr[0] + ptr[48];
+        r3 = ptr[0] - ptr[48];
+        r1 = ptr[16] + ptr[32];
+        r2 = ptr[16] - ptr[32];
+
+        ptr[0] = r0 + r1;
+        ptr[32] = r0 - r1;
+        ptr[16] = (r3 << 1) + r2;
+        ptr[48] = r3 - (r2 << 1);
+
+        ptr++;
+        j--;
+    }
+
+    return ;
+}
+
+
+/* do residue transform quant invquant, invtrans and write output out */
+int dct_luma(AVCEncObject *encvid, int blkidx, uint8 *cur, uint8 *org, int *coef_cost)
+{
+    AVCCommonObj *video = encvid->common;
+    int org_pitch = encvid->currInput->pitch;
+    int pitch = video->currPic->pitch;
+    int16 *coef = video->block;
+    uint8 *pred = video->pred_block; // size 16 for a 4x4 block
+    int pred_pitch = video->pred_pitch;
+    int r0, r1, r2, r3, j, k, idx;
+    int *level, *run;
+    int Qq, Rq, q_bits, qp_const, quant;
+    int data, lev, zero_run;
+    int numcoeff;
+
+    coef += ((blkidx & 0x3) << 2) + ((blkidx >> 2) << 6); /* point to the 4x4 block */
+
+    /* first take a 4x4 transform */
+    /* horizontal */
+    j = 4;
+    while (j > 0)
+    {
+        /* calculate the residue first */
+        r0 = org[0] - pred[0];   /* OPTIMIZEABLE */
+        r1 = org[1] - pred[1];
+        r2 = org[2] - pred[2];
+        r3 = org[3] - pred[3];
+
+        r0 += r3;           //ptr[0] + ptr[3];
+        r3 = r0 - (r3 << 1);    //ptr[0] - ptr[3];
+        r1 += r2;           //ptr[1] + ptr[2];
+        r2 = r1 - (r2 << 1);    //ptr[1] - ptr[2];
+
+        coef[0] = r0 + r1;
+        coef[2] = r0 - r1;
+        coef[1] = (r3 << 1) + r2;
+        coef[3] = r3 - (r2 << 1);
+
+        coef += 16;
+        org += org_pitch;
+        pred += pred_pitch;
+        j--;
+    }
+    /* vertical */
+    coef -= 64;
+    pred -= (pred_pitch << 2);
+    j = 4;
+    while (j > 0)   /* OPTIMIZABLE */
+    {
+        r0 = coef[0] + coef[48];
+        r3 = coef[0] - coef[48];
+        r1 = coef[16] + coef[32];
+        r2 = coef[16] - coef[32];
+
+        coef[0] = r0 + r1;
+        coef[32] = r0 - r1;
+        coef[16] = (r3 << 1) + r2;
+        coef[48] = r3 - (r2 << 1);
+
+        coef++;
+        j--;
+    }
+
+    coef -= 4;
+
+    /* quant */
+    level = encvid->level[ras2dec[blkidx]];
+    run = encvid->run[ras2dec[blkidx]];
+
+    Rq = video->QPy_mod_6;
+    Qq = video->QPy_div_6;
+    qp_const = encvid->qp_const;
+    q_bits = 15 + Qq;
+
+    zero_run = 0;
+    numcoeff = 0;
+    for (k = 0; k < 16; k++)
+    {
+        idx = ZZ_SCAN_BLOCK[k]; /* map back to raster scan order */
+        data = coef[idx];
+        quant = quant_coef[Rq][k];
+        if (data > 0)
+        {
+            lev = data * quant + qp_const;
+        }
+        else
+        {
+            lev = -data * quant + qp_const;
+        }
+        lev >>= q_bits;
+        if (lev)
+        {
+            *coef_cost += ((lev > 1) ? MAX_VALUE : COEFF_COST[DISABLE_THRESHOLDING][zero_run]);
+
+            /* dequant */
+            quant = dequant_coefres[Rq][k];
+            if (data > 0)
+            {
+                level[numcoeff] = lev;
+                coef[idx] = (lev * quant) << Qq;
+            }
+            else
+            {
+                level[numcoeff] = -lev;
+                coef[idx] = (-lev * quant) << Qq;
+            }
+            run[numcoeff++] = zero_run;
+            zero_run = 0;
+        }
+        else
+        {
+            zero_run++;
+            coef[idx] = 0;
+        }
+    }
+
+    if (video->currMB->mb_intra) // only do inverse transform with intra block
+    {
+        if (numcoeff) /* then do inverse transform */
+        {
+            for (j = 4; j > 0; j--) /* horizontal */
+            {
+                r0 = coef[0] + coef[2];
+                r1 = coef[0] - coef[2];
+                r2 = (coef[1] >> 1) - coef[3];
+                r3 = coef[1] + (coef[3] >> 1);
+
+                coef[0] = r0 + r3;
+                coef[1] = r1 + r2;
+                coef[2] = r1 - r2;
+                coef[3] = r0 - r3;
+
+                coef += 16;
+            }
+
+            coef -= 64;
+            for (j = 4; j > 0; j--) /* vertical, has to be done after horizontal */
+            {
+                r0 = coef[0] + coef[32];
+                r1 = coef[0] - coef[32];
+                r2 = (coef[16] >> 1) - coef[48];
+                r3 = coef[16] + (coef[48] >> 1);
+                r0 += r3;
+                r3 = (r0 - (r3 << 1)); /* r0-r3 */
+                r1 += r2;
+                r2 = (r1 - (r2 << 1)); /* r1-r2 */
+                r0 += 32;
+                r1 += 32;
+                r2 += 32;
+                r3 += 32;
+
+                r0 = pred[0] + (r0 >> 6);
+                if ((uint)r0 > 0xFF)   r0 = 0xFF & (~(r0 >> 31));  /* clip */
+                r1 = *(pred += pred_pitch) + (r1 >> 6);
+                if ((uint)r1 > 0xFF)   r1 = 0xFF & (~(r1 >> 31));  /* clip */
+                r2 = *(pred += pred_pitch) + (r2 >> 6);
+                if ((uint)r2 > 0xFF)   r2 = 0xFF & (~(r2 >> 31));  /* clip */
+                r3 = pred[pred_pitch] + (r3 >> 6);
+                if ((uint)r3 > 0xFF)   r3 = 0xFF & (~(r3 >> 31));  /* clip */
+
+                *cur = r0;
+                *(cur += pitch) = r1;
+                *(cur += pitch) = r2;
+                cur[pitch] = r3;
+                cur -= (pitch << 1);
+                cur++;
+                pred -= (pred_pitch << 1);
+                pred++;
+                coef++;
+            }
+        }
+        else  // copy from pred to cur
+        {
+            *((uint32*)cur) = *((uint32*)pred);
+            *((uint32*)(cur += pitch)) = *((uint32*)(pred += pred_pitch));
+            *((uint32*)(cur += pitch)) = *((uint32*)(pred += pred_pitch));
+            *((uint32*)(cur += pitch)) = *((uint32*)(pred += pred_pitch));
+        }
+    }
+
+    return numcoeff;
+}
+
+
+void MBInterIdct(AVCCommonObj *video, uint8 *curL, AVCMacroblock *currMB, int picPitch)
+{
+    int16 *coef, *coef8 = video->block;
+    uint8 *cur;  // the same as curL
+    int b8, b4;
+    int r0, r1, r2, r3, j, blkidx;
+
+    for (b8 = 0; b8 < 4; b8++)
+    {
+        cur = curL;
+        coef = coef8;
+
+        if (currMB->CBP&(1 << b8))
+        {
+            for (b4 = 0; b4 < 4; b4++)
+            {
+                blkidx = blkIdx2blkXY[b8][b4];
+                /* do IDCT */
+                if (currMB->nz_coeff[blkidx])
+                {
+                    for (j = 4; j > 0; j--) /* horizontal */
+                    {
+                        r0 = coef[0] + coef[2];
+                        r1 = coef[0] - coef[2];
+                        r2 = (coef[1] >> 1) - coef[3];
+                        r3 = coef[1] + (coef[3] >> 1);
+
+                        coef[0] = r0 + r3;
+                        coef[1] = r1 + r2;
+                        coef[2] = r1 - r2;
+                        coef[3] = r0 - r3;
+
+                        coef += 16;
+                    }
+
+                    coef -= 64;
+                    for (j = 4; j > 0; j--) /* vertical, has to be done after horizontal */
+                    {
+                        r0 = coef[0] + coef[32];
+                        r1 = coef[0] - coef[32];
+                        r2 = (coef[16] >> 1) - coef[48];
+                        r3 = coef[16] + (coef[48] >> 1);
+                        r0 += r3;
+                        r3 = (r0 - (r3 << 1)); /* r0-r3 */
+                        r1 += r2;
+                        r2 = (r1 - (r2 << 1)); /* r1-r2 */
+                        r0 += 32;
+                        r1 += 32;
+                        r2 += 32;
+                        r3 += 32;
+
+                        r0 = cur[0] + (r0 >> 6);
+                        if ((uint)r0 > 0xFF)   r0 = 0xFF & (~(r0 >> 31));  /* clip */
+                        *cur = r0;
+                        r1 = *(cur += picPitch) + (r1 >> 6);
+                        if ((uint)r1 > 0xFF)   r1 = 0xFF & (~(r1 >> 31));  /* clip */
+                        *cur = r1;
+                        r2 = *(cur += picPitch) + (r2 >> 6);
+                        if ((uint)r2 > 0xFF)   r2 = 0xFF & (~(r2 >> 31));  /* clip */
+                        *cur = r2;
+                        r3 = cur[picPitch] + (r3 >> 6);
+                        if ((uint)r3 > 0xFF)   r3 = 0xFF & (~(r3 >> 31));  /* clip */
+                        cur[picPitch] = r3;
+
+                        cur -= (picPitch << 1);
+                        cur++;
+                        coef++;
+                    }
+                    cur -= 4;
+                    coef -= 4;
+                }
+                if (b4&1)
+                {
+                    cur += ((picPitch << 2) - 4);
+                    coef += 60;
+                }
+                else
+                {
+                    cur += 4;
+                    coef += 4;
+                }
+            }
+        }
+
+        if (b8&1)
+        {
+            curL += ((picPitch << 3) - 8);
+            coef8 += 120;
+        }
+        else
+        {
+            curL += 8;
+            coef8 += 8;
+        }
+    }
+
+    return ;
+}
+
+/* performa dct, quant, iquant, idct for the entire MB */
+void dct_luma_16x16(AVCEncObject *encvid, uint8 *curL, uint8 *orgL)
+{
+    AVCCommonObj *video = encvid->common;
+    int pitch = video->currPic->pitch;
+    int org_pitch = encvid->currInput->pitch;
+    AVCMacroblock *currMB = video->currMB;
+    int16 *coef = video->block;
+    uint8 *pred = encvid->pred_i16[currMB->i16Mode];
+    int blk_x, blk_y, j, k, idx, b8, b4;
+    int r0, r1, r2, r3, m0, m1, m2 , m3;
+    int data, lev;
+    int *level, *run, zero_run, ncoeff;
+    int Rq, Qq, quant, q_bits, qp_const;
+    int offset_cur[4], offset_pred[4], offset;
+
+    /* horizontal */
+    for (j = 16; j > 0; j--)
+    {
+        for (blk_x = 4; blk_x > 0; blk_x--)
+        {
+            /* calculate the residue first */
+            r0 = *orgL++ - *pred++;
+            r1 = *orgL++ - *pred++;
+            r2 = *orgL++ - *pred++;
+            r3 = *orgL++ - *pred++;
+
+            r0 += r3;           //ptr[0] + ptr[3];
+            r3 = r0 - (r3 << 1);    //ptr[0] - ptr[3];
+            r1 += r2;           //ptr[1] + ptr[2];
+            r2 = r1 - (r2 << 1);    //ptr[1] - ptr[2];
+
+            *coef++ = r0 + r1;
+            *coef++ = (r3 << 1) + r2;
+            *coef++ = r0 - r1;
+            *coef++ = r3 - (r2 << 1);
+        }
+        orgL += (org_pitch - 16);
+    }
+    pred -= 256;
+    coef -= 256;
+    /* vertical */
+    for (blk_y = 4; blk_y > 0; blk_y--)
+    {
+        for (j = 16; j > 0; j--)
+        {
+            r0 = coef[0] + coef[48];
+            r3 = coef[0] - coef[48];
+            r1 = coef[16] + coef[32];
+            r2 = coef[16] - coef[32];
+
+            coef[0] = r0 + r1;
+            coef[32] = r0 - r1;
+            coef[16] = (r3 << 1) + r2;
+            coef[48] = r3 - (r2 << 1);
+
+            coef++;
+        }
+        coef += 48;
+    }
+
+    /* then perform DC transform */
+    coef -= 256;
+    for (j = 4; j > 0; j--)
+    {
+        r0 = coef[0] + coef[12];
+        r3 = coef[0] - coef[12];
+        r1 = coef[4] + coef[8];
+        r2 = coef[4] - coef[8];
+
+        coef[0] = r0 + r1;
+        coef[8] = r0 - r1;
+        coef[4] = r3 + r2;
+        coef[12] = r3 - r2;
+        coef += 64;
+    }
+    coef -= 256;
+    for (j = 4; j > 0; j--)
+    {
+        r0 = coef[0] + coef[192];
+        r3 = coef[0] - coef[192];
+        r1 = coef[64] + coef[128];
+        r2 = coef[64] - coef[128];
+
+        coef[0] = (r0 + r1) >> 1;
+        coef[128] = (r0 - r1) >> 1;
+        coef[64] = (r3 + r2) >> 1;
+        coef[192] = (r3 - r2) >> 1;
+        coef += 4;
+    }
+
+    coef -= 16;
+    // then quantize DC
+    level = encvid->leveldc;
+    run = encvid->rundc;
+
+    Rq = video->QPy_mod_6;
+    Qq = video->QPy_div_6;
+    quant = quant_coef[Rq][0];
+    q_bits = 15 + Qq;
+    qp_const = encvid->qp_const;
+
+    zero_run = 0;
+    ncoeff = 0;
+    for (k = 0; k < 16; k++) /* in zigzag scan order */
+    {
+        idx = ZIGZAG2RASTERDC[k];
+        data = coef[idx];
+        if (data > 0)   // quant
+        {
+            lev = data * quant + (qp_const << 1);
+        }
+        else
+        {
+            lev = -data * quant + (qp_const << 1);
+        }
+        lev >>= (q_bits + 1);
+        if (lev) // dequant
+        {
+            if (data > 0)
+            {
+                level[ncoeff] = lev;
+                coef[idx] = lev;
+            }
+            else
+            {
+                level[ncoeff] = -lev;
+                coef[idx] = -lev;
+            }
+            run[ncoeff++] = zero_run;
+            zero_run = 0;
+        }
+        else
+        {
+            zero_run++;
+            coef[idx] = 0;
+        }
+    }
+
+    /* inverse transform DC */
+    encvid->numcoefdc = ncoeff;
+    if (ncoeff)
+    {
+        quant = dequant_coefres[Rq][0];
+
+        for (j = 0; j < 4; j++)
+        {
+            m0 = coef[0] + coef[4];
+            m1 = coef[0] - coef[4];
+            m2 = coef[8] + coef[12];
+            m3 = coef[8] - coef[12];
+
+
+            coef[0] = m0 + m2;
+            coef[4] = m0 - m2;
+            coef[8] = m1 - m3;
+            coef[12] = m1 + m3;
+            coef += 64;
+        }
+
+        coef -= 256;
+
+        if (Qq >= 2)  /* this way should be faster than JM */
+        {           /* they use (((m4*scale)<<(QPy/6))+2)>>2 for both cases. */
+            Qq -= 2;
+            for (j = 0; j < 4; j++)
+            {
+                m0 = coef[0] + coef[64];
+                m1 = coef[0] - coef[64];
+                m2 = coef[128] + coef[192];
+                m3 = coef[128] - coef[192];
+
+                coef[0] = ((m0 + m2) * quant) << Qq;
+                coef[64] = ((m0 - m2) * quant) << Qq;
+                coef[128] = ((m1 - m3) * quant) << Qq;
+                coef[192] = ((m1 + m3) * quant) << Qq;
+                coef += 4;
+            }
+            Qq += 2; /* restore the value */
+        }
+        else
+        {
+            Qq = 2 - Qq;
+            offset = 1 << (Qq - 1);
+
+            for (j = 0; j < 4; j++)
+            {
+                m0 = coef[0] + coef[64];
+                m1 = coef[0] - coef[64];
+                m2 = coef[128] + coef[192];
+                m3 = coef[128] - coef[192];
+
+                coef[0] = (((m0 + m2) * quant + offset) >> Qq);
+                coef[64] = (((m0 - m2) * quant + offset) >> Qq);
+                coef[128] = (((m1 - m3) * quant + offset) >> Qq);
+                coef[192] = (((m1 + m3) * quant + offset) >> Qq);
+                coef += 4;
+            }
+            Qq = 2 - Qq; /* restore the value */
+        }
+        coef -= 16; /* back to the origin */
+    }
+
+    /* now zigzag scan ac coefs, quant, iquant and itrans */
+    run = encvid->run[0];
+    level = encvid->level[0];
+
+    /* offset btw 4x4 block */
+    offset_cur[0] = 0;
+    offset_cur[1] = (pitch << 2) - 8;
+
+    /* offset btw 8x8 block */
+    offset_cur[2] = 8 - (pitch << 3);
+    offset_cur[3] = -8;
+
+    /* similarly for pred */
+    offset_pred[0] = 0;
+    offset_pred[1] = 56;
+    offset_pred[2] = -120;
+    offset_pred[3] = -8;
+
+    currMB->CBP = 0;
+
+    for (b8 = 0; b8 < 4; b8++)
+    {
+        for (b4 = 0; b4 < 4; b4++)
+        {
+
+            zero_run = 0;
+            ncoeff = 0;
+
+            for (k = 1; k < 16; k++)
+            {
+                idx = ZZ_SCAN_BLOCK[k]; /* map back to raster scan order */
+                data = coef[idx];
+                quant = quant_coef[Rq][k];
+                if (data > 0)
+                {
+                    lev = data * quant + qp_const;
+                }
+                else
+                {
+                    lev = -data * quant + qp_const;
+                }
+                lev >>= q_bits;
+                if (lev)
+                {   /* dequant */
+                    quant = dequant_coefres[Rq][k];
+                    if (data > 0)
+                    {
+                        level[ncoeff] = lev;
+                        coef[idx] = (lev * quant) << Qq;
+                    }
+                    else
+                    {
+                        level[ncoeff] = -lev;
+                        coef[idx] = (-lev * quant) << Qq;
+                    }
+                    run[ncoeff++] = zero_run;
+                    zero_run = 0;
+                }
+                else
+                {
+                    zero_run++;
+                    coef[idx] = 0;
+                }
+            }
+
+            currMB->nz_coeff[blkIdx2blkXY[b8][b4]] = ncoeff; /* in raster scan !!! */
+            if (ncoeff)
+            {
+                currMB->CBP |= (1 << b8);
+
+                // do inverse transform here
+                for (j = 4; j > 0; j--)
+                {
+                    r0 = coef[0] + coef[2];
+                    r1 = coef[0] - coef[2];
+                    r2 = (coef[1] >> 1) - coef[3];
+                    r3 = coef[1] + (coef[3] >> 1);
+
+                    coef[0] = r0 + r3;
+                    coef[1] = r1 + r2;
+                    coef[2] = r1 - r2;
+                    coef[3] = r0 - r3;
+
+                    coef += 16;
+                }
+                coef -= 64;
+                for (j = 4; j > 0; j--)
+                {
+                    r0 = coef[0] + coef[32];
+                    r1 = coef[0] - coef[32];
+                    r2 = (coef[16] >> 1) - coef[48];
+                    r3 = coef[16] + (coef[48] >> 1);
+
+                    r0 += r3;
+                    r3 = (r0 - (r3 << 1)); /* r0-r3 */
+                    r1 += r2;
+                    r2 = (r1 - (r2 << 1)); /* r1-r2 */
+                    r0 += 32;
+                    r1 += 32;
+                    r2 += 32;
+                    r3 += 32;
+                    r0 = pred[0] + (r0 >> 6);
+                    if ((uint)r0 > 0xFF)   r0 = 0xFF & (~(r0 >> 31));  /* clip */
+                    r1 = pred[16] + (r1 >> 6);
+                    if ((uint)r1 > 0xFF)   r1 = 0xFF & (~(r1 >> 31));  /* clip */
+                    r2 = pred[32] + (r2 >> 6);
+                    if ((uint)r2 > 0xFF)   r2 = 0xFF & (~(r2 >> 31));  /* clip */
+                    r3 = pred[48] + (r3 >> 6);
+                    if ((uint)r3 > 0xFF)   r3 = 0xFF & (~(r3 >> 31));  /* clip */
+                    *curL = r0;
+                    *(curL += pitch) = r1;
+                    *(curL += pitch) = r2;
+                    curL[pitch] = r3;
+                    curL -= (pitch << 1);
+                    curL++;
+                    pred++;
+                    coef++;
+                }
+            }
+            else  // do DC-only inverse
+            {
+                m0 = coef[0] + 32;
+
+                for (j = 4; j > 0; j--)
+                {
+                    r0 = pred[0] + (m0 >> 6);
+                    if ((uint)r0 > 0xFF)   r0 = 0xFF & (~(r0 >> 31));  /* clip */
+                    r1 = pred[16] + (m0 >> 6);
+                    if ((uint)r1 > 0xFF)   r1 = 0xFF & (~(r1 >> 31));  /* clip */
+                    r2 = pred[32] + (m0 >> 6);
+                    if ((uint)r2 > 0xFF)   r2 = 0xFF & (~(r2 >> 31));  /* clip */
+                    r3 = pred[48] + (m0 >> 6);
+                    if ((uint)r3 > 0xFF)   r3 = 0xFF & (~(r3 >> 31));  /* clip */
+                    *curL = r0;
+                    *(curL += pitch) = r1;
+                    *(curL += pitch) = r2;
+                    curL[pitch] = r3;
+                    curL -= (pitch << 1);
+                    curL++;
+                    pred++;
+                }
+                coef += 4;
+            }
+
+            run += 16;  // follow coding order
+            level += 16;
+            curL += offset_cur[b4&1];
+            pred += offset_pred[b4&1];
+            coef += offset_pred[b4&1];
+        }
+
+        curL += offset_cur[2 + (b8&1)];
+        pred += offset_pred[2 + (b8&1)];
+        coef += offset_pred[2 + (b8&1)];
+    }
+
+    return ;
+}
+
+
+void dct_chroma(AVCEncObject *encvid, uint8 *curC, uint8 *orgC, int cr)
+{
+    AVCCommonObj *video = encvid->common;
+    AVCMacroblock *currMB = video->currMB;
+    int org_pitch = (encvid->currInput->pitch) >> 1;
+    int pitch = (video->currPic->pitch) >> 1;
+    int pred_pitch = 16;
+    int16 *coef = video->block + 256;
+    uint8 *pred = video->pred_block;
+    int j, blk_x, blk_y, k, idx, b4;
+    int r0, r1, r2, r3, m0;
+    int Qq, Rq, qp_const, q_bits, quant;
+    int *level, *run, zero_run, ncoeff;
+    int data, lev;
+    int offset_cur[2], offset_pred[2], offset_coef[2];
+    uint8 nz_temp[4];
+    int  coeff_cost;
+
+    if (cr)
+    {
+        coef += 8;
+        pred += 8;
+    }
+
+    if (currMB->mb_intra == 0) // inter mode
+    {
+        pred = curC;
+        pred_pitch = pitch;
+    }
+
+    /* do 4x4 transform */
+    /* horizontal */
+    for (j = 8; j > 0; j--)
+    {
+        for (blk_x = 2; blk_x > 0; blk_x--)
+        {
+            /* calculate the residue first */
+            r0 = *orgC++ - *pred++;
+            r1 = *orgC++ - *pred++;
+            r2 = *orgC++ - *pred++;
+            r3 = *orgC++ - *pred++;
+
+            r0 += r3;           //ptr[0] + ptr[3];
+            r3 = r0 - (r3 << 1);    //ptr[0] - ptr[3];
+            r1 += r2;           //ptr[1] + ptr[2];
+            r2 = r1 - (r2 << 1);    //ptr[1] - ptr[2];
+
+            *coef++ = r0 + r1;
+            *coef++ = (r3 << 1) + r2;
+            *coef++ = r0 - r1;
+            *coef++ = r3 - (r2 << 1);
+
+        }
+        coef += 8; // coef pitch is 16
+        pred += (pred_pitch - 8); // pred_pitch is 16
+        orgC += (org_pitch - 8);
+    }
+    pred -= (pred_pitch << 3);
+    coef -= 128;
+    /* vertical */
+    for (blk_y = 2; blk_y > 0; blk_y--)
+    {
+        for (j = 8; j > 0; j--)
+        {
+            r0 = coef[0] + coef[48];
+            r3 = coef[0] - coef[48];
+            r1 = coef[16] + coef[32];
+            r2 = coef[16] - coef[32];
+
+            coef[0] = r0 + r1;
+            coef[32] = r0 - r1;
+            coef[16] = (r3 << 1) + r2;
+            coef[48] = r3 - (r2 << 1);
+
+            coef++;
+        }
+        coef += 56;
+    }
+    /* then perform DC transform */
+    coef -= 128;
+
+    /* 2x2 transform of DC components*/
+    r0 = coef[0];
+    r1 = coef[4];
+    r2 = coef[64];
+    r3 = coef[68];
+
+    coef[0] = r0 + r1 + r2 + r3;
+    coef[4] = r0 - r1 + r2 - r3;
+    coef[64] = r0 + r1 - r2 - r3;
+    coef[68] = r0 - r1 - r2 + r3;
+
+    Qq    = video->QPc_div_6;
+    Rq    = video->QPc_mod_6;
+    quant = quant_coef[Rq][0];
+    q_bits    = 15 + Qq;
+    qp_const = encvid->qp_const_c;
+
+    zero_run = 0;
+    ncoeff = 0;
+    run = encvid->runcdc + (cr << 2);
+    level = encvid->levelcdc + (cr << 2);
+
+    /* in zigzag scan order */
+    for (k = 0; k < 4; k++)
+    {
+        idx = ((k >> 1) << 6) + ((k & 1) << 2);
+        data = coef[idx];
+        if (data > 0)
+        {
+            lev = data * quant + (qp_const << 1);
+        }
+        else
+        {
+            lev = -data * quant + (qp_const << 1);
+        }
+        lev >>= (q_bits + 1);
+        if (lev)
+        {
+            if (data > 0)
+            {
+                level[ncoeff] = lev;
+                coef[idx] = lev;
+            }
+            else
+            {
+                level[ncoeff] = -lev;
+                coef[idx] = -lev;
+            }
+            run[ncoeff++] = zero_run;
+            zero_run = 0;
+        }
+        else
+        {
+            zero_run++;
+            coef[idx] = 0;
+        }
+    }
+
+    encvid->numcoefcdc[cr] = ncoeff;
+
+    if (ncoeff)
+    {
+        currMB->CBP |= (1 << 4); // DC present
+        // do inverse transform
+        quant = dequant_coefres[Rq][0];
+
+        r0 = coef[0] + coef[4];
+        r1 = coef[0] - coef[4];
+        r2 = coef[64] + coef[68];
+        r3 = coef[64] - coef[68];
+
+        r0 += r2;
+        r2 = r0 - (r2 << 1);
+        r1 += r3;
+        r3 = r1 - (r3 << 1);
+
+        if (Qq >= 1)
+        {
+            Qq -= 1;
+            coef[0] = (r0 * quant) << Qq;
+            coef[4] = (r1 * quant) << Qq;
+            coef[64] = (r2 * quant) << Qq;
+            coef[68] = (r3 * quant) << Qq;
+            Qq++;
+        }
+        else
+        {
+            coef[0] = (r0 * quant) >> 1;
+            coef[4] = (r1 * quant) >> 1;
+            coef[64] = (r2 * quant) >> 1;
+            coef[68] = (r3 * quant) >> 1;
+        }
+    }
+
+    /* now do AC zigzag scan, quant, iquant and itrans */
+    if (cr)
+    {
+        run = encvid->run[20];
+        level = encvid->level[20];
+    }
+    else
+    {
+        run = encvid->run[16];
+        level = encvid->level[16];
+    }
+
+    /* offset btw 4x4 block */
+    offset_cur[0] = 0;
+    offset_cur[1] = (pitch << 2) - 8;
+    offset_pred[0] = 0;
+    offset_pred[1] = (pred_pitch << 2) - 8;
+    offset_coef[0] = 0;
+    offset_coef[1] = 56;
+
+    coeff_cost = 0;
+
+    for (b4 = 0; b4 < 4; b4++)
+    {
+        zero_run = 0;
+        ncoeff = 0;
+        for (k = 1; k < 16; k++) /* in zigzag scan order */
+        {
+            idx = ZZ_SCAN_BLOCK[k]; /* map back to raster scan order */
+            data = coef[idx];
+            quant = quant_coef[Rq][k];
+            if (data > 0)
+            {
+                lev = data * quant + qp_const;
+            }
+            else
+            {
+                lev = -data * quant + qp_const;
+            }
+            lev >>= q_bits;
+            if (lev)
+            {
+                /* for RD performance*/
+                if (lev > 1)
+                    coeff_cost += MAX_VALUE;                // set high cost, shall not be discarded
+                else
+                    coeff_cost += COEFF_COST[DISABLE_THRESHOLDING][zero_run];
+
+                /* dequant */
+                quant = dequant_coefres[Rq][k];
+                if (data > 0)
+                {
+                    level[ncoeff] = lev;
+                    coef[idx] = (lev * quant) << Qq;
+                }
+                else
+                {
+                    level[ncoeff] = -lev;
+                    coef[idx] = (-lev * quant) << Qq;
+                }
+                run[ncoeff++] = zero_run;
+                zero_run = 0;
+            }
+            else
+            {
+                zero_run++;
+                coef[idx] = 0;
+            }
+        }
+
+        nz_temp[b4] = ncoeff; // raster scan
+
+        // just advance the pointers for now, do IDCT later
+        coef += 4;
+        run += 16;
+        level += 16;
+        coef += offset_coef[b4&1];
+    }
+
+    /* rewind the pointers */
+    coef -= 128;
+
+    if (coeff_cost < _CHROMA_COEFF_COST_)
+    {
+        /* if it's not efficient to encode any blocks.
+        Just do DC only */
+        /* We can reset level and run also, but setting nz to zero should be enough. */
+        currMB->nz_coeff[16+(cr<<1)] = 0;
+        currMB->nz_coeff[17+(cr<<1)] = 0;
+        currMB->nz_coeff[20+(cr<<1)] = 0;
+        currMB->nz_coeff[21+(cr<<1)] = 0;
+
+        for (b4 = 0; b4 < 4; b4++)
+        {
+            // do DC-only inverse
+            m0 = coef[0] + 32;
+
+            for (j = 4; j > 0; j--)
+            {
+                r0 = pred[0] + (m0 >> 6);
+                if ((uint)r0 > 0xFF)   r0 = 0xFF & (~(r0 >> 31));  /* clip */
+                r1 = *(pred += pred_pitch) + (m0 >> 6);
+                if ((uint)r1 > 0xFF)   r1 = 0xFF & (~(r1 >> 31));  /* clip */
+                r2 = pred[pred_pitch] + (m0 >> 6);
+                if ((uint)r2 > 0xFF)   r2 = 0xFF & (~(r2 >> 31));  /* clip */
+                r3 = pred[pred_pitch<<1] + (m0 >> 6);
+                if ((uint)r3 > 0xFF)   r3 = 0xFF & (~(r3 >> 31));  /* clip */
+                *curC = r0;
+                *(curC += pitch) = r1;
+                *(curC += pitch) = r2;
+                curC[pitch] = r3;
+                curC -= (pitch << 1);
+                curC++;
+                pred += (1 - pred_pitch);
+            }
+            coef += 4;
+            curC += offset_cur[b4&1];
+            pred += offset_pred[b4&1];
+            coef += offset_coef[b4&1];
+        }
+    }
+    else // not dropping anything, continue with the IDCT
+    {
+        for (b4 = 0; b4 < 4; b4++)
+        {
+            ncoeff = nz_temp[b4] ; // in raster scan
+            currMB->nz_coeff[16+(b4&1)+(cr<<1)+((b4>>1)<<2)] = ncoeff; // in raster scan
+
+            if (ncoeff) // do a check on the nonzero-coeff
+            {
+                currMB->CBP |= (2 << 4);
+
+                // do inverse transform here
+                for (j = 4; j > 0; j--)
+                {
+                    r0 = coef[0] + coef[2];
+                    r1 = coef[0] - coef[2];
+                    r2 = (coef[1] >> 1) - coef[3];
+                    r3 = coef[1] + (coef[3] >> 1);
+
+                    coef[0] = r0 + r3;
+                    coef[1] = r1 + r2;
+                    coef[2] = r1 - r2;
+                    coef[3] = r0 - r3;
+
+                    coef += 16;
+                }
+                coef -= 64;
+                for (j = 4; j > 0; j--)
+                {
+                    r0 = coef[0] + coef[32];
+                    r1 = coef[0] - coef[32];
+                    r2 = (coef[16] >> 1) - coef[48];
+                    r3 = coef[16] + (coef[48] >> 1);
+
+                    r0 += r3;
+                    r3 = (r0 - (r3 << 1)); /* r0-r3 */
+                    r1 += r2;
+                    r2 = (r1 - (r2 << 1)); /* r1-r2 */
+                    r0 += 32;
+                    r1 += 32;
+                    r2 += 32;
+                    r3 += 32;
+                    r0 = pred[0] + (r0 >> 6);
+                    if ((uint)r0 > 0xFF)   r0 = 0xFF & (~(r0 >> 31));  /* clip */
+                    r1 = *(pred += pred_pitch) + (r1 >> 6);
+                    if ((uint)r1 > 0xFF)   r1 = 0xFF & (~(r1 >> 31));  /* clip */
+                    r2 = pred[pred_pitch] + (r2 >> 6);
+                    if ((uint)r2 > 0xFF)   r2 = 0xFF & (~(r2 >> 31));  /* clip */
+                    r3 = pred[pred_pitch<<1] + (r3 >> 6);
+                    if ((uint)r3 > 0xFF)   r3 = 0xFF & (~(r3 >> 31));  /* clip */
+                    *curC = r0;
+                    *(curC += pitch) = r1;
+                    *(curC += pitch) = r2;
+                    curC[pitch] = r3;
+                    curC -= (pitch << 1);
+                    curC++;
+                    pred += (1 - pred_pitch);
+                    coef++;
+                }
+            }
+            else
+            {
+                // do DC-only inverse
+                m0 = coef[0] + 32;
+
+                for (j = 4; j > 0; j--)
+                {
+                    r0 = pred[0] + (m0 >> 6);
+                    if ((uint)r0 > 0xFF)   r0 = 0xFF & (~(r0 >> 31));  /* clip */
+                    r1 = *(pred += pred_pitch) + (m0 >> 6);
+                    if ((uint)r1 > 0xFF)   r1 = 0xFF & (~(r1 >> 31));  /* clip */
+                    r2 = pred[pred_pitch] + (m0 >> 6);
+                    if ((uint)r2 > 0xFF)   r2 = 0xFF & (~(r2 >> 31));  /* clip */
+                    r3 = pred[pred_pitch<<1] + (m0 >> 6);
+                    if ((uint)r3 > 0xFF)   r3 = 0xFF & (~(r3 >> 31));  /* clip */
+                    *curC = r0;
+                    *(curC += pitch) = r1;
+                    *(curC += pitch) = r2;
+                    curC[pitch] = r3;
+                    curC -= (pitch << 1);
+                    curC++;
+                    pred += (1 - pred_pitch);
+                }
+                coef += 4;
+            }
+            curC += offset_cur[b4&1];
+            pred += offset_pred[b4&1];
+            coef += offset_coef[b4&1];
+        }
+    }
+
+    return ;
+}
+
+
+/* only DC transform */
+int TransQuantIntra16DC(AVCEncObject *encvid)
+{
+    AVCCommonObj *video = encvid->common;
+    int16 *block = video->block;
+    int *level = encvid->leveldc;
+    int *run = encvid->rundc;
+    int16 *ptr = block;
+    int r0, r1, r2, r3, j;
+    int Qq = video->QPy_div_6;
+    int Rq = video->QPy_mod_6;
+    int q_bits, qp_const, quant;
+    int data, lev, zero_run;
+    int k, ncoeff, idx;
+
+    /* DC transform */
+    /* horizontal */
+    j = 4;
+    while (j)
+    {
+        r0 = ptr[0] + ptr[12];
+        r3 = ptr[0] - ptr[12];
+        r1 = ptr[4] + ptr[8];
+        r2 = ptr[4] - ptr[8];
+
+        ptr[0] = r0 + r1;
+        ptr[8] = r0 - r1;
+        ptr[4] = r3 + r2;
+        ptr[12] = r3 - r2;
+        ptr += 64;
+        j--;
+    }
+    /* vertical */
+    ptr = block;
+    j = 4;
+    while (j)
+    {
+        r0 = ptr[0] + ptr[192];
+        r3 = ptr[0] - ptr[192];
+        r1 = ptr[64] + ptr[128];
+        r2 = ptr[64] - ptr[128];
+
+        ptr[0] = (r0 + r1) >> 1;
+        ptr[128] = (r0 - r1) >> 1;
+        ptr[64] = (r3 + r2) >> 1;
+        ptr[192] = (r3 - r2) >> 1;
+        ptr += 4;
+        j--;
+    }
+
+    quant = quant_coef[Rq][0];
+    q_bits    = 15 + Qq;
+    qp_const = (1 << q_bits) / 3;    // intra
+
+    zero_run = 0;
+    ncoeff = 0;
+
+    for (k = 0; k < 16; k++) /* in zigzag scan order */
+    {
+        idx = ZIGZAG2RASTERDC[k];
+        data = block[idx];
+        if (data > 0)
+        {
+            lev = data * quant + (qp_const << 1);
+        }
+        else
+        {
+            lev = -data * quant + (qp_const << 1);
+        }
+        lev >>= (q_bits + 1);
+        if (lev)
+        {
+            if (data > 0)
+            {
+                level[ncoeff] = lev;
+                block[idx] = lev;
+            }
+            else
+            {
+                level[ncoeff] = -lev;
+                block[idx] = -lev;
+            }
+            run[ncoeff++] = zero_run;
+            zero_run = 0;
+        }
+        else
+        {
+            zero_run++;
+            block[idx] = 0;
+        }
+    }
+    return ncoeff;
+}
+
+int TransQuantChromaDC(AVCEncObject *encvid, int16 *block, int slice_type, int cr)
+{
+    AVCCommonObj *video = encvid->common;
+    int *level, *run;
+    int r0, r1, r2, r3;
+    int Qq, Rq, q_bits, qp_const, quant;
+    int data, lev, zero_run;
+    int k, ncoeff, idx;
+
+    level = encvid->levelcdc + (cr << 2); /* cb or cr */
+    run = encvid->runcdc + (cr << 2);
+
+    /* 2x2 transform of DC components*/
+    r0 = block[0];
+    r1 = block[4];
+    r2 = block[64];
+    r3 = block[68];
+
+    block[0] = r0 + r1 + r2 + r3;
+    block[4] = r0 - r1 + r2 - r3;
+    block[64] = r0 + r1 - r2 - r3;
+    block[68] = r0 - r1 - r2 + r3;
+
+    Qq    = video->QPc_div_6;
+    Rq    = video->QPc_mod_6;
+    quant = quant_coef[Rq][0];
+    q_bits    = 15 + Qq;
+    if (slice_type == AVC_I_SLICE)
+    {
+        qp_const = (1 << q_bits) / 3;
+    }
+    else
+    {
+        qp_const = (1 << q_bits) / 6;
+    }
+
+    zero_run = 0;
+    ncoeff = 0;
+
+    for (k = 0; k < 4; k++) /* in zigzag scan order */
+    {
+        idx = ((k >> 1) << 6) + ((k & 1) << 2);
+        data = block[idx];
+        if (data > 0)
+        {
+            lev = data * quant + (qp_const << 1);
+        }
+        else
+        {
+            lev = -data * quant + (qp_const << 1);
+        }
+        lev >>= (q_bits + 1);
+        if (lev)
+        {
+            if (data > 0)
+            {
+                level[ncoeff] = lev;
+                block[idx] = lev;
+            }
+            else
+            {
+                level[ncoeff] = -lev;
+                block[idx] = -lev;
+            }
+            run[ncoeff++] = zero_run;
+            zero_run = 0;
+        }
+        else
+        {
+            zero_run++;
+            block[idx] = 0;
+        }
+    }
+    return ncoeff;
+}
+
+
diff --git a/media/libstagefright/codecs/avc/enc/src/findhalfpel.cpp b/media/libstagefright/codecs/avc/enc/src/findhalfpel.cpp
new file mode 100644
index 0000000..38a2a15
--- /dev/null
+++ b/media/libstagefright/codecs/avc/enc/src/findhalfpel.cpp
@@ -0,0 +1,622 @@
+/* ------------------------------------------------------------------
+ * Copyright (C) 1998-2009 PacketVideo
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
+ * express or implied.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ * -------------------------------------------------------------------
+ */
+#include "avcenc_lib.h"
+/* 3/29/01 fast half-pel search based on neighboring guess */
+/* value ranging from 0 to 4, high complexity (more accurate) to
+   low complexity (less accurate) */
+#define HP_DISTANCE_TH      5 // 2  /* half-pel distance threshold */
+
+#define PREF_16_VEC 129     /* 1MV bias versus 4MVs*/
+
+const static int distance_tab[9][9] =   /* [hp_guess][k] */
+{
+    {0, 1, 1, 1, 1, 1, 1, 1, 1},
+    {1, 0, 1, 2, 3, 4, 3, 2, 1},
+    {1, 0, 0, 0, 1, 2, 3, 2, 1},
+    {1, 2, 1, 0, 1, 2, 3, 4, 3},
+    {1, 2, 1, 0, 0, 0, 1, 2, 3},
+    {1, 4, 3, 2, 1, 0, 1, 2, 3},
+    {1, 2, 3, 2, 1, 0, 0, 0, 1},
+    {1, 2, 3, 4, 3, 2, 1, 0, 1},
+    {1, 0, 1, 2, 3, 2, 1, 0, 0}
+};
+
+#define CLIP_RESULT(x)      if((uint)x > 0xFF){ \
+                 x = 0xFF & (~(x>>31));}
+
+#define CLIP_UPPER16(x)     if((uint)x >= 0x20000000){ \
+        x = 0xFF0000 & (~(x>>31));} \
+        else { \
+        x = (x>>5)&0xFF0000; \
+        }
+
+/*=====================================================================
+    Function:   AVCFindHalfPelMB
+    Date:       10/31/2007
+    Purpose:    Find half pel resolution MV surrounding the full-pel MV
+=====================================================================*/
+
+int AVCFindHalfPelMB(AVCEncObject *encvid, uint8 *cur, AVCMV *mot, uint8 *ncand,
+                     int xpos, int ypos, int hp_guess, int cmvx, int cmvy)
+{
+    AVCPictureData *currPic = encvid->common->currPic;
+    int lx = currPic->pitch;
+    int d, dmin, satd_min;
+    uint8* cand;
+    int lambda_motion = encvid->lambda_motion;
+    uint8 *mvbits = encvid->mvbits;
+    int mvcost;
+    /* list of candidate to go through for half-pel search*/
+    uint8 *subpel_pred = (uint8*) encvid->subpel_pred; // all 16 sub-pel positions
+    uint8 **hpel_cand = (uint8**) encvid->hpel_cand; /* half-pel position */
+
+    int xh[9] = {0, 0, 2, 2, 2, 0, -2, -2, -2};
+    int yh[9] = {0, -2, -2, 0, 2, 2, 2, 0, -2};
+    int xq[8] = {0, 1, 1, 1, 0, -1, -1, -1};
+    int yq[8] = { -1, -1, 0, 1, 1, 1, 0, -1};
+    int h, hmin, q, qmin;
+
+    OSCL_UNUSED_ARG(xpos);
+    OSCL_UNUSED_ARG(ypos);
+    OSCL_UNUSED_ARG(hp_guess);
+
+    GenerateHalfPelPred(subpel_pred, ncand, lx);
+
+    cur = encvid->currYMB; // pre-load current original MB
+
+    cand = hpel_cand[0];
+
+    // find cost for the current full-pel position
+    dmin = SATD_MB(cand, cur, 65535); // get Hadamaard transform SAD
+    mvcost = MV_COST_S(lambda_motion, mot->x, mot->y, cmvx, cmvy);
+    satd_min = dmin;
+    dmin += mvcost;
+    hmin = 0;
+
+    /* find half-pel */
+    for (h = 1; h < 9; h++)
+    {
+        d = SATD_MB(hpel_cand[h], cur, dmin);
+        mvcost = MV_COST_S(lambda_motion, mot->x + xh[h], mot->y + yh[h], cmvx, cmvy);
+        d += mvcost;
+
+        if (d < dmin)
+        {
+            dmin = d;
+            hmin = h;
+            satd_min = d - mvcost;
+        }
+    }
+
+    mot->sad = dmin;
+    mot->x += xh[hmin];
+    mot->y += yh[hmin];
+    encvid->best_hpel_pos = hmin;
+
+    /*** search for quarter-pel ****/
+    GenerateQuartPelPred(encvid->bilin_base[hmin], &(encvid->qpel_cand[0][0]), hmin);
+
+    encvid->best_qpel_pos = qmin = -1;
+
+    for (q = 0; q < 8; q++)
+    {
+        d = SATD_MB(encvid->qpel_cand[q], cur, dmin);
+        mvcost = MV_COST_S(lambda_motion, mot->x + xq[q], mot->y + yq[q], cmvx, cmvy);
+        d += mvcost;
+        if (d < dmin)
+        {
+            dmin = d;
+            qmin = q;
+            satd_min = d - mvcost;
+        }
+    }
+
+    if (qmin != -1)
+    {
+        mot->sad = dmin;
+        mot->x += xq[qmin];
+        mot->y += yq[qmin];
+        encvid->best_qpel_pos = qmin;
+    }
+
+    return satd_min;
+}
+
+
+
+/** This function generates sub-pel prediction around the full-pel candidate.
+Each sub-pel position array is 20 pixel wide (for word-alignment) and 17 pixel tall. */
+/** The sub-pel position is labeled in spiral manner from the center. */
+
+void GenerateHalfPelPred(uint8* subpel_pred, uint8 *ncand, int lx)
+{
+    /* let's do straightforward way first */
+    uint8 *ref;
+    uint8 *dst;
+    uint8 tmp8;
+    int32 tmp32;
+    int16 tmp_horz[18*22], *dst_16, *src_16;
+    register int a = 0, b = 0, c = 0, d = 0, e = 0, f = 0; // temp register
+    int msk;
+    int i, j;
+
+    /* first copy full-pel to the first array */
+    /* to be optimized later based on byte-offset load */
+    ref = ncand - 3 - lx - (lx << 1); /* move back (-3,-3) */
+    dst = subpel_pred;
+
+    dst -= 4; /* offset */
+    for (j = 0; j < 22; j++) /* 24x22 */
+    {
+        i = 6;
+        while (i > 0)
+        {
+            tmp32 = *ref++;
+            tmp8 = *ref++;
+            tmp32 |= (tmp8 << 8);
+            tmp8 = *ref++;
+            tmp32 |= (tmp8 << 16);
+            tmp8 = *ref++;
+            tmp32 |= (tmp8 << 24);
+            *((uint32*)(dst += 4)) = tmp32;
+            i--;
+        }
+        ref += (lx - 24);
+    }
+
+    /* from the first array, we do horizontal interp */
+    ref = subpel_pred + 2;
+    dst_16 = tmp_horz; /* 17 x 22 */
+
+    for (j = 4; j > 0; j--)
+    {
+        for (i = 16; i > 0; i -= 4)
+        {
+            a = ref[-2];
+            b = ref[-1];
+            c = ref[0];
+            d = ref[1];
+            e = ref[2];
+            f = ref[3];
+            *dst_16++ = a + f - 5 * (b + e) + 20 * (c + d);
+            a = ref[4];
+            *dst_16++ = b + a - 5 * (c + f) + 20 * (d + e);
+            b = ref[5];
+            *dst_16++ = c + b - 5 * (d + a) + 20 * (e + f);
+            c = ref[6];
+            *dst_16++ = d + c - 5 * (e + b) + 20 * (f + a);
+
+            ref += 4;
+        }
+        /* do the 17th column here */
+        d = ref[3];
+        *dst_16 =  e + d - 5 * (f + c) + 20 * (a + b);
+        dst_16 += 2; /* stride for tmp_horz is 18 */
+        ref += 8;  /* stride for ref is 24 */
+        if (j == 3)  // move 18 lines down
+        {
+            dst_16 += 324;//18*18;
+            ref += 432;//18*24;
+        }
+    }
+
+    ref -= 480;//20*24;
+    dst_16 -= 360;//20*18;
+    dst = subpel_pred + V0Q_H2Q * SUBPEL_PRED_BLK_SIZE; /* go to the 14th array 17x18*/
+
+    for (j = 18; j > 0; j--)
+    {
+        for (i = 16; i > 0; i -= 4)
+        {
+            a = ref[-2];
+            b = ref[-1];
+            c = ref[0];
+            d = ref[1];
+            e = ref[2];
+            f = ref[3];
+            tmp32 = a + f - 5 * (b + e) + 20 * (c + d);
+            *dst_16++ = tmp32;
+            tmp32 = (tmp32 + 16) >> 5;
+            CLIP_RESULT(tmp32)
+            *dst++ = tmp32;
+
+            a = ref[4];
+            tmp32 = b + a - 5 * (c + f) + 20 * (d + e);
+            *dst_16++ = tmp32;
+            tmp32 = (tmp32 + 16) >> 5;
+            CLIP_RESULT(tmp32)
+            *dst++ = tmp32;
+
+            b = ref[5];
+            tmp32 = c + b - 5 * (d + a) + 20 * (e + f);
+            *dst_16++ = tmp32;
+            tmp32 = (tmp32 + 16) >> 5;
+            CLIP_RESULT(tmp32)
+            *dst++ = tmp32;
+
+            c = ref[6];
+            tmp32 = d + c - 5 * (e + b) + 20 * (f + a);
+            *dst_16++ = tmp32;
+            tmp32 = (tmp32 + 16) >> 5;
+            CLIP_RESULT(tmp32)
+            *dst++ = tmp32;
+
+            ref += 4;
+        }
+        /* do the 17th column here */
+        d = ref[3];
+        tmp32 =  e + d - 5 * (f + c) + 20 * (a + b);
+        *dst_16 = tmp32;
+        tmp32 = (tmp32 + 16) >> 5;
+        CLIP_RESULT(tmp32)
+        *dst = tmp32;
+
+        dst += 8;  /* stride for dst is 24 */
+        dst_16 += 2; /* stride for tmp_horz is 18 */
+        ref += 8;  /* stride for ref is 24 */
+    }
+
+
+    /* Do middle point filtering*/
+    src_16 = tmp_horz; /* 17 x 22 */
+    dst = subpel_pred + V2Q_H2Q * SUBPEL_PRED_BLK_SIZE; /* 12th array 17x17*/
+    dst -= 24; // offset
+    for (i = 0; i < 17; i++)
+    {
+        for (j = 16; j > 0; j -= 4)
+        {
+            a = *src_16;
+            b = *(src_16 += 18);
+            c = *(src_16 += 18);
+            d = *(src_16 += 18);
+            e = *(src_16 += 18);
+            f = *(src_16 += 18);
+
+            tmp32 = a + f - 5 * (b + e) + 20 * (c + d);
+            tmp32 = (tmp32 + 512) >> 10;
+            CLIP_RESULT(tmp32)
+            *(dst += 24) = tmp32;
+
+            a = *(src_16 += 18);
+            tmp32 = b + a - 5 * (c + f) + 20 * (d + e);
+            tmp32 = (tmp32 + 512) >> 10;
+            CLIP_RESULT(tmp32)
+            *(dst += 24) = tmp32;
+
+            b = *(src_16 += 18);
+            tmp32 = c + b - 5 * (d + a) + 20 * (e + f);
+            tmp32 = (tmp32 + 512) >> 10;
+            CLIP_RESULT(tmp32)
+            *(dst += 24) = tmp32;
+
+            c = *(src_16 += 18);
+            tmp32 = d + c - 5 * (e + b) + 20 * (f + a);
+            tmp32 = (tmp32 + 512) >> 10;
+            CLIP_RESULT(tmp32)
+            *(dst += 24) = tmp32;
+
+            src_16 -= (18 << 2);
+        }
+
+        d = src_16[90]; // 18*5
+        tmp32 = e + d - 5 * (f + c) + 20 * (a + b);
+        tmp32 = (tmp32 + 512) >> 10;
+        CLIP_RESULT(tmp32)
+        dst[24] = tmp32;
+
+        src_16 -= ((18 << 4) - 1);
+        dst -= ((24 << 4) - 1);
+    }
+
+    /* do vertical interpolation */
+    ref = subpel_pred + 2;
+    dst = subpel_pred + V2Q_H0Q * SUBPEL_PRED_BLK_SIZE; /* 10th array 18x17 */
+    dst -= 24; // offset
+
+    for (i = 2; i > 0; i--)
+    {
+        for (j = 16; j > 0; j -= 4)
+        {
+            a = *ref;
+            b = *(ref += 24);
+            c = *(ref += 24);
+            d = *(ref += 24);
+            e = *(ref += 24);
+            f = *(ref += 24);
+
+            tmp32 = a + f - 5 * (b + e) + 20 * (c + d);
+            tmp32 = (tmp32 + 16) >> 5;
+            CLIP_RESULT(tmp32)
+            *(dst += 24) = tmp32;  // 10th
+
+            a = *(ref += 24);
+            tmp32 = b + a - 5 * (c + f) + 20 * (d + e);
+            tmp32 = (tmp32 + 16) >> 5;
+            CLIP_RESULT(tmp32)
+            *(dst += 24) = tmp32;  // 10th
+
+            b = *(ref += 24);
+            tmp32 = c + b - 5 * (d + a) + 20 * (e + f);
+            tmp32 = (tmp32 + 16) >> 5;
+            CLIP_RESULT(tmp32)
+            *(dst += 24) = tmp32;  // 10th
+
+            c = *(ref += 24);
+            tmp32 = d + c - 5 * (e + b) + 20 * (f + a);
+            tmp32 = (tmp32 + 16) >> 5;
+            CLIP_RESULT(tmp32)
+            *(dst += 24) = tmp32;  // 10th
+
+            ref -= (24 << 2);
+        }
+
+        d = ref[120]; // 24*5
+        tmp32 = e + d - 5 * (f + c) + 20 * (a + b);
+        tmp32 = (tmp32 + 16) >> 5;
+        CLIP_RESULT(tmp32)
+        dst[24] = tmp32;  // 10th
+
+        dst -= ((24 << 4) - 1);
+        ref -= ((24 << 4) - 1);
+    }
+
+    // note that using SIMD here doesn't help much, the cycle almost stays the same
+    // one can just use the above code and change the for(i=2 to for(i=18
+    for (i = 16; i > 0; i -= 4)
+    {
+        msk = 0;
+        for (j = 17; j > 0; j--)
+        {
+            a = *((uint32*)ref); /* load 4 bytes */
+            b = (a >> 8) & 0xFF00FF; /* second and fourth byte */
+            a &= 0xFF00FF;
+
+            c = *((uint32*)(ref + 120));
+            d = (c >> 8) & 0xFF00FF;
+            c &= 0xFF00FF;
+
+            a += c;
+            b += d;
+
+            e = *((uint32*)(ref + 72)); /* e, f */
+            f = (e >> 8) & 0xFF00FF;
+            e &= 0xFF00FF;
+
+            c = *((uint32*)(ref + 48)); /* c, d */
+            d = (c >> 8) & 0xFF00FF;
+            c &= 0xFF00FF;
+
+            c += e;
+            d += f;
+
+            a += 20 * c;
+            b += 20 * d;
+            a += 0x100010;
+            b += 0x100010;
+
+            e = *((uint32*)(ref += 24)); /* e, f */
+            f = (e >> 8) & 0xFF00FF;
+            e &= 0xFF00FF;
+
+            c = *((uint32*)(ref + 72)); /* c, d */
+            d = (c >> 8) & 0xFF00FF;
+            c &= 0xFF00FF;
+
+            c += e;
+            d += f;
+
+            a -= 5 * c;
+            b -= 5 * d;
+
+            c = a << 16;
+            d = b << 16;
+            CLIP_UPPER16(a)
+            CLIP_UPPER16(c)
+            CLIP_UPPER16(b)
+            CLIP_UPPER16(d)
+
+            a |= (c >> 16);
+            b |= (d >> 16);
+            //  a>>=5;
+            //  b>>=5;
+            /* clip */
+            //  msk |= b;  msk|=a;
+            //  a &= 0xFF00FF;
+            //  b &= 0xFF00FF;
+            a |= (b << 8);  /* pack it back */
+
+            *((uint16*)(dst += 24)) = a & 0xFFFF; //dst is not word-aligned.
+            *((uint16*)(dst + 2)) = a >> 16;
+
+        }
+        dst -= 404; // 24*17-4
+        ref -= 404;
+        /*      if(msk & 0xFF00FF00) // need clipping
+                {
+                    VertInterpWClip(dst,ref); // re-do 4 column with clip
+                }*/
+    }
+
+    return ;
+}
+
+void VertInterpWClip(uint8 *dst, uint8 *ref)
+{
+    int i, j;
+    int a, b, c, d, e, f;
+    int32 tmp32;
+
+    dst -= 4;
+    ref -= 4;
+
+    for (i = 4; i > 0; i--)
+    {
+        for (j = 16; j > 0; j -= 4)
+        {
+            a = *ref;
+            b = *(ref += 24);
+            c = *(ref += 24);
+            d = *(ref += 24);
+            e = *(ref += 24);
+            f = *(ref += 24);
+
+            tmp32 = a + f - 5 * (b + e) + 20 * (c + d);
+            tmp32 = (tmp32 + 16) >> 5;
+            CLIP_RESULT(tmp32)
+            *(dst += 24) = tmp32;  // 10th
+
+            a = *(ref += 24);
+            tmp32 = b + a - 5 * (c + f) + 20 * (d + e);
+            tmp32 = (tmp32 + 16) >> 5;
+            CLIP_RESULT(tmp32)
+            *(dst += 24) = tmp32;  // 10th
+
+            b = *(ref += 24);
+            tmp32 = c + b - 5 * (d + a) + 20 * (e + f);
+            tmp32 = (tmp32 + 16) >> 5;
+            CLIP_RESULT(tmp32)
+            *(dst += 24) = tmp32;  // 10th
+
+            c = *(ref += 24);
+            tmp32 = d + c - 5 * (e + b) + 20 * (f + a);
+            tmp32 = (tmp32 + 16) >> 5;
+            CLIP_RESULT(tmp32)
+            *(dst += 24) = tmp32;  // 10th
+
+            ref -= (24 << 2);
+        }
+
+        d = ref[120]; // 24*5
+        tmp32 = e + d - 5 * (f + c) + 20 * (a + b);
+        tmp32 = (tmp32 + 16) >> 5;
+        CLIP_RESULT(tmp32)
+        dst[24] = tmp32;  // 10th
+
+        dst -= ((24 << 4) - 1);
+        ref -= ((24 << 4) - 1);
+    }
+
+    return ;
+}
+
+
+void GenerateQuartPelPred(uint8 **bilin_base, uint8 *qpel_cand, int hpel_pos)
+{
+    // for even value of hpel_pos, start with pattern 1, otherwise, start with pattern 2
+    int i, j;
+
+    uint8 *c1 = qpel_cand;
+    uint8 *tl = bilin_base[0];
+    uint8 *tr = bilin_base[1];
+    uint8 *bl = bilin_base[2];
+    uint8 *br = bilin_base[3];
+    int a, b, c, d;
+    int offset = 1 - (384 * 7);
+
+    if (!(hpel_pos&1)) // diamond pattern
+    {
+        j = 16;
+        while (j--)
+        {
+            i = 16;
+            while (i--)
+            {
+                d = tr[24];
+                a = *tr++;
+                b = bl[1];
+                c = *br++;
+
+                *c1 = (c + a + 1) >> 1;
+                *(c1 += 384) = (b + a + 1) >> 1; /* c2 */
+                *(c1 += 384) = (b + c + 1) >> 1; /* c3 */
+                *(c1 += 384) = (b + d + 1) >> 1; /* c4 */
+
+                b = *bl++;
+
+                *(c1 += 384) = (c + d + 1) >> 1;  /* c5 */
+                *(c1 += 384) = (b + d + 1) >> 1;  /* c6 */
+                *(c1 += 384) = (b + c + 1) >> 1;  /* c7 */
+                *(c1 += 384) = (b + a + 1) >> 1;  /* c8 */
+
+                c1 += offset;
+            }
+            // advance to the next line, pitch is 24
+            tl += 8;
+            tr += 8;
+            bl += 8;
+            br += 8;
+            c1 += 8;
+        }
+    }
+    else // star pattern
+    {
+        j = 16;
+        while (j--)
+        {
+            i = 16;
+            while (i--)
+            {
+                a = *br++;
+                b = *tr++;
+                c = tl[1];
+                *c1 = (a + b + 1) >> 1;
+                b = bl[1];
+                *(c1 += 384) = (a + c + 1) >> 1; /* c2 */
+                c = tl[25];
+                *(c1 += 384) = (a + b + 1) >> 1; /* c3 */
+                b = tr[23];
+                *(c1 += 384) = (a + c + 1) >> 1; /* c4 */
+                c = tl[24];
+                *(c1 += 384) = (a + b + 1) >> 1; /* c5 */
+                b = *bl++;
+                *(c1 += 384) = (a + c + 1) >> 1; /* c6 */
+                c = *tl++;
+                *(c1 += 384) = (a + b + 1) >> 1; /* c7 */
+                *(c1 += 384) = (a + c + 1) >> 1; /* c8 */
+
+                c1 += offset;
+            }
+            // advance to the next line, pitch is 24
+            tl += 8;
+            tr += 8;
+            bl += 8;
+            br += 8;
+            c1 += 8;
+        }
+    }
+
+    return ;
+}
+
+
+/* assuming cand always has a pitch of 24 */
+int SATD_MB(uint8 *cand, uint8 *cur, int dmin)
+{
+    int cost;
+
+
+    dmin = (dmin << 16) | 24;
+    cost = AVCSAD_Macroblock_C(cand, cur, dmin, NULL);
+
+    return cost;
+}
+
+
+
+
+
diff --git a/media/libstagefright/codecs/avc/enc/src/header.cpp b/media/libstagefright/codecs/avc/enc/src/header.cpp
new file mode 100644
index 0000000..9acff9e
--- /dev/null
+++ b/media/libstagefright/codecs/avc/enc/src/header.cpp
@@ -0,0 +1,917 @@
+/* ------------------------------------------------------------------
+ * Copyright (C) 1998-2009 PacketVideo
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
+ * express or implied.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ * -------------------------------------------------------------------
+ */
+#include "avcenc_lib.h"
+#include "avcenc_api.h"
+
+/** see subclause 7.4.2.1 */
+/* no need for checking the valid range , already done in SetEncodeParam(),
+if we have to send another SPS, the ranges should be verified first before
+users call PVAVCEncodeSPS() */
+AVCEnc_Status EncodeSPS(AVCEncObject *encvid, AVCEncBitstream *stream)
+{
+    AVCCommonObj *video = encvid->common;
+    AVCSeqParamSet *seqParam = video->currSeqParams;
+    AVCVUIParams *vui = &(seqParam->vui_parameters);
+    int i;
+    AVCEnc_Status status = AVCENC_SUCCESS;
+
+    //DEBUG_LOG(userData,AVC_LOGTYPE_INFO,"EncodeSPS",-1,-1);
+
+    status = BitstreamWriteBits(stream, 8, seqParam->profile_idc);
+    status = BitstreamWrite1Bit(stream, seqParam->constrained_set0_flag);
+    status = BitstreamWrite1Bit(stream, seqParam->constrained_set1_flag);
+    status = BitstreamWrite1Bit(stream, seqParam->constrained_set2_flag);
+    status = BitstreamWrite1Bit(stream, seqParam->constrained_set3_flag);
+    status = BitstreamWriteBits(stream, 4, 0);  /* forbidden zero bits */
+    if (status != AVCENC_SUCCESS)  /* we can check after each write also */
+    {
+        return status;
+    }
+
+    status = BitstreamWriteBits(stream, 8, seqParam->level_idc);
+    status = ue_v(stream, seqParam->seq_parameter_set_id);
+    status = ue_v(stream, seqParam->log2_max_frame_num_minus4);
+    status = ue_v(stream, seqParam->pic_order_cnt_type);
+    if (status != AVCENC_SUCCESS)
+    {
+        return status;
+    }
+
+    if (seqParam->pic_order_cnt_type == 0)
+    {
+        status = ue_v(stream, seqParam->log2_max_pic_order_cnt_lsb_minus4);
+    }
+    else if (seqParam->pic_order_cnt_type == 1)
+    {
+        status = BitstreamWrite1Bit(stream, seqParam->delta_pic_order_always_zero_flag);
+        status = se_v(stream, seqParam->offset_for_non_ref_pic); /* upto 32 bits */
+        status = se_v(stream, seqParam->offset_for_top_to_bottom_field); /* upto 32 bits */
+        status = ue_v(stream, seqParam->num_ref_frames_in_pic_order_cnt_cycle);
+
+        for (i = 0; i < (int)(seqParam->num_ref_frames_in_pic_order_cnt_cycle); i++)
+        {
+            status = se_v(stream, seqParam->offset_for_ref_frame[i]); /* upto 32 bits */
+        }
+    }
+    if (status != AVCENC_SUCCESS)
+    {
+        return status;
+    }
+
+    status = ue_v(stream, seqParam->num_ref_frames);
+    status = BitstreamWrite1Bit(stream, seqParam->gaps_in_frame_num_value_allowed_flag);
+    status = ue_v(stream, seqParam->pic_width_in_mbs_minus1);
+    status = ue_v(stream, seqParam->pic_height_in_map_units_minus1);
+    status = BitstreamWrite1Bit(stream, seqParam->frame_mbs_only_flag);
+    if (status != AVCENC_SUCCESS)
+    {
+        return status;
+    }
+    /* if frame_mbs_only_flag is 0, then write, mb_adaptive_frame_field_frame here */
+
+    status = BitstreamWrite1Bit(stream, seqParam->direct_8x8_inference_flag);
+    status = BitstreamWrite1Bit(stream, seqParam->frame_cropping_flag);
+    if (seqParam->frame_cropping_flag)
+    {
+        status = ue_v(stream, seqParam->frame_crop_left_offset);
+        status = ue_v(stream, seqParam->frame_crop_right_offset);
+        status = ue_v(stream, seqParam->frame_crop_top_offset);
+        status = ue_v(stream, seqParam->frame_crop_bottom_offset);
+    }
+    if (status != AVCENC_SUCCESS)
+    {
+        return status;
+    }
+
+    status = BitstreamWrite1Bit(stream, seqParam->vui_parameters_present_flag);
+    if (seqParam->vui_parameters_present_flag)
+    {
+        /* not supported */
+        //return AVCENC_SPS_FAIL;
+        EncodeVUI(stream, vui);
+    }
+
+    return status;
+}
+
+
+void EncodeVUI(AVCEncBitstream* stream, AVCVUIParams* vui)
+{
+    int temp;
+
+    temp = vui->aspect_ratio_info_present_flag;
+    BitstreamWrite1Bit(stream, temp);
+    if (temp)
+    {
+        BitstreamWriteBits(stream, 8, vui->aspect_ratio_idc);
+        if (vui->aspect_ratio_idc == 255)
+        {
+            BitstreamWriteBits(stream, 16, vui->sar_width);
+            BitstreamWriteBits(stream, 16, vui->sar_height);
+        }
+    }
+    temp = vui->overscan_info_present_flag;
+    BitstreamWrite1Bit(stream, temp);
+    if (temp)
+    {
+        BitstreamWrite1Bit(stream, vui->overscan_appropriate_flag);
+    }
+    temp = vui->video_signal_type_present_flag;
+    BitstreamWrite1Bit(stream, temp);
+    if (temp)
+    {
+        BitstreamWriteBits(stream, 3, vui->video_format);
+        BitstreamWrite1Bit(stream, vui->video_full_range_flag);
+        temp = vui->colour_description_present_flag;
+        BitstreamWrite1Bit(stream, temp);
+        if (temp)
+        {
+            BitstreamWriteBits(stream, 8, vui->colour_primaries);
+            BitstreamWriteBits(stream, 8, vui->transfer_characteristics);
+            BitstreamWriteBits(stream, 8, vui->matrix_coefficients);
+        }
+    }
+    temp = vui->chroma_location_info_present_flag;
+    BitstreamWrite1Bit(stream, temp);
+    if (temp)
+    {
+        ue_v(stream, vui->chroma_sample_loc_type_top_field);
+        ue_v(stream, vui->chroma_sample_loc_type_bottom_field);
+    }
+
+    temp = vui->timing_info_present_flag;
+    BitstreamWrite1Bit(stream, temp);
+    if (temp)
+    {
+        BitstreamWriteBits(stream, 32, vui->num_units_in_tick);
+        BitstreamWriteBits(stream, 32, vui->time_scale);
+        BitstreamWrite1Bit(stream, vui->fixed_frame_rate_flag);
+    }
+
+    temp = vui->nal_hrd_parameters_present_flag;
+    BitstreamWrite1Bit(stream, temp);
+    if (temp)
+    {
+        EncodeHRD(stream, &(vui->nal_hrd_parameters));
+    }
+    temp = vui->vcl_hrd_parameters_present_flag;
+    BitstreamWrite1Bit(stream, temp);
+    if (temp)
+    {
+        EncodeHRD(stream, &(vui->vcl_hrd_parameters));
+    }
+    if (vui->nal_hrd_parameters_present_flag || vui->vcl_hrd_parameters_present_flag)
+    {
+        BitstreamWrite1Bit(stream, vui->low_delay_hrd_flag);
+    }
+    BitstreamWrite1Bit(stream, vui->pic_struct_present_flag);
+    temp = vui->bitstream_restriction_flag;
+    BitstreamWrite1Bit(stream, temp);
+    if (temp)
+    {
+        BitstreamWrite1Bit(stream, vui->motion_vectors_over_pic_boundaries_flag);
+        ue_v(stream, vui->max_bytes_per_pic_denom);
+        ue_v(stream, vui->max_bits_per_mb_denom);
+        ue_v(stream, vui->log2_max_mv_length_horizontal);
+        ue_v(stream, vui->log2_max_mv_length_vertical);
+        ue_v(stream, vui->max_dec_frame_reordering);
+        ue_v(stream, vui->max_dec_frame_buffering);
+    }
+
+    return ;
+}
+
+
+void EncodeHRD(AVCEncBitstream* stream, AVCHRDParams* hrd)
+{
+    int i;
+
+    ue_v(stream, hrd->cpb_cnt_minus1);
+    BitstreamWriteBits(stream, 4, hrd->bit_rate_scale);
+    BitstreamWriteBits(stream, 4, hrd->cpb_size_scale);
+    for (i = 0; i <= (int)hrd->cpb_cnt_minus1; i++)
+    {
+        ue_v(stream, hrd->bit_rate_value_minus1[i]);
+        ue_v(stream, hrd->cpb_size_value_minus1[i]);
+        ue_v(stream, hrd->cbr_flag[i]);
+    }
+    BitstreamWriteBits(stream, 5, hrd->initial_cpb_removal_delay_length_minus1);
+    BitstreamWriteBits(stream, 5, hrd->cpb_removal_delay_length_minus1);
+    BitstreamWriteBits(stream, 5, hrd->dpb_output_delay_length_minus1);
+    BitstreamWriteBits(stream, 5, hrd->time_offset_length);
+
+    return ;
+}
+
+
+
+/** see subclause 7.4.2.2 */
+/* no need for checking the valid range , already done in SetEncodeParam().
+If we have to send another SPS, the ranges should be verified first before
+users call PVAVCEncodeSPS()*/
+AVCEnc_Status EncodePPS(AVCEncObject *encvid, AVCEncBitstream *stream)
+{
+    AVCCommonObj *video = encvid->common;
+    AVCEnc_Status status = AVCENC_SUCCESS;
+    AVCPicParamSet *picParam = video->currPicParams;
+    int i, iGroup, numBits;
+    uint temp;
+
+    status = ue_v(stream, picParam->pic_parameter_set_id);
+    status = ue_v(stream, picParam->seq_parameter_set_id);
+    status = BitstreamWrite1Bit(stream, picParam->entropy_coding_mode_flag);
+    status = BitstreamWrite1Bit(stream, picParam->pic_order_present_flag);
+    if (status != AVCENC_SUCCESS)
+    {
+        return status;
+    }
+
+    status = ue_v(stream, picParam->num_slice_groups_minus1);
+    if (picParam->num_slice_groups_minus1 > 0)
+    {
+        status = ue_v(stream, picParam->slice_group_map_type);
+        if (picParam->slice_group_map_type == 0)
+        {
+            for (iGroup = 0; iGroup <= (int)picParam->num_slice_groups_minus1; iGroup++)
+            {
+                status = ue_v(stream, picParam->run_length_minus1[iGroup]);
+            }
+        }
+        else if (picParam->slice_group_map_type == 2)
+        {
+            for (iGroup = 0; iGroup < (int)picParam->num_slice_groups_minus1; iGroup++)
+            {
+                status = ue_v(stream, picParam->top_left[iGroup]);
+                status = ue_v(stream, picParam->bottom_right[iGroup]);
+            }
+        }
+        else if (picParam->slice_group_map_type == 3 ||
+                 picParam->slice_group_map_type == 4 ||
+                 picParam->slice_group_map_type == 5)
+        {
+            status = BitstreamWrite1Bit(stream, picParam->slice_group_change_direction_flag);
+            status = ue_v(stream, picParam->slice_group_change_rate_minus1);
+        }
+        else /*if(picParam->slice_group_map_type == 6)*/
+        {
+            status = ue_v(stream, picParam->pic_size_in_map_units_minus1);
+
+            numBits = 0;/* ceil(log2(num_slice_groups_minus1+1)) bits */
+            i = picParam->num_slice_groups_minus1;
+            while (i > 0)
+            {
+                numBits++;
+                i >>= 1;
+            }
+
+            for (i = 0; i <= (int)picParam->pic_size_in_map_units_minus1; i++)
+            {
+                status = BitstreamWriteBits(stream, numBits, picParam->slice_group_id[i]);
+            }
+        }
+    }
+    if (status != AVCENC_SUCCESS)
+    {
+        return status;
+    }
+
+    status = ue_v(stream, picParam->num_ref_idx_l0_active_minus1);
+    status = ue_v(stream, picParam->num_ref_idx_l1_active_minus1);
+    status = BitstreamWrite1Bit(stream, picParam->weighted_pred_flag);
+    status = BitstreamWriteBits(stream, 2, picParam->weighted_bipred_idc);
+    if (status != AVCENC_SUCCESS)
+    {
+        return status;
+    }
+
+    status = se_v(stream, picParam->pic_init_qp_minus26);
+    status = se_v(stream, picParam->pic_init_qs_minus26);
+    status = se_v(stream, picParam->chroma_qp_index_offset);
+
+    temp = picParam->deblocking_filter_control_present_flag << 2;
+    temp |= (picParam->constrained_intra_pred_flag << 1);
+    temp |= picParam->redundant_pic_cnt_present_flag;
+
+    status = BitstreamWriteBits(stream, 3, temp);
+
+    return status;
+}
+
+/** see subclause 7.4.3 */
+AVCEnc_Status EncodeSliceHeader(AVCEncObject *encvid, AVCEncBitstream *stream)
+{
+    AVCCommonObj *video = encvid->common;
+    AVCSliceHeader *sliceHdr = video->sliceHdr;
+    AVCPicParamSet *currPPS = video->currPicParams;
+    AVCSeqParamSet *currSPS = video->currSeqParams;
+    AVCEnc_Status status = AVCENC_SUCCESS;
+    int slice_type, temp, i;
+    int num_bits;
+
+    num_bits = (stream->write_pos << 3) - stream->bit_left;
+
+    status = ue_v(stream, sliceHdr->first_mb_in_slice);
+
+    slice_type = video->slice_type;
+
+    if (video->mbNum == 0) /* first mb in frame */
+    {
+        status = ue_v(stream, sliceHdr->slice_type);
+    }
+    else
+    {
+        status = ue_v(stream, slice_type);
+    }
+
+    status = ue_v(stream, sliceHdr->pic_parameter_set_id);
+
+    status = BitstreamWriteBits(stream, currSPS->log2_max_frame_num_minus4 + 4, sliceHdr->frame_num);
+
+    if (status != AVCENC_SUCCESS)
+    {
+        return status;
+    }
+    /* if frame_mbs_only_flag is 0, encode field_pic_flag, bottom_field_flag here */
+
+    if (video->nal_unit_type == AVC_NALTYPE_IDR)
+    {
+        status = ue_v(stream, sliceHdr->idr_pic_id);
+    }
+
+    if (currSPS->pic_order_cnt_type == 0)
+    {
+        status = BitstreamWriteBits(stream, currSPS->log2_max_pic_order_cnt_lsb_minus4 + 4,
+                                    sliceHdr->pic_order_cnt_lsb);
+
+        if (currPPS->pic_order_present_flag && !sliceHdr->field_pic_flag)
+        {
+            status = se_v(stream, sliceHdr->delta_pic_order_cnt_bottom); /* 32 bits */
+        }
+    }
+    if (currSPS->pic_order_cnt_type == 1 && !currSPS->delta_pic_order_always_zero_flag)
+    {
+        status = se_v(stream, sliceHdr->delta_pic_order_cnt[0]);    /* 32 bits */
+        if (currPPS->pic_order_present_flag && !sliceHdr->field_pic_flag)
+        {
+            status = se_v(stream, sliceHdr->delta_pic_order_cnt[1]); /* 32 bits */
+        }
+    }
+
+    if (currPPS->redundant_pic_cnt_present_flag)
+    {
+        status = ue_v(stream, sliceHdr->redundant_pic_cnt);
+    }
+
+    if (slice_type == AVC_B_SLICE)
+    {
+        status = BitstreamWrite1Bit(stream, sliceHdr->direct_spatial_mv_pred_flag);
+    }
+
+    if (status != AVCENC_SUCCESS)
+    {
+        return status;
+    }
+
+    if (slice_type == AVC_P_SLICE || slice_type == AVC_SP_SLICE || slice_type == AVC_B_SLICE)
+    {
+        status = BitstreamWrite1Bit(stream, sliceHdr->num_ref_idx_active_override_flag);
+        if (sliceHdr->num_ref_idx_active_override_flag)
+        {
+            /* we shouldn't enter this part at all */
+            status = ue_v(stream, sliceHdr->num_ref_idx_l0_active_minus1);
+            if (slice_type == AVC_B_SLICE)
+            {
+                status = ue_v(stream, sliceHdr->num_ref_idx_l1_active_minus1);
+            }
+        }
+    }
+    if (status != AVCENC_SUCCESS)
+    {
+        return status;
+    }
+
+    /* ref_pic_list_reordering() */
+    status = ref_pic_list_reordering(video, stream, sliceHdr, slice_type);
+    if (status != AVCENC_SUCCESS)
+    {
+        return status;
+    }
+
+    if ((currPPS->weighted_pred_flag && (slice_type == AVC_P_SLICE || slice_type == AVC_SP_SLICE)) ||
+            (currPPS->weighted_bipred_idc == 1 && slice_type == AVC_B_SLICE))
+    {
+        //      pred_weight_table(); // not supported !!
+        return AVCENC_PRED_WEIGHT_TAB_FAIL;
+    }
+
+    if (video->nal_ref_idc != 0)
+    {
+        status = dec_ref_pic_marking(video, stream, sliceHdr);
+        if (status != AVCENC_SUCCESS)
+        {
+            return status;
+        }
+    }
+
+    if (currPPS->entropy_coding_mode_flag && slice_type != AVC_I_SLICE && slice_type != AVC_SI_SLICE)
+    {
+        return AVCENC_CABAC_FAIL;
+        /*      ue_v(stream,&(sliceHdr->cabac_init_idc));
+                if(sliceHdr->cabac_init_idc > 2){
+                    // not supported !!!!
+                }*/
+    }
+
+    status = se_v(stream, sliceHdr->slice_qp_delta);
+    if (status != AVCENC_SUCCESS)
+    {
+        return status;
+    }
+
+    if (slice_type == AVC_SP_SLICE || slice_type == AVC_SI_SLICE)
+    {
+        if (slice_type == AVC_SP_SLICE)
+        {
+            status = BitstreamWrite1Bit(stream, sliceHdr->sp_for_switch_flag);
+            /* if sp_for_switch_flag is 0, P macroblocks in SP slice is decoded using
+            SP decoding process for non-switching pictures in 8.6.1 */
+            /* else, P macroblocks in SP slice is decoded using SP and SI decoding
+            process for switching picture in 8.6.2 */
+        }
+        status = se_v(stream, sliceHdr->slice_qs_delta);
+        if (status != AVCENC_SUCCESS)
+        {
+            return status;
+        }
+    }
+
+    if (currPPS->deblocking_filter_control_present_flag)
+    {
+
+        status = ue_v(stream, sliceHdr->disable_deblocking_filter_idc);
+
+        if (sliceHdr->disable_deblocking_filter_idc != 1)
+        {
+            status = se_v(stream, sliceHdr->slice_alpha_c0_offset_div2);
+
+            status = se_v(stream, sliceHdr->slice_beta_offset_div_2);
+        }
+        if (status != AVCENC_SUCCESS)
+        {
+            return status;
+        }
+    }
+
+    if (currPPS->num_slice_groups_minus1 > 0 && currPPS->slice_group_map_type >= 3
+            && currPPS->slice_group_map_type <= 5)
+    {
+        /* Ceil(Log2(PicSizeInMapUnits/(float)SliceGroupChangeRate + 1)) */
+        temp = video->PicSizeInMapUnits / video->SliceGroupChangeRate;
+        if (video->PicSizeInMapUnits % video->SliceGroupChangeRate)
+        {
+            temp++;
+        }
+        i = 0;
+        while (temp > 1)
+        {
+            temp >>= 1;
+            i++;
+        }
+
+        BitstreamWriteBits(stream, i, sliceHdr->slice_group_change_cycle);
+    }
+
+
+    encvid->rateCtrl->NumberofHeaderBits += (stream->write_pos << 3) - stream->bit_left - num_bits;
+
+    return AVCENC_SUCCESS;
+}
+
+/** see subclause 7.4.3.1 */
+AVCEnc_Status ref_pic_list_reordering(AVCCommonObj *video, AVCEncBitstream *stream, AVCSliceHeader *sliceHdr, int slice_type)
+{
+    (void)(video);
+    int i;
+    AVCEnc_Status status = AVCENC_SUCCESS;
+
+    if (slice_type != AVC_I_SLICE && slice_type != AVC_SI_SLICE)
+    {
+        status = BitstreamWrite1Bit(stream, sliceHdr->ref_pic_list_reordering_flag_l0);
+        if (sliceHdr->ref_pic_list_reordering_flag_l0)
+        {
+            i = 0;
+            do
+            {
+                status = ue_v(stream, sliceHdr->reordering_of_pic_nums_idc_l0[i]);
+                if (sliceHdr->reordering_of_pic_nums_idc_l0[i] == 0 ||
+                        sliceHdr->reordering_of_pic_nums_idc_l0[i] == 1)
+                {
+                    status = ue_v(stream, sliceHdr->abs_diff_pic_num_minus1_l0[i]);
+                    /* this check should be in InitSlice(), if we ever use it */
+                    /*if(sliceHdr->reordering_of_pic_nums_idc_l0[i] == 0 &&
+                        sliceHdr->abs_diff_pic_num_minus1_l0[i] > video->MaxPicNum/2 -1)
+                    {
+                        return AVCENC_REF_PIC_REORDER_FAIL; // out of range
+                    }
+                    if(sliceHdr->reordering_of_pic_nums_idc_l0[i] == 1 &&
+                        sliceHdr->abs_diff_pic_num_minus1_l0[i] > video->MaxPicNum/2 -2)
+                    {
+                        return AVCENC_REF_PIC_REORDER_FAIL; // out of range
+                    }*/
+                }
+                else if (sliceHdr->reordering_of_pic_nums_idc_l0[i] == 2)
+                {
+                    status = ue_v(stream, sliceHdr->long_term_pic_num_l0[i]);
+                }
+                i++;
+            }
+            while (sliceHdr->reordering_of_pic_nums_idc_l0[i] != 3
+                    && i <= (int)sliceHdr->num_ref_idx_l0_active_minus1 + 1) ;
+        }
+    }
+    if (slice_type == AVC_B_SLICE)
+    {
+        status = BitstreamWrite1Bit(stream, sliceHdr->ref_pic_list_reordering_flag_l1);
+        if (sliceHdr->ref_pic_list_reordering_flag_l1)
+        {
+            i = 0;
+            do
+            {
+                status = ue_v(stream, sliceHdr->reordering_of_pic_nums_idc_l1[i]);
+                if (sliceHdr->reordering_of_pic_nums_idc_l1[i] == 0 ||
+                        sliceHdr->reordering_of_pic_nums_idc_l1[i] == 1)
+                {
+                    status = ue_v(stream, sliceHdr->abs_diff_pic_num_minus1_l1[i]);
+                    /* This check should be in InitSlice() if we ever use it
+                    if(sliceHdr->reordering_of_pic_nums_idc_l1[i] == 0 &&
+                        sliceHdr->abs_diff_pic_num_minus1_l1[i] > video->MaxPicNum/2 -1)
+                    {
+                        return AVCENC_REF_PIC_REORDER_FAIL; // out of range
+                    }
+                    if(sliceHdr->reordering_of_pic_nums_idc_l1[i] == 1 &&
+                        sliceHdr->abs_diff_pic_num_minus1_l1[i] > video->MaxPicNum/2 -2)
+                    {
+                        return AVCENC_REF_PIC_REORDER_FAIL; // out of range
+                    }*/
+                }
+                else if (sliceHdr->reordering_of_pic_nums_idc_l1[i] == 2)
+                {
+                    status = ue_v(stream, sliceHdr->long_term_pic_num_l1[i]);
+                }
+                i++;
+            }
+            while (sliceHdr->reordering_of_pic_nums_idc_l1[i] != 3
+                    && i <= (int)sliceHdr->num_ref_idx_l1_active_minus1 + 1) ;
+        }
+    }
+
+    return status;
+}
+
+/** see subclause 7.4.3.3 */
+AVCEnc_Status dec_ref_pic_marking(AVCCommonObj *video, AVCEncBitstream *stream, AVCSliceHeader *sliceHdr)
+{
+    int i;
+    AVCEnc_Status status = AVCENC_SUCCESS;
+
+    if (video->nal_unit_type == AVC_NALTYPE_IDR)
+    {
+        status = BitstreamWrite1Bit(stream, sliceHdr->no_output_of_prior_pics_flag);
+        status = BitstreamWrite1Bit(stream, sliceHdr->long_term_reference_flag);
+        if (sliceHdr->long_term_reference_flag == 0) /* used for short-term */
+        {
+            video->MaxLongTermFrameIdx = -1; /* no long-term frame indx */
+        }
+        else /* used for long-term */
+        {
+            video->MaxLongTermFrameIdx = 0;
+            video->LongTermFrameIdx = 0;
+        }
+    }
+    else
+    {
+        status = BitstreamWrite1Bit(stream, sliceHdr->adaptive_ref_pic_marking_mode_flag); /* default to zero */
+        if (sliceHdr->adaptive_ref_pic_marking_mode_flag)
+        {
+            i = 0;
+            do
+            {
+                status = ue_v(stream, sliceHdr->memory_management_control_operation[i]);
+                if (sliceHdr->memory_management_control_operation[i] == 1 ||
+                        sliceHdr->memory_management_control_operation[i] == 3)
+                {
+                    status = ue_v(stream, sliceHdr->difference_of_pic_nums_minus1[i]);
+                }
+                if (sliceHdr->memory_management_control_operation[i] == 2)
+                {
+                    status = ue_v(stream, sliceHdr->long_term_pic_num[i]);
+                }
+                if (sliceHdr->memory_management_control_operation[i] == 3 ||
+                        sliceHdr->memory_management_control_operation[i] == 6)
+                {
+                    status = ue_v(stream, sliceHdr->long_term_frame_idx[i]);
+                }
+                if (sliceHdr->memory_management_control_operation[i] == 4)
+                {
+                    status = ue_v(stream, sliceHdr->max_long_term_frame_idx_plus1[i]);
+                }
+                i++;
+            }
+            while (sliceHdr->memory_management_control_operation[i] != 0 && i < MAX_DEC_REF_PIC_MARKING);
+            if (i >= MAX_DEC_REF_PIC_MARKING && sliceHdr->memory_management_control_operation[i] != 0)
+            {
+                return AVCENC_DEC_REF_PIC_MARK_FAIL; /* we're screwed!!, not enough memory */
+            }
+        }
+    }
+
+    return status;
+}
+
+/* see subclause 8.2.1 Decoding process for picture order count.
+See also PostPOC() for initialization of some variables. */
+AVCEnc_Status InitPOC(AVCEncObject *encvid)
+{
+    AVCCommonObj *video = encvid->common;
+    AVCSeqParamSet *currSPS = video->currSeqParams;
+    AVCSliceHeader *sliceHdr = video->sliceHdr;
+    AVCFrameIO  *currInput = encvid->currInput;
+    int i;
+
+    switch (currSPS->pic_order_cnt_type)
+    {
+        case 0: /* POC MODE 0 , subclause 8.2.1.1 */
+            /* encoding part */
+            if (video->nal_unit_type == AVC_NALTYPE_IDR)
+            {
+                encvid->dispOrdPOCRef = currInput->disp_order;
+            }
+            while (currInput->disp_order < encvid->dispOrdPOCRef)
+            {
+                encvid->dispOrdPOCRef -= video->MaxPicOrderCntLsb;
+            }
+            sliceHdr->pic_order_cnt_lsb = currInput->disp_order - encvid->dispOrdPOCRef;
+            while (sliceHdr->pic_order_cnt_lsb >= video->MaxPicOrderCntLsb)
+            {
+                sliceHdr->pic_order_cnt_lsb -= video->MaxPicOrderCntLsb;
+            }
+            /* decoding part */
+            /* Calculate the MSBs of current picture */
+            if (video->nal_unit_type == AVC_NALTYPE_IDR)
+            {
+                video->prevPicOrderCntMsb = 0;
+                video->prevPicOrderCntLsb = 0;
+            }
+            if (sliceHdr->pic_order_cnt_lsb  <  video->prevPicOrderCntLsb  &&
+                    (video->prevPicOrderCntLsb - sliceHdr->pic_order_cnt_lsb)  >= (video->MaxPicOrderCntLsb / 2))
+                video->PicOrderCntMsb = video->prevPicOrderCntMsb + video->MaxPicOrderCntLsb;
+            else if (sliceHdr->pic_order_cnt_lsb  >  video->prevPicOrderCntLsb  &&
+                     (sliceHdr->pic_order_cnt_lsb - video->prevPicOrderCntLsb)  > (video->MaxPicOrderCntLsb / 2))
+                video->PicOrderCntMsb = video->prevPicOrderCntMsb - video->MaxPicOrderCntLsb;
+            else
+                video->PicOrderCntMsb = video->prevPicOrderCntMsb;
+
+            /* JVT-I010 page 81 is different from JM7.3 */
+            if (!sliceHdr->field_pic_flag || !sliceHdr->bottom_field_flag)
+            {
+                video->PicOrderCnt = video->TopFieldOrderCnt = video->PicOrderCntMsb + sliceHdr->pic_order_cnt_lsb;
+            }
+
+            if (!sliceHdr->field_pic_flag)
+            {
+                video->BottomFieldOrderCnt = video->TopFieldOrderCnt + sliceHdr->delta_pic_order_cnt_bottom;
+            }
+            else if (sliceHdr->bottom_field_flag)
+            {
+                video->PicOrderCnt = video->BottomFieldOrderCnt = video->PicOrderCntMsb + sliceHdr->pic_order_cnt_lsb;
+            }
+
+            if (!sliceHdr->field_pic_flag)
+            {
+                video->PicOrderCnt = AVC_MIN(video->TopFieldOrderCnt, video->BottomFieldOrderCnt);
+            }
+
+            if (video->currPicParams->pic_order_present_flag && !sliceHdr->field_pic_flag)
+            {
+                sliceHdr->delta_pic_order_cnt_bottom = 0; /* defaulted to zero */
+            }
+
+            break;
+        case 1: /* POC MODE 1, subclause 8.2.1.2 */
+            /* calculate FrameNumOffset */
+            if (video->nal_unit_type == AVC_NALTYPE_IDR)
+            {
+                encvid->dispOrdPOCRef = currInput->disp_order;  /* reset the reference point */
+                video->prevFrameNumOffset = 0;
+                video->FrameNumOffset = 0;
+            }
+            else if (video->prevFrameNum > sliceHdr->frame_num)
+            {
+                video->FrameNumOffset = video->prevFrameNumOffset + video->MaxFrameNum;
+            }
+            else
+            {
+                video->FrameNumOffset = video->prevFrameNumOffset;
+            }
+            /* calculate absFrameNum */
+            if (currSPS->num_ref_frames_in_pic_order_cnt_cycle)
+            {
+                video->absFrameNum = video->FrameNumOffset + sliceHdr->frame_num;
+            }
+            else
+            {
+                video->absFrameNum = 0;
+            }
+
+            if (video->absFrameNum > 0 && video->nal_ref_idc == 0)
+            {
+                video->absFrameNum--;
+            }
+
+            /* derive picOrderCntCycleCnt and frameNumInPicOrderCntCycle */
+            if (video->absFrameNum > 0)
+            {
+                video->picOrderCntCycleCnt = (video->absFrameNum - 1) / currSPS->num_ref_frames_in_pic_order_cnt_cycle;
+                video->frameNumInPicOrderCntCycle = (video->absFrameNum - 1) % currSPS->num_ref_frames_in_pic_order_cnt_cycle;
+            }
+            /* derive expectedDeltaPerPicOrderCntCycle, this value can be computed up front. */
+            video->expectedDeltaPerPicOrderCntCycle = 0;
+            for (i = 0; i < (int)currSPS->num_ref_frames_in_pic_order_cnt_cycle; i++)
+            {
+                video->expectedDeltaPerPicOrderCntCycle += currSPS->offset_for_ref_frame[i];
+            }
+            /* derive expectedPicOrderCnt */
+            if (video->absFrameNum)
+            {
+                video->expectedPicOrderCnt = video->picOrderCntCycleCnt * video->expectedDeltaPerPicOrderCntCycle;
+                for (i = 0; i <= video->frameNumInPicOrderCntCycle; i++)
+                {
+                    video->expectedPicOrderCnt += currSPS->offset_for_ref_frame[i];
+                }
+            }
+            else
+            {
+                video->expectedPicOrderCnt = 0;
+            }
+
+            if (video->nal_ref_idc == 0)
+            {
+                video->expectedPicOrderCnt += currSPS->offset_for_non_ref_pic;
+            }
+            /* derive TopFieldOrderCnt and BottomFieldOrderCnt */
+            /* encoding part */
+            if (!currSPS->delta_pic_order_always_zero_flag)
+            {
+                sliceHdr->delta_pic_order_cnt[0] = currInput->disp_order - encvid->dispOrdPOCRef - video->expectedPicOrderCnt;
+
+                if (video->currPicParams->pic_order_present_flag && !sliceHdr->field_pic_flag)
+                {
+                    sliceHdr->delta_pic_order_cnt[1] = sliceHdr->delta_pic_order_cnt[0]; /* should be calculated from currInput->bottom_field->disp_order */
+                }
+                else
+                {
+                    sliceHdr->delta_pic_order_cnt[1] = 0;
+                }
+            }
+            else
+            {
+                sliceHdr->delta_pic_order_cnt[0] = sliceHdr->delta_pic_order_cnt[1] = 0;
+            }
+
+            if (sliceHdr->field_pic_flag == 0)
+            {
+                video->TopFieldOrderCnt = video->expectedPicOrderCnt + sliceHdr->delta_pic_order_cnt[0];
+                video->BottomFieldOrderCnt = video->TopFieldOrderCnt + currSPS->offset_for_top_to_bottom_field + sliceHdr->delta_pic_order_cnt[1];
+
+                video->PicOrderCnt = AVC_MIN(video->TopFieldOrderCnt, video->BottomFieldOrderCnt);
+            }
+            else if (sliceHdr->bottom_field_flag == 0)
+            {
+                video->TopFieldOrderCnt = video->expectedPicOrderCnt + sliceHdr->delta_pic_order_cnt[0];
+                video->PicOrderCnt = video->TopFieldOrderCnt;
+            }
+            else
+            {
+                video->BottomFieldOrderCnt = video->expectedPicOrderCnt + currSPS->offset_for_top_to_bottom_field + sliceHdr->delta_pic_order_cnt[0];
+                video->PicOrderCnt = video->BottomFieldOrderCnt;
+            }
+            break;
+
+
+        case 2: /* POC MODE 2, subclause 8.2.1.3 */
+            /* decoding order must be the same as display order */
+            /* we don't check for that. The decoder will just output in decoding order. */
+            /* Check for 2 consecutive non-reference frame */
+            if (video->nal_ref_idc == 0)
+            {
+                if (encvid->dispOrdPOCRef == 1)
+                {
+                    return AVCENC_CONSECUTIVE_NONREF;
+                }
+                encvid->dispOrdPOCRef = 1;  /* act as a flag for non ref */
+            }
+            else
+            {
+                encvid->dispOrdPOCRef = 0;
+            }
+
+
+            if (video->nal_unit_type == AVC_NALTYPE_IDR)
+            {
+                video->FrameNumOffset = 0;
+            }
+            else if (video->prevFrameNum > sliceHdr->frame_num)
+            {
+                video->FrameNumOffset = video->prevFrameNumOffset + video->MaxFrameNum;
+            }
+            else
+            {
+                video->FrameNumOffset = video->prevFrameNumOffset;
+            }
+            /* derive tempPicOrderCnt, we just use PicOrderCnt */
+            if (video->nal_unit_type == AVC_NALTYPE_IDR)
+            {
+                video->PicOrderCnt = 0;
+            }
+            else if (video->nal_ref_idc == 0)
+            {
+                video->PicOrderCnt = 2 * (video->FrameNumOffset + sliceHdr->frame_num) - 1;
+            }
+            else
+            {
+                video->PicOrderCnt = 2 * (video->FrameNumOffset + sliceHdr->frame_num);
+            }
+            /* derive TopFieldOrderCnt and BottomFieldOrderCnt */
+            if (sliceHdr->field_pic_flag == 0)
+            {
+                video->TopFieldOrderCnt = video->BottomFieldOrderCnt = video->PicOrderCnt;
+            }
+            else if (sliceHdr->bottom_field_flag)
+            {
+                video->BottomFieldOrderCnt = video->PicOrderCnt;
+            }
+            else
+            {
+                video->TopFieldOrderCnt = video->PicOrderCnt;
+            }
+            break;
+        default:
+            return AVCENC_POC_FAIL;
+    }
+
+    return AVCENC_SUCCESS;
+}
+
+/** see subclause 8.2.1 */
+AVCEnc_Status PostPOC(AVCCommonObj *video)
+{
+    AVCSliceHeader *sliceHdr = video->sliceHdr;
+    AVCSeqParamSet *currSPS = video->currSeqParams;
+
+    video->prevFrameNum = sliceHdr->frame_num;
+
+    switch (currSPS->pic_order_cnt_type)
+    {
+        case 0: /* subclause 8.2.1.1 */
+            if (video->mem_mgr_ctrl_eq_5)
+            {
+                video->prevPicOrderCntMsb = 0;
+                video->prevPicOrderCntLsb = video->TopFieldOrderCnt;
+            }
+            else
+            {
+                video->prevPicOrderCntMsb = video->PicOrderCntMsb;
+                video->prevPicOrderCntLsb = sliceHdr->pic_order_cnt_lsb;
+            }
+            break;
+        case 1:  /* subclause 8.2.1.2 and 8.2.1.3 */
+        case 2:
+            if (video->mem_mgr_ctrl_eq_5)
+            {
+                video->prevFrameNumOffset = 0;
+            }
+            else
+            {
+                video->prevFrameNumOffset = video->FrameNumOffset;
+            }
+            break;
+    }
+
+    return AVCENC_SUCCESS;
+}
+
diff --git a/media/libstagefright/codecs/avc/enc/src/init.cpp b/media/libstagefright/codecs/avc/enc/src/init.cpp
new file mode 100644
index 0000000..c258b57
--- /dev/null
+++ b/media/libstagefright/codecs/avc/enc/src/init.cpp
@@ -0,0 +1,899 @@
+/* ------------------------------------------------------------------
+ * Copyright (C) 1998-2009 PacketVideo
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
+ * express or implied.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ * -------------------------------------------------------------------
+ */
+#include "avcenc_lib.h"
+#include "avcenc_api.h"
+
+#define LOG2_MAX_FRAME_NUM_MINUS4   12   /* 12 default */
+#define SLICE_GROUP_CHANGE_CYCLE    1    /* default */
+
+/* initialized variables to be used in SPS*/
+AVCEnc_Status  SetEncodeParam(AVCHandle* avcHandle, AVCEncParams* encParam,
+                              void* extSPS, void* extPPS)
+{
+    AVCEncObject *encvid = (AVCEncObject*) avcHandle->AVCObject;
+    AVCCommonObj *video = encvid->common;
+    AVCSeqParamSet *seqParam = video->currSeqParams;
+    AVCPicParamSet *picParam = video->currPicParams;
+    AVCSliceHeader *sliceHdr = video->sliceHdr;
+    AVCRateControl *rateCtrl = encvid->rateCtrl;
+    AVCEnc_Status status;
+    void *userData = avcHandle->userData;
+    int ii, maxFrameNum;
+
+    AVCSeqParamSet* extS = NULL;
+    AVCPicParamSet* extP = NULL;
+
+    if (extSPS) extS = (AVCSeqParamSet*) extSPS;
+    if (extPPS) extP = (AVCPicParamSet*) extPPS;
+
+    /* This part sets the default values of the encoding options this
+    library supports in seqParam, picParam and sliceHdr structures and
+    also copy the values from the encParam into the above 3 structures.
+
+    Some parameters will be assigned later when we encode SPS or PPS such as
+    the seq_parameter_id or pic_parameter_id. Also some of the slice parameters
+    have to be re-assigned per slice basis such as frame_num, slice_type,
+    first_mb_in_slice, pic_order_cnt_lsb, slice_qp_delta, slice_group_change_cycle */
+
+    /* profile_idc, constrained_setx_flag and level_idc is set by VerifyProfile(),
+    and VerifyLevel() functions later. */
+
+    encvid->fullsearch_enable = encParam->fullsearch;
+
+    encvid->outOfBandParamSet = ((encParam->out_of_band_param_set == AVC_ON) ? TRUE : FALSE);
+
+    /* parameters derived from the the encParam that are used in SPS */
+    if (extS)
+    {
+        video->MaxPicOrderCntLsb =  1 << (extS->log2_max_pic_order_cnt_lsb_minus4 + 4);
+        video->PicWidthInMbs = extS->pic_width_in_mbs_minus1 + 1;
+        video->PicHeightInMapUnits = extS->pic_height_in_map_units_minus1 + 1 ;
+        video->FrameHeightInMbs = (2 - extS->frame_mbs_only_flag) * video->PicHeightInMapUnits ;
+    }
+    else
+    {
+        video->MaxPicOrderCntLsb =  1 << (encParam->log2_max_poc_lsb_minus_4 + 4);
+        video->PicWidthInMbs = (encParam->width + 15) >> 4; /* round it to multiple of 16 */
+        video->FrameHeightInMbs = (encParam->height + 15) >> 4; /* round it to multiple of 16 */
+        video->PicHeightInMapUnits = video->FrameHeightInMbs;
+    }
+
+    video->PicWidthInSamplesL = video->PicWidthInMbs * 16 ;
+    if (video->PicWidthInSamplesL + 32 > 0xFFFF)
+    {
+        return AVCENC_NOT_SUPPORTED; // we use 2-bytes for pitch
+    }
+
+    video->PicWidthInSamplesC = video->PicWidthInMbs * 8 ;
+    video->PicHeightInMbs = video->FrameHeightInMbs;
+    video->PicSizeInMapUnits = video->PicWidthInMbs * video->PicHeightInMapUnits ;
+    video->PicHeightInSamplesL = video->PicHeightInMbs * 16;
+    video->PicHeightInSamplesC = video->PicHeightInMbs * 8;
+    video->PicSizeInMbs = video->PicWidthInMbs * video->PicHeightInMbs;
+
+    if (!extS && !extP)
+    {
+        maxFrameNum = (encParam->idr_period == -1) ? (1 << 16) : encParam->idr_period;
+        ii = 0;
+        while (maxFrameNum > 0)
+        {
+            ii++;
+            maxFrameNum >>= 1;
+        }
+        if (ii < 4) ii = 4;
+        else if (ii > 16) ii = 16;
+
+        seqParam->log2_max_frame_num_minus4 = ii - 4;//LOG2_MAX_FRAME_NUM_MINUS4; /* default */
+
+        video->MaxFrameNum = 1 << ii; //(LOG2_MAX_FRAME_NUM_MINUS4 + 4); /* default */
+        video->MaxPicNum = video->MaxFrameNum;
+
+        /************* set the SPS *******************/
+        seqParam->seq_parameter_set_id = 0; /* start with zero */
+        /* POC */
+        seqParam->pic_order_cnt_type = encParam->poc_type; /* POC type */
+        if (encParam->poc_type == 0)
+        {
+            if (/*encParam->log2_max_poc_lsb_minus_4<0 || (no need, it's unsigned)*/
+                encParam->log2_max_poc_lsb_minus_4 > 12)
+            {
+                return AVCENC_INVALID_POC_LSB;
+            }
+            seqParam->log2_max_pic_order_cnt_lsb_minus4 = encParam->log2_max_poc_lsb_minus_4;
+        }
+        else if (encParam->poc_type == 1)
+        {
+            seqParam->delta_pic_order_always_zero_flag = encParam->delta_poc_zero_flag;
+            seqParam->offset_for_non_ref_pic = encParam->offset_poc_non_ref;
+            seqParam->offset_for_top_to_bottom_field = encParam->offset_top_bottom;
+            seqParam->num_ref_frames_in_pic_order_cnt_cycle = encParam->num_ref_in_cycle;
+            if (encParam->offset_poc_ref == NULL)
+            {
+                return AVCENC_ENCPARAM_MEM_FAIL;
+            }
+            for (ii = 0; ii < encParam->num_ref_frame; ii++)
+            {
+                seqParam->offset_for_ref_frame[ii] = encParam->offset_poc_ref[ii];
+            }
+        }
+        /* number of reference frame */
+        if (encParam->num_ref_frame > 16 || encParam->num_ref_frame < 0)
+        {
+            return AVCENC_INVALID_NUM_REF;
+        }
+        seqParam->num_ref_frames = encParam->num_ref_frame; /* num reference frame range 0...16*/
+        seqParam->gaps_in_frame_num_value_allowed_flag = FALSE;
+        seqParam->pic_width_in_mbs_minus1 = video->PicWidthInMbs - 1;
+        seqParam->pic_height_in_map_units_minus1 = video->PicHeightInMapUnits - 1;
+        seqParam->frame_mbs_only_flag = TRUE;
+        seqParam->mb_adaptive_frame_field_flag = FALSE;
+        seqParam->direct_8x8_inference_flag = FALSE; /* default */
+        seqParam->frame_cropping_flag = FALSE;
+        seqParam->frame_crop_bottom_offset = 0;
+        seqParam->frame_crop_left_offset = 0;
+        seqParam->frame_crop_right_offset = 0;
+        seqParam->frame_crop_top_offset = 0;
+        seqParam->vui_parameters_present_flag = FALSE; /* default */
+    }
+    else if (extS) // use external SPS and PPS
+    {
+        seqParam->seq_parameter_set_id = extS->seq_parameter_set_id;
+        seqParam->log2_max_frame_num_minus4 = extS->log2_max_frame_num_minus4;
+        video->MaxFrameNum = 1 << (extS->log2_max_frame_num_minus4 + 4);
+        video->MaxPicNum = video->MaxFrameNum;
+        if (encParam->idr_period > (int)(video->MaxFrameNum) || (encParam->idr_period == -1))
+        {
+            encParam->idr_period = (int)video->MaxFrameNum;
+        }
+
+        seqParam->pic_order_cnt_type = extS->pic_order_cnt_type;
+        if (seqParam->pic_order_cnt_type == 0)
+        {
+            if (/*extS->log2_max_pic_order_cnt_lsb_minus4<0 || (no need it's unsigned)*/
+                extS->log2_max_pic_order_cnt_lsb_minus4 > 12)
+            {
+                return AVCENC_INVALID_POC_LSB;
+            }
+            seqParam->log2_max_pic_order_cnt_lsb_minus4 = extS->log2_max_pic_order_cnt_lsb_minus4;
+        }
+        else if (seqParam->pic_order_cnt_type == 1)
+        {
+            seqParam->delta_pic_order_always_zero_flag = extS->delta_pic_order_always_zero_flag;
+            seqParam->offset_for_non_ref_pic = extS->offset_for_non_ref_pic;
+            seqParam->offset_for_top_to_bottom_field = extS->offset_for_top_to_bottom_field;
+            seqParam->num_ref_frames_in_pic_order_cnt_cycle = extS->num_ref_frames_in_pic_order_cnt_cycle;
+            if (extS->offset_for_ref_frame == NULL)
+            {
+                return AVCENC_ENCPARAM_MEM_FAIL;
+            }
+            for (ii = 0; ii < (int) extS->num_ref_frames; ii++)
+            {
+                seqParam->offset_for_ref_frame[ii] = extS->offset_for_ref_frame[ii];
+            }
+        }
+        /* number of reference frame */
+        if (extS->num_ref_frames > 16 /*|| extS->num_ref_frames<0 (no need, it's unsigned)*/)
+        {
+            return AVCENC_INVALID_NUM_REF;
+        }
+        seqParam->num_ref_frames = extS->num_ref_frames; /* num reference frame range 0...16*/
+        seqParam->gaps_in_frame_num_value_allowed_flag = extS->gaps_in_frame_num_value_allowed_flag;
+        seqParam->pic_width_in_mbs_minus1 = extS->pic_width_in_mbs_minus1;
+        seqParam->pic_height_in_map_units_minus1 = extS->pic_height_in_map_units_minus1;
+        seqParam->frame_mbs_only_flag = extS->frame_mbs_only_flag;
+        if (extS->frame_mbs_only_flag != TRUE)
+        {
+            return AVCENC_NOT_SUPPORTED;
+        }
+        seqParam->mb_adaptive_frame_field_flag = extS->mb_adaptive_frame_field_flag;
+        if (extS->mb_adaptive_frame_field_flag != FALSE)
+        {
+            return AVCENC_NOT_SUPPORTED;
+        }
+
+        seqParam->direct_8x8_inference_flag = extS->direct_8x8_inference_flag;
+        seqParam->frame_cropping_flag = extS->frame_cropping_flag ;
+        if (extS->frame_cropping_flag != FALSE)
+        {
+            return AVCENC_NOT_SUPPORTED;
+        }
+
+        seqParam->frame_crop_bottom_offset = 0;
+        seqParam->frame_crop_left_offset = 0;
+        seqParam->frame_crop_right_offset = 0;
+        seqParam->frame_crop_top_offset = 0;
+        seqParam->vui_parameters_present_flag = extS->vui_parameters_present_flag;
+        if (extS->vui_parameters_present_flag)
+        {
+            memcpy(&(seqParam->vui_parameters), &(extS->vui_parameters), sizeof(AVCVUIParams));
+        }
+    }
+    else
+    {
+        return AVCENC_NOT_SUPPORTED;
+    }
+
+    /***************** now PPS ******************************/
+    if (!extP && !extS)
+    {
+        picParam->pic_parameter_set_id = (uint)(-1); /* start with zero */
+        picParam->seq_parameter_set_id = (uint)(-1); /* start with zero */
+        picParam->entropy_coding_mode_flag = 0; /* default to CAVLC */
+        picParam->pic_order_present_flag = 0; /* default for now, will need it for B-slice */
+        /* FMO */
+        if (encParam->num_slice_group < 1 || encParam->num_slice_group > MAX_NUM_SLICE_GROUP)
+        {
+            return AVCENC_INVALID_NUM_SLICEGROUP;
+        }
+        picParam->num_slice_groups_minus1 = encParam->num_slice_group - 1;
+
+        if (picParam->num_slice_groups_minus1 > 0)
+        {
+            picParam->slice_group_map_type = encParam->fmo_type;
+            switch (encParam->fmo_type)
+            {
+                case 0:
+                    for (ii = 0; ii <= (int)picParam->num_slice_groups_minus1; ii++)
+                    {
+                        picParam->run_length_minus1[ii] = encParam->run_length_minus1[ii];
+                    }
+                    break;
+                case 2:
+                    for (ii = 0; ii < (int)picParam->num_slice_groups_minus1; ii++)
+                    {
+                        picParam->top_left[ii] = encParam->top_left[ii];
+                        picParam->bottom_right[ii] = encParam->bottom_right[ii];
+                    }
+                    break;
+                case 3:
+                case 4:
+                case 5:
+                    if (encParam->change_dir_flag == AVC_ON)
+                    {
+                        picParam->slice_group_change_direction_flag = TRUE;
+                    }
+                    else
+                    {
+                        picParam->slice_group_change_direction_flag = FALSE;
+                    }
+                    if (/*encParam->change_rate_minus1 < 0 || (no need it's unsigned) */
+                        encParam->change_rate_minus1 > video->PicSizeInMapUnits - 1)
+                    {
+                        return AVCENC_INVALID_CHANGE_RATE;
+                    }
+                    picParam->slice_group_change_rate_minus1 = encParam->change_rate_minus1;
+                    video->SliceGroupChangeRate = picParam->slice_group_change_rate_minus1 + 1;
+                    break;
+                case 6:
+                    picParam->pic_size_in_map_units_minus1 = video->PicSizeInMapUnits - 1;
+
+                    /* allocate picParam->slice_group_id */
+                    picParam->slice_group_id = (uint*)avcHandle->CBAVC_Malloc(userData, sizeof(uint) * video->PicSizeInMapUnits, DEFAULT_ATTR);
+                    if (picParam->slice_group_id == NULL)
+                    {
+                        return AVCENC_MEMORY_FAIL;
+                    }
+
+                    if (encParam->slice_group == NULL)
+                    {
+                        return AVCENC_ENCPARAM_MEM_FAIL;
+                    }
+                    for (ii = 0; ii < (int)video->PicSizeInMapUnits; ii++)
+                    {
+                        picParam->slice_group_id[ii] = encParam->slice_group[ii];
+                    }
+                    break;
+                default:
+                    return AVCENC_INVALID_FMO_TYPE;
+            }
+        }
+        picParam->num_ref_idx_l0_active_minus1 = encParam->num_ref_frame - 1; /* assume frame only */
+        picParam->num_ref_idx_l1_active_minus1 = 0; /* default value */
+        picParam->weighted_pred_flag = 0; /* no weighted prediction supported */
+        picParam->weighted_bipred_idc = 0; /* range 0,1,2 */
+        if (/*picParam->weighted_bipred_idc < 0 || (no need, it's unsigned) */
+            picParam->weighted_bipred_idc > 2)
+        {
+            return AVCENC_WEIGHTED_BIPRED_FAIL;
+        }
+        picParam->pic_init_qp_minus26 = 0; /* default, will be changed at slice level anyway */
+        if (picParam->pic_init_qp_minus26 < -26 || picParam->pic_init_qp_minus26 > 25)
+        {
+            return AVCENC_INIT_QP_FAIL; /* out of range */
+        }
+        picParam->pic_init_qs_minus26 = 0;
+        if (picParam->pic_init_qs_minus26 < -26 || picParam->pic_init_qs_minus26 > 25)
+        {
+            return AVCENC_INIT_QS_FAIL; /* out of range */
+        }
+
+        picParam->chroma_qp_index_offset = 0; /* default to zero for now */
+        if (picParam->chroma_qp_index_offset < -12 || picParam->chroma_qp_index_offset > 12)
+        {
+            return AVCENC_CHROMA_QP_FAIL; /* out of range */
+        }
+        /* deblocking */
+        picParam->deblocking_filter_control_present_flag = (encParam->db_filter == AVC_ON) ? TRUE : FALSE ;
+        /* constrained intra prediction */
+        picParam->constrained_intra_pred_flag = (encParam->constrained_intra_pred == AVC_ON) ? TRUE : FALSE;
+        picParam->redundant_pic_cnt_present_flag = 0; /* default */
+    }
+    else if (extP)// external PPS
+    {
+        picParam->pic_parameter_set_id = extP->pic_parameter_set_id - 1; /* to be increased by one */
+        picParam->seq_parameter_set_id = extP->seq_parameter_set_id;
+        picParam->entropy_coding_mode_flag = extP->entropy_coding_mode_flag;
+        if (extP->entropy_coding_mode_flag != 0) /* default to CAVLC */
+        {
+            return AVCENC_NOT_SUPPORTED;
+        }
+        picParam->pic_order_present_flag = extP->pic_order_present_flag; /* default for now, will need it for B-slice */
+        if (extP->pic_order_present_flag != 0)
+        {
+            return AVCENC_NOT_SUPPORTED;
+        }
+        /* FMO */
+        if (/*(extP->num_slice_groups_minus1<0) || (no need it's unsigned) */
+            (extP->num_slice_groups_minus1 > MAX_NUM_SLICE_GROUP - 1))
+        {
+            return AVCENC_INVALID_NUM_SLICEGROUP;
+        }
+        picParam->num_slice_groups_minus1 = extP->num_slice_groups_minus1;
+
+        if (picParam->num_slice_groups_minus1 > 0)
+        {
+            picParam->slice_group_map_type = extP->slice_group_map_type;
+            switch (extP->slice_group_map_type)
+            {
+                case 0:
+                    for (ii = 0; ii <= (int)extP->num_slice_groups_minus1; ii++)
+                    {
+                        picParam->run_length_minus1[ii] = extP->run_length_minus1[ii];
+                    }
+                    break;
+                case 2:
+                    for (ii = 0; ii < (int)picParam->num_slice_groups_minus1; ii++)
+                    {
+                        picParam->top_left[ii] = extP->top_left[ii];
+                        picParam->bottom_right[ii] = extP->bottom_right[ii];
+                    }
+                    break;
+                case 3:
+                case 4:
+                case 5:
+                    picParam->slice_group_change_direction_flag = extP->slice_group_change_direction_flag;
+                    if (/*extP->slice_group_change_rate_minus1 < 0 || (no need, it's unsigned) */
+                        extP->slice_group_change_rate_minus1 > video->PicSizeInMapUnits - 1)
+                    {
+                        return AVCENC_INVALID_CHANGE_RATE;
+                    }
+                    picParam->slice_group_change_rate_minus1 = extP->slice_group_change_rate_minus1;
+                    video->SliceGroupChangeRate = picParam->slice_group_change_rate_minus1 + 1;
+                    break;
+                case 6:
+                    if (extP->pic_size_in_map_units_minus1 != video->PicSizeInMapUnits - 1)
+                    {
+                        return AVCENC_NOT_SUPPORTED;
+                    }
+
+                    picParam->pic_size_in_map_units_minus1 = extP->pic_size_in_map_units_minus1;
+
+                    /* allocate picParam->slice_group_id */
+                    picParam->slice_group_id = (uint*)avcHandle->CBAVC_Malloc(userData, sizeof(uint) * video->PicSizeInMapUnits, DEFAULT_ATTR);
+                    if (picParam->slice_group_id == NULL)
+                    {
+                        return AVCENC_MEMORY_FAIL;
+                    }
+
+                    if (extP->slice_group_id == NULL)
+                    {
+                        return AVCENC_ENCPARAM_MEM_FAIL;
+                    }
+                    for (ii = 0; ii < (int)video->PicSizeInMapUnits; ii++)
+                    {
+                        picParam->slice_group_id[ii] = extP->slice_group_id[ii];
+                    }
+                    break;
+                default:
+                    return AVCENC_INVALID_FMO_TYPE;
+            }
+        }
+        picParam->num_ref_idx_l0_active_minus1 = extP->num_ref_idx_l0_active_minus1;
+        picParam->num_ref_idx_l1_active_minus1 = extP->num_ref_idx_l1_active_minus1; /* default value */
+        if (picParam->num_ref_idx_l1_active_minus1 != 0)
+        {
+            return AVCENC_NOT_SUPPORTED;
+        }
+
+        if (extP->weighted_pred_flag)
+        {
+            return AVCENC_NOT_SUPPORTED;
+        }
+
+        picParam->weighted_pred_flag = 0; /* no weighted prediction supported */
+        picParam->weighted_bipred_idc = extP->weighted_bipred_idc; /* range 0,1,2 */
+        if (/*picParam->weighted_bipred_idc < 0 || (no need, it's unsigned) */
+            picParam->weighted_bipred_idc > 2)
+        {
+            return AVCENC_WEIGHTED_BIPRED_FAIL;
+        }
+        picParam->pic_init_qp_minus26 = extP->pic_init_qp_minus26; /* default, will be changed at slice level anyway */
+        if (picParam->pic_init_qp_minus26 < -26 || picParam->pic_init_qp_minus26 > 25)
+        {
+            return AVCENC_INIT_QP_FAIL; /* out of range */
+        }
+        picParam->pic_init_qs_minus26 = extP->pic_init_qs_minus26;
+        if (picParam->pic_init_qs_minus26 < -26 || picParam->pic_init_qs_minus26 > 25)
+        {
+            return AVCENC_INIT_QS_FAIL; /* out of range */
+        }
+
+        picParam->chroma_qp_index_offset = extP->chroma_qp_index_offset; /* default to zero for now */
+        if (picParam->chroma_qp_index_offset < -12 || picParam->chroma_qp_index_offset > 12)
+        {
+            return AVCENC_CHROMA_QP_FAIL; /* out of range */
+        }
+        /* deblocking */
+        picParam->deblocking_filter_control_present_flag = extP->deblocking_filter_control_present_flag;
+        /* constrained intra prediction */
+        picParam->constrained_intra_pred_flag = extP->constrained_intra_pred_flag;
+        if (extP->redundant_pic_cnt_present_flag  != 0)
+        {
+            return AVCENC_NOT_SUPPORTED;
+        }
+        picParam->redundant_pic_cnt_present_flag = extP->redundant_pic_cnt_present_flag; /* default */
+    }
+    else
+    {
+        return AVCENC_NOT_SUPPORTED;
+    }
+
+    /****************** now set up some SliceHeader parameters ***********/
+    if (picParam->deblocking_filter_control_present_flag == TRUE)
+    {
+        /* these values only present when db_filter is ON */
+        if (encParam->disable_db_idc > 2)
+        {
+            return AVCENC_INVALID_DEBLOCK_IDC; /* out of range */
+        }
+        sliceHdr->disable_deblocking_filter_idc = encParam->disable_db_idc;
+
+        if (encParam->alpha_offset < -6 || encParam->alpha_offset > 6)
+        {
+            return AVCENC_INVALID_ALPHA_OFFSET;
+        }
+        sliceHdr->slice_alpha_c0_offset_div2 = encParam->alpha_offset;
+
+        if (encParam->beta_offset < -6 || encParam->beta_offset > 6)
+        {
+            return AVCENC_INVALID_BETA_OFFSET;
+        }
+        sliceHdr->slice_beta_offset_div_2 =  encParam->beta_offset;
+    }
+    if (encvid->outOfBandParamSet == TRUE)
+    {
+        sliceHdr->idr_pic_id = 0;
+    }
+    else
+    {
+        sliceHdr->idr_pic_id = (uint)(-1); /* start with zero */
+    }
+    sliceHdr->field_pic_flag = FALSE;
+    sliceHdr->bottom_field_flag = FALSE;  /* won't be used anyway */
+    video->MbaffFrameFlag = (seqParam->mb_adaptive_frame_field_flag && !sliceHdr->field_pic_flag);
+
+    /* the rest will be set in InitSlice() */
+
+    /* now the rate control and performance related parameters */
+    rateCtrl->scdEnable = (encParam->auto_scd == AVC_ON) ? TRUE : FALSE;
+    rateCtrl->idrPeriod = encParam->idr_period + 1;
+    rateCtrl->intraMBRate = encParam->intramb_refresh;
+    rateCtrl->dpEnable = (encParam->data_par == AVC_ON) ? TRUE : FALSE;
+
+    rateCtrl->subPelEnable = (encParam->sub_pel == AVC_ON) ? TRUE : FALSE;
+    rateCtrl->mvRange = encParam->search_range;
+
+    rateCtrl->subMBEnable = (encParam->submb_pred == AVC_ON) ? TRUE : FALSE;
+    rateCtrl->rdOptEnable = (encParam->rdopt_mode == AVC_ON) ? TRUE : FALSE;
+    rateCtrl->bidirPred = (encParam->bidir_pred == AVC_ON) ? TRUE : FALSE;
+
+    rateCtrl->rcEnable = (encParam->rate_control == AVC_ON) ? TRUE : FALSE;
+    rateCtrl->initQP = encParam->initQP;
+    rateCtrl->initQP = AVC_CLIP3(0, 51, rateCtrl->initQP);
+
+    rateCtrl->bitRate = encParam->bitrate;
+    rateCtrl->cpbSize = encParam->CPB_size;
+    rateCtrl->initDelayOffset = (rateCtrl->bitRate * encParam->init_CBP_removal_delay / 1000);
+
+    if (encParam->frame_rate == 0)
+    {
+        return AVCENC_INVALID_FRAMERATE;
+    }
+
+    rateCtrl->frame_rate = (OsclFloat)(encParam->frame_rate * 1.0 / 1000);
+//  rateCtrl->srcInterval = encParam->src_interval;
+    rateCtrl->first_frame = 1; /* set this flag for the first time */
+
+    /* contrained_setx_flag will be set inside the VerifyProfile called below.*/
+    if (!extS && !extP)
+    {
+        seqParam->profile_idc = encParam->profile;
+        seqParam->constrained_set0_flag = FALSE;
+        seqParam->constrained_set1_flag = FALSE;
+        seqParam->constrained_set2_flag = FALSE;
+        seqParam->constrained_set3_flag = FALSE;
+        seqParam->level_idc = encParam->level;
+    }
+    else
+    {
+        seqParam->profile_idc = extS->profile_idc;
+        seqParam->constrained_set0_flag = extS->constrained_set0_flag;
+        seqParam->constrained_set1_flag = extS->constrained_set1_flag;
+        seqParam->constrained_set2_flag = extS->constrained_set2_flag;
+        seqParam->constrained_set3_flag = extS->constrained_set3_flag;
+        seqParam->level_idc = extS->level_idc;
+    }
+
+
+    status = VerifyProfile(encvid, seqParam, picParam);
+    if (status != AVCENC_SUCCESS)
+    {
+        return status;
+    }
+
+    status = VerifyLevel(encvid, seqParam, picParam);
+    if (status != AVCENC_SUCCESS)
+    {
+        return status;
+    }
+
+    return AVCENC_SUCCESS;
+}
+
+/* verify the profile setting */
+AVCEnc_Status VerifyProfile(AVCEncObject *encvid, AVCSeqParamSet *seqParam, AVCPicParamSet *picParam)
+{
+    AVCRateControl *rateCtrl = encvid->rateCtrl;
+    AVCEnc_Status status = AVCENC_SUCCESS;
+
+    if (seqParam->profile_idc == 0) /* find profile for this setting */
+    {
+        /* find the right profile for it */
+        if (seqParam->direct_8x8_inference_flag == TRUE &&
+                picParam->entropy_coding_mode_flag == FALSE &&
+                picParam->num_slice_groups_minus1 <= 7 /*&&
+            picParam->num_slice_groups_minus1>=0 (no need, it's unsigned) */)
+        {
+            seqParam->profile_idc = AVC_EXTENDED;
+            seqParam->constrained_set2_flag = TRUE;
+        }
+
+        if (rateCtrl->dpEnable == FALSE &&
+                picParam->num_slice_groups_minus1 == 0 &&
+                picParam->redundant_pic_cnt_present_flag == FALSE)
+        {
+            seqParam->profile_idc = AVC_MAIN;
+            seqParam->constrained_set1_flag = TRUE;
+        }
+
+        if (rateCtrl->bidirPred == FALSE &&
+                rateCtrl->dpEnable == FALSE &&
+                seqParam->frame_mbs_only_flag == TRUE &&
+                picParam->weighted_pred_flag == FALSE &&
+                picParam->weighted_bipred_idc == 0 &&
+                picParam->entropy_coding_mode_flag == FALSE &&
+                picParam->num_slice_groups_minus1 <= 7 /*&&
+            picParam->num_slice_groups_minus1>=0 (no need, it's unsigned)*/)
+        {
+            seqParam->profile_idc = AVC_BASELINE;
+            seqParam->constrained_set0_flag = TRUE;
+        }
+
+        if (seqParam->profile_idc == 0) /* still zero */
+        {
+            return AVCENC_PROFILE_NOT_SUPPORTED;
+        }
+    }
+
+    /* check the list of supported profile by this library */
+    switch (seqParam->profile_idc)
+    {
+        case AVC_BASELINE:
+            if (rateCtrl->bidirPred == TRUE ||
+                    rateCtrl->dpEnable == TRUE ||
+                    seqParam->frame_mbs_only_flag != TRUE ||
+                    picParam->weighted_pred_flag == TRUE ||
+                    picParam->weighted_bipred_idc != 0 ||
+                    picParam->entropy_coding_mode_flag == TRUE ||
+                    picParam->num_slice_groups_minus1 > 7 /*||
+            picParam->num_slice_groups_minus1<0 (no need, it's unsigned) */)
+            {
+                status = AVCENC_TOOLS_NOT_SUPPORTED;
+            }
+            break;
+
+        case AVC_MAIN:
+        case AVC_EXTENDED:
+            status = AVCENC_PROFILE_NOT_SUPPORTED;
+    }
+
+    return status;
+}
+
+/* verify the level setting */
+AVCEnc_Status VerifyLevel(AVCEncObject *encvid, AVCSeqParamSet *seqParam, AVCPicParamSet *picParam)
+{
+    (void)(picParam);
+
+    AVCRateControl *rateCtrl = encvid->rateCtrl;
+    AVCCommonObj *video = encvid->common;
+    int mb_per_sec, ii;
+    int lev_idx;
+    int dpb_size;
+
+    mb_per_sec = (int)(video->PicSizeInMbs * rateCtrl->frame_rate + 0.5);
+    dpb_size = (seqParam->num_ref_frames * video->PicSizeInMbs * 3) >> 6;
+
+    if (seqParam->level_idc == 0) /* find level for this setting */
+    {
+        for (ii = 0; ii < MAX_LEVEL_IDX; ii++)
+        {
+            if (mb_per_sec <= MaxMBPS[ii] &&
+                    video->PicSizeInMbs <= (uint)MaxFS[ii] &&
+                    rateCtrl->bitRate <= (int32)MaxBR[ii]*1000 &&
+                    rateCtrl->cpbSize <= (int32)MaxCPB[ii]*1000 &&
+                    rateCtrl->mvRange <= MaxVmvR[ii] &&
+                    dpb_size <= MaxDPBX2[ii]*512)
+            {
+                seqParam->level_idc = mapIdx2Lev[ii];
+                break;
+            }
+        }
+        if (seqParam->level_idc == 0)
+        {
+            return AVCENC_LEVEL_NOT_SUPPORTED;
+        }
+    }
+
+    /* check if this level is supported by this library */
+    lev_idx = mapLev2Idx[seqParam->level_idc];
+    if (seqParam->level_idc == AVC_LEVEL1_B)
+    {
+        seqParam->constrained_set3_flag = 1;
+    }
+
+
+    if (lev_idx == 255) /* not defined */
+    {
+        return AVCENC_LEVEL_NOT_SUPPORTED;
+    }
+
+    /* check if the encoding setting complies with the level */
+    if (mb_per_sec > MaxMBPS[lev_idx] ||
+            video->PicSizeInMbs > (uint)MaxFS[lev_idx] ||
+            rateCtrl->bitRate > (int32)MaxBR[lev_idx]*1000 ||
+            rateCtrl->cpbSize > (int32)MaxCPB[lev_idx]*1000 ||
+            rateCtrl->mvRange > MaxVmvR[lev_idx])
+    {
+        return AVCENC_LEVEL_FAIL;
+    }
+
+    return AVCENC_SUCCESS;
+}
+
+/* initialize variables at the beginning of each frame */
+/* determine the picture type */
+/* encode POC */
+/* maybe we should do more stuff here. MotionEstimation+SCD and generate a new SPS and PPS */
+AVCEnc_Status InitFrame(AVCEncObject *encvid)
+{
+    AVCStatus ret;
+    AVCEnc_Status status;
+    AVCCommonObj *video = encvid->common;
+    AVCSliceHeader *sliceHdr = video->sliceHdr;
+
+    /* look for the next frame in coding_order and look for available picture
+       in the DPB. Note, video->currFS->PicOrderCnt, currFS->FrameNum and currPic->PicNum
+       are set to wrong number in this function (right for decoder). */
+    if (video->nal_unit_type == AVC_NALTYPE_IDR)
+    {
+        // call init DPB in here.
+        ret = AVCConfigureSequence(encvid->avcHandle, video, TRUE);
+        if (ret != AVC_SUCCESS)
+        {
+            return AVCENC_FAIL;
+        }
+    }
+
+    /* flexible macroblock ordering (every frame)*/
+    /* populate video->mapUnitToSliceGroupMap and video->MbToSliceGroupMap */
+    /* It changes once per each PPS. */
+    FMOInit(video);
+
+    ret = DPBInitBuffer(encvid->avcHandle, video); // get new buffer
+
+    if (ret != AVC_SUCCESS)
+    {
+        return (AVCEnc_Status)ret; // AVCENC_PICTURE_READY, FAIL
+    }
+
+    DPBInitPic(video, 0); /* 0 is dummy */
+
+    /************* determine picture type IDR or non-IDR ***********/
+    video->currPicType = AVC_FRAME;
+    video->slice_data_partitioning = FALSE;
+    encvid->currInput->is_reference = 1; /* default to all frames */
+    video->nal_ref_idc = 1;  /* need to set this for InitPOC */
+    video->currPic->isReference = TRUE;
+
+    /************* set frame_num ********************/
+    if (video->nal_unit_type == AVC_NALTYPE_IDR)
+    {
+        video->prevFrameNum = video->MaxFrameNum;
+        video->PrevRefFrameNum = 0;
+        sliceHdr->frame_num = 0;
+    }
+    /* otherwise, it's set to previous reference frame access unit's frame_num in decoding order,
+       see the end of PVAVCDecodeSlice()*/
+    /* There's also restriction on the frame_num, see page 59 of JVT-I1010.doc. */
+    /* Basically, frame_num can't be repeated unless it's opposite fields or non reference fields */
+    else
+    {
+        sliceHdr->frame_num = (video->PrevRefFrameNum + 1) % video->MaxFrameNum;
+    }
+    video->CurrPicNum = sliceHdr->frame_num;  /* for field_pic_flag = 0 */
+    //video->CurrPicNum = 2*sliceHdr->frame_num + 1; /* for field_pic_flag = 1 */
+
+    /* assign pic_order_cnt, video->PicOrderCnt */
+    status = InitPOC(encvid);
+    if (status != AVCENC_SUCCESS)  /* incorrigable fail */
+    {
+        return status;
+    }
+
+    /* Initialize refListIdx for this picture */
+    RefListInit(video);
+
+    /************* motion estimation and scene analysis ************/
+    // , to move this to MB-based MV search for comparison
+    // use sub-optimal QP for mv search
+    AVCMotionEstimation(encvid);  /* AVCENC_SUCCESS or AVCENC_NEW_IDR */
+
+    /* after this point, the picture type will be fixed to either IDR or non-IDR */
+    video->currFS->PicOrderCnt = video->PicOrderCnt;
+    video->currFS->FrameNum = video->sliceHdr->frame_num;
+    video->currPic->PicNum = video->CurrPicNum;
+    video->mbNum = 0; /* start from zero MB */
+    encvid->currSliceGroup = 0; /* start from slice group #0 */
+    encvid->numIntraMB = 0; /* reset this counter */
+
+    if (video->nal_unit_type == AVC_NALTYPE_IDR)
+    {
+        RCInitGOP(encvid);
+
+        /* calculate picture QP */
+        RCInitFrameQP(encvid);
+
+        return AVCENC_NEW_IDR;
+    }
+
+    /* calculate picture QP */
+    RCInitFrameQP(encvid); /* get QP after MV search */
+
+    return AVCENC_SUCCESS;
+}
+
+/* initialize variables for this slice */
+AVCEnc_Status InitSlice(AVCEncObject *encvid)
+{
+    AVCCommonObj *video = encvid->common;
+    AVCSliceHeader *sliceHdr = video->sliceHdr;
+    AVCPicParamSet *currPPS = video->currPicParams;
+    AVCSeqParamSet *currSPS = video->currSeqParams;
+    int slice_type = video->slice_type;
+
+    sliceHdr->first_mb_in_slice = video->mbNum;
+    if (video->mbNum) // not first slice of a frame
+    {
+        video->sliceHdr->slice_type = (AVCSliceType)slice_type;
+    }
+
+    /* sliceHdr->slice_type already set in InitFrame */
+
+    sliceHdr->pic_parameter_set_id = video->currPicParams->pic_parameter_set_id;
+
+    /* sliceHdr->frame_num already set in InitFrame */
+
+    if (!currSPS->frame_mbs_only_flag)  /* we shouldn't need this check */
+    {
+        sliceHdr->field_pic_flag = sliceHdr->bottom_field_flag = FALSE;
+        return AVCENC_TOOLS_NOT_SUPPORTED;
+    }
+
+    /* sliceHdr->idr_pic_id already set in PVAVCEncodeNAL
+
+     sliceHdr->pic_order_cnt_lsb already set in InitFrame..InitPOC
+     sliceHdr->delta_pic_order_cnt_bottom  already set in InitPOC
+
+    sliceHdr->delta_pic_order_cnt[0] already set in InitPOC
+    sliceHdr->delta_pic_order_cnt[1] already set in InitPOC
+    */
+
+    sliceHdr->redundant_pic_cnt = 0; /* default if(currPPS->redundant_pic_cnt_present_flag), range 0..127 */
+    sliceHdr->direct_spatial_mv_pred_flag = 0; // default if(slice_type == AVC_B_SLICE)
+
+    sliceHdr->num_ref_idx_active_override_flag = FALSE; /* default, if(slice_type== P,SP or B)*/
+    sliceHdr->num_ref_idx_l0_active_minus1 = 0; /* default, if (num_ref_idx_active_override_flag) */
+    sliceHdr->num_ref_idx_l1_active_minus1 = 0; /* default, if above and B_slice */
+    /* the above 2 values range from 0..15 for frame picture and 0..31 for field picture */
+
+    /* ref_pic_list_reordering(), currently we don't do anything */
+    sliceHdr->ref_pic_list_reordering_flag_l0 = FALSE; /* default */
+    sliceHdr->ref_pic_list_reordering_flag_l1 = FALSE; /* default */
+    /* if the above are TRUE, some other params must be set */
+
+    if ((currPPS->weighted_pred_flag && (slice_type == AVC_P_SLICE || slice_type == AVC_SP_SLICE)) ||
+            (currPPS->weighted_bipred_idc == 1 && slice_type == AVC_B_SLICE))
+    {
+        //      pred_weight_table(); // not supported !!
+        return AVCENC_TOOLS_NOT_SUPPORTED;
+    }
+
+    /* dec_ref_pic_marking(), this will be done later*/
+    sliceHdr->no_output_of_prior_pics_flag = FALSE; /* default */
+    sliceHdr->long_term_reference_flag = FALSE; /* for IDR frame, do not make it long term */
+    sliceHdr->adaptive_ref_pic_marking_mode_flag = FALSE; /* default */
+    /* other params are not set here because they are not used */
+
+    sliceHdr->cabac_init_idc = 0; /* default, if entropy_coding_mode_flag && slice_type==I or SI, range 0..2  */
+    sliceHdr->slice_qp_delta = 0; /* default for now */
+    sliceHdr->sp_for_switch_flag = FALSE; /* default, if slice_type == SP */
+    sliceHdr->slice_qs_delta = 0; /* default, if slice_type == SP or SI */
+
+    /* derived variables from encParam */
+    /* deblocking filter */
+    video->FilterOffsetA = video->FilterOffsetB = 0;
+    if (currPPS->deblocking_filter_control_present_flag == TRUE)
+    {
+        video->FilterOffsetA = sliceHdr->slice_alpha_c0_offset_div2 << 1;
+        video->FilterOffsetB = sliceHdr->slice_beta_offset_div_2 << 1;
+    }
+
+    /* flexible macroblock ordering */
+    /* populate video->mapUnitToSliceGroupMap and video->MbToSliceGroupMap */
+    /* We already call it at the end of PVAVCEncInitialize(). It changes once per each PPS. */
+    if (video->currPicParams->num_slice_groups_minus1 > 0 && video->currPicParams->slice_group_map_type >= 3
+            && video->currPicParams->slice_group_map_type <= 5)
+    {
+        sliceHdr->slice_group_change_cycle = SLICE_GROUP_CHANGE_CYCLE;  /* default, don't understand how to set it!!!*/
+
+        video->MapUnitsInSliceGroup0 =
+            AVC_MIN(sliceHdr->slice_group_change_cycle * video->SliceGroupChangeRate, video->PicSizeInMapUnits);
+
+        FMOInit(video);
+    }
+
+    /* calculate SliceQPy first  */
+    /* calculate QSy first */
+
+    sliceHdr->slice_qp_delta = video->QPy - 26 - currPPS->pic_init_qp_minus26;
+    //sliceHdr->slice_qs_delta = video->QSy - 26 - currPPS->pic_init_qs_minus26;
+
+    return AVCENC_SUCCESS;
+}
+
diff --git a/media/libstagefright/codecs/avc/enc/src/intra_est.cpp b/media/libstagefright/codecs/avc/enc/src/intra_est.cpp
new file mode 100644
index 0000000..17e5985
--- /dev/null
+++ b/media/libstagefright/codecs/avc/enc/src/intra_est.cpp
@@ -0,0 +1,2199 @@
+/* ------------------------------------------------------------------
+ * Copyright (C) 1998-2009 PacketVideo
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
+ * express or implied.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ * -------------------------------------------------------------------
+ */
+#include "avcenc_lib.h"
+
+#define TH_I4  0  /* threshold biasing toward I16 mode instead of I4 mode */
+#define TH_Intra  0 /* threshold biasing toward INTER mode instead of intra mode */
+
+#define FIXED_INTRAPRED_MODE  AVC_I16
+#define FIXED_I16_MODE  AVC_I16_DC
+#define FIXED_I4_MODE   AVC_I4_Diagonal_Down_Left
+#define FIXED_INTRA_CHROMA_MODE AVC_IC_DC
+
+#define CLIP_RESULT(x)      if((uint)x > 0xFF){ \
+                 x = 0xFF & (~(x>>31));}
+
+
+bool IntraDecisionABE(AVCEncObject *encvid, int min_cost, uint8 *curL, int picPitch)
+{
+    AVCCommonObj *video = encvid->common;
+    AVCFrameIO *currInput = encvid->currInput;
+    int orgPitch = currInput->pitch;
+    int x_pos = (video->mb_x) << 4;
+    int y_pos = (video->mb_y) << 4;
+    uint8 *orgY = currInput->YCbCr[0] + y_pos * orgPitch + x_pos;
+    int j;
+    uint8 *topL, *leftL, *orgY_2, *orgY_3;
+    int temp, SBE, offset;
+    OsclFloat ABE;
+    bool intra = true;
+
+    if (((x_pos >> 4) != (int)video->PicWidthInMbs - 1) &&
+            ((y_pos >> 4) != (int)video->PicHeightInMbs - 1) &&
+            video->intraAvailA &&
+            video->intraAvailB)
+    {
+        SBE = 0;
+        /* top neighbor */
+        topL = curL - picPitch;
+        /* left neighbor */
+        leftL = curL - 1;
+        orgY_2 = orgY - orgPitch;
+
+        for (j = 0; j < 16; j++)
+        {
+            temp = *topL++ - orgY[j];
+            SBE += ((temp >= 0) ? temp : -temp);
+            temp = *(leftL += picPitch) - *(orgY_2 += orgPitch);
+            SBE += ((temp >= 0) ? temp : -temp);
+        }
+
+        /* calculate chroma */
+        offset = (y_pos >> 2) * picPitch + (x_pos >> 1);
+        topL = video->currPic->Scb + offset;
+        orgY_2 = currInput->YCbCr[1] + offset + (y_pos >> 2) * (orgPitch - picPitch);
+
+        leftL = topL - 1;
+        topL -= (picPitch >> 1);
+        orgY_3 = orgY_2 - (orgPitch >> 1);
+        for (j = 0; j < 8; j++)
+        {
+            temp = *topL++ - orgY_2[j];
+            SBE += ((temp >= 0) ? temp : -temp);
+            temp = *(leftL += (picPitch >> 1)) - *(orgY_3 += (orgPitch >> 1));
+            SBE += ((temp >= 0) ? temp : -temp);
+        }
+
+        topL = video->currPic->Scr + offset;
+        orgY_2 = currInput->YCbCr[2] + offset + (y_pos >> 2) * (orgPitch - picPitch);
+
+        leftL = topL - 1;
+        topL -= (picPitch >> 1);
+        orgY_3 = orgY_2 - (orgPitch >> 1);
+        for (j = 0; j < 8; j++)
+        {
+            temp = *topL++ - orgY_2[j];
+            SBE += ((temp >= 0) ? temp : -temp);
+            temp = *(leftL += (picPitch >> 1)) - *(orgY_3 += (orgPitch >> 1));
+            SBE += ((temp >= 0) ? temp : -temp);
+        }
+
+        /* compare mincost/384 and SBE/64 */
+        ABE = SBE / 64.0;
+        if (ABE*0.8 >= min_cost / 384.0)
+        {
+            intra = false;
+        }
+    }
+
+    return intra;
+}
+
+/* perform searching for MB mode */
+/* assuming that this is done inside the encoding loop,
+no need to call InitNeighborAvailability */
+
+void MBIntraSearch(AVCEncObject *encvid, int mbnum, uint8 *curL, int picPitch)
+{
+    AVCCommonObj *video = encvid->common;
+    AVCFrameIO *currInput = encvid->currInput;
+    AVCMacroblock *currMB = video->currMB;
+    int min_cost;
+    uint8 *orgY;
+    int x_pos = (video->mb_x) << 4;
+    int y_pos = (video->mb_y) << 4;
+    uint32 *saved_inter;
+    int j;
+    int orgPitch = currInput->pitch;
+    bool intra = true;
+
+    currMB->CBP = 0;
+
+    /* first do motion vector and variable block size search */
+    min_cost = encvid->min_cost[mbnum];
+
+    /* now perform intra prediction search */
+    /* need to add the check for encvid->intraSearch[video->mbNum] to skip intra
+       if it's not worth checking. */
+    if (video->slice_type == AVC_P_SLICE)
+    {
+        /* Decide whether intra search is necessary or not */
+        /* This one, we do it in the encoding loop so the neighboring pixel are the
+        actual reconstructed pixels. */
+        intra = IntraDecisionABE(encvid, min_cost, curL, picPitch);
+    }
+
+    if (intra == true || video->slice_type == AVC_I_SLICE)
+    {
+        orgY = currInput->YCbCr[0] + y_pos * orgPitch + x_pos;
+
+        /* i16 mode search */
+        /* generate all the predictions */
+        intrapred_luma_16x16(encvid);
+
+        /* evaluate them one by one */
+        find_cost_16x16(encvid, orgY, &min_cost);
+
+        if (video->slice_type == AVC_P_SLICE)
+        {
+            /* save current inter prediction */
+            saved_inter = encvid->subpel_pred; /* reuse existing buffer */
+            j = 16;
+            curL -= 4;
+            picPitch -= 16;
+            while (j--)
+            {
+                *saved_inter++ = *((uint32*)(curL += 4));
+                *saved_inter++ = *((uint32*)(curL += 4));
+                *saved_inter++ = *((uint32*)(curL += 4));
+                *saved_inter++ = *((uint32*)(curL += 4));
+                curL += picPitch;
+            }
+
+        }
+
+        /* i4 mode search */
+        mb_intra4x4_search(encvid, &min_cost);
+
+        encvid->min_cost[mbnum] = min_cost; /* update min_cost */
+    }
+
+
+    if (currMB->mb_intra)
+    {
+        chroma_intra_search(encvid);
+
+        /* need to set this in order for the MBInterPrediction to work!! */
+        memset(currMB->mvL0, 0, sizeof(int32)*16);
+        currMB->ref_idx_L0[0] = currMB->ref_idx_L0[1] =
+                                    currMB->ref_idx_L0[2] = currMB->ref_idx_L0[3] = -1;
+    }
+    else if (video->slice_type == AVC_P_SLICE && intra == true)
+    {
+        /* restore current inter prediction */
+        saved_inter = encvid->subpel_pred; /* reuse existing buffer */
+        j = 16;
+        curL -= ((picPitch + 16) << 4);
+        while (j--)
+        {
+            *((uint32*)(curL += 4)) = *saved_inter++;
+            *((uint32*)(curL += 4)) = *saved_inter++;
+            *((uint32*)(curL += 4)) = *saved_inter++;
+            *((uint32*)(curL += 4)) = *saved_inter++;
+            curL += picPitch;
+        }
+    }
+
+    return ;
+}
+
+/* generate all the prediction values */
+void intrapred_luma_16x16(AVCEncObject *encvid)
+{
+    AVCCommonObj *video = encvid->common;
+    AVCPictureData *currPic = video->currPic;
+
+    int x_pos = (video->mb_x) << 4;
+    int y_pos = (video->mb_y) << 4;
+    int pitch = currPic->pitch;
+
+    int offset = y_pos * pitch + x_pos;
+
+    uint8 *pred, *top, *left;
+    uint8 *curL = currPic->Sl + offset; /* point to reconstructed frame */
+    uint32 word1, word2, word3, word4;
+    uint32 sum = 0;
+
+    int a_16, b, c, factor_c;
+    uint8 *comp_ref_x0, *comp_ref_x1, *comp_ref_y0, *comp_ref_y1;
+    int H = 0, V = 0, tmp, value;
+    int i;
+
+    if (video->intraAvailB)
+    {
+        //get vertical prediction mode
+        top = curL - pitch;
+
+        pred = encvid->pred_i16[AVC_I16_Vertical] - 16;
+
+        word1 = *((uint32*)(top));  /* read 4 bytes from top */
+        word2 = *((uint32*)(top + 4)); /* read 4 bytes from top */
+        word3 = *((uint32*)(top + 8)); /* read 4 bytes from top */
+        word4 = *((uint32*)(top + 12)); /* read 4 bytes from top */
+
+        for (i = 0; i < 16; i++)
+        {
+            *((uint32*)(pred += 16)) = word1;
+            *((uint32*)(pred + 4)) = word2;
+            *((uint32*)(pred + 8)) = word3;
+            *((uint32*)(pred + 12)) = word4;
+
+        }
+
+        sum = word1 & 0xFF00FF;
+        word1 = (word1 >> 8) & 0xFF00FF;
+        sum += word1;
+        word1 = (word2 & 0xFF00FF);
+        sum += word1;
+        word2 = (word2 >> 8) & 0xFF00FF;
+        sum += word2;
+        word1 = (word3 & 0xFF00FF);
+        sum += word1;
+        word3 = (word3 >> 8) & 0xFF00FF;
+        sum += word3;
+        word1 = (word4 & 0xFF00FF);
+        sum += word1;
+        word4 = (word4 >> 8) & 0xFF00FF;
+        sum += word4;
+
+        sum += (sum >> 16);
+        sum &= 0xFFFF;
+
+        if (!video->intraAvailA)
+        {
+            sum = (sum + 8) >> 4;
+        }
+    }
+
+    if (video->intraAvailA)
+    {
+        // get horizontal mode
+        left = curL - 1 - pitch;
+
+        pred = encvid->pred_i16[AVC_I16_Horizontal] - 16;
+
+        for (i = 0; i < 16; i++)
+        {
+            word1 = *(left += pitch);
+            sum += word1;
+
+            word1 = (word1 << 8) | word1;
+            word1 = (word1 << 16) | word1; /* make it 4 */
+
+            *(uint32*)(pred += 16) = word1;
+            *(uint32*)(pred + 4) = word1;
+            *(uint32*)(pred + 8) = word1;
+            *(uint32*)(pred + 12) = word1;
+        }
+
+        if (!video->intraAvailB)
+        {
+            sum = (sum + 8) >> 4;
+        }
+        else
+        {
+            sum = (sum + 16) >> 5;
+        }
+    }
+
+    // get DC mode
+    if (!video->intraAvailA && !video->intraAvailB)
+    {
+        sum = 0x80808080;
+    }
+    else
+    {
+        sum = (sum << 8) | sum;
+        sum = (sum << 16) | sum;
+    }
+
+    pred = encvid->pred_i16[AVC_I16_DC] - 16;
+    for (i = 0; i < 16; i++)
+    {
+        *((uint32*)(pred += 16)) = sum;
+        *((uint32*)(pred + 4)) = sum;
+        *((uint32*)(pred + 8)) = sum;
+        *((uint32*)(pred + 12)) = sum;
+    }
+
+    // get plane mode
+    if (video->intraAvailA && video->intraAvailB && video->intraAvailD)
+    {
+        pred = encvid->pred_i16[AVC_I16_Plane] - 16;
+
+        comp_ref_x0 = curL - pitch + 8;
+        comp_ref_x1 = curL - pitch + 6;
+        comp_ref_y0 = curL - 1 + (pitch << 3);
+        comp_ref_y1 = curL - 1 + 6 * pitch;
+
+        for (i = 1; i < 8; i++)
+        {
+            H += i * (*comp_ref_x0++ - *comp_ref_x1--);
+            V += i * (*comp_ref_y0 - *comp_ref_y1);
+            comp_ref_y0 += pitch;
+            comp_ref_y1 -= pitch;
+        }
+
+        H += i * (*comp_ref_x0++ - curL[-pitch-1]);
+        V += i * (*comp_ref_y0 - *comp_ref_y1);
+
+
+        a_16 = ((*(curL - pitch + 15) + *(curL - 1 + 15 * pitch)) << 4) + 16;;
+        b = (5 * H + 32) >> 6;
+        c = (5 * V + 32) >> 6;
+
+        tmp = 0;
+        for (i = 0; i < 16; i++)
+        {
+            factor_c = a_16 + c * (tmp++ - 7);
+            factor_c -= 7 * b;
+
+            value = factor_c >> 5;
+            factor_c += b;
+            CLIP_RESULT(value)
+            word1 = value;
+            value = factor_c >> 5;
+            factor_c += b;
+            CLIP_RESULT(value)
+            word1 = (word1) | (value << 8);
+            value = factor_c >> 5;
+            factor_c += b;
+            CLIP_RESULT(value)
+            word1 = (word1) | (value << 16);
+            value = factor_c >> 5;
+            factor_c += b;
+            CLIP_RESULT(value)
+            word1 = (word1) | (value << 24);
+            *((uint32*)(pred += 16)) = word1;
+            value = factor_c >> 5;
+            factor_c += b;
+            CLIP_RESULT(value)
+            word1 = value;
+            value = factor_c >> 5;
+            factor_c += b;
+            CLIP_RESULT(value)
+            word1 = (word1) | (value << 8);
+            value = factor_c >> 5;
+            factor_c += b;
+            CLIP_RESULT(value)
+            word1 = (word1) | (value << 16);
+            value = factor_c >> 5;
+            factor_c += b;
+            CLIP_RESULT(value)
+            word1 = (word1) | (value << 24);
+            *((uint32*)(pred + 4)) = word1;
+            value = factor_c >> 5;
+            factor_c += b;
+            CLIP_RESULT(value)
+            word1 = value;
+            value = factor_c >> 5;
+            factor_c += b;
+            CLIP_RESULT(value)
+            word1 = (word1) | (value << 8);
+            value = factor_c >> 5;
+            factor_c += b;
+            CLIP_RESULT(value)
+            word1 = (word1) | (value << 16);
+            value = factor_c >> 5;
+            factor_c += b;
+            CLIP_RESULT(value)
+            word1 = (word1) | (value << 24);
+            *((uint32*)(pred + 8)) = word1;
+            value = factor_c >> 5;
+            factor_c += b;
+            CLIP_RESULT(value)
+            word1 = value;
+            value = factor_c >> 5;
+            factor_c += b;
+            CLIP_RESULT(value)
+            word1 = (word1) | (value << 8);
+            value = factor_c >> 5;
+            factor_c += b;
+            CLIP_RESULT(value)
+            word1 = (word1) | (value << 16);
+            value = factor_c >> 5;
+            CLIP_RESULT(value)
+            word1 = (word1) | (value << 24);
+            *((uint32*)(pred + 12)) = word1;
+        }
+    }
+
+    return ;
+}
+
+
+/* evaluate each prediction mode of I16 */
+void find_cost_16x16(AVCEncObject *encvid, uint8 *orgY, int *min_cost)
+{
+    AVCCommonObj *video = encvid->common;
+    AVCMacroblock *currMB = video->currMB;
+    int cost;
+    int org_pitch = encvid->currInput->pitch;
+
+    /* evaluate vertical mode */
+    if (video->intraAvailB)
+    {
+        cost = cost_i16(orgY, org_pitch, encvid->pred_i16[AVC_I16_Vertical], *min_cost);
+        if (cost < *min_cost)
+        {
+            *min_cost = cost;
+            currMB->mbMode = AVC_I16;
+            currMB->mb_intra = 1;
+            currMB->i16Mode = AVC_I16_Vertical;
+        }
+    }
+
+
+    /* evaluate horizontal mode */
+    if (video->intraAvailA)
+    {
+        cost = cost_i16(orgY, org_pitch, encvid->pred_i16[AVC_I16_Horizontal], *min_cost);
+        if (cost < *min_cost)
+        {
+            *min_cost = cost;
+            currMB->mbMode = AVC_I16;
+            currMB->mb_intra = 1;
+            currMB->i16Mode = AVC_I16_Horizontal;
+        }
+    }
+
+    /* evaluate DC mode */
+    cost = cost_i16(orgY, org_pitch, encvid->pred_i16[AVC_I16_DC], *min_cost);
+    if (cost < *min_cost)
+    {
+        *min_cost = cost;
+        currMB->mbMode = AVC_I16;
+        currMB->mb_intra = 1;
+        currMB->i16Mode = AVC_I16_DC;
+    }
+
+    /* evaluate plane mode */
+    if (video->intraAvailA && video->intraAvailB && video->intraAvailD)
+    {
+        cost = cost_i16(orgY, org_pitch, encvid->pred_i16[AVC_I16_Plane], *min_cost);
+        if (cost < *min_cost)
+        {
+            *min_cost = cost;
+            currMB->mbMode = AVC_I16;
+            currMB->mb_intra = 1;
+            currMB->i16Mode = AVC_I16_Plane;
+        }
+    }
+
+    return ;
+}
+
+
+int cost_i16(uint8 *org, int org_pitch, uint8 *pred, int min_cost)
+{
+
+    int cost;
+    int j, k;
+    int16 res[256], *pres; // residue
+    int m0, m1, m2, m3;
+
+    // calculate SATD
+    org_pitch -= 16;
+    pres = res;
+    // horizontal transform
+    for (j = 0; j < 16; j++)
+    {
+        k = 4;
+        while (k > 0)
+        {
+            m0 = org[0] - pred[0];
+            m3 = org[3] - pred[3];
+            m0 += m3;
+            m3 = m0 - (m3 << 1);
+            m1 = org[1] - pred[1];
+            m2 = org[2] - pred[2];
+            m1 += m2;
+            m2 = m1 - (m2 << 1);
+            pres[0] = m0 + m1;
+            pres[2] = m0 - m1;
+            pres[1] = m2 + m3;
+            pres[3] = m3 - m2;
+
+            org += 4;
+            pres += 4;
+            pred += 4;
+            k--;
+        }
+        org += org_pitch;
+    }
+    /* vertical transform */
+    cost = 0;
+    for (j = 0; j < 4; j++)
+    {
+        pres = res + (j << 6);
+        k = 16;
+        while (k > 0)
+        {
+            m0 = pres[0];
+            m3 = pres[3<<4];
+            m0 += m3;
+            m3 = m0 - (m3 << 1);
+            m1 = pres[1<<4];
+            m2 = pres[2<<4];
+            m1 += m2;
+            m2 = m1 - (m2 << 1);
+            pres[0] = m0 = m0 + m1;
+
+            if (k&0x3)  // only sum up non DC values.
+            {
+                cost += ((m0 > 0) ? m0 : -m0);
+            }
+
+            m1 = m0 - (m1 << 1);
+            cost += ((m1 > 0) ? m1 : -m1);
+            m3 = m2 + m3;
+            cost += ((m3 > 0) ? m3 : -m3);
+            m2 = m3 - (m2 << 1);
+            cost += ((m2 > 0) ? m2 : -m2);
+
+            pres++;
+            k--;
+        }
+        if ((cost >> 1) > min_cost) /* early drop out */
+        {
+            return (cost >> 1);
+        }
+    }
+
+    /* Hadamard of the DC coefficient */
+    pres = res;
+    k = 4;
+    while (k > 0)
+    {
+        m0 = pres[0];
+        m3 = pres[3<<2];
+        m0 >>= 2;
+        m0 += (m3 >> 2);
+        m3 = m0 - (m3 >> 1);
+        m1 = pres[1<<2];
+        m2 = pres[2<<2];
+        m1 >>= 2;
+        m1 += (m2 >> 2);
+        m2 = m1 - (m2 >> 1);
+        pres[0] = (m0 + m1);
+        pres[2<<2] = (m0 - m1);
+        pres[1<<2] = (m2 + m3);
+        pres[3<<2] = (m3 - m2);
+        pres += (4 << 4);
+        k--;
+    }
+
+    pres = res;
+    k = 4;
+    while (k > 0)
+    {
+        m0 = pres[0];
+        m3 = pres[3<<6];
+        m0 += m3;
+        m3 = m0 - (m3 << 1);
+        m1 = pres[1<<6];
+        m2 = pres[2<<6];
+        m1 += m2;
+        m2 = m1 - (m2 << 1);
+        m0 = m0 + m1;
+        cost += ((m0 >= 0) ? m0 : -m0);
+        m1 = m0 - (m1 << 1);
+        cost += ((m1 >= 0) ? m1 : -m1);
+        m3 = m2 + m3;
+        cost += ((m3 >= 0) ? m3 : -m3);
+        m2 = m3 - (m2 << 1);
+        cost += ((m2 >= 0) ? m2 : -m2);
+        pres += 4;
+
+        if ((cost >> 1) > min_cost) /* early drop out */
+        {
+            return (cost >> 1);
+        }
+
+        k--;
+    }
+
+    return (cost >> 1);
+}
+
+
+void mb_intra4x4_search(AVCEncObject *encvid, int *min_cost)
+{
+    AVCCommonObj *video = encvid->common;
+    AVCMacroblock *currMB = video->currMB;
+    AVCPictureData *currPic = video->currPic;
+    AVCFrameIO *currInput = encvid->currInput;
+    int pitch = currPic->pitch;
+    int org_pitch = currInput->pitch;
+    int offset;
+    uint8 *curL, *comp, *org4, *org8;
+    int y = video->mb_y << 4;
+    int x = video->mb_x << 4;
+
+    int b8, b4, cost4x4, blkidx;
+    int cost = 0;
+    int numcoef;
+    int dummy = 0;
+    int mb_intra = currMB->mb_intra; // save the original value
+
+    offset = y * pitch + x;
+
+    curL = currPic->Sl + offset;
+    org8 = currInput->YCbCr[0] + y * org_pitch + x;
+    video->pred_pitch = 4;
+
+    cost = (int)(6.0 * encvid->lambda_mode + 0.4999);
+    cost <<= 2;
+
+    currMB->mb_intra = 1;  // temporary set this to one to enable the IDCT
+    // operation inside dct_luma
+
+    for (b8 = 0; b8 < 4; b8++)
+    {
+        comp = curL;
+        org4 = org8;
+
+        for (b4 = 0; b4 < 4; b4++)
+        {
+            blkidx = blkIdx2blkXY[b8][b4];
+            cost4x4 = blk_intra4x4_search(encvid, blkidx, comp, org4);
+            cost += cost4x4;
+            if (cost > *min_cost)
+            {
+                currMB->mb_intra = mb_intra; // restore the value
+                return ;
+            }
+
+            /* do residue, Xfrm, Q, invQ, invXfrm, recon and save the DCT coefs.*/
+            video->pred_block = encvid->pred_i4[currMB->i4Mode[blkidx]];
+            numcoef = dct_luma(encvid, blkidx, comp, org4, &dummy);
+            currMB->nz_coeff[blkidx] = numcoef;
+            if (numcoef)
+            {
+                video->cbp4x4 |= (1 << blkidx);
+                currMB->CBP |= (1 << b8);
+            }
+
+            if (b4&1)
+            {
+                comp += ((pitch << 2) - 4);
+                org4 += ((org_pitch << 2) - 4);
+            }
+            else
+            {
+                comp += 4;
+                org4 += 4;
+            }
+        }
+
+        if (b8&1)
+        {
+            curL += ((pitch << 3) - 8);
+            org8 += ((org_pitch << 3) - 8);
+        }
+        else
+        {
+            curL += 8;
+            org8 += 8;
+        }
+    }
+
+    currMB->mb_intra = mb_intra; // restore the value
+
+    if (cost < *min_cost)
+    {
+        *min_cost = cost;
+        currMB->mbMode = AVC_I4;
+        currMB->mb_intra = 1;
+    }
+
+    return ;
+}
+
+
+/* search for i4 mode for a 4x4 block */
+int blk_intra4x4_search(AVCEncObject *encvid, int blkidx, uint8 *cur, uint8 *org)
+{
+    AVCCommonObj *video = encvid->common;
+    AVCNeighborAvailability availability;
+    AVCMacroblock *currMB = video->currMB;
+    bool top_left = FALSE;
+    int pitch = video->currPic->pitch;
+    uint8 mode_avail[AVCNumI4PredMode];
+    uint32 temp, DC;
+    uint8 *pred;
+    int org_pitch = encvid->currInput->pitch;
+    uint16 min_cost, cost;
+
+    int P_x, Q_x, R_x, P_y, Q_y, R_y, D, D0, D1;
+    int P0, Q0, R0, S0, P1, Q1, R1, P2, Q2;
+    uint8 P_A, P_B, P_C, P_D, P_E, P_F, P_G, P_H, P_I, P_J, P_K, P_L, P_X;
+    int r0, r1, r2, r3, r4, r5, r6, r7;
+    int x0, x1, x2, x3, x4, x5;
+    uint32 temp1, temp2;
+
+    int ipmode, mostProbableMode;
+    int fixedcost = 4 * encvid->lambda_mode;
+    int min_sad = 0x7FFF;
+
+    availability.left = TRUE;
+    availability.top = TRUE;
+    if (blkidx <= 3) /* top row block  (!block_y) */
+    { /* check availability up */
+        availability.top = video->intraAvailB ;
+    }
+    if (!(blkidx&0x3)) /* left column block (!block_x)*/
+    { /* check availability left */
+        availability.left = video->intraAvailA ;
+    }
+    availability.top_right = BlkTopRight[blkidx];
+
+    if (availability.top_right == 2)
+    {
+        availability.top_right = video->intraAvailB;
+    }
+    else if (availability.top_right == 3)
+    {
+        availability.top_right = video->intraAvailC;
+    }
+
+    if (availability.top == TRUE)
+    {
+        temp = *(uint32*)(cur - pitch);
+        P_A = temp & 0xFF;
+        P_B = (temp >> 8) & 0xFF;
+        P_C = (temp >> 16) & 0xFF;
+        P_D = (temp >> 24) & 0xFF;
+    }
+    else
+    {
+        P_A = P_B = P_C = P_D = 128;
+    }
+
+    if (availability.top_right == TRUE)
+    {
+        temp = *(uint32*)(cur - pitch + 4);
+        P_E = temp & 0xFF;
+        P_F = (temp >> 8) & 0xFF;
+        P_G = (temp >> 16) & 0xFF;
+        P_H = (temp >> 24) & 0xFF;
+    }
+    else
+    {
+        P_E = P_F = P_G = P_H = 128;
+    }
+
+    if (availability.left == TRUE)
+    {
+        cur--;
+        P_I = *cur;
+        P_J = *(cur += pitch);
+        P_K = *(cur += pitch);
+        P_L = *(cur + pitch);
+        cur -= (pitch << 1);
+        cur++;
+    }
+    else
+    {
+        P_I = P_J = P_K = P_L = 128;
+    }
+
+    /* check if top-left pixel is available */
+    if (((blkidx > 3) && (blkidx&0x3)) || ((blkidx > 3) && video->intraAvailA)
+            || ((blkidx&0x3) && video->intraAvailB)
+            || (video->intraAvailA && video->intraAvailD && video->intraAvailB))
+    {
+        top_left = TRUE;
+        P_X = *(cur - pitch - 1);
+    }
+    else
+    {
+        P_X = 128;
+    }
+
+    //===== INTRA PREDICTION FOR 4x4 BLOCK =====
+    /* vertical */
+    mode_avail[AVC_I4_Vertical] = 0;
+    if (availability.top)
+    {
+        mode_avail[AVC_I4_Vertical] = 1;
+        pred = encvid->pred_i4[AVC_I4_Vertical];
+
+        temp = (P_D << 24) | (P_C << 16) | (P_B << 8) | P_A ;
+        *((uint32*)pred) =  temp; /* write 4 at a time */
+        *((uint32*)(pred += 4)) =  temp;
+        *((uint32*)(pred += 4)) =  temp;
+        *((uint32*)(pred += 4)) =  temp;
+    }
+    /* horizontal */
+    mode_avail[AVC_I4_Horizontal] = 0;
+    mode_avail[AVC_I4_Horizontal_Up] = 0;
+    if (availability.left)
+    {
+        mode_avail[AVC_I4_Horizontal] = 1;
+        pred = encvid->pred_i4[AVC_I4_Horizontal];
+
+        temp = P_I | (P_I << 8);
+        temp = temp | (temp << 16);
+        *((uint32*)pred) = temp;
+        temp = P_J | (P_J << 8);
+        temp = temp | (temp << 16);
+        *((uint32*)(pred += 4)) = temp;
+        temp = P_K | (P_K << 8);
+        temp = temp | (temp << 16);
+        *((uint32*)(pred += 4)) = temp;
+        temp = P_L | (P_L << 8);
+        temp = temp | (temp << 16);
+        *((uint32*)(pred += 4)) = temp;
+
+        mode_avail[AVC_I4_Horizontal_Up] = 1;
+        pred = encvid->pred_i4[AVC_I4_Horizontal_Up];
+
+        Q0 = (P_J + P_K + 1) >> 1;
+        Q1 = (P_J + (P_K << 1) + P_L + 2) >> 2;
+        P0 = ((P_I + P_J + 1) >> 1);
+        P1 = ((P_I + (P_J << 1) + P_K + 2) >> 2);
+
+        temp = P0 | (P1 << 8);      // [P0 P1 Q0 Q1]
+        temp |= (Q0 << 16);     // [Q0 Q1 R0 DO]
+        temp |= (Q1 << 24);     // [R0 D0 D1 D1]
+        *((uint32*)pred) = temp;      // [D1 D1 D1 D1]
+
+        D0 = (P_K + 3 * P_L + 2) >> 2;
+        R0 = (P_K + P_L + 1) >> 1;
+
+        temp = Q0 | (Q1 << 8);
+        temp |= (R0 << 16);
+        temp |= (D0 << 24);
+        *((uint32*)(pred += 4)) = temp;
+
+        D1 = P_L;
+
+        temp = R0 | (D0 << 8);
+        temp |= (D1 << 16);
+        temp |= (D1 << 24);
+        *((uint32*)(pred += 4)) = temp;
+
+        temp = D1 | (D1 << 8);
+        temp |= (temp << 16);
+        *((uint32*)(pred += 4)) = temp;
+    }
+    /* DC */
+    mode_avail[AVC_I4_DC] = 1;
+    pred = encvid->pred_i4[AVC_I4_DC];
+    if (availability.left)
+    {
+        DC = P_I + P_J + P_K + P_L;
+
+        if (availability.top)
+        {
+            DC = (P_A + P_B + P_C + P_D + DC + 4) >> 3;
+        }
+        else
+        {
+            DC = (DC + 2) >> 2;
+
+        }
+    }
+    else if (availability.top)
+    {
+        DC = (P_A + P_B + P_C + P_D + 2) >> 2;
+
+    }
+    else
+    {
+        DC = 128;
+    }
+
+    temp = DC | (DC << 8);
+    temp = temp | (temp << 16);
+    *((uint32*)pred) = temp;
+    *((uint32*)(pred += 4)) = temp;
+    *((uint32*)(pred += 4)) = temp;
+    *((uint32*)(pred += 4)) = temp;
+
+    /* Down-left */
+    mode_avail[AVC_I4_Diagonal_Down_Left] = 0;
+
+    if (availability.top)
+    {
+        mode_avail[AVC_I4_Diagonal_Down_Left] = 1;
+
+        pred = encvid->pred_i4[AVC_I4_Diagonal_Down_Left];
+
+        r0 = P_A;
+        r1 = P_B;
+        r2 = P_C;
+        r3 = P_D;
+
+        r0 += (r1 << 1);
+        r0 += r2;
+        r0 += 2;
+        r0 >>= 2;
+        r1 += (r2 << 1);
+        r1 += r3;
+        r1 += 2;
+        r1 >>= 2;
+
+        if (availability.top_right)
+        {
+            r4 = P_E;
+            r5 = P_F;
+            r6 = P_G;
+            r7 = P_H;
+
+            r2 += (r3 << 1);
+            r2 += r4;
+            r2 += 2;
+            r2 >>= 2;
+            r3 += (r4 << 1);
+            r3 += r5;
+            r3 += 2;
+            r3 >>= 2;
+            r4 += (r5 << 1);
+            r4 += r6;
+            r4 += 2;
+            r4 >>= 2;
+            r5 += (r6 << 1);
+            r5 += r7;
+            r5 += 2;
+            r5 >>= 2;
+            r6 += (3 * r7);
+            r6 += 2;
+            r6 >>= 2;
+            temp = r0 | (r1 << 8);
+            temp |= (r2 << 16);
+            temp |= (r3 << 24);
+            *((uint32*)pred) = temp;
+
+            temp = (temp >> 8) | (r4 << 24);
+            *((uint32*)(pred += 4)) = temp;
+
+            temp = (temp >> 8) | (r5 << 24);
+            *((uint32*)(pred += 4)) = temp;
+
+            temp = (temp >> 8) | (r6 << 24);
+            *((uint32*)(pred += 4)) = temp;
+        }
+        else
+        {
+            r2 += (r3 * 3);
+            r2 += 2;
+            r2 >>= 2;
+            r3 = ((r3 << 2) + 2);
+            r3 >>= 2;
+
+            temp = r0 | (r1 << 8);
+            temp |= (r2 << 16);
+            temp |= (r3 << 24);
+            *((uint32*)pred) = temp;
+
+            temp = (temp >> 8) | (r3 << 24);
+            *((uint32*)(pred += 4)) = temp;
+
+            temp = (temp >> 8) | (r3 << 24);
+            *((uint32*)(pred += 4)) = temp;
+
+            temp = (temp >> 8) | (r3 << 24);
+            *((uint32*)(pred += 4)) = temp;
+
+        }
+    }
+
+    /* Down Right */
+    mode_avail[AVC_I4_Diagonal_Down_Right] = 0;
+    /* Diagonal Vertical Right */
+    mode_avail[AVC_I4_Vertical_Right] = 0;
+    /* Horizontal Down */
+    mode_avail[AVC_I4_Horizontal_Down] = 0;
+
+    if (top_left == TRUE)
+    {
+        /* Down Right */
+        mode_avail[AVC_I4_Diagonal_Down_Right] = 1;
+        pred = encvid->pred_i4[AVC_I4_Diagonal_Down_Right];
+
+        Q_x = (P_A + 2 * P_B + P_C + 2) >> 2;
+        R_x = (P_B + 2 * P_C + P_D + 2) >> 2;
+        P_x = (P_X + 2 * P_A + P_B + 2) >> 2;
+        D   = (P_A + 2 * P_X + P_I + 2) >> 2;
+        P_y = (P_X + 2 * P_I + P_J + 2) >> 2;
+        Q_y = (P_I + 2 * P_J + P_K + 2) >> 2;
+        R_y = (P_J + 2 * P_K + P_L + 2) >> 2;
+
+        /* we can pack these */
+        temp =  D | (P_x << 8);   //[D   P_x Q_x R_x]
+        //[P_y D   P_x Q_x]
+        temp |= (Q_x << 16); //[Q_y P_y D   P_x]
+        temp |= (R_x << 24);  //[R_y Q_y P_y D  ]
+        *((uint32*)pred) = temp;
+
+        temp =  P_y | (D << 8);
+        temp |= (P_x << 16);
+        temp |= (Q_x << 24);
+        *((uint32*)(pred += 4)) = temp;
+
+        temp =  Q_y | (P_y << 8);
+        temp |= (D << 16);
+        temp |= (P_x << 24);
+        *((uint32*)(pred += 4)) = temp;
+
+        temp = R_y | (Q_y << 8);
+        temp |= (P_y << 16);
+        temp |= (D << 24);
+        *((uint32*)(pred += 4)) = temp;
+
+
+        /* Diagonal Vertical Right */
+        mode_avail[AVC_I4_Vertical_Right] = 1;
+        pred = encvid->pred_i4[AVC_I4_Vertical_Right];
+
+        Q0 = P_A + P_B + 1;
+        R0 = P_B + P_C + 1;
+        S0 = P_C + P_D + 1;
+        P0 = P_X + P_A + 1;
+        D = (P_I + 2 * P_X + P_A + 2) >> 2;
+
+        P1 = (P0 + Q0) >> 2;
+        Q1 = (Q0 + R0) >> 2;
+        R1 = (R0 + S0) >> 2;
+
+        P0 >>= 1;
+        Q0 >>= 1;
+        R0 >>= 1;
+        S0 >>= 1;
+
+        P2 = (P_X + 2 * P_I + P_J + 2) >> 2;
+        Q2 = (P_I + 2 * P_J + P_K + 2) >> 2;
+
+        temp =  P0 | (Q0 << 8);  //[P0 Q0 R0 S0]
+        //[D  P1 Q1 R1]
+        temp |= (R0 << 16); //[P2 P0 Q0 R0]
+        temp |= (S0 << 24); //[Q2 D  P1 Q1]
+        *((uint32*)pred) =  temp;
+
+        temp =  D | (P1 << 8);
+        temp |= (Q1 << 16);
+        temp |= (R1 << 24);
+        *((uint32*)(pred += 4)) =  temp;
+
+        temp = P2 | (P0 << 8);
+        temp |= (Q0 << 16);
+        temp |= (R0 << 24);
+        *((uint32*)(pred += 4)) =  temp;
+
+        temp = Q2 | (D << 8);
+        temp |= (P1 << 16);
+        temp |= (Q1 << 24);
+        *((uint32*)(pred += 4)) =  temp;
+
+
+        /* Horizontal Down */
+        mode_avail[AVC_I4_Horizontal_Down] = 1;
+        pred = encvid->pred_i4[AVC_I4_Horizontal_Down];
+
+
+        Q2 = (P_A + 2 * P_B + P_C + 2) >> 2;
+        P2 = (P_X + 2 * P_A + P_B + 2) >> 2;
+        D = (P_I + 2 * P_X + P_A + 2) >> 2;
+        P0 = P_X + P_I + 1;
+        Q0 = P_I + P_J + 1;
+        R0 = P_J + P_K + 1;
+        S0 = P_K + P_L + 1;
+
+        P1 = (P0 + Q0) >> 2;
+        Q1 = (Q0 + R0) >> 2;
+        R1 = (R0 + S0) >> 2;
+
+        P0 >>= 1;
+        Q0 >>= 1;
+        R0 >>= 1;
+        S0 >>= 1;
+
+
+        /* we can pack these */
+        temp = P0 | (D << 8);   //[P0 D  P2 Q2]
+        //[Q0 P1 P0 D ]
+        temp |= (P2 << 16);  //[R0 Q1 Q0 P1]
+        temp |= (Q2 << 24); //[S0 R1 R0 Q1]
+        *((uint32*)pred) = temp;
+
+        temp = Q0 | (P1 << 8);
+        temp |= (P0 << 16);
+        temp |= (D << 24);
+        *((uint32*)(pred += 4)) = temp;
+
+        temp = R0 | (Q1 << 8);
+        temp |= (Q0 << 16);
+        temp |= (P1 << 24);
+        *((uint32*)(pred += 4)) = temp;
+
+        temp = S0 | (R1 << 8);
+        temp |= (R0 << 16);
+        temp |= (Q1 << 24);
+        *((uint32*)(pred += 4)) = temp;
+
+    }
+
+    /* vertical left */
+    mode_avail[AVC_I4_Vertical_Left] = 0;
+    if (availability.top)
+    {
+        mode_avail[AVC_I4_Vertical_Left] = 1;
+        pred = encvid->pred_i4[AVC_I4_Vertical_Left];
+
+        x0 = P_A + P_B + 1;
+        x1 = P_B + P_C + 1;
+        x2 = P_C + P_D + 1;
+        if (availability.top_right)
+        {
+            x3 = P_D + P_E + 1;
+            x4 = P_E + P_F + 1;
+            x5 = P_F + P_G + 1;
+        }
+        else
+        {
+            x3 = x4 = x5 = (P_D << 1) + 1;
+        }
+
+        temp1 = (x0 >> 1);
+        temp1 |= ((x1 >> 1) << 8);
+        temp1 |= ((x2 >> 1) << 16);
+        temp1 |= ((x3 >> 1) << 24);
+
+        *((uint32*)pred) = temp1;
+
+        temp2 = ((x0 + x1) >> 2);
+        temp2 |= (((x1 + x2) >> 2) << 8);
+        temp2 |= (((x2 + x3) >> 2) << 16);
+        temp2 |= (((x3 + x4) >> 2) << 24);
+
+        *((uint32*)(pred += 4)) = temp2;
+
+        temp1 = (temp1 >> 8) | ((x4 >> 1) << 24);   /* rotate out old value */
+        *((uint32*)(pred += 4)) = temp1;
+
+        temp2 = (temp2 >> 8) | (((x4 + x5) >> 2) << 24); /* rotate out old value */
+        *((uint32*)(pred += 4)) = temp2;
+    }
+
+    //===== LOOP OVER ALL 4x4 INTRA PREDICTION MODES =====
+    // can re-order the search here instead of going in order
+
+    // find most probable mode
+    encvid->mostProbableI4Mode[blkidx] = mostProbableMode = FindMostProbableI4Mode(video, blkidx);
+
+    min_cost = 0xFFFF;
+
+    for (ipmode = 0; ipmode < AVCNumI4PredMode; ipmode++)
+    {
+        if (mode_avail[ipmode] == TRUE)
+        {
+            cost  = (ipmode == mostProbableMode) ? 0 : fixedcost;
+            pred = encvid->pred_i4[ipmode];
+
+            cost_i4(org, org_pitch, pred, &cost);
+
+            if (cost < min_cost)
+            {
+                currMB->i4Mode[blkidx] = (AVCIntra4x4PredMode)ipmode;
+                min_cost   = cost;
+                min_sad = cost - ((ipmode == mostProbableMode) ? 0 : fixedcost);
+            }
+        }
+    }
+
+    if (blkidx == 0)
+    {
+        encvid->i4_sad = min_sad;
+    }
+    else
+    {
+        encvid->i4_sad += min_sad;
+    }
+
+    return min_cost;
+}
+
+int FindMostProbableI4Mode(AVCCommonObj *video, int blkidx)
+{
+    int dcOnlyPredictionFlag;
+    AVCMacroblock *currMB = video->currMB;
+    int intra4x4PredModeA, intra4x4PredModeB, predIntra4x4PredMode;
+
+
+    dcOnlyPredictionFlag = 0;
+    if (blkidx&0x3)
+    {
+        intra4x4PredModeA = currMB->i4Mode[blkidx-1]; // block to the left
+    }
+    else /* for blk 0, 4, 8, 12 */
+    {
+        if (video->intraAvailA)
+        {
+            if (video->mblock[video->mbAddrA].mbMode == AVC_I4)
+            {
+                intra4x4PredModeA = video->mblock[video->mbAddrA].i4Mode[blkidx + 3];
+            }
+            else
+            {
+                intra4x4PredModeA = AVC_I4_DC;
+            }
+        }
+        else
+        {
+            dcOnlyPredictionFlag = 1;
+            goto PRED_RESULT_READY;  // skip below
+        }
+    }
+
+    if (blkidx >> 2)
+    {
+        intra4x4PredModeB = currMB->i4Mode[blkidx-4]; // block above
+    }
+    else /* block 0, 1, 2, 3 */
+    {
+        if (video->intraAvailB)
+        {
+            if (video->mblock[video->mbAddrB].mbMode == AVC_I4)
+            {
+                intra4x4PredModeB = video->mblock[video->mbAddrB].i4Mode[blkidx+12];
+            }
+            else
+            {
+                intra4x4PredModeB = AVC_I4_DC;
+            }
+        }
+        else
+        {
+            dcOnlyPredictionFlag = 1;
+        }
+    }
+
+PRED_RESULT_READY:
+    if (dcOnlyPredictionFlag)
+    {
+        intra4x4PredModeA = intra4x4PredModeB = AVC_I4_DC;
+    }
+
+    predIntra4x4PredMode = AVC_MIN(intra4x4PredModeA, intra4x4PredModeB);
+
+    return predIntra4x4PredMode;
+}
+
+void cost_i4(uint8 *org, int org_pitch, uint8 *pred, uint16 *cost)
+{
+    int k;
+    int16 res[16], *pres;
+    int m0, m1, m2, m3, tmp1;
+    int satd = 0;
+
+    pres = res;
+    // horizontal transform
+    k = 4;
+    while (k > 0)
+    {
+        m0 = org[0] - pred[0];
+        m3 = org[3] - pred[3];
+        m0 += m3;
+        m3 = m0 - (m3 << 1);
+        m1 = org[1] - pred[1];
+        m2 = org[2] - pred[2];
+        m1 += m2;
+        m2 = m1 - (m2 << 1);
+        pres[0] = m0 + m1;
+        pres[2] = m0 - m1;
+        pres[1] = m2 + m3;
+        pres[3] = m3 - m2;
+
+        org += org_pitch;
+        pres += 4;
+        pred += 4;
+        k--;
+    }
+    /* vertical transform */
+    pres = res;
+    k = 4;
+    while (k > 0)
+    {
+        m0 = pres[0];
+        m3 = pres[12];
+        m0 += m3;
+        m3 = m0 - (m3 << 1);
+        m1 = pres[4];
+        m2 = pres[8];
+        m1 += m2;
+        m2 = m1 - (m2 << 1);
+        pres[0] = m0 + m1;
+        pres[8] = m0 - m1;
+        pres[4] = m2 + m3;
+        pres[12] = m3 - m2;
+
+        pres++;
+        k--;
+
+    }
+
+    pres = res;
+    k = 4;
+    while (k > 0)
+    {
+        tmp1 = *pres++;
+        satd += ((tmp1 >= 0) ? tmp1 : -tmp1);
+        tmp1 = *pres++;
+        satd += ((tmp1 >= 0) ? tmp1 : -tmp1);
+        tmp1 = *pres++;
+        satd += ((tmp1 >= 0) ? tmp1 : -tmp1);
+        tmp1 = *pres++;
+        satd += ((tmp1 >= 0) ? tmp1 : -tmp1);
+        k--;
+    }
+
+    satd = (satd + 1) >> 1;
+    *cost += satd;
+
+    return ;
+}
+
+void chroma_intra_search(AVCEncObject *encvid)
+{
+    AVCCommonObj *video = encvid->common;
+    AVCPictureData *currPic = video->currPic;
+
+    int x_pos = video->mb_x << 3;
+    int y_pos = video->mb_y << 3;
+    int pitch = currPic->pitch >> 1;
+    int offset = y_pos * pitch + x_pos;
+
+    uint8 *comp_ref_x, *comp_ref_y, *pred;
+    int  sum_x0, sum_x1, sum_y0, sum_y1;
+    int pred_0[2], pred_1[2], pred_2[2], pred_3[2];
+    uint32 pred_a, pred_b, pred_c, pred_d;
+    int i, j, component;
+    int a_16, b, c, factor_c, topleft;
+    int H, V, value;
+    uint8 *comp_ref_x0, *comp_ref_x1,  *comp_ref_y0, *comp_ref_y1;
+
+    uint8 *curCb = currPic->Scb + offset;
+    uint8 *curCr = currPic->Scr + offset;
+
+    uint8 *orgCb, *orgCr;
+    AVCFrameIO *currInput = encvid->currInput;
+    AVCMacroblock *currMB = video->currMB;
+    int org_pitch;
+    int cost, mincost;
+
+    /* evaluate DC mode */
+    if (video->intraAvailB & video->intraAvailA)
+    {
+        comp_ref_x = curCb - pitch;
+        comp_ref_y = curCb - 1;
+
+        for (i = 0; i < 2; i++)
+        {
+            pred_a = *((uint32*)comp_ref_x);
+            comp_ref_x += 4;
+            pred_b = (pred_a >> 8) & 0xFF00FF;
+            pred_a &= 0xFF00FF;
+            pred_a += pred_b;
+            pred_a += (pred_a >> 16);
+            sum_x0 = pred_a & 0xFFFF;
+
+            pred_a = *((uint32*)comp_ref_x);
+            pred_b = (pred_a >> 8) & 0xFF00FF;
+            pred_a &= 0xFF00FF;
+            pred_a += pred_b;
+            pred_a += (pred_a >> 16);
+            sum_x1 = pred_a & 0xFFFF;
+
+            pred_1[i] = (sum_x1 + 2) >> 2;
+
+            sum_y0 = *comp_ref_y;
+            sum_y0 += *(comp_ref_y += pitch);
+            sum_y0 += *(comp_ref_y += pitch);
+            sum_y0 += *(comp_ref_y += pitch);
+
+            sum_y1 = *(comp_ref_y += pitch);
+            sum_y1 += *(comp_ref_y += pitch);
+            sum_y1 += *(comp_ref_y += pitch);
+            sum_y1 += *(comp_ref_y += pitch);
+
+            pred_2[i] = (sum_y1 + 2) >> 2;
+
+            pred_0[i] = (sum_y0 + sum_x0 + 4) >> 3;
+            pred_3[i] = (sum_y1 + sum_x1 + 4) >> 3;
+
+            comp_ref_x = curCr - pitch;
+            comp_ref_y = curCr - 1;
+        }
+    }
+
+    else if (video->intraAvailA)
+    {
+        comp_ref_y = curCb - 1;
+        for (i = 0; i < 2; i++)
+        {
+            sum_y0 = *comp_ref_y;
+            sum_y0 += *(comp_ref_y += pitch);
+            sum_y0 += *(comp_ref_y += pitch);
+            sum_y0 += *(comp_ref_y += pitch);
+
+            sum_y1 = *(comp_ref_y += pitch);
+            sum_y1 += *(comp_ref_y += pitch);
+            sum_y1 += *(comp_ref_y += pitch);
+            sum_y1 += *(comp_ref_y += pitch);
+
+            pred_0[i] = pred_1[i] = (sum_y0 + 2) >> 2;
+            pred_2[i] = pred_3[i] = (sum_y1 + 2) >> 2;
+
+            comp_ref_y = curCr - 1;
+        }
+    }
+    else if (video->intraAvailB)
+    {
+        comp_ref_x = curCb - pitch;
+        for (i = 0; i < 2; i++)
+        {
+            pred_a = *((uint32*)comp_ref_x);
+            comp_ref_x += 4;
+            pred_b = (pred_a >> 8) & 0xFF00FF;
+            pred_a &= 0xFF00FF;
+            pred_a += pred_b;
+            pred_a += (pred_a >> 16);
+            sum_x0 = pred_a & 0xFFFF;
+
+            pred_a = *((uint32*)comp_ref_x);
+            pred_b = (pred_a >> 8) & 0xFF00FF;
+            pred_a &= 0xFF00FF;
+            pred_a += pred_b;
+            pred_a += (pred_a >> 16);
+            sum_x1 = pred_a & 0xFFFF;
+
+            pred_0[i] = pred_2[i] = (sum_x0 + 2) >> 2;
+            pred_1[i] = pred_3[i] = (sum_x1 + 2) >> 2;
+
+            comp_ref_x = curCr - pitch;
+        }
+    }
+    else
+    {
+        pred_0[0] = pred_0[1] = pred_1[0] = pred_1[1] =
+                                                pred_2[0] = pred_2[1] = pred_3[0] = pred_3[1] = 128;
+    }
+
+    pred = encvid->pred_ic[AVC_IC_DC];
+
+    pred_a = pred_0[0];
+    pred_b = pred_1[0];
+    pred_a |= (pred_a << 8);
+    pred_a |= (pred_a << 16);
+    pred_b |= (pred_b << 8);
+    pred_b |= (pred_b << 16);
+
+    pred_c = pred_0[1];
+    pred_d = pred_1[1];
+    pred_c |= (pred_c << 8);
+    pred_c |= (pred_c << 16);
+    pred_d |= (pred_d << 8);
+    pred_d |= (pred_d << 16);
+
+
+    for (j = 0; j < 4; j++) /* 4 lines */
+    {
+        *((uint32*)pred) = pred_a;
+        *((uint32*)(pred + 4)) = pred_b;
+        *((uint32*)(pred + 8)) = pred_c;
+        *((uint32*)(pred + 12)) = pred_d;
+        pred += 16; /* move to the next line */
+    }
+
+    pred_a = pred_2[0];
+    pred_b = pred_3[0];
+    pred_a |= (pred_a << 8);
+    pred_a |= (pred_a << 16);
+    pred_b |= (pred_b << 8);
+    pred_b |= (pred_b << 16);
+
+    pred_c = pred_2[1];
+    pred_d = pred_3[1];
+    pred_c |= (pred_c << 8);
+    pred_c |= (pred_c << 16);
+    pred_d |= (pred_d << 8);
+    pred_d |= (pred_d << 16);
+
+    for (j = 0; j < 4; j++) /* 4 lines */
+    {
+        *((uint32*)pred) = pred_a;
+        *((uint32*)(pred + 4)) = pred_b;
+        *((uint32*)(pred + 8)) = pred_c;
+        *((uint32*)(pred + 12)) = pred_d;
+        pred += 16; /* move to the next line */
+    }
+
+    /* predict horizontal mode */
+    if (video->intraAvailA)
+    {
+        comp_ref_y = curCb - 1;
+        comp_ref_x = curCr - 1;
+        pred = encvid->pred_ic[AVC_IC_Horizontal];
+
+        for (i = 4; i < 6; i++)
+        {
+            for (j = 0; j < 4; j++)
+            {
+                pred_a = *comp_ref_y;
+                comp_ref_y += pitch;
+                pred_a |= (pred_a << 8);
+                pred_a |= (pred_a << 16);
+                *((uint32*)pred) = pred_a;
+                *((uint32*)(pred + 4)) = pred_a;
+
+                pred_a = *comp_ref_x;
+                comp_ref_x += pitch;
+                pred_a |= (pred_a << 8);
+                pred_a |= (pred_a << 16);
+                *((uint32*)(pred + 8)) = pred_a;
+                *((uint32*)(pred + 12)) = pred_a;
+
+                pred += 16;
+            }
+        }
+    }
+
+    /* vertical mode */
+    if (video->intraAvailB)
+    {
+        comp_ref_x = curCb - pitch;
+        comp_ref_y = curCr - pitch;
+        pred = encvid->pred_ic[AVC_IC_Vertical];
+
+        pred_a = *((uint32*)comp_ref_x);
+        pred_b = *((uint32*)(comp_ref_x + 4));
+        pred_c = *((uint32*)comp_ref_y);
+        pred_d = *((uint32*)(comp_ref_y + 4));
+
+        for (j = 0; j < 8; j++)
+        {
+            *((uint32*)pred) = pred_a;
+            *((uint32*)(pred + 4)) = pred_b;
+            *((uint32*)(pred + 8)) = pred_c;
+            *((uint32*)(pred + 12)) = pred_d;
+            pred += 16;
+        }
+    }
+
+    /* Intra_Chroma_Plane */
+    if (video->intraAvailA && video->intraAvailB && video->intraAvailD)
+    {
+        comp_ref_x = curCb - pitch;
+        comp_ref_y = curCb - 1;
+        topleft = curCb[-pitch-1];
+
+        pred = encvid->pred_ic[AVC_IC_Plane];
+        for (component = 0; component < 2; component++)
+        {
+            H = V = 0;
+            comp_ref_x0 = comp_ref_x + 4;
+            comp_ref_x1 = comp_ref_x + 2;
+            comp_ref_y0 = comp_ref_y + (pitch << 2);
+            comp_ref_y1 = comp_ref_y + (pitch << 1);
+            for (i = 1; i < 4; i++)
+            {
+                H += i * (*comp_ref_x0++ - *comp_ref_x1--);
+                V += i * (*comp_ref_y0 - *comp_ref_y1);
+                comp_ref_y0 += pitch;
+                comp_ref_y1 -= pitch;
+            }
+            H += i * (*comp_ref_x0++ - topleft);
+            V += i * (*comp_ref_y0 - *comp_ref_y1);
+
+            a_16 = ((*(comp_ref_x + 7) + *(comp_ref_y + 7 * pitch)) << 4) + 16;
+            b = (17 * H + 16) >> 5;
+            c = (17 * V + 16) >> 5;
+
+            pred_a = 0;
+            for (i = 4; i < 6; i++)
+            {
+                for (j = 0; j < 4; j++)
+                {
+                    factor_c = a_16 + c * (pred_a++ - 3);
+
+                    factor_c -= 3 * b;
+
+                    value = factor_c >> 5;
+                    factor_c += b;
+                    CLIP_RESULT(value)
+                    pred_b = value;
+                    value = factor_c >> 5;
+                    factor_c += b;
+                    CLIP_RESULT(value)
+                    pred_b |= (value << 8);
+                    value = factor_c >> 5;
+                    factor_c += b;
+                    CLIP_RESULT(value)
+                    pred_b |= (value << 16);
+                    value = factor_c >> 5;
+                    factor_c += b;
+                    CLIP_RESULT(value)
+                    pred_b |= (value << 24);
+                    *((uint32*)pred) = pred_b;
+
+                    value = factor_c >> 5;
+                    factor_c += b;
+                    CLIP_RESULT(value)
+                    pred_b = value;
+                    value = factor_c >> 5;
+                    factor_c += b;
+                    CLIP_RESULT(value)
+                    pred_b |= (value << 8);
+                    value = factor_c >> 5;
+                    factor_c += b;
+                    CLIP_RESULT(value)
+                    pred_b |= (value << 16);
+                    value = factor_c >> 5;
+                    factor_c += b;
+                    CLIP_RESULT(value)
+                    pred_b |= (value << 24);
+                    *((uint32*)(pred + 4)) = pred_b;
+                    pred += 16;
+                }
+            }
+
+            pred -= 120; /* point to cr */
+            comp_ref_x = curCr - pitch;
+            comp_ref_y = curCr - 1;
+            topleft = curCr[-pitch-1];
+        }
+    }
+
+    /* now evaluate it */
+
+    org_pitch = (currInput->pitch) >> 1;
+    offset = x_pos + y_pos * org_pitch;
+
+    orgCb = currInput->YCbCr[1] + offset;
+    orgCr = currInput->YCbCr[2] + offset;
+
+    mincost = 0x7fffffff;
+    cost = SATDChroma(orgCb, orgCr, org_pitch, encvid->pred_ic[AVC_IC_DC], mincost);
+    if (cost < mincost)
+    {
+        mincost = cost;
+        currMB->intra_chroma_pred_mode = AVC_IC_DC;
+    }
+
+    if (video->intraAvailA)
+    {
+        cost = SATDChroma(orgCb, orgCr, org_pitch, encvid->pred_ic[AVC_IC_Horizontal], mincost);
+        if (cost < mincost)
+        {
+            mincost = cost;
+            currMB->intra_chroma_pred_mode = AVC_IC_Horizontal;
+        }
+    }
+
+    if (video->intraAvailB)
+    {
+        cost = SATDChroma(orgCb, orgCr, org_pitch, encvid->pred_ic[AVC_IC_Vertical], mincost);
+        if (cost < mincost)
+        {
+            mincost = cost;
+            currMB->intra_chroma_pred_mode = AVC_IC_Vertical;
+        }
+    }
+
+    if (video->intraAvailA && video->intraAvailB && video->intraAvailD)
+    {
+        cost = SATDChroma(orgCb, orgCr, org_pitch, encvid->pred_ic[AVC_IC_Plane], mincost);
+        if (cost < mincost)
+        {
+            mincost = cost;
+            currMB->intra_chroma_pred_mode = AVC_IC_Plane;
+        }
+    }
+
+
+    return ;
+}
+
+
+int SATDChroma(uint8 *orgCb, uint8 *orgCr, int org_pitch, uint8 *pred, int min_cost)
+{
+    int cost;
+    /* first take difference between orgCb, orgCr and pred */
+    int16 res[128], *pres; // residue
+    int m0, m1, m2, m3, tmp1;
+    int j, k;
+
+    pres = res;
+    org_pitch -= 8;
+    // horizontal transform
+    for (j = 0; j < 8; j++)
+    {
+        k = 2;
+        while (k > 0)
+        {
+            m0 = orgCb[0] - pred[0];
+            m3 = orgCb[3] - pred[3];
+            m0 += m3;
+            m3 = m0 - (m3 << 1);
+            m1 = orgCb[1] - pred[1];
+            m2 = orgCb[2] - pred[2];
+            m1 += m2;
+            m2 = m1 - (m2 << 1);
+            pres[0] = m0 + m1;
+            pres[2] = m0 - m1;
+            pres[1] = m2 + m3;
+            pres[3] = m3 - m2;
+
+            orgCb += 4;
+            pres += 4;
+            pred += 4;
+            k--;
+        }
+        orgCb += org_pitch;
+        k = 2;
+        while (k > 0)
+        {
+            m0 = orgCr[0] - pred[0];
+            m3 = orgCr[3] - pred[3];
+            m0 += m3;
+            m3 = m0 - (m3 << 1);
+            m1 = orgCr[1] - pred[1];
+            m2 = orgCr[2] - pred[2];
+            m1 += m2;
+            m2 = m1 - (m2 << 1);
+            pres[0] = m0 + m1;
+            pres[2] = m0 - m1;
+            pres[1] = m2 + m3;
+            pres[3] = m3 - m2;
+
+            orgCr += 4;
+            pres += 4;
+            pred += 4;
+            k--;
+        }
+        orgCr += org_pitch;
+    }
+
+    /* vertical transform */
+    for (j = 0; j < 2; j++)
+    {
+        pres = res + (j << 6);
+        k = 16;
+        while (k > 0)
+        {
+            m0 = pres[0];
+            m3 = pres[3<<4];
+            m0 += m3;
+            m3 = m0 - (m3 << 1);
+            m1 = pres[1<<4];
+            m2 = pres[2<<4];
+            m1 += m2;
+            m2 = m1 - (m2 << 1);
+            pres[0] = m0 + m1;
+            pres[2<<4] = m0 - m1;
+            pres[1<<4] = m2 + m3;
+            pres[3<<4] = m3 - m2;
+
+            pres++;
+            k--;
+        }
+    }
+
+    /* now sum of absolute value */
+    pres = res;
+    cost = 0;
+    k = 128;
+    while (k > 0)
+    {
+        tmp1 = *pres++;
+        cost += ((tmp1 >= 0) ? tmp1 : -tmp1);
+        tmp1 = *pres++;
+        cost += ((tmp1 >= 0) ? tmp1 : -tmp1);
+        tmp1 = *pres++;
+        cost += ((tmp1 >= 0) ? tmp1 : -tmp1);
+        tmp1 = *pres++;
+        cost += ((tmp1 >= 0) ? tmp1 : -tmp1);
+        tmp1 = *pres++;
+        cost += ((tmp1 >= 0) ? tmp1 : -tmp1);
+        tmp1 = *pres++;
+        cost += ((tmp1 >= 0) ? tmp1 : -tmp1);
+        tmp1 = *pres++;
+        cost += ((tmp1 >= 0) ? tmp1 : -tmp1);
+        tmp1 = *pres++;
+        cost += ((tmp1 >= 0) ? tmp1 : -tmp1);
+        k -= 8;
+        if (cost > min_cost) /* early drop out */
+        {
+            return cost;
+        }
+    }
+
+    return cost;
+}
+
+
+
+///////////////////////////////// old code, unused
+/* find the best intra mode based on original (unencoded) frame */
+/* output is
+    currMB->mb_intra, currMB->mbMode,
+    currMB->i16Mode  (if currMB->mbMode == AVC_I16)
+    currMB->i4Mode[..] (if currMB->mbMode == AVC_I4) */
+
+#ifdef FIXED_INTRAPRED_MODE
+void MBIntraSearch(AVCEncObject *encvid, AVCMacroblock *currMB, int mbNum)
+{
+    (void)(mbNum);
+
+    AVCCommonObj *video = encvid->common;
+    int indx, block_x, block_y;
+
+    video->intraAvailA = video->intraAvailB = video->intraAvailC = video->intraAvailD = 0;
+
+    if (!video->currPicParams->constrained_intra_pred_flag)
+    {
+        video->intraAvailA = video->mbAvailA;
+        video->intraAvailB = video->mbAvailB;
+        video->intraAvailC = video->mbAvailC;
+        video->intraAvailD = video->mbAvailD;
+    }
+    else
+    {
+        if (video->mbAvailA)
+        {
+            video->intraAvailA = video->mblock[video->mbAddrA].mb_intra;
+        }
+        if (video->mbAvailB)
+        {
+            video->intraAvailB = video->mblock[video->mbAddrB].mb_intra ;
+        }
+        if (video->mbAvailC)
+        {
+            video->intraAvailC = video->mblock[video->mbAddrC].mb_intra;
+        }
+        if (video->mbAvailD)
+        {
+            video->intraAvailD = video->mblock[video->mbAddrD].mb_intra;
+        }
+    }
+
+    currMB->mb_intra = TRUE;
+    currMB->mbMode = FIXED_INTRAPRED_MODE;
+
+    if (currMB->mbMode == AVC_I16)
+    {
+        currMB->i16Mode = FIXED_I16_MODE;
+
+        if (FIXED_I16_MODE == AVC_I16_Vertical && !video->intraAvailB)
+        {
+            currMB->i16Mode = AVC_I16_DC;
+        }
+
+        if (FIXED_I16_MODE == AVC_I16_Horizontal && !video->intraAvailA)
+        {
+            currMB->i16Mode = AVC_I16_DC;
+        }
+
+        if (FIXED_I16_MODE == AVC_I16_Plane && !(video->intraAvailA && video->intraAvailB && video->intraAvailD))
+        {
+            currMB->i16Mode = AVC_I16_DC;
+        }
+    }
+    else //if(currMB->mbMode == AVC_I4)
+    {
+        for (indx = 0; indx < 16; indx++)
+        {
+            block_x = blkIdx2blkX[indx];
+            block_y = blkIdx2blkY[indx];
+
+            currMB->i4Mode[(block_y<<2)+block_x] = FIXED_I4_MODE;
+
+            if (FIXED_I4_MODE == AVC_I4_Vertical && !(block_y > 0 || video->intraAvailB))
+            {
+                currMB->i4Mode[(block_y<<2)+block_x] = AVC_I4_DC;
+            }
+
+            if (FIXED_I4_MODE == AVC_I4_Horizontal && !(block_x || video->intraAvailA))
+            {
+                currMB->i4Mode[(block_y<<2)+block_x] = AVC_I4_DC;
+            }
+
+            if (FIXED_I4_MODE == AVC_I4_Diagonal_Down_Left &&
+                    (block_y == 0 && !video->intraAvailB))
+            {
+                currMB->i4Mode[(block_y<<2)+block_x] = AVC_I4_DC;
+            }
+
+            if (FIXED_I4_MODE == AVC_I4_Diagonal_Down_Right &&
+                    !((block_y && block_x)
+                      || (block_y && video->intraAvailA)
+                      || (block_x && video->intraAvailB)
+                      || (video->intraAvailA && video->intraAvailD && video->intraAvailB)))
+            {
+                currMB->i4Mode[(block_y<<2)+block_x] = AVC_I4_DC;
+            }
+
+            if (FIXED_I4_MODE == AVC_I4_Vertical_Right &&
+                    !((block_y && block_x)
+                      || (block_y && video->intraAvailA)
+                      || (block_x && video->intraAvailB)
+                      || (video->intraAvailA && video->intraAvailD && video->intraAvailB)))
+            {
+                currMB->i4Mode[(block_y<<2)+block_x] = AVC_I4_DC;
+            }
+
+            if (FIXED_I4_MODE == AVC_I4_Horizontal_Down &&
+                    !((block_y && block_x)
+                      || (block_y && video->intraAvailA)
+                      || (block_x && video->intraAvailB)
+                      || (video->intraAvailA && video->intraAvailD && video->intraAvailB)))
+            {
+                currMB->i4Mode[(block_y<<2)+block_x] = AVC_I4_DC;
+            }
+
+            if (FIXED_I4_MODE == AVC_I4_Vertical_Left &&
+                    (block_y == 0 && !video->intraAvailB))
+            {
+                currMB->i4Mode[(block_y<<2)+block_x] = AVC_I4_DC;
+            }
+
+            if (FIXED_I4_MODE == AVC_I4_Horizontal_Up && !(block_x || video->intraAvailA))
+            {
+                currMB->i4Mode[(block_y<<2)+block_x] = AVC_I4_DC;
+            }
+        }
+    }
+
+    currMB->intra_chroma_pred_mode = FIXED_INTRA_CHROMA_MODE;
+
+    if (FIXED_INTRA_CHROMA_MODE == AVC_IC_Horizontal && !(video->intraAvailA))
+    {
+        currMB->intra_chroma_pred_mode = AVC_IC_DC;
+    }
+
+    if (FIXED_INTRA_CHROMA_MODE == AVC_IC_Vertical && !(video->intraAvailB))
+    {
+        currMB->intra_chroma_pred_mode = AVC_IC_DC;
+    }
+
+    if (FIXED_INTRA_CHROMA_MODE == AVC_IC_Plane && !(video->intraAvailA && video->intraAvailB && video->intraAvailD))
+    {
+        currMB->intra_chroma_pred_mode = AVC_IC_DC;
+    }
+
+    /* also reset the motion vectors */
+    /* set MV and Ref_Idx codes of Intra blocks in P-slices */
+    memset(currMB->mvL0, 0, sizeof(int32)*16);
+    currMB->ref_idx_L0[0] = -1;
+    currMB->ref_idx_L0[1] = -1;
+    currMB->ref_idx_L0[2] = -1;
+    currMB->ref_idx_L0[3] = -1;
+
+    // output from this function, currMB->mbMode should be set to either
+    // AVC_I4, AVC_I16, or else in AVCMBMode enum, mbType, mb_intra, intra_chroma_pred_mode */
+    return ;
+}
+#else // faster combined prediction+SAD calculation
+void MBIntraSearch(AVCEncObject *encvid, AVCMacroblock *currMB, int mbNum)
+{
+    AVCCommonObj *video = encvid->common;
+    AVCFrameIO *currInput = encvid->currInput;
+    uint8 *curL, *curCb, *curCr;
+    uint8 *comp, *pred_block;
+    int block_x, block_y, offset;
+    uint sad, sad4, sadI4, sadI16;
+    int component, SubBlock_indx, temp;
+    int pitch = video->currPic->pitch;
+
+    /* calculate the cost of each intra prediction mode  and compare to the
+    inter mode */
+    /* full search for all intra prediction */
+    offset = (video->mb_y << 4) * pitch + (video->mb_x << 4);
+    curL = currInput->YCbCr[0] + offset;
+    pred_block = video->pred_block + 84;
+
+    /* Assuming that InitNeighborAvailability has been called prior to this function */
+    video->intraAvailA = video->intraAvailB = video->intraAvailC = video->intraAvailD = 0;
+
+    if (!video->currPicParams->constrained_intra_pred_flag)
+    {
+        video->intraAvailA = video->mbAvailA;
+        video->intraAvailB = video->mbAvailB;
+        video->intraAvailC = video->mbAvailC;
+        video->intraAvailD = video->mbAvailD;
+    }
+    else
+    {
+        if (video->mbAvailA)
+        {
+            video->intraAvailA = video->mblock[video->mbAddrA].mb_intra;
+        }
+        if (video->mbAvailB)
+        {
+            video->intraAvailB = video->mblock[video->mbAddrB].mb_intra ;
+        }
+        if (video->mbAvailC)
+        {
+            video->intraAvailC = video->mblock[video->mbAddrC].mb_intra;
+        }
+        if (video->mbAvailD)
+        {
+            video->intraAvailD = video->mblock[video->mbAddrD].mb_intra;
+        }
+    }
+
+    /* currently we're doing exhaustive search. Smart search will be used later */
+
+    /* I16 modes */
+    curL = currInput->YCbCr[0] + offset;
+    video->pintra_pred_top = curL - pitch;
+    video->pintra_pred_left = curL - 1;
+    if (video->mb_y)
+    {
+        video->intra_pred_topleft = *(curL - pitch - 1);
+    }
+
+    /* Intra_16x16_Vertical */
+    sadI16 = 65536;
+    /* check availability of top */
+    if (video->intraAvailB)
+    {
+        sad = SAD_I16_Vert(video, curL, sadI16);
+
+        if (sad < sadI16)
+        {
+            sadI16 = sad;
+            currMB->i16Mode = AVC_I16_Vertical;
+        }
+    }
+    /* Intra_16x16_Horizontal */
+    /* check availability of left */
+    if (video->intraAvailA)
+    {
+        sad = SAD_I16_HorzDC(video, curL, AVC_I16_Horizontal, sadI16);
+
+        if (sad < sadI16)
+        {
+            sadI16 = sad;
+            currMB->i16Mode = AVC_I16_Horizontal;
+        }
+    }
+
+    /* Intra_16x16_DC, default mode */
+    sad = SAD_I16_HorzDC(video, curL, AVC_I16_DC, sadI16);
+    if (sad < sadI16)
+    {
+        sadI16 = sad;
+        currMB->i16Mode = AVC_I16_DC;
+    }
+
+    /* Intra_16x16_Plane */
+    if (video->intraAvailA && video->intraAvailB && video->intraAvailD)
+    {
+        sad = SAD_I16_Plane(video, curL, sadI16);
+
+        if (sad < sadI16)
+        {
+            sadI16 = sad;
+            currMB->i16Mode = AVC_I16_Plane;
+        }
+    }
+
+    sadI16 >>= 1;  /* before comparison */
+
+    /* selection between intra4, intra16 or inter mode */
+    if (sadI16 < encvid->min_cost)
+    {
+        currMB->mb_intra = TRUE;
+        currMB->mbMode = AVC_I16;
+        encvid->min_cost = sadI16;
+    }
+
+    if (currMB->mb_intra) /* only do the chrominance search when intra is decided */
+    {
+        /* Note that we might be able to guess the type of prediction from
+        the luma prediction type */
+
+        /* now search for the best chroma intra prediction */
+        offset = (offset >> 2) + (video->mb_x << 2);
+        curCb = currInput->YCbCr[1] + offset;
+        curCr = currInput->YCbCr[2] + offset;
+
+        pitch >>= 1;
+        video->pintra_pred_top_cb = curCb - pitch;
+        video->pintra_pred_left_cb = curCb - 1;
+        video->pintra_pred_top_cr = curCr - pitch;
+        video->pintra_pred_left_cr = curCr - 1;
+
+        if (video->mb_y)
+        {
+            video->intra_pred_topleft_cb = *(curCb - pitch - 1);
+            video->intra_pred_topleft_cr = *(curCr - pitch - 1);
+        }
+
+        /* Intra_Chroma_DC */
+        sad4 = SAD_Chroma_DC(video, curCb, curCr, 65536);
+        currMB->intra_chroma_pred_mode = AVC_IC_DC;
+
+        /* Intra_Chroma_Horizontal */
+        if (video->intraAvailA)
+        {
+            /* check availability of left */
+            sad = SAD_Chroma_Horz(video, curCb, curCr, sad4);
+            if (sad < sad4)
+            {
+                sad4 = sad;
+                currMB->intra_chroma_pred_mode = AVC_IC_Horizontal;
+            }
+        }
+
+        /* Intra_Chroma_Vertical */
+        if (video->intraAvailB)
+        {
+            /* check availability of top */
+            sad = SAD_Chroma_Vert(video, curCb, curCr, sad4);
+
+            if (sad < sad4)
+            {
+                sad4 = sad;
+                currMB->intra_chroma_pred_mode = AVC_IC_Vertical;
+            }
+        }
+
+        /* Intra_Chroma_Plane */
+        if (video->intraAvailA && video->intraAvailB && video->intraAvailD)
+        {
+            /* check availability of top and left */
+            Intra_Chroma_Plane(video, pitch);
+
+            sad = SADChroma(pred_block + 452, curCb, curCr, pitch);
+
+            if (sad < sad4)
+            {
+                sad4 = sad;
+                currMB->intra_chroma_pred_mode = AVC_IC_Plane;
+            }
+        }
+
+        /* also reset the motion vectors */
+        /* set MV and Ref_Idx codes of Intra blocks in P-slices */
+        memset(currMB->mvL0, 0, sizeof(int32)*16);
+        memset(currMB->ref_idx_L0, -1, sizeof(int16)*4);
+
+    }
+
+    // output from this function, currMB->mbMode should be set to either
+    // AVC_I4, AVC_I16, or else in AVCMBMode enum, mbType, mb_intra, intra_chroma_pred_mode */
+
+    return ;
+}
+#endif
+
+
diff --git a/media/libstagefright/codecs/avc/enc/src/motion_comp.cpp b/media/libstagefright/codecs/avc/enc/src/motion_comp.cpp
new file mode 100644
index 0000000..ac62d78
--- /dev/null
+++ b/media/libstagefright/codecs/avc/enc/src/motion_comp.cpp
@@ -0,0 +1,2156 @@
+/* ------------------------------------------------------------------
+ * Copyright (C) 1998-2009 PacketVideo
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
+ * express or implied.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ * -------------------------------------------------------------------
+ */
+#include "avcenc_lib.h"
+#include "avcenc_int.h"
+
+
+#define CLIP_RESULT(x)      if((uint)x > 0xFF){ \
+                 x = 0xFF & (~(x>>31));}
+
+/* (blkwidth << 2) + (dy << 1) + dx */
+static void (*const eChromaMC_SIMD[8])(uint8 *, int , int , int , uint8 *, int, int , int) =
+{
+    &eChromaFullMC_SIMD,
+    &eChromaHorizontalMC_SIMD,
+    &eChromaVerticalMC_SIMD,
+    &eChromaDiagonalMC_SIMD,
+    &eChromaFullMC_SIMD,
+    &eChromaHorizontalMC2_SIMD,
+    &eChromaVerticalMC2_SIMD,
+    &eChromaDiagonalMC2_SIMD
+};
+/* Perform motion prediction and compensation with residue if exist. */
+void AVCMBMotionComp(AVCEncObject *encvid, AVCCommonObj *video)
+{
+    (void)(encvid);
+
+    AVCMacroblock *currMB = video->currMB;
+    AVCPictureData *currPic = video->currPic;
+    int mbPartIdx, subMbPartIdx;
+    int ref_idx;
+    int offset_MbPart_indx = 0;
+    int16 *mv;
+    uint32 x_pos, y_pos;
+    uint8 *curL, *curCb, *curCr;
+    uint8 *ref_l, *ref_Cb, *ref_Cr;
+    uint8 *predBlock, *predCb, *predCr;
+    int block_x, block_y, offset_x, offset_y, offsetP, offset;
+    int x_position = (video->mb_x << 4);
+    int y_position = (video->mb_y << 4);
+    int MbHeight, MbWidth, mbPartIdx_X, mbPartIdx_Y, offset_indx;
+    int picWidth = currPic->width;
+    int picPitch = currPic->pitch;
+    int picHeight = currPic->height;
+    uint32 tmp_word;
+
+    tmp_word = y_position * picPitch;
+    curL = currPic->Sl + tmp_word + x_position;
+    offset = (tmp_word >> 2) + (x_position >> 1);
+    curCb = currPic->Scb + offset;
+    curCr = currPic->Scr + offset;
+
+    predBlock = curL;
+    predCb = curCb;
+    predCr = curCr;
+
+    GetMotionVectorPredictor(video, 1);
+
+    for (mbPartIdx = 0; mbPartIdx < currMB->NumMbPart; mbPartIdx++)
+    {
+        MbHeight = currMB->SubMbPartHeight[mbPartIdx];
+        MbWidth = currMB->SubMbPartWidth[mbPartIdx];
+        mbPartIdx_X = ((mbPartIdx + offset_MbPart_indx) & 1);
+        mbPartIdx_Y = (mbPartIdx + offset_MbPart_indx) >> 1;
+        ref_idx = currMB->ref_idx_L0[(mbPartIdx_Y << 1) + mbPartIdx_X];
+        offset_indx = 0;
+
+        ref_l = video->RefPicList0[ref_idx]->Sl;
+        ref_Cb = video->RefPicList0[ref_idx]->Scb;
+        ref_Cr = video->RefPicList0[ref_idx]->Scr;
+
+        for (subMbPartIdx = 0; subMbPartIdx < currMB->NumSubMbPart[mbPartIdx]; subMbPartIdx++)
+        {
+            block_x = (mbPartIdx_X << 1) + ((subMbPartIdx + offset_indx) & 1);
+            block_y = (mbPartIdx_Y << 1) + (((subMbPartIdx + offset_indx) >> 1) & 1);
+            mv = (int16*)(currMB->mvL0 + block_x + (block_y << 2));
+            offset_x = x_position + (block_x << 2);
+            offset_y = y_position + (block_y << 2);
+            x_pos = (offset_x << 2) + *mv++;   /*quarter pel */
+            y_pos = (offset_y << 2) + *mv;   /*quarter pel */
+
+            //offset = offset_y * currPic->width;
+            //offsetC = (offset >> 2) + (offset_x >> 1);
+            offsetP = (block_y << 2) * picPitch + (block_x << 2);
+            eLumaMotionComp(ref_l, picPitch, picHeight, x_pos, y_pos,
+                            /*comp_Sl + offset + offset_x,*/
+                            predBlock + offsetP, picPitch, MbWidth, MbHeight);
+
+            offsetP = (block_y * picWidth) + (block_x << 1);
+            eChromaMotionComp(ref_Cb, picWidth >> 1, picHeight >> 1, x_pos, y_pos,
+                              /*comp_Scb +  offsetC,*/
+                              predCb + offsetP, picPitch >> 1, MbWidth >> 1, MbHeight >> 1);
+            eChromaMotionComp(ref_Cr, picWidth >> 1, picHeight >> 1, x_pos, y_pos,
+                              /*comp_Scr +  offsetC,*/
+                              predCr + offsetP, picPitch >> 1, MbWidth >> 1, MbHeight >> 1);
+
+            offset_indx = currMB->SubMbPartWidth[mbPartIdx] >> 3;
+        }
+        offset_MbPart_indx = currMB->MbPartWidth >> 4;
+    }
+
+    return ;
+}
+
+
+/* preform the actual  motion comp here */
+void eLumaMotionComp(uint8 *ref, int picpitch, int picheight,
+                     int x_pos, int y_pos,
+                     uint8 *pred, int pred_pitch,
+                     int blkwidth, int blkheight)
+{
+    (void)(picheight);
+
+    int dx, dy;
+    int temp2[21][21]; /* for intermediate results */
+    uint8 *ref2;
+
+    dx = x_pos & 3;
+    dy = y_pos & 3;
+    x_pos = x_pos >> 2;  /* round it to full-pel resolution */
+    y_pos = y_pos >> 2;
+
+    /* perform actual motion compensation */
+    if (dx == 0 && dy == 0)
+    {  /* fullpel position *//* G */
+
+        ref += y_pos * picpitch + x_pos;
+
+        eFullPelMC(ref, picpitch, pred, pred_pitch, blkwidth, blkheight);
+
+    }   /* other positions */
+    else  if (dy == 0)
+    { /* no vertical interpolation *//* a,b,c*/
+
+        ref += y_pos * picpitch + x_pos;
+
+        eHorzInterp1MC(ref, picpitch, pred, pred_pitch, blkwidth, blkheight, dx);
+    }
+    else if (dx == 0)
+    { /*no horizontal interpolation *//* d,h,n */
+
+        ref += y_pos * picpitch + x_pos;
+
+        eVertInterp1MC(ref, picpitch, pred, pred_pitch, blkwidth, blkheight, dy);
+    }
+    else if (dy == 2)
+    {  /* horizontal cross *//* i, j, k */
+
+        ref += y_pos * picpitch + x_pos - 2; /* move to the left 2 pixels */
+
+        eVertInterp2MC(ref, picpitch, &temp2[0][0], 21, blkwidth + 5, blkheight);
+
+        eHorzInterp2MC(&temp2[0][2], 21, pred, pred_pitch, blkwidth, blkheight, dx);
+    }
+    else if (dx == 2)
+    { /* vertical cross */ /* f,q */
+
+        ref += (y_pos - 2) * picpitch + x_pos; /* move to up 2 lines */
+
+        eHorzInterp3MC(ref, picpitch, &temp2[0][0], 21, blkwidth, blkheight + 5);
+        eVertInterp3MC(&temp2[2][0], 21, pred, pred_pitch, blkwidth, blkheight, dy);
+    }
+    else
+    { /* diagonal *//* e,g,p,r */
+
+        ref2 = ref + (y_pos + (dy / 2)) * picpitch + x_pos;
+
+        ref += (y_pos * picpitch) + x_pos + (dx / 2);
+
+        eDiagonalInterpMC(ref2, ref, picpitch, pred, pred_pitch, blkwidth, blkheight);
+    }
+
+    return ;
+}
+
+void eCreateAlign(uint8 *ref, int picpitch, int y_pos,
+                  uint8 *out, int blkwidth, int blkheight)
+{
+    int i, j;
+    int offset, out_offset;
+    uint32 prev_pix, result, pix1, pix2, pix4;
+
+    ref += y_pos * picpitch;// + x_pos;
+    out_offset = 24 - blkwidth;
+
+    //switch(x_pos&0x3){
+    switch (((uint32)ref)&0x3)
+    {
+        case 1:
+            offset =  picpitch - blkwidth - 3;
+            for (j = 0; j < blkheight; j++)
+            {
+                pix1 = *ref++;
+                pix2 = *((uint16*)ref);
+                ref += 2;
+                result = (pix2 << 8) | pix1;
+
+                for (i = 3; i < blkwidth; i += 4)
+                {
+                    pix4 = *((uint32*)ref);
+                    ref += 4;
+                    prev_pix = (pix4 << 24) & 0xFF000000; /* mask out byte belong to previous word */
+                    result |= prev_pix;
+                    *((uint32*)out) = result;  /* write 4 bytes */
+                    out += 4;
+                    result = pix4 >> 8; /* for the next loop */
+                }
+                ref += offset;
+                out += out_offset;
+            }
+            break;
+        case 2:
+            offset =  picpitch - blkwidth - 2;
+            for (j = 0; j < blkheight; j++)
+            {
+                result = *((uint16*)ref);
+                ref += 2;
+                for (i = 2; i < blkwidth; i += 4)
+                {
+                    pix4 = *((uint32*)ref);
+                    ref += 4;
+                    prev_pix = (pix4 << 16) & 0xFFFF0000; /* mask out byte belong to previous word */
+                    result |= prev_pix;
+                    *((uint32*)out) = result;  /* write 4 bytes */
+                    out += 4;
+                    result = pix4 >> 16; /* for the next loop */
+                }
+                ref += offset;
+                out += out_offset;
+            }
+            break;
+        case 3:
+            offset =  picpitch - blkwidth - 1;
+            for (j = 0; j < blkheight; j++)
+            {
+                result = *ref++;
+                for (i = 1; i < blkwidth; i += 4)
+                {
+                    pix4 = *((uint32*)ref);
+                    ref += 4;
+                    prev_pix = (pix4 << 8) & 0xFFFFFF00; /* mask out byte belong to previous word */
+                    result |= prev_pix;
+                    *((uint32*)out) = result;  /* write 4 bytes */
+                    out += 4;
+                    result = pix4 >> 24; /* for the next loop */
+                }
+                ref += offset;
+                out += out_offset;
+            }
+            break;
+    }
+}
+
+void eHorzInterp1MC(uint8 *in, int inpitch, uint8 *out, int outpitch,
+                    int blkwidth, int blkheight, int dx)
+{
+    uint8 *p_ref;
+    uint32 *p_cur;
+    uint32 tmp, pkres;
+    int result, curr_offset, ref_offset;
+    int j;
+    int32 r0, r1, r2, r3, r4, r5;
+    int32 r13, r6;
+
+    p_cur = (uint32*)out; /* assume it's word aligned */
+    curr_offset = (outpitch - blkwidth) >> 2;
+    p_ref = in;
+    ref_offset = inpitch - blkwidth;
+
+    if (dx&1)
+    {
+        dx = ((dx >> 1) ? -3 : -4); /* use in 3/4 pel */
+        p_ref -= 2;
+        r13 = 0;
+        for (j = blkheight; j > 0; j--)
+        {
+            tmp = (uint32)(p_ref + blkwidth);
+            r0 = p_ref[0];
+            r1 = p_ref[2];
+            r0 |= (r1 << 16);           /* 0,c,0,a */
+            r1 = p_ref[1];
+            r2 = p_ref[3];
+            r1 |= (r2 << 16);           /* 0,d,0,b */
+            while ((uint32)p_ref < tmp)
+            {
+                r2 = *(p_ref += 4); /* move pointer to e */
+                r3 = p_ref[2];
+                r2 |= (r3 << 16);           /* 0,g,0,e */
+                r3 = p_ref[1];
+                r4 = p_ref[3];
+                r3 |= (r4 << 16);           /* 0,h,0,f */
+
+                r4 = r0 + r3;       /* c+h, a+f */
+                r5 = r0 + r1;   /* c+d, a+b */
+                r6 = r2 + r3;   /* g+h, e+f */
+                r5 >>= 16;
+                r5 |= (r6 << 16);   /* e+f, c+d */
+                r4 += r5 * 20;      /* c+20*e+20*f+h, a+20*c+20*d+f */
+                r4 += 0x100010; /* +16, +16 */
+                r5 = r1 + r2;       /* d+g, b+e */
+                r4 -= r5 * 5;       /* c-5*d+20*e+20*f-5*g+h, a-5*b+20*c+20*d-5*e+f */
+                r4 >>= 5;
+                r13 |= r4;      /* check clipping */
+
+                r5 = p_ref[dx+2];
+                r6 = p_ref[dx+4];
+                r5 |= (r6 << 16);
+                r4 += r5;
+                r4 += 0x10001;
+                r4 = (r4 >> 1) & 0xFF00FF;
+
+                r5 = p_ref[4];  /* i */
+                r6 = (r5 << 16);
+                r5 = r6 | (r2 >> 16);/* 0,i,0,g */
+                r5 += r1;       /* d+i, b+g */ /* r5 not free */
+                r1 >>= 16;
+                r1 |= (r3 << 16); /* 0,f,0,d */ /* r1 has changed */
+                r1 += r2;       /* f+g, d+e */
+                r5 += 20 * r1;  /* d+20f+20g+i, b+20d+20e+g */
+                r0 >>= 16;
+                r0 |= (r2 << 16); /* 0,e,0,c */ /* r0 has changed */
+                r0 += r3;       /* e+h, c+f */
+                r5 += 0x100010; /* 16,16 */
+                r5 -= r0 * 5;       /* d-5e+20f+20g-5h+i, b-5c+20d+20e-5f+g */
+                r5 >>= 5;
+                r13 |= r5;      /* check clipping */
+
+                r0 = p_ref[dx+3];
+                r1 = p_ref[dx+5];
+                r0 |= (r1 << 16);
+                r5 += r0;
+                r5 += 0x10001;
+                r5 = (r5 >> 1) & 0xFF00FF;
+
+                r4 |= (r5 << 8);    /* pack them together */
+                *p_cur++ = r4;
+                r1 = r3;
+                r0 = r2;
+            }
+            p_cur += curr_offset; /* move to the next line */
+            p_ref += ref_offset;  /*    ref_offset = inpitch-blkwidth; */
+
+            if (r13&0xFF000700) /* need clipping */
+            {
+                /* move back to the beginning of the line */
+                p_ref -= (ref_offset + blkwidth);   /* input */
+                p_cur -= (outpitch >> 2);
+
+                tmp = (uint32)(p_ref + blkwidth);
+                for (; (uint32)p_ref < tmp;)
+                {
+
+                    r0 = *p_ref++;
+                    r1 = *p_ref++;
+                    r2 = *p_ref++;
+                    r3 = *p_ref++;
+                    r4 = *p_ref++;
+                    /* first pixel */
+                    r5 = *p_ref++;
+                    result = (r0 + r5);
+                    r0 = (r1 + r4);
+                    result -= (r0 * 5);//result -= r0;  result -= (r0<<2);
+                    r0 = (r2 + r3);
+                    result += (r0 * 20);//result += (r0<<4);    result += (r0<<2);
+                    result = (result + 16) >> 5;
+                    CLIP_RESULT(result)
+                    /* 3/4 pel,  no need to clip */
+                    result = (result + p_ref[dx] + 1);
+                    pkres = (result >> 1) ;
+                    /* second pixel */
+                    r0 = *p_ref++;
+                    result = (r1 + r0);
+                    r1 = (r2 + r5);
+                    result -= (r1 * 5);//result -= r1;  result -= (r1<<2);
+                    r1 = (r3 + r4);
+                    result += (r1 * 20);//result += (r1<<4);    result += (r1<<2);
+                    result = (result + 16) >> 5;
+                    CLIP_RESULT(result)
+                    /* 3/4 pel,  no need to clip */
+                    result = (result + p_ref[dx] + 1);
+                    result = (result >> 1);
+                    pkres  |= (result << 8);
+                    /* third pixel */
+                    r1 = *p_ref++;
+                    result = (r2 + r1);
+                    r2 = (r3 + r0);
+                    result -= (r2 * 5);//result -= r2;  result -= (r2<<2);
+                    r2 = (r4 + r5);
+                    result += (r2 * 20);//result += (r2<<4);    result += (r2<<2);
+                    result = (result + 16) >> 5;
+                    CLIP_RESULT(result)
+                    /* 3/4 pel,  no need to clip */
+                    result = (result + p_ref[dx] + 1);
+                    result = (result >> 1);
+                    pkres  |= (result << 16);
+                    /* fourth pixel */
+                    r2 = *p_ref++;
+                    result = (r3 + r2);
+                    r3 = (r4 + r1);
+                    result -= (r3 * 5);//result -= r3;  result -= (r3<<2);
+                    r3 = (r5 + r0);
+                    result += (r3 * 20);//result += (r3<<4);    result += (r3<<2);
+                    result = (result + 16) >> 5;
+                    CLIP_RESULT(result)
+                    /* 3/4 pel,  no need to clip */
+                    result = (result + p_ref[dx] + 1);
+                    result = (result >> 1);
+                    pkres  |= (result << 24);
+                    *p_cur++ = pkres; /* write 4 pixels */
+                    p_ref -= 5;  /* offset back to the middle of filter */
+                }
+                p_cur += curr_offset;  /* move to the next line */
+                p_ref += ref_offset;    /* move to the next line */
+            }
+        }
+    }
+    else
+    {
+        p_ref -= 2;
+        r13 = 0;
+        for (j = blkheight; j > 0; j--)
+        {
+            tmp = (uint32)(p_ref + blkwidth);
+            r0 = p_ref[0];
+            r1 = p_ref[2];
+            r0 |= (r1 << 16);           /* 0,c,0,a */
+            r1 = p_ref[1];
+            r2 = p_ref[3];
+            r1 |= (r2 << 16);           /* 0,d,0,b */
+            while ((uint32)p_ref < tmp)
+            {
+                r2 = *(p_ref += 4); /* move pointer to e */
+                r3 = p_ref[2];
+                r2 |= (r3 << 16);           /* 0,g,0,e */
+                r3 = p_ref[1];
+                r4 = p_ref[3];
+                r3 |= (r4 << 16);           /* 0,h,0,f */
+
+                r4 = r0 + r3;       /* c+h, a+f */
+                r5 = r0 + r1;   /* c+d, a+b */
+                r6 = r2 + r3;   /* g+h, e+f */
+                r5 >>= 16;
+                r5 |= (r6 << 16);   /* e+f, c+d */
+                r4 += r5 * 20;      /* c+20*e+20*f+h, a+20*c+20*d+f */
+                r4 += 0x100010; /* +16, +16 */
+                r5 = r1 + r2;       /* d+g, b+e */
+                r4 -= r5 * 5;       /* c-5*d+20*e+20*f-5*g+h, a-5*b+20*c+20*d-5*e+f */
+                r4 >>= 5;
+                r13 |= r4;      /* check clipping */
+                r4 &= 0xFF00FF; /* mask */
+
+                r5 = p_ref[4];  /* i */
+                r6 = (r5 << 16);
+                r5 = r6 | (r2 >> 16);/* 0,i,0,g */
+                r5 += r1;       /* d+i, b+g */ /* r5 not free */
+                r1 >>= 16;
+                r1 |= (r3 << 16); /* 0,f,0,d */ /* r1 has changed */
+                r1 += r2;       /* f+g, d+e */
+                r5 += 20 * r1;  /* d+20f+20g+i, b+20d+20e+g */
+                r0 >>= 16;
+                r0 |= (r2 << 16); /* 0,e,0,c */ /* r0 has changed */
+                r0 += r3;       /* e+h, c+f */
+                r5 += 0x100010; /* 16,16 */
+                r5 -= r0 * 5;       /* d-5e+20f+20g-5h+i, b-5c+20d+20e-5f+g */
+                r5 >>= 5;
+                r13 |= r5;      /* check clipping */
+                r5 &= 0xFF00FF; /* mask */
+
+                r4 |= (r5 << 8);    /* pack them together */
+                *p_cur++ = r4;
+                r1 = r3;
+                r0 = r2;
+            }
+            p_cur += curr_offset; /* move to the next line */
+            p_ref += ref_offset;  /*    ref_offset = inpitch-blkwidth; */
+
+            if (r13&0xFF000700) /* need clipping */
+            {
+                /* move back to the beginning of the line */
+                p_ref -= (ref_offset + blkwidth);   /* input */
+                p_cur -= (outpitch >> 2);
+
+                tmp = (uint32)(p_ref + blkwidth);
+                for (; (uint32)p_ref < tmp;)
+                {
+
+                    r0 = *p_ref++;
+                    r1 = *p_ref++;
+                    r2 = *p_ref++;
+                    r3 = *p_ref++;
+                    r4 = *p_ref++;
+                    /* first pixel */
+                    r5 = *p_ref++;
+                    result = (r0 + r5);
+                    r0 = (r1 + r4);
+                    result -= (r0 * 5);//result -= r0;  result -= (r0<<2);
+                    r0 = (r2 + r3);
+                    result += (r0 * 20);//result += (r0<<4);    result += (r0<<2);
+                    result = (result + 16) >> 5;
+                    CLIP_RESULT(result)
+                    pkres  = result;
+                    /* second pixel */
+                    r0 = *p_ref++;
+                    result = (r1 + r0);
+                    r1 = (r2 + r5);
+                    result -= (r1 * 5);//result -= r1;  result -= (r1<<2);
+                    r1 = (r3 + r4);
+                    result += (r1 * 20);//result += (r1<<4);    result += (r1<<2);
+                    result = (result + 16) >> 5;
+                    CLIP_RESULT(result)
+                    pkres  |= (result << 8);
+                    /* third pixel */
+                    r1 = *p_ref++;
+                    result = (r2 + r1);
+                    r2 = (r3 + r0);
+                    result -= (r2 * 5);//result -= r2;  result -= (r2<<2);
+                    r2 = (r4 + r5);
+                    result += (r2 * 20);//result += (r2<<4);    result += (r2<<2);
+                    result = (result + 16) >> 5;
+                    CLIP_RESULT(result)
+                    pkres  |= (result << 16);
+                    /* fourth pixel */
+                    r2 = *p_ref++;
+                    result = (r3 + r2);
+                    r3 = (r4 + r1);
+                    result -= (r3 * 5);//result -= r3;  result -= (r3<<2);
+                    r3 = (r5 + r0);
+                    result += (r3 * 20);//result += (r3<<4);    result += (r3<<2);
+                    result = (result + 16) >> 5;
+                    CLIP_RESULT(result)
+                    pkres  |= (result << 24);
+                    *p_cur++ = pkres;   /* write 4 pixels */
+                    p_ref -= 5;
+                }
+                p_cur += curr_offset; /* move to the next line */
+                p_ref += ref_offset;
+            }
+        }
+    }
+
+    return ;
+}
+
+void eHorzInterp2MC(int *in, int inpitch, uint8 *out, int outpitch,
+                    int blkwidth, int blkheight, int dx)
+{
+    int *p_ref;
+    uint32 *p_cur;
+    uint32 tmp, pkres;
+    int result, result2, curr_offset, ref_offset;
+    int j, r0, r1, r2, r3, r4, r5;
+
+    p_cur = (uint32*)out; /* assume it's word aligned */
+    curr_offset = (outpitch - blkwidth) >> 2;
+    p_ref = in;
+    ref_offset = inpitch - blkwidth;
+
+    if (dx&1)
+    {
+        dx = ((dx >> 1) ? -3 : -4); /* use in 3/4 pel */
+
+        for (j = blkheight; j > 0 ; j--)
+        {
+            tmp = (uint32)(p_ref + blkwidth);
+            for (; (uint32)p_ref < tmp;)
+            {
+
+                r0 = p_ref[-2];
+                r1 = p_ref[-1];
+                r2 = *p_ref++;
+                r3 = *p_ref++;
+                r4 = *p_ref++;
+                /* first pixel */
+                r5 = *p_ref++;
+                result = (r0 + r5);
+                r0 = (r1 + r4);
+                result -= (r0 * 5);//result -= r0;  result -= (r0<<2);
+                r0 = (r2 + r3);
+                result += (r0 * 20);//result += (r0<<4);    result += (r0<<2);
+                result = (result + 512) >> 10;
+                CLIP_RESULT(result)
+                result2 = ((p_ref[dx] + 16) >> 5);
+                CLIP_RESULT(result2)
+                /* 3/4 pel,  no need to clip */
+                result = (result + result2 + 1);
+                pkres = (result >> 1);
+                /* second pixel */
+                r0 = *p_ref++;
+                result = (r1 + r0);
+                r1 = (r2 + r5);
+                result -= (r1 * 5);//result -= r1;  result -= (r1<<2);
+                r1 = (r3 + r4);
+                result += (r1 * 20);//result += (r1<<4);    result += (r1<<2);
+                result = (result + 512) >> 10;
+                CLIP_RESULT(result)
+                result2 = ((p_ref[dx] + 16) >> 5);
+                CLIP_RESULT(result2)
+                /* 3/4 pel,  no need to clip */
+                result = (result + result2 + 1);
+                result = (result >> 1);
+                pkres  |= (result << 8);
+                /* third pixel */
+                r1 = *p_ref++;
+                result = (r2 + r1);
+                r2 = (r3 + r0);
+                result -= (r2 * 5);//result -= r2;  result -= (r2<<2);
+                r2 = (r4 + r5);
+                result += (r2 * 20);//result += (r2<<4);    result += (r2<<2);
+                result = (result + 512) >> 10;
+                CLIP_RESULT(result)
+                result2 = ((p_ref[dx] + 16) >> 5);
+                CLIP_RESULT(result2)
+                /* 3/4 pel,  no need to clip */
+                result = (result + result2 + 1);
+                result = (result >> 1);
+                pkres  |= (result << 16);
+                /* fourth pixel */
+                r2 = *p_ref++;
+                result = (r3 + r2);
+                r3 = (r4 + r1);
+                result -= (r3 * 5);//result -= r3;  result -= (r3<<2);
+                r3 = (r5 + r0);
+                result += (r3 * 20);//result += (r3<<4);    result += (r3<<2);
+                result = (result + 512) >> 10;
+                CLIP_RESULT(result)
+                result2 = ((p_ref[dx] + 16) >> 5);
+                CLIP_RESULT(result2)
+                /* 3/4 pel,  no need to clip */
+                result = (result + result2 + 1);
+                result = (result >> 1);
+                pkres  |= (result << 24);
+                *p_cur++ = pkres; /* write 4 pixels */
+                p_ref -= 3;  /* offset back to the middle of filter */
+            }
+            p_cur += curr_offset;  /* move to the next line */
+            p_ref += ref_offset;    /* move to the next line */
+        }
+    }
+    else
+    {
+        for (j = blkheight; j > 0 ; j--)
+        {
+            tmp = (uint32)(p_ref + blkwidth);
+            for (; (uint32)p_ref < tmp;)
+            {
+
+                r0 = p_ref[-2];
+                r1 = p_ref[-1];
+                r2 = *p_ref++;
+                r3 = *p_ref++;
+                r4 = *p_ref++;
+                /* first pixel */
+                r5 = *p_ref++;
+                result = (r0 + r5);
+                r0 = (r1 + r4);
+                result -= (r0 * 5);//result -= r0;  result -= (r0<<2);
+                r0 = (r2 + r3);
+                result += (r0 * 20);//result += (r0<<4);    result += (r0<<2);
+                result = (result + 512) >> 10;
+                CLIP_RESULT(result)
+                pkres  = result;
+                /* second pixel */
+                r0 = *p_ref++;
+                result = (r1 + r0);
+                r1 = (r2 + r5);
+                result -= (r1 * 5);//result -= r1;  result -= (r1<<2);
+                r1 = (r3 + r4);
+                result += (r1 * 20);//result += (r1<<4);    result += (r1<<2);
+                result = (result + 512) >> 10;
+                CLIP_RESULT(result)
+                pkres  |= (result << 8);
+                /* third pixel */
+                r1 = *p_ref++;
+                result = (r2 + r1);
+                r2 = (r3 + r0);
+                result -= (r2 * 5);//result -= r2;  result -= (r2<<2);
+                r2 = (r4 + r5);
+                result += (r2 * 20);//result += (r2<<4);    result += (r2<<2);
+                result = (result + 512) >> 10;
+                CLIP_RESULT(result)
+                pkres  |= (result << 16);
+                /* fourth pixel */
+                r2 = *p_ref++;
+                result = (r3 + r2);
+                r3 = (r4 + r1);
+                result -= (r3 * 5);//result -= r3;  result -= (r3<<2);
+                r3 = (r5 + r0);
+                result += (r3 * 20);//result += (r3<<4);    result += (r3<<2);
+                result = (result + 512) >> 10;
+                CLIP_RESULT(result)
+                pkres  |= (result << 24);
+                *p_cur++ = pkres; /* write 4 pixels */
+                p_ref -= 3;  /* offset back to the middle of filter */
+            }
+            p_cur += curr_offset;  /* move to the next line */
+            p_ref += ref_offset;    /* move to the next line */
+        }
+    }
+
+    return ;
+}
+
+void eHorzInterp3MC(uint8 *in, int inpitch, int *out, int outpitch,
+                    int blkwidth, int blkheight)
+{
+    uint8 *p_ref;
+    int   *p_cur;
+    uint32 tmp;
+    int result, curr_offset, ref_offset;
+    int j, r0, r1, r2, r3, r4, r5;
+
+    p_cur = out;
+    curr_offset = (outpitch - blkwidth);
+    p_ref = in;
+    ref_offset = inpitch - blkwidth;
+
+    for (j = blkheight; j > 0 ; j--)
+    {
+        tmp = (uint32)(p_ref + blkwidth);
+        for (; (uint32)p_ref < tmp;)
+        {
+
+            r0 = p_ref[-2];
+            r1 = p_ref[-1];
+            r2 = *p_ref++;
+            r3 = *p_ref++;
+            r4 = *p_ref++;
+            /* first pixel */
+            r5 = *p_ref++;
+            result = (r0 + r5);
+            r0 = (r1 + r4);
+            result -= (r0 * 5);//result -= r0;  result -= (r0<<2);
+            r0 = (r2 + r3);
+            result += (r0 * 20);//result += (r0<<4);    result += (r0<<2);
+            *p_cur++ = result;
+            /* second pixel */
+            r0 = *p_ref++;
+            result = (r1 + r0);
+            r1 = (r2 + r5);
+            result -= (r1 * 5);//result -= r1;  result -= (r1<<2);
+            r1 = (r3 + r4);
+            result += (r1 * 20);//result += (r1<<4);    result += (r1<<2);
+            *p_cur++ = result;
+            /* third pixel */
+            r1 = *p_ref++;
+            result = (r2 + r1);
+            r2 = (r3 + r0);
+            result -= (r2 * 5);//result -= r2;  result -= (r2<<2);
+            r2 = (r4 + r5);
+            result += (r2 * 20);//result += (r2<<4);    result += (r2<<2);
+            *p_cur++ = result;
+            /* fourth pixel */
+            r2 = *p_ref++;
+            result = (r3 + r2);
+            r3 = (r4 + r1);
+            result -= (r3 * 5);//result -= r3;  result -= (r3<<2);
+            r3 = (r5 + r0);
+            result += (r3 * 20);//result += (r3<<4);    result += (r3<<2);
+            *p_cur++ = result;
+            p_ref -= 3; /* move back to the middle of the filter */
+        }
+        p_cur += curr_offset; /* move to the next line */
+        p_ref += ref_offset;
+    }
+
+    return ;
+}
+void eVertInterp1MC(uint8 *in, int inpitch, uint8 *out, int outpitch,
+                    int blkwidth, int blkheight, int dy)
+{
+    uint8 *p_cur, *p_ref;
+    uint32 tmp;
+    int result, curr_offset, ref_offset;
+    int j, i;
+    int32 r0, r1, r2, r3, r4, r5, r6, r7, r8, r13;
+    uint8  tmp_in[24][24];
+
+    /* not word-aligned */
+    if (((uint32)in)&0x3)
+    {
+        eCreateAlign(in, inpitch, -2, &tmp_in[0][0], blkwidth, blkheight + 5);
+        in = &tmp_in[2][0];
+        inpitch = 24;
+    }
+    p_cur = out;
+    curr_offset = 1 - outpitch * (blkheight - 1); /* offset vertically back up and one pixel to right */
+    ref_offset = blkheight * inpitch; /* for limit */
+
+    curr_offset += 3;
+
+    if (dy&1)
+    {
+        dy = (dy >> 1) ? 0 : -inpitch;
+
+        for (j = 0; j < blkwidth; j += 4, in += 4)
+        {
+            r13 = 0;
+            p_ref = in;
+            p_cur -= outpitch;  /* compensate for the first offset */
+            tmp = (uint32)(p_ref + ref_offset); /* limit */
+            while ((uint32)p_ref < tmp)  /* the loop un-rolled  */
+            {
+                r0 = *((uint32*)(p_ref - (inpitch << 1))); /* load 4 bytes */
+                p_ref += inpitch;
+                r6 = (r0 >> 8) & 0xFF00FF; /* second and fourth byte */
+                r0 &= 0xFF00FF;
+
+                r1 = *((uint32*)(p_ref + (inpitch << 1)));  /* r1, r7, ref[3] */
+                r7 = (r1 >> 8) & 0xFF00FF;
+                r1 &= 0xFF00FF;
+
+                r0 += r1;
+                r6 += r7;
+
+                r2 = *((uint32*)p_ref); /* r2, r8, ref[1] */
+                r8 = (r2 >> 8) & 0xFF00FF;
+                r2 &= 0xFF00FF;
+
+                r1 = *((uint32*)(p_ref - inpitch)); /* r1, r7, ref[0] */
+                r7 = (r1 >> 8) & 0xFF00FF;
+                r1 &= 0xFF00FF;
+                r1 += r2;
+
+                r7 += r8;
+
+                r0 += 20 * r1;
+                r6 += 20 * r7;
+                r0 += 0x100010;
+                r6 += 0x100010;
+
+                r2 = *((uint32*)(p_ref - (inpitch << 1))); /* r2, r8, ref[-1] */
+                r8 = (r2 >> 8) & 0xFF00FF;
+                r2 &= 0xFF00FF;
+
+                r1 = *((uint32*)(p_ref + inpitch)); /* r1, r7, ref[2] */
+                r7 = (r1 >> 8) & 0xFF00FF;
+                r1 &= 0xFF00FF;
+                r1 += r2;
+
+                r7 += r8;
+
+                r0 -= 5 * r1;
+                r6 -= 5 * r7;
+
+                r0 >>= 5;
+                r6 >>= 5;
+                /* clip */
+                r13 |= r6;
+                r13 |= r0;
+                //CLIPPACK(r6,result)
+
+                r1 = *((uint32*)(p_ref + dy));
+                r2 = (r1 >> 8) & 0xFF00FF;
+                r1 &= 0xFF00FF;
+                r0 += r1;
+                r6 += r2;
+                r0 += 0x10001;
+                r6 += 0x10001;
+                r0 = (r0 >> 1) & 0xFF00FF;
+                r6 = (r6 >> 1) & 0xFF00FF;
+
+                r0 |= (r6 << 8);  /* pack it back */
+                *((uint32*)(p_cur += outpitch)) = r0;
+            }
+            p_cur += curr_offset; /* offset to the next pixel */
+            if (r13 & 0xFF000700) /* this column need clipping */
+            {
+                p_cur -= 4;
+                for (i = 0; i < 4; i++)
+                {
+                    p_ref = in + i;
+                    p_cur -= outpitch;  /* compensate for the first offset */
+
+                    tmp = (uint32)(p_ref + ref_offset); /* limit */
+                    while ((uint32)p_ref < tmp)
+                    {                           /* loop un-rolled */
+                        r0 = *(p_ref - (inpitch << 1));
+                        r1 = *(p_ref - inpitch);
+                        r2 = *p_ref;
+                        r3 = *(p_ref += inpitch);  /* modify pointer before loading */
+                        r4 = *(p_ref += inpitch);
+                        /* first pixel */
+                        r5 = *(p_ref += inpitch);
+                        result = (r0 + r5);
+                        r0 = (r1 + r4);
+                        result -= (r0 * 5);//result -= r0;  result -= (r0<<2);
+                        r0 = (r2 + r3);
+                        result += (r0 * 20);//result += (r0<<4);    result += (r0<<2);
+                        result = (result + 16) >> 5;
+                        CLIP_RESULT(result)
+                        /* 3/4 pel,  no need to clip */
+                        result = (result + p_ref[dy-(inpitch<<1)] + 1);
+                        result = (result >> 1);
+                        *(p_cur += outpitch) = result;
+                        /* second pixel */
+                        r0 = *(p_ref += inpitch);
+                        result = (r1 + r0);
+                        r1 = (r2 + r5);
+                        result -= (r1 * 5);//result -= r1;  result -= (r1<<2);
+                        r1 = (r3 + r4);
+                        result += (r1 * 20);//result += (r1<<4);    result += (r1<<2);
+                        result = (result + 16) >> 5;
+                        CLIP_RESULT(result)
+                        /* 3/4 pel,  no need to clip */
+                        result = (result + p_ref[dy-(inpitch<<1)] + 1);
+                        result = (result >> 1);
+                        *(p_cur += outpitch) = result;
+                        /* third pixel */
+                        r1 = *(p_ref += inpitch);
+                        result = (r2 + r1);
+                        r2 = (r3 + r0);
+                        result -= (r2 * 5);//result -= r2;  result -= (r2<<2);
+                        r2 = (r4 + r5);
+                        result += (r2 * 20);//result += (r2<<4);    result += (r2<<2);
+                        result = (result + 16) >> 5;
+                        CLIP_RESULT(result)
+                        /* 3/4 pel,  no need to clip */
+                        result = (result + p_ref[dy-(inpitch<<1)] + 1);
+                        result = (result >> 1);
+                        *(p_cur += outpitch) = result;
+                        /* fourth pixel */
+                        r2 = *(p_ref += inpitch);
+                        result = (r3 + r2);
+                        r3 = (r4 + r1);
+                        result -= (r3 * 5);//result -= r3;  result -= (r3<<2);
+                        r3 = (r5 + r0);
+                        result += (r3 * 20);//result += (r3<<4);    result += (r3<<2);
+                        result = (result + 16) >> 5;
+                        CLIP_RESULT(result)
+                        /* 3/4 pel,  no need to clip */
+                        result = (result + p_ref[dy-(inpitch<<1)] + 1);
+                        result = (result >> 1);
+                        *(p_cur += outpitch) = result;
+                        p_ref -= (inpitch << 1);  /* move back to center of the filter of the next one */
+                    }
+                    p_cur += (curr_offset - 3);
+                }
+            }
+        }
+    }
+    else
+    {
+        for (j = 0; j < blkwidth; j += 4, in += 4)
+        {
+            r13 = 0;
+            p_ref = in;
+            p_cur -= outpitch;  /* compensate for the first offset */
+            tmp = (uint32)(p_ref + ref_offset); /* limit */
+            while ((uint32)p_ref < tmp)  /* the loop un-rolled  */
+            {
+                r0 = *((uint32*)(p_ref - (inpitch << 1))); /* load 4 bytes */
+                p_ref += inpitch;
+                r6 = (r0 >> 8) & 0xFF00FF; /* second and fourth byte */
+                r0 &= 0xFF00FF;
+
+                r1 = *((uint32*)(p_ref + (inpitch << 1)));  /* r1, r7, ref[3] */
+                r7 = (r1 >> 8) & 0xFF00FF;
+                r1 &= 0xFF00FF;
+
+                r0 += r1;
+                r6 += r7;
+
+                r2 = *((uint32*)p_ref); /* r2, r8, ref[1] */
+                r8 = (r2 >> 8) & 0xFF00FF;
+                r2 &= 0xFF00FF;
+
+                r1 = *((uint32*)(p_ref - inpitch)); /* r1, r7, ref[0] */
+                r7 = (r1 >> 8) & 0xFF00FF;
+                r1 &= 0xFF00FF;
+                r1 += r2;
+
+                r7 += r8;
+
+                r0 += 20 * r1;
+                r6 += 20 * r7;
+                r0 += 0x100010;
+                r6 += 0x100010;
+
+                r2 = *((uint32*)(p_ref - (inpitch << 1))); /* r2, r8, ref[-1] */
+                r8 = (r2 >> 8) & 0xFF00FF;
+                r2 &= 0xFF00FF;
+
+                r1 = *((uint32*)(p_ref + inpitch)); /* r1, r7, ref[2] */
+                r7 = (r1 >> 8) & 0xFF00FF;
+                r1 &= 0xFF00FF;
+                r1 += r2;
+
+                r7 += r8;
+
+                r0 -= 5 * r1;
+                r6 -= 5 * r7;
+
+                r0 >>= 5;
+                r6 >>= 5;
+                /* clip */
+                r13 |= r6;
+                r13 |= r0;
+                //CLIPPACK(r6,result)
+                r0 &= 0xFF00FF;
+                r6 &= 0xFF00FF;
+                r0 |= (r6 << 8);  /* pack it back */
+                *((uint32*)(p_cur += outpitch)) = r0;
+            }
+            p_cur += curr_offset; /* offset to the next pixel */
+            if (r13 & 0xFF000700) /* this column need clipping */
+            {
+                p_cur -= 4;
+                for (i = 0; i < 4; i++)
+                {
+                    p_ref = in + i;
+                    p_cur -= outpitch;  /* compensate for the first offset */
+                    tmp = (uint32)(p_ref + ref_offset); /* limit */
+                    while ((uint32)p_ref < tmp)
+                    {                           /* loop un-rolled */
+                        r0 = *(p_ref - (inpitch << 1));
+                        r1 = *(p_ref - inpitch);
+                        r2 = *p_ref;
+                        r3 = *(p_ref += inpitch);  /* modify pointer before loading */
+                        r4 = *(p_ref += inpitch);
+                        /* first pixel */
+                        r5 = *(p_ref += inpitch);
+                        result = (r0 + r5);
+                        r0 = (r1 + r4);
+                        result -= (r0 * 5);//result -= r0;  result -= (r0<<2);
+                        r0 = (r2 + r3);
+                        result += (r0 * 20);//result += (r0<<4);    result += (r0<<2);
+                        result = (result + 16) >> 5;
+                        CLIP_RESULT(result)
+                        *(p_cur += outpitch) = result;
+                        /* second pixel */
+                        r0 = *(p_ref += inpitch);
+                        result = (r1 + r0);
+                        r1 = (r2 + r5);
+                        result -= (r1 * 5);//result -= r1;  result -= (r1<<2);
+                        r1 = (r3 + r4);
+                        result += (r1 * 20);//result += (r1<<4);    result += (r1<<2);
+                        result = (result + 16) >> 5;
+                        CLIP_RESULT(result)
+                        *(p_cur += outpitch) = result;
+                        /* third pixel */
+                        r1 = *(p_ref += inpitch);
+                        result = (r2 + r1);
+                        r2 = (r3 + r0);
+                        result -= (r2 * 5);//result -= r2;  result -= (r2<<2);
+                        r2 = (r4 + r5);
+                        result += (r2 * 20);//result += (r2<<4);    result += (r2<<2);
+                        result = (result + 16) >> 5;
+                        CLIP_RESULT(result)
+                        *(p_cur += outpitch) = result;
+                        /* fourth pixel */
+                        r2 = *(p_ref += inpitch);
+                        result = (r3 + r2);
+                        r3 = (r4 + r1);
+                        result -= (r3 * 5);//result -= r3;  result -= (r3<<2);
+                        r3 = (r5 + r0);
+                        result += (r3 * 20);//result += (r3<<4);    result += (r3<<2);
+                        result = (result + 16) >> 5;
+                        CLIP_RESULT(result)
+                        *(p_cur += outpitch) = result;
+                        p_ref -= (inpitch << 1);  /* move back to center of the filter of the next one */
+                    }
+                    p_cur += (curr_offset - 3);
+                }
+            }
+        }
+    }
+
+    return ;
+}
+
+void eVertInterp2MC(uint8 *in, int inpitch, int *out, int outpitch,
+                    int blkwidth, int blkheight)
+{
+    int *p_cur;
+    uint8 *p_ref;
+    uint32 tmp;
+    int result, curr_offset, ref_offset;
+    int j, r0, r1, r2, r3, r4, r5;
+
+    p_cur = out;
+    curr_offset = 1 - outpitch * (blkheight - 1); /* offset vertically back up and one pixel to right */
+    ref_offset = blkheight * inpitch; /* for limit */
+
+    for (j = 0; j < blkwidth; j++)
+    {
+        p_cur -= outpitch; /* compensate for the first offset */
+        p_ref = in++;
+
+        tmp = (uint32)(p_ref + ref_offset); /* limit */
+        while ((uint32)p_ref < tmp)
+        {                           /* loop un-rolled */
+            r0 = *(p_ref - (inpitch << 1));
+            r1 = *(p_ref - inpitch);
+            r2 = *p_ref;
+            r3 = *(p_ref += inpitch);  /* modify pointer before loading */
+            r4 = *(p_ref += inpitch);
+            /* first pixel */
+            r5 = *(p_ref += inpitch);
+            result = (r0 + r5);
+            r0 = (r1 + r4);
+            result -= (r0 * 5);//result -= r0;  result -= (r0<<2);
+            r0 = (r2 + r3);
+            result += (r0 * 20);//result += (r0<<4);    result += (r0<<2);
+            *(p_cur += outpitch) = result;
+            /* second pixel */
+            r0 = *(p_ref += inpitch);
+            result = (r1 + r0);
+            r1 = (r2 + r5);
+            result -= (r1 * 5);//result -= r1;  result -= (r1<<2);
+            r1 = (r3 + r4);
+            result += (r1 * 20);//result += (r1<<4);    result += (r1<<2);
+            *(p_cur += outpitch) = result;
+            /* third pixel */
+            r1 = *(p_ref += inpitch);
+            result = (r2 + r1);
+            r2 = (r3 + r0);
+            result -= (r2 * 5);//result -= r2;  result -= (r2<<2);
+            r2 = (r4 + r5);
+            result += (r2 * 20);//result += (r2<<4);    result += (r2<<2);
+            *(p_cur += outpitch) = result;
+            /* fourth pixel */
+            r2 = *(p_ref += inpitch);
+            result = (r3 + r2);
+            r3 = (r4 + r1);
+            result -= (r3 * 5);//result -= r3;  result -= (r3<<2);
+            r3 = (r5 + r0);
+            result += (r3 * 20);//result += (r3<<4);    result += (r3<<2);
+            *(p_cur += outpitch) = result;
+            p_ref -= (inpitch << 1);  /* move back to center of the filter of the next one */
+        }
+        p_cur += curr_offset;
+    }
+
+    return ;
+}
+
+void eVertInterp3MC(int *in, int inpitch, uint8 *out, int outpitch,
+                    int blkwidth, int blkheight, int dy)
+{
+    uint8 *p_cur;
+    int *p_ref;
+    uint32 tmp;
+    int result, result2, curr_offset, ref_offset;
+    int j, r0, r1, r2, r3, r4, r5;
+
+    p_cur = out;
+    curr_offset = 1 - outpitch * (blkheight - 1); /* offset vertically back up and one pixel to right */
+    ref_offset = blkheight * inpitch; /* for limit */
+
+    if (dy&1)
+    {
+        dy = (dy >> 1) ? -(inpitch << 1) : -(inpitch << 1) - inpitch;
+
+        for (j = 0; j < blkwidth; j++)
+        {
+            p_cur -= outpitch; /* compensate for the first offset */
+            p_ref = in++;
+
+            tmp = (uint32)(p_ref + ref_offset); /* limit */
+            while ((uint32)p_ref < tmp)
+            {                           /* loop un-rolled */
+                r0 = *(p_ref - (inpitch << 1));
+                r1 = *(p_ref - inpitch);
+                r2 = *p_ref;
+                r3 = *(p_ref += inpitch);  /* modify pointer before loading */
+                r4 = *(p_ref += inpitch);
+                /* first pixel */
+                r5 = *(p_ref += inpitch);
+                result = (r0 + r5);
+                r0 = (r1 + r4);
+                result -= (r0 * 5);//result -= r0;  result -= (r0<<2);
+                r0 = (r2 + r3);
+                result += (r0 * 20);//result += (r0<<4);    result += (r0<<2);
+                result = (result + 512) >> 10;
+                CLIP_RESULT(result)
+                result2 = ((p_ref[dy] + 16) >> 5);
+                CLIP_RESULT(result2)
+                /* 3/4 pel,  no need to clip */
+                result = (result + result2 + 1);
+                result = (result >> 1);
+                *(p_cur += outpitch) = result;
+                /* second pixel */
+                r0 = *(p_ref += inpitch);
+                result = (r1 + r0);
+                r1 = (r2 + r5);
+                result -= (r1 * 5);//result -= r1;  result -= (r1<<2);
+                r1 = (r3 + r4);
+                result += (r1 * 20);//result += (r1<<4);    result += (r1<<2);
+                result = (result + 512) >> 10;
+                CLIP_RESULT(result)
+                result2 = ((p_ref[dy] + 16) >> 5);
+                CLIP_RESULT(result2)
+                /* 3/4 pel,  no need to clip */
+                result = (result + result2 + 1);
+                result = (result >> 1);
+                *(p_cur += outpitch) = result;
+                /* third pixel */
+                r1 = *(p_ref += inpitch);
+                result = (r2 + r1);
+                r2 = (r3 + r0);
+                result -= (r2 * 5);//result -= r2;  result -= (r2<<2);
+                r2 = (r4 + r5);
+                result += (r2 * 20);//result += (r2<<4);    result += (r2<<2);
+                result = (result + 512) >> 10;
+                CLIP_RESULT(result)
+                result2 = ((p_ref[dy] + 16) >> 5);
+                CLIP_RESULT(result2)
+                /* 3/4 pel,  no need to clip */
+                result = (result + result2 + 1);
+                result = (result >> 1);
+                *(p_cur += outpitch) = result;
+                /* fourth pixel */
+                r2 = *(p_ref += inpitch);
+                result = (r3 + r2);
+                r3 = (r4 + r1);
+                result -= (r3 * 5);//result -= r3;  result -= (r3<<2);
+                r3 = (r5 + r0);
+                result += (r3 * 20);//result += (r3<<4);    result += (r3<<2);
+                result = (result + 512) >> 10;
+                CLIP_RESULT(result)
+                result2 = ((p_ref[dy] + 16) >> 5);
+                CLIP_RESULT(result2)
+                /* 3/4 pel,  no need to clip */
+                result = (result + result2 + 1);
+                result = (result >> 1);
+                *(p_cur += outpitch) = result;
+                p_ref -= (inpitch << 1);  /* move back to center of the filter of the next one */
+            }
+            p_cur += curr_offset;
+        }
+    }
+    else
+    {
+        for (j = 0; j < blkwidth; j++)
+        {
+            p_cur -= outpitch; /* compensate for the first offset */
+            p_ref = in++;
+
+            tmp = (uint32)(p_ref + ref_offset); /* limit */
+            while ((uint32)p_ref < tmp)
+            {                           /* loop un-rolled */
+                r0 = *(p_ref - (inpitch << 1));
+                r1 = *(p_ref - inpitch);
+                r2 = *p_ref;
+                r3 = *(p_ref += inpitch);  /* modify pointer before loading */
+                r4 = *(p_ref += inpitch);
+                /* first pixel */
+                r5 = *(p_ref += inpitch);
+                result = (r0 + r5);
+                r0 = (r1 + r4);
+                result -= (r0 * 5);//result -= r0;  result -= (r0<<2);
+                r0 = (r2 + r3);
+                result += (r0 * 20);//result += (r0<<4);    result += (r0<<2);
+                result = (result + 512) >> 10;
+                CLIP_RESULT(result)
+                *(p_cur += outpitch) = result;
+                /* second pixel */
+                r0 = *(p_ref += inpitch);
+                result = (r1 + r0);
+                r1 = (r2 + r5);
+                result -= (r1 * 5);//result -= r1;  result -= (r1<<2);
+                r1 = (r3 + r4);
+                result += (r1 * 20);//result += (r1<<4);    result += (r1<<2);
+                result = (result + 512) >> 10;
+                CLIP_RESULT(result)
+                *(p_cur += outpitch) = result;
+                /* third pixel */
+                r1 = *(p_ref += inpitch);
+                result = (r2 + r1);
+                r2 = (r3 + r0);
+                result -= (r2 * 5);//result -= r2;  result -= (r2<<2);
+                r2 = (r4 + r5);
+                result += (r2 * 20);//result += (r2<<4);    result += (r2<<2);
+                result = (result + 512) >> 10;
+                CLIP_RESULT(result)
+                *(p_cur += outpitch) = result;
+                /* fourth pixel */
+                r2 = *(p_ref += inpitch);
+                result = (r3 + r2);
+                r3 = (r4 + r1);
+                result -= (r3 * 5);//result -= r3;  result -= (r3<<2);
+                r3 = (r5 + r0);
+                result += (r3 * 20);//result += (r3<<4);    result += (r3<<2);
+                result = (result + 512) >> 10;
+                CLIP_RESULT(result)
+                *(p_cur += outpitch) = result;
+                p_ref -= (inpitch << 1);  /* move back to center of the filter of the next one */
+            }
+            p_cur += curr_offset;
+        }
+    }
+
+    return ;
+}
+
+void eDiagonalInterpMC(uint8 *in1, uint8 *in2, int inpitch,
+                       uint8 *out, int outpitch,
+                       int blkwidth, int blkheight)
+{
+    int j, i;
+    int result;
+    uint8 *p_cur, *p_ref, *p_tmp8;
+    int curr_offset, ref_offset;
+    uint8 tmp_res[24][24], tmp_in[24][24];
+    uint32 *p_tmp;
+    uint32 tmp, pkres, tmp_result;
+    int32 r0, r1, r2, r3, r4, r5;
+    int32 r6, r7, r8, r9, r10, r13;
+
+    ref_offset = inpitch - blkwidth;
+    p_ref = in1 - 2;
+    /* perform horizontal interpolation */
+    /* not word-aligned */
+    /* It is faster to read 1 byte at time to avoid calling CreateAlign */
+    /*  if(((uint32)p_ref)&0x3)
+        {
+            CreateAlign(p_ref,inpitch,0,&tmp_in[0][0],blkwidth+8,blkheight);
+            p_ref = &tmp_in[0][0];
+            ref_offset = 24-blkwidth;
+        }*/
+
+    p_tmp = (uint32*) & (tmp_res[0][0]);
+    for (j = blkheight; j > 0; j--)
+    {
+        r13 = 0;
+        tmp = (uint32)(p_ref + blkwidth);
+
+        //r0 = *((uint32*)p_ref);   /* d,c,b,a */
+        //r1 = (r0>>8)&0xFF00FF;    /* 0,d,0,b */
+        //r0 &= 0xFF00FF;           /* 0,c,0,a */
+        /* It is faster to read 1 byte at a time */
+        r0 = p_ref[0];
+        r1 = p_ref[2];
+        r0 |= (r1 << 16);           /* 0,c,0,a */
+        r1 = p_ref[1];
+        r2 = p_ref[3];
+        r1 |= (r2 << 16);           /* 0,d,0,b */
+
+        while ((uint32)p_ref < tmp)
+        {
+            //r2 = *((uint32*)(p_ref+=4));/* h,g,f,e */
+            //r3 = (r2>>8)&0xFF00FF;  /* 0,h,0,f */
+            //r2 &= 0xFF00FF;           /* 0,g,0,e */
+            /* It is faster to read 1 byte at a time */
+            r2 = *(p_ref += 4);
+            r3 = p_ref[2];
+            r2 |= (r3 << 16);           /* 0,g,0,e */
+            r3 = p_ref[1];
+            r4 = p_ref[3];
+            r3 |= (r4 << 16);           /* 0,h,0,f */
+
+            r4 = r0 + r3;       /* c+h, a+f */
+            r5 = r0 + r1;   /* c+d, a+b */
+            r6 = r2 + r3;   /* g+h, e+f */
+            r5 >>= 16;
+            r5 |= (r6 << 16);   /* e+f, c+d */
+            r4 += r5 * 20;      /* c+20*e+20*f+h, a+20*c+20*d+f */
+            r4 += 0x100010; /* +16, +16 */
+            r5 = r1 + r2;       /* d+g, b+e */
+            r4 -= r5 * 5;       /* c-5*d+20*e+20*f-5*g+h, a-5*b+20*c+20*d-5*e+f */
+            r4 >>= 5;
+            r13 |= r4;      /* check clipping */
+            r4 &= 0xFF00FF; /* mask */
+
+            r5 = p_ref[4];  /* i */
+            r6 = (r5 << 16);
+            r5 = r6 | (r2 >> 16);/* 0,i,0,g */
+            r5 += r1;       /* d+i, b+g */ /* r5 not free */
+            r1 >>= 16;
+            r1 |= (r3 << 16); /* 0,f,0,d */ /* r1 has changed */
+            r1 += r2;       /* f+g, d+e */
+            r5 += 20 * r1;  /* d+20f+20g+i, b+20d+20e+g */
+            r0 >>= 16;
+            r0 |= (r2 << 16); /* 0,e,0,c */ /* r0 has changed */
+            r0 += r3;       /* e+h, c+f */
+            r5 += 0x100010; /* 16,16 */
+            r5 -= r0 * 5;       /* d-5e+20f+20g-5h+i, b-5c+20d+20e-5f+g */
+            r5 >>= 5;
+            r13 |= r5;      /* check clipping */
+            r5 &= 0xFF00FF; /* mask */
+
+            r4 |= (r5 << 8);    /* pack them together */
+            *p_tmp++ = r4;
+            r1 = r3;
+            r0 = r2;
+        }
+        p_tmp += ((24 - blkwidth) >> 2); /* move to the next line */
+        p_ref += ref_offset;  /*    ref_offset = inpitch-blkwidth; */
+
+        if (r13&0xFF000700) /* need clipping */
+        {
+            /* move back to the beginning of the line */
+            p_ref -= (ref_offset + blkwidth);   /* input */
+            p_tmp -= 6; /* intermediate output */
+            tmp = (uint32)(p_ref + blkwidth);
+            while ((uint32)p_ref < tmp)
+            {
+                r0 = *p_ref++;
+                r1 = *p_ref++;
+                r2 = *p_ref++;
+                r3 = *p_ref++;
+                r4 = *p_ref++;
+                /* first pixel */
+                r5 = *p_ref++;
+                result = (r0 + r5);
+                r0 = (r1 + r4);
+                result -= (r0 * 5);//result -= r0;  result -= (r0<<2);
+                r0 = (r2 + r3);
+                result += (r0 * 20);//result += (r0<<4);    result += (r0<<2);
+                result = (result + 16) >> 5;
+                CLIP_RESULT(result)
+                pkres = result;
+                /* second pixel */
+                r0 = *p_ref++;
+                result = (r1 + r0);
+                r1 = (r2 + r5);
+                result -= (r1 * 5);//result -= r1;  result -= (r1<<2);
+                r1 = (r3 + r4);
+                result += (r1 * 20);//result += (r1<<4);    result += (r1<<2);
+                result = (result + 16) >> 5;
+                CLIP_RESULT(result)
+                pkres |= (result << 8);
+                /* third pixel */
+                r1 = *p_ref++;
+                result = (r2 + r1);
+                r2 = (r3 + r0);
+                result -= (r2 * 5);//result -= r2;  result -= (r2<<2);
+                r2 = (r4 + r5);
+                result += (r2 * 20);//result += (r2<<4);    result += (r2<<2);
+                result = (result + 16) >> 5;
+                CLIP_RESULT(result)
+                pkres |= (result << 16);
+                /* fourth pixel */
+                r2 = *p_ref++;
+                result = (r3 + r2);
+                r3 = (r4 + r1);
+                result -= (r3 * 5);//result -= r3;  result -= (r3<<2);
+                r3 = (r5 + r0);
+                result += (r3 * 20);//result += (r3<<4);    result += (r3<<2);
+                result = (result + 16) >> 5;
+                CLIP_RESULT(result)
+                pkres |= (result << 24);
+
+                *p_tmp++ = pkres; /* write 4 pixel */
+                p_ref -= 5;
+            }
+            p_tmp += ((24 - blkwidth) >> 2); /* move to the next line */
+            p_ref += ref_offset;  /*    ref_offset = inpitch-blkwidth; */
+        }
+    }
+
+    /*  perform vertical interpolation */
+    /* not word-aligned */
+    if (((uint32)in2)&0x3)
+    {
+        eCreateAlign(in2, inpitch, -2, &tmp_in[0][0], blkwidth, blkheight + 5);
+        in2 = &tmp_in[2][0];
+        inpitch = 24;
+    }
+
+    p_cur = out;
+    curr_offset = 1 - outpitch * (blkheight - 1); /* offset vertically up and one pixel right */
+    pkres = blkheight * inpitch; /* reuse it for limit */
+
+    curr_offset += 3;
+
+    for (j = 0; j < blkwidth; j += 4, in2 += 4)
+    {
+        r13 = 0;
+        p_ref = in2;
+        p_tmp8 = &(tmp_res[0][j]); /* intermediate result */
+        p_tmp8 -= 24;  /* compensate for the first offset */
+        p_cur -= outpitch;  /* compensate for the first offset */
+        tmp = (uint32)(p_ref + pkres); /* limit */
+        while ((uint32)p_ref < tmp)  /* the loop un-rolled  */
+        {
+            /* Read 1 byte at a time is too slow, too many read and pack ops, need to call CreateAlign */
+            /*p_ref8 = p_ref-(inpitch<<1);          r0 = p_ref8[0];         r1 = p_ref8[2];
+            r0 |= (r1<<16);         r6 = p_ref8[1];         r1 = p_ref8[3];
+            r6 |= (r1<<16);         p_ref+=inpitch; */
+            r0 = *((uint32*)(p_ref - (inpitch << 1))); /* load 4 bytes */
+            p_ref += inpitch;
+            r6 = (r0 >> 8) & 0xFF00FF; /* second and fourth byte */
+            r0 &= 0xFF00FF;
+
+            /*p_ref8 = p_ref+(inpitch<<1);
+            r1 = p_ref8[0];         r7 = p_ref8[2];         r1 |= (r7<<16);
+            r7 = p_ref8[1];         r2 = p_ref8[3];         r7 |= (r2<<16);*/
+            r1 = *((uint32*)(p_ref + (inpitch << 1)));  /* r1, r7, ref[3] */
+            r7 = (r1 >> 8) & 0xFF00FF;
+            r1 &= 0xFF00FF;
+
+            r0 += r1;
+            r6 += r7;
+
+            /*r2 = p_ref[0];            r8 = p_ref[2];          r2 |= (r8<<16);
+            r8 = p_ref[1];          r1 = p_ref[3];          r8 |= (r1<<16);*/
+            r2 = *((uint32*)p_ref); /* r2, r8, ref[1] */
+            r8 = (r2 >> 8) & 0xFF00FF;
+            r2 &= 0xFF00FF;
+
+            /*p_ref8 = p_ref-inpitch;           r1 = p_ref8[0];         r7 = p_ref8[2];
+            r1 |= (r7<<16);         r1 += r2;           r7 = p_ref8[1];
+            r2 = p_ref8[3];         r7 |= (r2<<16);*/
+            r1 = *((uint32*)(p_ref - inpitch)); /* r1, r7, ref[0] */
+            r7 = (r1 >> 8) & 0xFF00FF;
+            r1 &= 0xFF00FF;
+            r1 += r2;
+
+            r7 += r8;
+
+            r0 += 20 * r1;
+            r6 += 20 * r7;
+            r0 += 0x100010;
+            r6 += 0x100010;
+
+            /*p_ref8 = p_ref-(inpitch<<1);          r2 = p_ref8[0];         r8 = p_ref8[2];
+            r2 |= (r8<<16);         r8 = p_ref8[1];         r1 = p_ref8[3];         r8 |= (r1<<16);*/
+            r2 = *((uint32*)(p_ref - (inpitch << 1))); /* r2, r8, ref[-1] */
+            r8 = (r2 >> 8) & 0xFF00FF;
+            r2 &= 0xFF00FF;
+
+            /*p_ref8 = p_ref+inpitch;           r1 = p_ref8[0];         r7 = p_ref8[2];
+            r1 |= (r7<<16);         r1 += r2;           r7 = p_ref8[1];
+            r2 = p_ref8[3];         r7 |= (r2<<16);*/
+            r1 = *((uint32*)(p_ref + inpitch)); /* r1, r7, ref[2] */
+            r7 = (r1 >> 8) & 0xFF00FF;
+            r1 &= 0xFF00FF;
+            r1 += r2;
+
+            r7 += r8;
+
+            r0 -= 5 * r1;
+            r6 -= 5 * r7;
+
+            r0 >>= 5;
+            r6 >>= 5;
+            /* clip */
+            r13 |= r6;
+            r13 |= r0;
+            //CLIPPACK(r6,result)
+            /* add with horizontal results */
+            r10 = *((uint32*)(p_tmp8 += 24));
+            r9 = (r10 >> 8) & 0xFF00FF;
+            r10 &= 0xFF00FF;
+
+            r0 += r10;
+            r0 += 0x10001;
+            r0 = (r0 >> 1) & 0xFF00FF;   /* mask to 8 bytes */
+
+            r6 += r9;
+            r6 += 0x10001;
+            r6 = (r6 >> 1) & 0xFF00FF;   /* mask to 8 bytes */
+
+            r0 |= (r6 << 8);  /* pack it back */
+            *((uint32*)(p_cur += outpitch)) = r0;
+        }
+        p_cur += curr_offset; /* offset to the next pixel */
+        if (r13 & 0xFF000700) /* this column need clipping */
+        {
+            p_cur -= 4;
+            for (i = 0; i < 4; i++)
+            {
+                p_ref = in2 + i;
+                p_tmp8 = &(tmp_res[0][j+i]); /* intermediate result */
+                p_tmp8 -= 24;  /* compensate for the first offset */
+                p_cur -= outpitch;  /* compensate for the first offset */
+                tmp = (uint32)(p_ref + pkres); /* limit */
+                while ((uint32)p_ref < tmp)  /* the loop un-rolled  */
+                {
+                    r0 = *(p_ref - (inpitch << 1));
+                    r1 = *(p_ref - inpitch);
+                    r2 = *p_ref;
+                    r3 = *(p_ref += inpitch);  /* modify pointer before loading */
+                    r4 = *(p_ref += inpitch);
+                    /* first pixel */
+                    r5 = *(p_ref += inpitch);
+                    result = (r0 + r5);
+                    r0 = (r1 + r4);
+                    result -= (r0 * 5);//result -= r0;  result -= (r0<<2);
+                    r0 = (r2 + r3);
+                    result += (r0 * 20);//result += (r0<<4);    result += (r0<<2);
+                    result = (result + 16) >> 5;
+                    CLIP_RESULT(result)
+                    tmp_result = *(p_tmp8 += 24);  /* modify pointer before loading */
+                    result = (result + tmp_result + 1);  /* no clip */
+                    result = (result >> 1);
+                    *(p_cur += outpitch) = result;
+                    /* second pixel */
+                    r0 = *(p_ref += inpitch);
+                    result = (r1 + r0);
+                    r1 = (r2 + r5);
+                    result -= (r1 * 5);//result -= r1;  result -= (r1<<2);
+                    r1 = (r3 + r4);
+                    result += (r1 * 20);//result += (r1<<4);    result += (r1<<2);
+                    result = (result + 16) >> 5;
+                    CLIP_RESULT(result)
+                    tmp_result = *(p_tmp8 += 24);  /* intermediate result */
+                    result = (result + tmp_result + 1);  /* no clip */
+                    result = (result >> 1);
+                    *(p_cur += outpitch) = result;
+                    /* third pixel */
+                    r1 = *(p_ref += inpitch);
+                    result = (r2 + r1);
+                    r2 = (r3 + r0);
+                    result -= (r2 * 5);//result -= r2;  result -= (r2<<2);
+                    r2 = (r4 + r5);
+                    result += (r2 * 20);//result += (r2<<4);    result += (r2<<2);
+                    result = (result + 16) >> 5;
+                    CLIP_RESULT(result)
+                    tmp_result = *(p_tmp8 += 24);  /* intermediate result */
+                    result = (result + tmp_result + 1);  /* no clip */
+                    result = (result >> 1);
+                    *(p_cur += outpitch) = result;
+                    /* fourth pixel */
+                    r2 = *(p_ref += inpitch);
+                    result = (r3 + r2);
+                    r3 = (r4 + r1);
+                    result -= (r3 * 5);//result -= r3;  result -= (r3<<2);
+                    r3 = (r5 + r0);
+                    result += (r3 * 20);//result += (r3<<4);    result += (r3<<2);
+                    result = (result + 16) >> 5;
+                    CLIP_RESULT(result)
+                    tmp_result = *(p_tmp8 += 24);  /* intermediate result */
+                    result = (result + tmp_result + 1);  /* no clip */
+                    result = (result >> 1);
+                    *(p_cur += outpitch) = result;
+                    p_ref -= (inpitch << 1);  /* move back to center of the filter of the next one */
+                }
+                p_cur += (curr_offset - 3);
+            }
+        }
+    }
+
+    return ;
+}
+
+/* position G */
+void eFullPelMC(uint8 *in, int inpitch, uint8 *out, int outpitch,
+                int blkwidth, int blkheight)
+{
+    int i, j;
+    int offset_in = inpitch - blkwidth;
+    int offset_out = outpitch - blkwidth;
+    uint32 temp;
+    uint8 byte;
+
+    if (((uint32)in)&3)
+    {
+        for (j = blkheight; j > 0; j--)
+        {
+            for (i = blkwidth; i > 0; i -= 4)
+            {
+                temp = *in++;
+                byte = *in++;
+                temp |= (byte << 8);
+                byte = *in++;
+                temp |= (byte << 16);
+                byte = *in++;
+                temp |= (byte << 24);
+
+                *((uint32*)out) = temp; /* write 4 bytes */
+                out += 4;
+            }
+            out += offset_out;
+            in += offset_in;
+        }
+    }
+    else
+    {
+        for (j = blkheight; j > 0; j--)
+        {
+            for (i = blkwidth; i > 0; i -= 4)
+            {
+                temp = *((uint32*)in);
+                *((uint32*)out) = temp;
+                in += 4;
+                out += 4;
+            }
+            out += offset_out;
+            in += offset_in;
+        }
+    }
+    return ;
+}
+
+void ePadChroma(uint8 *ref, int picwidth, int picheight, int picpitch, int x_pos, int y_pos)
+{
+    int pad_height;
+    int pad_width;
+    uint8 *start;
+    uint32 word1, word2, word3;
+    int offset, j;
+
+
+    pad_height = 8 + ((y_pos & 7) ? 1 : 0);
+    pad_width = 8 + ((x_pos & 7) ? 1 : 0);
+
+    y_pos >>= 3;
+    x_pos >>= 3;
+    // pad vertical first
+    if (y_pos < 0) // need to pad up
+    {
+        if (x_pos < -8) start = ref - 8;
+        else if (x_pos + pad_width > picwidth + 7) start = ref + picwidth + 7 - pad_width;
+        else start = ref + x_pos;
+
+        /* word-align start */
+        offset = (uint32)start & 0x3;
+        if (offset) start -= offset;
+
+        word1 = *((uint32*)start);
+        word2 = *((uint32*)(start + 4));
+        word3 = *((uint32*)(start + 8));
+
+        /* pad up N rows */
+        j = -y_pos;
+        if (j > 8) j = 8;
+        while (j--)
+        {
+            *((uint32*)(start -= picpitch)) = word1;
+            *((uint32*)(start + 4)) = word2;
+            *((uint32*)(start + 8)) = word3;
+        }
+
+    }
+    else if (y_pos + pad_height >= picheight) /* pad down */
+    {
+        if (x_pos < -8) start = ref + picpitch * (picheight - 1) - 8;
+        else if (x_pos + pad_width > picwidth + 7) start = ref + picpitch * (picheight - 1) +
+                    picwidth + 7 - pad_width;
+        else    start = ref + picpitch * (picheight - 1) + x_pos;
+
+        /* word-align start */
+        offset = (uint32)start & 0x3;
+        if (offset) start -= offset;
+
+        word1 = *((uint32*)start);
+        word2 = *((uint32*)(start + 4));
+        word3 = *((uint32*)(start + 8));
+
+        /* pad down N rows */
+        j = y_pos + pad_height - picheight;
+        if (j > 8) j = 8;
+        while (j--)
+        {
+            *((uint32*)(start += picpitch)) = word1;
+            *((uint32*)(start + 4)) = word2;
+            *((uint32*)(start + 8)) = word3;
+        }
+    }
+
+    /* now pad horizontal */
+    if (x_pos < 0) // pad left
+    {
+        if (y_pos < -8) start = ref - (picpitch << 3);
+        else if (y_pos + pad_height > picheight + 7) start = ref + (picheight + 7 - pad_height) * picpitch;
+        else start = ref + y_pos * picpitch;
+
+        // now pad left 8 pixels for pad_height rows */
+        j = pad_height;
+        start -= picpitch;
+        while (j--)
+        {
+            word1 = *(start += picpitch);
+            word1 |= (word1 << 8);
+            word1 |= (word1 << 16);
+            *((uint32*)(start - 8)) = word1;
+            *((uint32*)(start - 4)) = word1;
+        }
+    }
+    else if (x_pos + pad_width >= picwidth) /* pad right */
+    {
+        if (y_pos < -8) start = ref - (picpitch << 3) + picwidth - 1;
+        else if (y_pos + pad_height > picheight + 7) start = ref + (picheight + 7 - pad_height) * picpitch + picwidth - 1;
+        else start = ref + y_pos * picpitch + picwidth - 1;
+
+        // now pad right 8 pixels for pad_height rows */
+        j = pad_height;
+        start -= picpitch;
+        while (j--)
+        {
+            word1 = *(start += picpitch);
+            word1 |= (word1 << 8);
+            word1 |= (word1 << 16);
+            *((uint32*)(start + 1)) = word1;
+            *((uint32*)(start + 5)) = word1;
+        }
+    }
+
+    return ;
+}
+
+
+void eChromaMotionComp(uint8 *ref, int picwidth, int picheight,
+                       int x_pos, int y_pos,
+                       uint8 *pred, int picpitch,
+                       int blkwidth, int blkheight)
+{
+    int dx, dy;
+    int offset_dx, offset_dy;
+    int index;
+
+    ePadChroma(ref, picwidth, picheight, picpitch, x_pos, y_pos);
+
+    dx = x_pos & 7;
+    dy = y_pos & 7;
+    offset_dx = (dx + 7) >> 3;
+    offset_dy = (dy + 7) >> 3;
+    x_pos = x_pos >> 3;  /* round it to full-pel resolution */
+    y_pos = y_pos >> 3;
+
+    ref += y_pos * picpitch + x_pos;
+
+    index = offset_dx + (offset_dy << 1) + ((blkwidth << 1) & 0x7);
+
+    (*(eChromaMC_SIMD[index]))(ref, picpitch , dx, dy, pred, picpitch, blkwidth, blkheight);
+    return ;
+}
+
+
+/* SIMD routines, unroll the loops in vertical direction, decreasing loops (things to be done) */
+void eChromaDiagonalMC_SIMD(uint8 *pRef, int srcPitch, int dx, int dy,
+                            uint8 *pOut, int predPitch, int blkwidth, int blkheight)
+{
+    int32 r0, r1, r2, r3, result0, result1;
+    uint8 temp[288];
+    uint8 *ref, *out;
+    int i, j;
+    int dx_8 = 8 - dx;
+    int dy_8 = 8 - dy;
+
+    /* horizontal first */
+    out = temp;
+    for (i = 0; i < blkheight + 1; i++)
+    {
+        ref = pRef;
+        r0 = ref[0];
+        for (j = 0; j < blkwidth; j += 4)
+        {
+            r0 |= (ref[2] << 16);
+            result0 = dx_8 * r0;
+
+            r1 = ref[1] | (ref[3] << 16);
+            result0 += dx * r1;
+            *(int32 *)out = result0;
+
+            result0 = dx_8 * r1;
+
+            r2 = ref[4];
+            r0 = r0 >> 16;
+            r1 = r0 | (r2 << 16);
+            result0 += dx * r1;
+            *(int32 *)(out + 16) = result0;
+
+            ref += 4;
+            out += 4;
+            r0 = r2;
+        }
+        pRef += srcPitch;
+        out += (32 - blkwidth);
+    }
+
+//  pRef -= srcPitch*(blkheight+1);
+    ref = temp;
+
+    for (j = 0; j < blkwidth; j += 4)
+    {
+        r0 = *(int32 *)ref;
+        r1 = *(int32 *)(ref + 16);
+        ref += 32;
+        out = pOut;
+        for (i = 0; i < (blkheight >> 1); i++)
+        {
+            result0 = dy_8 * r0 + 0x00200020;
+            r2 = *(int32 *)ref;
+            result0 += dy * r2;
+            result0 >>= 6;
+            result0 &= 0x00FF00FF;
+            r0 = r2;
+
+            result1 = dy_8 * r1 + 0x00200020;
+            r3 = *(int32 *)(ref + 16);
+            result1 += dy * r3;
+            result1 >>= 6;
+            result1 &= 0x00FF00FF;
+            r1 = r3;
+            *(int32 *)out = result0 | (result1 << 8);
+            out += predPitch;
+            ref += 32;
+
+            result0 = dy_8 * r0 + 0x00200020;
+            r2 = *(int32 *)ref;
+            result0 += dy * r2;
+            result0 >>= 6;
+            result0 &= 0x00FF00FF;
+            r0 = r2;
+
+            result1 = dy_8 * r1 + 0x00200020;
+            r3 = *(int32 *)(ref + 16);
+            result1 += dy * r3;
+            result1 >>= 6;
+            result1 &= 0x00FF00FF;
+            r1 = r3;
+            *(int32 *)out = result0 | (result1 << 8);
+            out += predPitch;
+            ref += 32;
+        }
+        pOut += 4;
+        ref = temp + 4; /* since it can only iterate twice max */
+    }
+    return;
+}
+
+void eChromaHorizontalMC_SIMD(uint8 *pRef, int srcPitch, int dx, int dy,
+                              uint8 *pOut, int predPitch, int blkwidth, int blkheight)
+{
+    (void)(dy);
+
+    int32 r0, r1, r2, result0, result1;
+    uint8 *ref, *out;
+    int i, j;
+    int dx_8 = 8 - dx;
+
+    /* horizontal first */
+    for (i = 0; i < blkheight; i++)
+    {
+        ref = pRef;
+        out = pOut;
+
+        r0 = ref[0];
+        for (j = 0; j < blkwidth; j += 4)
+        {
+            r0 |= (ref[2] << 16);
+            result0 = dx_8 * r0 + 0x00040004;
+
+            r1 = ref[1] | (ref[3] << 16);
+            result0 += dx * r1;
+            result0 >>= 3;
+            result0 &= 0x00FF00FF;
+
+            result1 = dx_8 * r1 + 0x00040004;
+
+            r2 = ref[4];
+            r0 = r0 >> 16;
+            r1 = r0 | (r2 << 16);
+            result1 += dx * r1;
+            result1 >>= 3;
+            result1 &= 0x00FF00FF;
+
+            *(int32 *)out = result0 | (result1 << 8);
+
+            ref += 4;
+            out += 4;
+            r0 = r2;
+        }
+
+        pRef += srcPitch;
+        pOut += predPitch;
+    }
+    return;
+}
+
+void eChromaVerticalMC_SIMD(uint8 *pRef, int srcPitch, int dx, int dy,
+                            uint8 *pOut, int predPitch, int blkwidth, int blkheight)
+{
+    (void)(dx);
+
+    int32 r0, r1, r2, r3, result0, result1;
+    int i, j;
+    uint8 *ref, *out;
+    int dy_8 = 8 - dy;
+    /* vertical first */
+    for (i = 0; i < blkwidth; i += 4)
+    {
+        ref = pRef;
+        out = pOut;
+
+        r0 = ref[0] | (ref[2] << 16);
+        r1 = ref[1] | (ref[3] << 16);
+        ref += srcPitch;
+        for (j = 0; j < blkheight; j++)
+        {
+            result0 = dy_8 * r0 + 0x00040004;
+            r2 = ref[0] | (ref[2] << 16);
+            result0 += dy * r2;
+            result0 >>= 3;
+            result0 &= 0x00FF00FF;
+            r0 = r2;
+
+            result1 = dy_8 * r1 + 0x00040004;
+            r3 = ref[1] | (ref[3] << 16);
+            result1 += dy * r3;
+            result1 >>= 3;
+            result1 &= 0x00FF00FF;
+            r1 = r3;
+            *(int32 *)out = result0 | (result1 << 8);
+            ref += srcPitch;
+            out += predPitch;
+        }
+        pOut += 4;
+        pRef += 4;
+    }
+    return;
+}
+
+void eChromaDiagonalMC2_SIMD(uint8 *pRef, int srcPitch, int dx, int dy,
+                             uint8 *pOut,  int predPitch, int blkwidth, int blkheight)
+{
+    (void)(blkwidth);
+
+    int32 r0, r1, temp0, temp1, result;
+    int32 temp[9];
+    int32 *out;
+    int i, r_temp;
+    int dy_8 = 8 - dy;
+
+    /* horizontal first */
+    out = temp;
+    for (i = 0; i < blkheight + 1; i++)
+    {
+        r_temp = pRef[1];
+        temp0 = (pRef[0] << 3) + dx * (r_temp - pRef[0]);
+        temp1 = (r_temp << 3) + dx * (pRef[2] - r_temp);
+        r0 = temp0 | (temp1 << 16);
+        *out++ = r0;
+        pRef += srcPitch;
+    }
+
+    pRef -= srcPitch * (blkheight + 1);
+
+    out = temp;
+
+    r0 = *out++;
+
+    for (i = 0; i < blkheight; i++)
+    {
+        result = dy_8 * r0 + 0x00200020;
+        r1 = *out++;
+        result += dy * r1;
+        result >>= 6;
+        result &= 0x00FF00FF;
+        *(int16 *)pOut = (result >> 8) | (result & 0xFF);
+        r0 = r1;
+        pOut += predPitch;
+    }
+    return;
+}
+
+void eChromaHorizontalMC2_SIMD(uint8 *pRef, int srcPitch, int dx, int dy,
+                               uint8 *pOut, int predPitch, int blkwidth, int blkheight)
+{
+    (void)(dy);
+    (void)(blkwidth);
+
+    int i, temp, temp0, temp1;
+
+    /* horizontal first */
+    for (i = 0; i < blkheight; i++)
+    {
+        temp = pRef[1];
+        temp0 = ((pRef[0] << 3) + dx * (temp - pRef[0]) + 4) >> 3;
+        temp1 = ((temp << 3) + dx * (pRef[2] - temp) + 4) >> 3;
+
+        *(int16 *)pOut = temp0 | (temp1 << 8);
+        pRef += srcPitch;
+        pOut += predPitch;
+
+    }
+    return;
+}
+void eChromaVerticalMC2_SIMD(uint8 *pRef, int srcPitch, int dx, int dy,
+                             uint8 *pOut, int predPitch, int blkwidth, int blkheight)
+{
+    (void)(dx);
+    (void)(blkwidth);
+
+    int32 r0, r1, result;
+    int i;
+    int dy_8 = 8 - dy;
+    r0 = pRef[0] | (pRef[1] << 16);
+    pRef += srcPitch;
+    for (i = 0; i < blkheight; i++)
+    {
+        result = dy_8 * r0 + 0x00040004;
+        r1 = pRef[0] | (pRef[1] << 16);
+        result += dy * r1;
+        result >>= 3;
+        result &= 0x00FF00FF;
+        *(int16 *)pOut = (result >> 8) | (result & 0xFF);
+        r0 = r1;
+        pRef += srcPitch;
+        pOut += predPitch;
+    }
+    return;
+}
+
+void eChromaFullMC_SIMD(uint8 *pRef, int srcPitch, int dx, int dy,
+                        uint8 *pOut, int predPitch, int blkwidth, int blkheight)
+{
+    (void)(dx);
+    (void)(dy);
+
+    int i, j;
+    int offset_in = srcPitch - blkwidth;
+    int offset_out = predPitch - blkwidth;
+    uint16 temp;
+    uint8 byte;
+
+    if (((uint32)pRef)&1)
+    {
+        for (j = blkheight; j > 0; j--)
+        {
+            for (i = blkwidth; i > 0; i -= 2)
+            {
+                temp = *pRef++;
+                byte = *pRef++;
+                temp |= (byte << 8);
+                *((uint16*)pOut) = temp; /* write 2 bytes */
+                pOut += 2;
+            }
+            pOut += offset_out;
+            pRef += offset_in;
+        }
+    }
+    else
+    {
+        for (j = blkheight; j > 0; j--)
+        {
+            for (i = blkwidth; i > 0; i -= 2)
+            {
+                temp = *((uint16*)pRef);
+                *((uint16*)pOut) = temp;
+                pRef += 2;
+                pOut += 2;
+            }
+            pOut += offset_out;
+            pRef += offset_in;
+        }
+    }
+    return ;
+}
diff --git a/media/libstagefright/codecs/avc/enc/src/motion_est.cpp b/media/libstagefright/codecs/avc/enc/src/motion_est.cpp
new file mode 100644
index 0000000..f650ef9
--- /dev/null
+++ b/media/libstagefright/codecs/avc/enc/src/motion_est.cpp
@@ -0,0 +1,1774 @@
+/* ------------------------------------------------------------------
+ * Copyright (C) 1998-2009 PacketVideo
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
+ * express or implied.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ * -------------------------------------------------------------------
+ */
+#include "avcenc_lib.h"
+
+#define MIN_GOP     1   /* minimum size of GOP, 1/23/01, need to be tested */
+
+#define DEFAULT_REF_IDX     0  /* always from the first frame in the reflist */
+
+#define ALL_CAND_EQUAL  10  /*  any number greater than 5 will work */
+
+
+/* from TMN 3.2 */
+#define PREF_NULL_VEC 129   /* zero vector bias */
+#define PREF_16_VEC 129     /* 1MV bias versus 4MVs*/
+#define PREF_INTRA  3024//512       /* bias for INTRA coding */
+
+const static int tab_exclude[9][9] =  // [last_loc][curr_loc]
+{
+    {0, 0, 0, 0, 0, 0, 0, 0, 0},
+    {0, 0, 0, 0, 1, 1, 1, 0, 0},
+    {0, 0, 0, 0, 1, 1, 1, 1, 1},
+    {0, 0, 0, 0, 0, 0, 1, 1, 1},
+    {0, 1, 1, 0, 0, 0, 1, 1, 1},
+    {0, 1, 1, 0, 0, 0, 0, 0, 1},
+    {0, 1, 1, 1, 1, 0, 0, 0, 1},
+    {0, 0, 1, 1, 1, 0, 0, 0, 0},
+    {0, 0, 1, 1, 1, 1, 1, 0, 0}
+}; //to decide whether to continue or compute
+
+const static int refine_next[8][2] =    /* [curr_k][increment] */
+{
+    {0, 0}, {2, 0}, {1, 1}, {0, 2}, { -1, 1}, { -2, 0}, { -1, -1}, {0, -2}
+};
+
+#ifdef _SAD_STAT
+uint32 num_MB = 0;
+uint32 num_cand = 0;
+#endif
+
+/************************************************************************/
+#define TH_INTER_2  100  /* temporary for now */
+
+//#define FIXED_INTERPRED_MODE  AVC_P16
+#define FIXED_REF_IDX   0
+#define FIXED_MVX 0
+#define FIXED_MVY 0
+
+// only use when AVC_P8 or AVC_P8ref0
+#define FIXED_SUBMB_MODE    AVC_4x4
+/*************************************************************************/
+
+/* Initialize arrays necessary for motion search */
+AVCEnc_Status InitMotionSearchModule(AVCHandle *avcHandle)
+{
+    AVCEncObject *encvid = (AVCEncObject*) avcHandle->AVCObject;
+    AVCRateControl *rateCtrl = encvid->rateCtrl;
+    int search_range = rateCtrl->mvRange;
+    int number_of_subpel_positions = 4 * (2 * search_range + 3);
+    int max_mv_bits, max_mvd;
+    int temp_bits = 0;
+    uint8 *mvbits;
+    int bits, imax, imin, i;
+    uint8* subpel_pred = (uint8*) encvid->subpel_pred; // all 16 sub-pel positions
+
+
+    while (number_of_subpel_positions > 0)
+    {
+        temp_bits++;
+        number_of_subpel_positions >>= 1;
+    }
+
+    max_mv_bits = 3 + 2 * temp_bits;
+    max_mvd  = (1 << (max_mv_bits >> 1)) - 1;
+
+    encvid->mvbits_array = (uint8*) avcHandle->CBAVC_Malloc(encvid->avcHandle->userData,
+                           sizeof(uint8) * (2 * max_mvd + 1), DEFAULT_ATTR);
+
+    if (encvid->mvbits_array == NULL)
+    {
+        return AVCENC_MEMORY_FAIL;
+    }
+
+    mvbits = encvid->mvbits  = encvid->mvbits_array + max_mvd;
+
+    mvbits[0] = 1;
+    for (bits = 3; bits <= max_mv_bits; bits += 2)
+    {
+        imax = 1    << (bits >> 1);
+        imin = imax >> 1;
+
+        for (i = imin; i < imax; i++)   mvbits[-i] = mvbits[i] = bits;
+    }
+
+    /* initialize half-pel search */
+    encvid->hpel_cand[0] = subpel_pred + REF_CENTER;
+    encvid->hpel_cand[1] = subpel_pred + V2Q_H0Q * SUBPEL_PRED_BLK_SIZE + 1 ;
+    encvid->hpel_cand[2] = subpel_pred + V2Q_H2Q * SUBPEL_PRED_BLK_SIZE + 1;
+    encvid->hpel_cand[3] = subpel_pred + V0Q_H2Q * SUBPEL_PRED_BLK_SIZE + 25;
+    encvid->hpel_cand[4] = subpel_pred + V2Q_H2Q * SUBPEL_PRED_BLK_SIZE + 25;
+    encvid->hpel_cand[5] = subpel_pred + V2Q_H0Q * SUBPEL_PRED_BLK_SIZE + 25;
+    encvid->hpel_cand[6] = subpel_pred + V2Q_H2Q * SUBPEL_PRED_BLK_SIZE + 24;
+    encvid->hpel_cand[7] = subpel_pred + V0Q_H2Q * SUBPEL_PRED_BLK_SIZE + 24;
+    encvid->hpel_cand[8] = subpel_pred + V2Q_H2Q * SUBPEL_PRED_BLK_SIZE;
+
+    /* For quarter-pel interpolation around best half-pel result */
+
+    encvid->bilin_base[0][0] = subpel_pred + V2Q_H2Q * SUBPEL_PRED_BLK_SIZE;
+    encvid->bilin_base[0][1] = subpel_pred + V2Q_H0Q * SUBPEL_PRED_BLK_SIZE + 1;
+    encvid->bilin_base[0][2] = subpel_pred + V0Q_H2Q * SUBPEL_PRED_BLK_SIZE + 24;
+    encvid->bilin_base[0][3] = subpel_pred + REF_CENTER;
+
+
+    encvid->bilin_base[1][0] = subpel_pred + V0Q_H2Q * SUBPEL_PRED_BLK_SIZE;
+    encvid->bilin_base[1][1] = subpel_pred + REF_CENTER - 24;
+    encvid->bilin_base[1][2] = subpel_pred + V2Q_H2Q * SUBPEL_PRED_BLK_SIZE;
+    encvid->bilin_base[1][3] = subpel_pred + V2Q_H0Q * SUBPEL_PRED_BLK_SIZE + 1;
+
+    encvid->bilin_base[2][0] = subpel_pred + REF_CENTER - 24;
+    encvid->bilin_base[2][1] = subpel_pred + V0Q_H2Q * SUBPEL_PRED_BLK_SIZE + 1;
+    encvid->bilin_base[2][2] = subpel_pred + V2Q_H0Q * SUBPEL_PRED_BLK_SIZE + 1;
+    encvid->bilin_base[2][3] = subpel_pred + V2Q_H2Q * SUBPEL_PRED_BLK_SIZE + 1;
+
+    encvid->bilin_base[3][0] = subpel_pred + V2Q_H0Q * SUBPEL_PRED_BLK_SIZE + 1;
+    encvid->bilin_base[3][1] = subpel_pred + V2Q_H2Q * SUBPEL_PRED_BLK_SIZE + 1;
+    encvid->bilin_base[3][2] = subpel_pred + REF_CENTER;
+    encvid->bilin_base[3][3] = subpel_pred + V0Q_H2Q * SUBPEL_PRED_BLK_SIZE + 25;
+
+    encvid->bilin_base[4][0] = subpel_pred + REF_CENTER;
+    encvid->bilin_base[4][1] = subpel_pred + V0Q_H2Q * SUBPEL_PRED_BLK_SIZE + 25;
+    encvid->bilin_base[4][2] = subpel_pred + V2Q_H0Q * SUBPEL_PRED_BLK_SIZE + 25;
+    encvid->bilin_base[4][3] = subpel_pred + V2Q_H2Q * SUBPEL_PRED_BLK_SIZE + 25;
+
+    encvid->bilin_base[5][0] = subpel_pred + V0Q_H2Q * SUBPEL_PRED_BLK_SIZE + 24;
+    encvid->bilin_base[5][1] = subpel_pred + REF_CENTER;
+    encvid->bilin_base[5][2] = subpel_pred + V2Q_H2Q * SUBPEL_PRED_BLK_SIZE + 24;
+    encvid->bilin_base[5][3] = subpel_pred + V2Q_H0Q * SUBPEL_PRED_BLK_SIZE + 25;
+
+    encvid->bilin_base[6][0] = subpel_pred + REF_CENTER - 1;
+    encvid->bilin_base[6][1] = subpel_pred + V0Q_H2Q * SUBPEL_PRED_BLK_SIZE + 24;
+    encvid->bilin_base[6][2] = subpel_pred + V2Q_H0Q * SUBPEL_PRED_BLK_SIZE + 24;
+    encvid->bilin_base[6][3] = subpel_pred + V2Q_H2Q * SUBPEL_PRED_BLK_SIZE + 24;
+
+    encvid->bilin_base[7][0] = subpel_pred + V2Q_H0Q * SUBPEL_PRED_BLK_SIZE;
+    encvid->bilin_base[7][1] = subpel_pred + V2Q_H2Q * SUBPEL_PRED_BLK_SIZE;
+    encvid->bilin_base[7][2] = subpel_pred + REF_CENTER - 1;
+    encvid->bilin_base[7][3] = subpel_pred + V0Q_H2Q * SUBPEL_PRED_BLK_SIZE + 24;
+
+    encvid->bilin_base[8][0] = subpel_pred + REF_CENTER - 25;
+    encvid->bilin_base[8][1] = subpel_pred + V0Q_H2Q * SUBPEL_PRED_BLK_SIZE;
+    encvid->bilin_base[8][2] = subpel_pred + V2Q_H0Q * SUBPEL_PRED_BLK_SIZE;
+    encvid->bilin_base[8][3] = subpel_pred + V2Q_H2Q * SUBPEL_PRED_BLK_SIZE;
+
+
+    return AVCENC_SUCCESS;
+}
+
+/* Clean-up memory */
+void CleanMotionSearchModule(AVCHandle *avcHandle)
+{
+    AVCEncObject *encvid = (AVCEncObject*) avcHandle->AVCObject;
+
+    if (encvid->mvbits_array)
+    {
+        avcHandle->CBAVC_Free(avcHandle->userData, (int)(encvid->mvbits_array));
+        encvid->mvbits = NULL;
+    }
+
+    return ;
+}
+
+
+bool IntraDecisionABE(int *min_cost, uint8 *cur, int pitch, bool ave)
+{
+    int j;
+    uint8 *out;
+    int temp, SBE;
+    OsclFloat ABE;
+    bool intra = true;
+
+    SBE = 0;
+    /* top neighbor */
+    out = cur - pitch;
+    for (j = 0; j < 16; j++)
+    {
+        temp = out[j] - cur[j];
+        SBE += ((temp >= 0) ? temp : -temp);
+    }
+
+    /* left neighbor */
+    out = cur - 1;
+    out -= pitch;
+    cur -= pitch;
+    for (j = 0; j < 16; j++)
+    {
+        temp = *(out += pitch) - *(cur += pitch);
+        SBE += ((temp >= 0) ? temp : -temp);
+    }
+
+    /* compare mincost/384 and SBE/64 */
+    ABE = SBE / 32.0; //ABE = SBE/64.0; //
+    if (ABE >= *min_cost / 256.0) //if( ABE*0.8 >= min_cost/384.0) //
+    {
+        intra = false; // no possibility of intra, just use inter
+    }
+    else
+    {
+        if (ave == true)
+        {
+            *min_cost = (*min_cost + (int)(SBE * 8)) >> 1; // possibility of intra, averaging the cost
+        }
+        else
+        {
+            *min_cost = (int)(SBE * 8);
+        }
+    }
+
+    return intra;
+}
+
+/******* main function for macroblock prediction for the entire frame ***/
+/* if turns out to be IDR frame, set video->nal_unit_type to AVC_NALTYPE_IDR */
+void AVCMotionEstimation(AVCEncObject *encvid)
+{
+    AVCCommonObj *video = encvid->common;
+    int slice_type = video->slice_type;
+    AVCFrameIO *currInput = encvid->currInput;
+    AVCPictureData *refPic = video->RefPicList0[0];
+    int i, j, k;
+    int mbwidth = video->PicWidthInMbs;
+    int mbheight = video->PicHeightInMbs;
+    int totalMB = video->PicSizeInMbs;
+    int pitch = currInput->pitch;
+    AVCMacroblock *currMB, *mblock = video->mblock;
+    AVCMV *mot_mb_16x16, *mot16x16 = encvid->mot16x16;
+    // AVCMV *mot_mb_16x8, *mot_mb_8x16, *mot_mb_8x8, etc;
+    AVCRateControl *rateCtrl = encvid->rateCtrl;
+    uint8 *intraSearch = encvid->intraSearch;
+    uint FS_en = encvid->fullsearch_enable;
+
+    int NumIntraSearch, start_i, numLoop, incr_i;
+    int mbnum, offset;
+    uint8 *cur, *best_cand[5];
+    int totalSAD = 0;   /* average SAD for rate control */
+    int type_pred;
+    int abe_cost;
+
+#ifdef HTFM
+    /***** HYPOTHESIS TESTING ********/  /* 2/28/01 */
+    int collect = 0;
+    HTFM_Stat htfm_stat;
+    double newvar[16];
+    double exp_lamda[15];
+    /*********************************/
+#endif
+    int hp_guess = 0;
+    uint32 mv_uint32;
+
+    offset = 0;
+
+    if (slice_type == AVC_I_SLICE)
+    {
+        /* cannot do I16 prediction here because it needs full decoding. */
+        for (i = 0; i < totalMB; i++)
+        {
+            encvid->min_cost[i] = 0x7FFFFFFF;  /* max value for int */
+        }
+
+        memset(intraSearch, 1, sizeof(uint8)*totalMB);
+
+        encvid->firstIntraRefreshMBIndx = 0; /* reset this */
+
+        return ;
+    }
+    else   // P_SLICE
+    {
+        for (i = 0; i < totalMB; i++)
+        {
+            mblock[i].mb_intra = 0;
+        }
+        memset(intraSearch, 1, sizeof(uint8)*totalMB);
+    }
+
+    if (refPic->padded == 0)
+    {
+        AVCPaddingEdge(refPic);
+        refPic->padded = 1;
+    }
+    /* Random INTRA update */
+    if (rateCtrl->intraMBRate)
+    {
+        AVCRasterIntraUpdate(encvid, mblock, totalMB, rateCtrl->intraMBRate);
+    }
+
+    encvid->sad_extra_info = NULL;
+#ifdef HTFM
+    /***** HYPOTHESIS TESTING ********/
+    InitHTFM(video, &htfm_stat, newvar, &collect);
+    /*********************************/
+#endif
+
+    if ((rateCtrl->scdEnable == 1)
+            && ((rateCtrl->frame_rate < 5.0) || (video->sliceHdr->frame_num > MIN_GOP)))
+        /* do not try to detect a new scene if low frame rate and too close to previous I-frame */
+    {
+        incr_i = 2;
+        numLoop = 2;
+        start_i = 1;
+        type_pred = 0; /* for initial candidate selection */
+    }
+    else
+    {
+        incr_i = 1;
+        numLoop = 1;
+        start_i = 0;
+        type_pred = 2;
+    }
+
+    /* First pass, loop thru half the macroblock */
+    /* determine scene change */
+    /* Second pass, for the rest of macroblocks */
+    NumIntraSearch = 0; // to be intra searched in the encoding loop.
+    while (numLoop--)
+    {
+        for (j = 0; j < mbheight; j++)
+        {
+            if (incr_i > 1)
+                start_i = (start_i == 0 ? 1 : 0) ; /* toggle 0 and 1 */
+
+            offset = pitch * (j << 4) + (start_i << 4);
+
+            mbnum = j * mbwidth + start_i;
+
+            for (i = start_i; i < mbwidth; i += incr_i)
+            {
+                video->mbNum = mbnum;
+                video->currMB = currMB = mblock + mbnum;
+                mot_mb_16x16 = mot16x16 + mbnum;
+
+                cur = currInput->YCbCr[0] + offset;
+
+                if (currMB->mb_intra == 0) /* for INTER mode */
+                {
+#if defined(HTFM)
+                    HTFMPrepareCurMB_AVC(encvid, &htfm_stat, cur, pitch);
+#else
+                    AVCPrepareCurMB(encvid, cur, pitch);
+#endif
+                    /************************************************************/
+                    /******** full-pel 1MV search **********************/
+
+                    AVCMBMotionSearch(encvid, cur, best_cand, i << 4, j << 4, type_pred,
+                                      FS_en, &hp_guess);
+
+                    abe_cost = encvid->min_cost[mbnum] = mot_mb_16x16->sad;
+
+                    /* set mbMode and MVs */
+                    currMB->mbMode = AVC_P16;
+                    currMB->MBPartPredMode[0][0] = AVC_Pred_L0;
+                    mv_uint32 = ((mot_mb_16x16->y) << 16) | ((mot_mb_16x16->x) & 0xffff);
+                    for (k = 0; k < 32; k += 2)
+                    {
+                        currMB->mvL0[k>>1] = mv_uint32;
+                    }
+
+                    /* make a decision whether it should be tested for intra or not */
+                    if (i != mbwidth - 1 && j != mbheight - 1 && i != 0 && j != 0)
+                    {
+                        if (false == IntraDecisionABE(&abe_cost, cur, pitch, true))
+                        {
+                            intraSearch[mbnum] = 0;
+                        }
+                        else
+                        {
+                            NumIntraSearch++;
+                            rateCtrl->MADofMB[mbnum] = abe_cost;
+                        }
+                    }
+                    else // boundary MBs, always do intra search
+                    {
+                        NumIntraSearch++;
+                    }
+
+                    totalSAD += (int) rateCtrl->MADofMB[mbnum];//mot_mb_16x16->sad;
+                }
+                else    /* INTRA update, use for prediction */
+                {
+                    mot_mb_16x16[0].x = mot_mb_16x16[0].y = 0;
+
+                    /* reset all other MVs to zero */
+                    /* mot_mb_16x8, mot_mb_8x16, mot_mb_8x8, etc. */
+                    abe_cost = encvid->min_cost[mbnum] = 0x7FFFFFFF;  /* max value for int */
+
+                    if (i != mbwidth - 1 && j != mbheight - 1 && i != 0 && j != 0)
+                    {
+                        IntraDecisionABE(&abe_cost, cur, pitch, false);
+
+                        rateCtrl->MADofMB[mbnum] = abe_cost;
+                        totalSAD += abe_cost;
+                    }
+
+                    NumIntraSearch++ ;
+                    /* cannot do I16 prediction here because it needs full decoding. */
+                    // intraSearch[mbnum] = 1;
+
+                }
+
+                mbnum += incr_i;
+                offset += (incr_i << 4);
+
+            } /* for i */
+        } /* for j */
+
+        /* since we cannot do intra/inter decision here, the SCD has to be
+        based on other criteria such as motion vectors coherency or the SAD */
+        if (incr_i > 1 && numLoop) /* scene change on and first loop */
+        {
+            //if(NumIntraSearch > ((totalMB>>3)<<1) + (totalMB>>3)) /* 75% of 50%MBs */
+            if (NumIntraSearch*99 > (48*totalMB)) /* 20% of 50%MBs */
+                /* need to do more investigation about this threshold since the NumIntraSearch
+                only show potential intra MBs, not the actual one */
+            {
+                /* we can choose to just encode I_SLICE without IDR */
+                //video->nal_unit_type = AVC_NALTYPE_IDR;
+                video->nal_unit_type = AVC_NALTYPE_SLICE;
+                video->sliceHdr->slice_type = AVC_I_ALL_SLICE;
+                video->slice_type = AVC_I_SLICE;
+                memset(intraSearch, 1, sizeof(uint8)*totalMB);
+                i = totalMB;
+                while (i--)
+                {
+                    mblock[i].mb_intra = 1;
+                    encvid->min_cost[i] = 0x7FFFFFFF;  /* max value for int */
+                }
+
+                rateCtrl->totalSAD = totalSAD * 2;  /* SAD */
+
+                return ;
+            }
+        }
+        /******** no scene change, continue motion search **********************/
+        start_i = 0;
+        type_pred++; /* second pass */
+    }
+
+    rateCtrl->totalSAD = totalSAD;  /* SAD */
+
+#ifdef HTFM
+    /***** HYPOTHESIS TESTING ********/
+    if (collect)
+    {
+        collect = 0;
+        UpdateHTFM(encvid, newvar, exp_lamda, &htfm_stat);
+    }
+    /*********************************/
+#endif
+
+    return ;
+}
+
+/*=====================================================================
+    Function:   PaddingEdge
+    Date:       09/16/2000
+    Purpose:    Pad edge of a Vop
+=====================================================================*/
+
+void  AVCPaddingEdge(AVCPictureData *refPic)
+{
+    uint8 *src, *dst;
+    int i;
+    int pitch, width, height;
+    uint32 temp1, temp2;
+
+    width = refPic->width;
+    height = refPic->height;
+    pitch = refPic->pitch;
+
+    /* pad top */
+    src = refPic->Sl;
+
+    temp1 = *src; /* top-left corner */
+    temp2 = src[width-1]; /* top-right corner */
+    temp1 |= (temp1 << 8);
+    temp1 |= (temp1 << 16);
+    temp2 |= (temp2 << 8);
+    temp2 |= (temp2 << 16);
+
+    dst = src - (pitch << 4);
+
+    *((uint32*)(dst - 16)) = temp1;
+    *((uint32*)(dst - 12)) = temp1;
+    *((uint32*)(dst - 8)) = temp1;
+    *((uint32*)(dst - 4)) = temp1;
+
+    memcpy(dst, src, width);
+
+    *((uint32*)(dst += width)) = temp2;
+    *((uint32*)(dst + 4)) = temp2;
+    *((uint32*)(dst + 8)) = temp2;
+    *((uint32*)(dst + 12)) = temp2;
+
+    dst = dst - width - 16;
+
+    i = 15;
+    while (i--)
+    {
+        memcpy(dst + pitch, dst, pitch);
+        dst += pitch;
+    }
+
+    /* pad sides */
+    dst += (pitch + 16);
+    src = dst;
+    i = height;
+    while (i--)
+    {
+        temp1 = *src;
+        temp2 = src[width-1];
+        temp1 |= (temp1 << 8);
+        temp1 |= (temp1 << 16);
+        temp2 |= (temp2 << 8);
+        temp2 |= (temp2 << 16);
+
+        *((uint32*)(dst - 16)) = temp1;
+        *((uint32*)(dst - 12)) = temp1;
+        *((uint32*)(dst - 8)) = temp1;
+        *((uint32*)(dst - 4)) = temp1;
+
+        *((uint32*)(dst += width)) = temp2;
+        *((uint32*)(dst + 4)) = temp2;
+        *((uint32*)(dst + 8)) = temp2;
+        *((uint32*)(dst + 12)) = temp2;
+
+        src += pitch;
+        dst = src;
+    }
+
+    /* pad bottom */
+    dst -= 16;
+    i = 16;
+    while (i--)
+    {
+        memcpy(dst, dst - pitch, pitch);
+        dst += pitch;
+    }
+
+
+    return ;
+}
+
+/*===========================================================================
+    Function:   AVCRasterIntraUpdate
+    Date:       2/26/01
+    Purpose:    To raster-scan assign INTRA-update .
+                N macroblocks are updated (also was programmable).
+===========================================================================*/
+void AVCRasterIntraUpdate(AVCEncObject *encvid, AVCMacroblock *mblock, int totalMB, int numRefresh)
+{
+    int indx, i;
+
+    indx = encvid->firstIntraRefreshMBIndx;
+    for (i = 0; i < numRefresh && indx < totalMB; i++)
+    {
+        (mblock + indx)->mb_intra = 1;
+        encvid->intraSearch[indx++] = 1;
+    }
+
+    /* if read the end of frame, reset and loop around */
+    if (indx >= totalMB - 1)
+    {
+        indx = 0;
+        while (i < numRefresh && indx < totalMB)
+        {
+            (mblock + indx)->mb_intra = 1;
+            encvid->intraSearch[indx++] = 1;
+            i++;
+        }
+    }
+
+    encvid->firstIntraRefreshMBIndx = indx; /* update with a new value */
+
+    return ;
+}
+
+
+#ifdef HTFM
+void InitHTFM(VideoEncData *encvid, HTFM_Stat *htfm_stat, double *newvar, int *collect)
+{
+    AVCCommonObj *video = encvid->common;
+    int i;
+    int lx = video->currPic->width; // padding
+    int lx2 = lx << 1;
+    int lx3 = lx2 + lx;
+    int rx = video->currPic->pitch;
+    int rx2 = rx << 1;
+    int rx3 = rx2 + rx;
+
+    int *offset, *offset2;
+
+    /* 4/11/01, collect data every 30 frames, doesn't have to be base layer */
+    if (((int)video->sliceHdr->frame_num) % 30 == 1)
+    {
+
+        *collect = 1;
+
+        htfm_stat->countbreak = 0;
+        htfm_stat->abs_dif_mad_avg = 0;
+
+        for (i = 0; i < 16; i++)
+        {
+            newvar[i] = 0.0;
+        }
+//      encvid->functionPointer->SAD_MB_PADDING = &SAD_MB_PADDING_HTFM_Collect;
+        encvid->functionPointer->SAD_Macroblock = &SAD_MB_HTFM_Collect;
+        encvid->functionPointer->SAD_MB_HalfPel[0] = NULL;
+        encvid->functionPointer->SAD_MB_HalfPel[1] = &SAD_MB_HP_HTFM_Collectxh;
+        encvid->functionPointer->SAD_MB_HalfPel[2] = &SAD_MB_HP_HTFM_Collectyh;
+        encvid->functionPointer->SAD_MB_HalfPel[3] = &SAD_MB_HP_HTFM_Collectxhyh;
+        encvid->sad_extra_info = (void*)(htfm_stat);
+        offset = htfm_stat->offsetArray;
+        offset2 = htfm_stat->offsetRef;
+    }
+    else
+    {
+//      encvid->functionPointer->SAD_MB_PADDING = &SAD_MB_PADDING_HTFM;
+        encvid->functionPointer->SAD_Macroblock = &SAD_MB_HTFM;
+        encvid->functionPointer->SAD_MB_HalfPel[0] = NULL;
+        encvid->functionPointer->SAD_MB_HalfPel[1] = &SAD_MB_HP_HTFMxh;
+        encvid->functionPointer->SAD_MB_HalfPel[2] = &SAD_MB_HP_HTFMyh;
+        encvid->functionPointer->SAD_MB_HalfPel[3] = &SAD_MB_HP_HTFMxhyh;
+        encvid->sad_extra_info = (void*)(encvid->nrmlz_th);
+        offset = encvid->nrmlz_th + 16;
+        offset2 = encvid->nrmlz_th + 32;
+    }
+
+    offset[0] = 0;
+    offset[1] = lx2 + 2;
+    offset[2] = 2;
+    offset[3] = lx2;
+    offset[4] = lx + 1;
+    offset[5] = lx3 + 3;
+    offset[6] = lx + 3;
+    offset[7] = lx3 + 1;
+    offset[8] = lx;
+    offset[9] = lx3 + 2;
+    offset[10] = lx3 ;
+    offset[11] = lx + 2 ;
+    offset[12] = 1;
+    offset[13] = lx2 + 3;
+    offset[14] = lx2 + 1;
+    offset[15] = 3;
+
+    offset2[0] = 0;
+    offset2[1] = rx2 + 2;
+    offset2[2] = 2;
+    offset2[3] = rx2;
+    offset2[4] = rx + 1;
+    offset2[5] = rx3 + 3;
+    offset2[6] = rx + 3;
+    offset2[7] = rx3 + 1;
+    offset2[8] = rx;
+    offset2[9] = rx3 + 2;
+    offset2[10] = rx3 ;
+    offset2[11] = rx + 2 ;
+    offset2[12] = 1;
+    offset2[13] = rx2 + 3;
+    offset2[14] = rx2 + 1;
+    offset2[15] = 3;
+
+    return ;
+}
+
+void UpdateHTFM(AVCEncObject *encvid, double *newvar, double *exp_lamda, HTFM_Stat *htfm_stat)
+{
+    if (htfm_stat->countbreak == 0)
+        htfm_stat->countbreak = 1;
+
+    newvar[0] = (double)(htfm_stat->abs_dif_mad_avg) / (htfm_stat->countbreak * 16.);
+
+    if (newvar[0] < 0.001)
+    {
+        newvar[0] = 0.001; /* to prevent floating overflow */
+    }
+    exp_lamda[0] =  1 / (newvar[0] * 1.4142136);
+    exp_lamda[1] = exp_lamda[0] * 1.5825;
+    exp_lamda[2] = exp_lamda[0] * 2.1750;
+    exp_lamda[3] = exp_lamda[0] * 3.5065;
+    exp_lamda[4] = exp_lamda[0] * 3.1436;
+    exp_lamda[5] = exp_lamda[0] * 3.5315;
+    exp_lamda[6] = exp_lamda[0] * 3.7449;
+    exp_lamda[7] = exp_lamda[0] * 4.5854;
+    exp_lamda[8] = exp_lamda[0] * 4.6191;
+    exp_lamda[9] = exp_lamda[0] * 5.4041;
+    exp_lamda[10] = exp_lamda[0] * 6.5974;
+    exp_lamda[11] = exp_lamda[0] * 10.5341;
+    exp_lamda[12] = exp_lamda[0] * 10.0719;
+    exp_lamda[13] = exp_lamda[0] * 12.0516;
+    exp_lamda[14] = exp_lamda[0] * 15.4552;
+
+    CalcThreshold(HTFM_Pf, exp_lamda, encvid->nrmlz_th);
+    return ;
+}
+
+
+void CalcThreshold(double pf, double exp_lamda[], int nrmlz_th[])
+{
+    int i;
+    double temp[15];
+    //  printf("\nLamda: ");
+
+    /* parametric PREMODELling */
+    for (i = 0; i < 15; i++)
+    {
+        //    printf("%g ",exp_lamda[i]);
+        if (pf < 0.5)
+            temp[i] = 1 / exp_lamda[i] * M4VENC_LOG(2 * pf);
+        else
+            temp[i] = -1 / exp_lamda[i] * M4VENC_LOG(2 * (1 - pf));
+    }
+
+    nrmlz_th[15] = 0;
+    for (i = 0; i < 15; i++)        /* scale upto no.pixels */
+        nrmlz_th[i] = (int)(temp[i] * ((i + 1) << 4) + 0.5);
+
+    return ;
+}
+
+void    HTFMPrepareCurMB_AVC(AVCEncObject *encvid, HTFM_Stat *htfm_stat, uint8 *cur, int pitch)
+{
+    AVCCommonObj *video = encvid->common;
+    uint32 *htfmMB = (uint32*)(encvid->currYMB);
+    uint8 *ptr, byte;
+    int *offset;
+    int i;
+    uint32 word;
+
+    if (((int)video->sliceHdr->frame_num) % 30 == 1)
+    {
+        offset = htfm_stat->offsetArray;
+    }
+    else
+    {
+        offset = encvid->nrmlz_th + 16;
+    }
+
+    for (i = 0; i < 16; i++)
+    {
+        ptr = cur + offset[i];
+        word = ptr[0];
+        byte = ptr[4];
+        word |= (byte << 8);
+        byte = ptr[8];
+        word |= (byte << 16);
+        byte = ptr[12];
+        word |= (byte << 24);
+        *htfmMB++ = word;
+
+        word = *(ptr += (pitch << 2));
+        byte = ptr[4];
+        word |= (byte << 8);
+        byte = ptr[8];
+        word |= (byte << 16);
+        byte = ptr[12];
+        word |= (byte << 24);
+        *htfmMB++ = word;
+
+        word = *(ptr += (pitch << 2));
+        byte = ptr[4];
+        word |= (byte << 8);
+        byte = ptr[8];
+        word |= (byte << 16);
+        byte = ptr[12];
+        word |= (byte << 24);
+        *htfmMB++ = word;
+
+        word = *(ptr += (pitch << 2));
+        byte = ptr[4];
+        word |= (byte << 8);
+        byte = ptr[8];
+        word |= (byte << 16);
+        byte = ptr[12];
+        word |= (byte << 24);
+        *htfmMB++ = word;
+    }
+
+    return ;
+}
+
+
+#endif // HTFM
+
+void    AVCPrepareCurMB(AVCEncObject *encvid, uint8 *cur, int pitch)
+{
+    void* tmp = (void*)(encvid->currYMB);
+    uint32 *currYMB = (uint32*) tmp;
+    int i;
+
+    cur -= pitch;
+
+    for (i = 0; i < 16; i++)
+    {
+        *currYMB++ = *((uint32*)(cur += pitch));
+        *currYMB++ = *((uint32*)(cur + 4));
+        *currYMB++ = *((uint32*)(cur + 8));
+        *currYMB++ = *((uint32*)(cur + 12));
+    }
+
+    return ;
+}
+
+#ifdef FIXED_INTERPRED_MODE
+
+/* due to the complexity of the predicted motion vector, we may not decide to skip
+a macroblock here just yet. */
+/* We will find the best motion vector and the best intra prediction mode for each block. */
+/* output are
+    currMB->NumMbPart,  currMB->MbPartWidth, currMB->MbPartHeight,
+    currMB->NumSubMbPart[], currMB->SubMbPartWidth[], currMB->SubMbPartHeight,
+    currMB->MBPartPredMode[][] (L0 or L1 or BiPred)
+    currMB->RefIdx[], currMB->ref_idx_L0[],
+    currMB->mvL0[], currMB->mvL1[]
+    */
+
+AVCEnc_Status AVCMBMotionSearch(AVCEncObject *encvid, AVCMacroblock *currMB, int mbNum,
+                                int num_pass)
+{
+    AVCCommonObj *video = encvid->common;
+    int mbPartIdx, subMbPartIdx;
+    int16 *mv;
+    int i;
+    int SubMbPartHeight, SubMbPartWidth, NumSubMbPart;
+
+    /* assign value to currMB->MBPartPredMode[][x],subMbMode[],NumSubMbPart[],SubMbPartWidth[],SubMbPartHeight[] */
+
+    currMB->mbMode = FIXED_INTERPRED_MODE;
+    currMB->mb_intra = 0;
+
+    if (currMB->mbMode == AVC_P16)
+    {
+        currMB->NumMbPart = 1;
+        currMB->MbPartWidth = 16;
+        currMB->MbPartHeight = 16;
+        currMB->SubMbPartHeight[0] = 16;
+        currMB->SubMbPartWidth[0] = 16;
+        currMB->NumSubMbPart[0] =  1;
+    }
+    else if (currMB->mbMode == AVC_P16x8)
+    {
+        currMB->NumMbPart = 2;
+        currMB->MbPartWidth = 16;
+        currMB->MbPartHeight = 8;
+        for (i = 0; i < 2; i++)
+        {
+            currMB->SubMbPartWidth[i] = 16;
+            currMB->SubMbPartHeight[i] = 8;
+            currMB->NumSubMbPart[i] = 1;
+        }
+    }
+    else if (currMB->mbMode == AVC_P8x16)
+    {
+        currMB->NumMbPart = 2;
+        currMB->MbPartWidth = 8;
+        currMB->MbPartHeight = 16;
+        for (i = 0; i < 2; i++)
+        {
+            currMB->SubMbPartWidth[i] = 8;
+            currMB->SubMbPartHeight[i] = 16;
+            currMB->NumSubMbPart[i] = 1;
+        }
+    }
+    else if (currMB->mbMode == AVC_P8 || currMB->mbMode == AVC_P8ref0)
+    {
+        currMB->NumMbPart = 4;
+        currMB->MbPartWidth = 8;
+        currMB->MbPartHeight = 8;
+        if (FIXED_SUBMB_MODE == AVC_8x8)
+        {
+            SubMbPartHeight = 8;
+            SubMbPartWidth = 8;
+            NumSubMbPart = 1;
+        }
+        else if (FIXED_SUBMB_MODE == AVC_8x4)
+        {
+            SubMbPartHeight = 4;
+            SubMbPartWidth = 8;
+            NumSubMbPart = 2;
+        }
+        else if (FIXED_SUBMB_MODE == AVC_4x8)
+        {
+            SubMbPartHeight = 8;
+            SubMbPartWidth = 4;
+            NumSubMbPart = 2;
+        }
+        else if (FIXED_SUBMB_MODE == AVC_4x4)
+        {
+            SubMbPartHeight = 4;
+            SubMbPartWidth = 4;
+            NumSubMbPart = 4;
+        }
+
+        for (i = 0; i < 4; i++)
+        {
+            currMB->subMbMode[i] = FIXED_SUBMB_MODE;
+            currMB->SubMbPartHeight[i] = SubMbPartHeight;
+            currMB->SubMbPartWidth[i] = SubMbPartWidth;
+            currMB->NumSubMbPart[i] = NumSubMbPart;
+        }
+    }
+    else /* it's probably intra mode */
+    {
+        return AVCENC_SUCCESS;
+    }
+
+    for (mbPartIdx = 0; mbPartIdx < 4; mbPartIdx++)
+    {
+        currMB->MBPartPredMode[mbPartIdx][0]  = AVC_Pred_L0;
+        currMB->ref_idx_L0[mbPartIdx] = FIXED_REF_IDX;
+        currMB->RefIdx[mbPartIdx] = video->RefPicList0[FIXED_REF_IDX]->RefIdx;
+
+        for (subMbPartIdx = 0; subMbPartIdx < 4; subMbPartIdx++)
+        {
+            mv = (int16*)(currMB->mvL0 + (mbPartIdx << 2) + subMbPartIdx);
+
+            *mv++ = FIXED_MVX;
+            *mv = FIXED_MVY;
+        }
+    }
+
+    encvid->min_cost = 0;
+
+    return AVCENC_SUCCESS;
+}
+
+#else /* perform the search */
+
+/* This option #1 search is very similar to PV's MPEG4 motion search algorithm.
+  The search is done in hierarchical manner from 16x16 MB down to smaller and smaller
+  partition. At each level, a decision can be made to stop the search if the expected
+  prediction gain is not worth the computation. The decision can also be made at the finest
+  level for more fullsearch-like behavior with the price of heavier computation. */
+void AVCMBMotionSearch(AVCEncObject *encvid, uint8 *cur, uint8 *best_cand[],
+                       int i0, int j0, int type_pred, int FS_en, int *hp_guess)
+{
+    AVCCommonObj *video = encvid->common;
+    AVCPictureData *currPic = video->currPic;
+    AVCSeqParamSet *currSPS = video->currSeqParams;
+    AVCRateControl *rateCtrl = encvid->rateCtrl;
+    AVCMacroblock *currMB = video->currMB;
+    uint8 *ref, *cand, *ncand;
+    void *extra_info = encvid->sad_extra_info;
+    int mbnum = video->mbNum;
+    int width = currPic->width; /* 6/12/01, must be multiple of 16 */
+    int height = currPic->height;
+    AVCMV *mot16x16 = encvid->mot16x16;
+    int (*SAD_Macroblock)(uint8*, uint8*, int, void*) = encvid->functionPointer->SAD_Macroblock;
+
+    int range = rateCtrl->mvRange;
+
+    int lx = currPic->pitch; /*  padding */
+    int i, j, imin, jmin, ilow, ihigh, jlow, jhigh;
+    int d, dmin, dn[9];
+    int k;
+    int mvx[5], mvy[5];
+    int num_can, center_again;
+    int last_loc, new_loc = 0;
+    int step, max_step = range >> 1;
+    int next;
+
+    int cmvx, cmvy; /* estimated predicted MV */
+    int lev_idx;
+    int lambda_motion = encvid->lambda_motion;
+    uint8 *mvbits = encvid->mvbits;
+    int mvshift = 2;
+    int mvcost;
+
+    int min_sad = 65535;
+
+    ref = video->RefPicList0[DEFAULT_REF_IDX]->Sl; /* origin of actual frame */
+
+    /* have to initialize these params, necessary for interprediction part */
+    currMB->NumMbPart = 1;
+    currMB->SubMbPartHeight[0] = 16;
+    currMB->SubMbPartWidth[0] = 16;
+    currMB->NumSubMbPart[0] = 1;
+    currMB->ref_idx_L0[0] = currMB->ref_idx_L0[1] =
+                                currMB->ref_idx_L0[2] = currMB->ref_idx_L0[3] = DEFAULT_REF_IDX;
+    currMB->ref_idx_L1[0] = currMB->ref_idx_L1[1] =
+                                currMB->ref_idx_L1[2] = currMB->ref_idx_L1[3] = DEFAULT_REF_IDX;
+    currMB->RefIdx[0] = currMB->RefIdx[1] =
+                            currMB->RefIdx[2] = currMB->RefIdx[3] = video->RefPicList0[DEFAULT_REF_IDX]->RefIdx;
+
+    cur = encvid->currYMB; /* use smaller memory space for current MB */
+
+    /*  find limit of the search (adjusting search range)*/
+    lev_idx = mapLev2Idx[currSPS->level_idc];
+
+    /* we can make this part dynamic based on previous statistics */
+    ilow = i0 - range;
+    if (i0 - ilow > 2047) /* clip to conform with the standard */
+    {
+        ilow = i0 - 2047;
+    }
+    if (ilow < -13)  // change it from -15 to -13 because of 6-tap filter needs extra 2 lines.
+    {
+        ilow = -13;
+    }
+
+    ihigh = i0 + range - 1;
+    if (ihigh - i0 > 2047) /* clip to conform with the standard */
+    {
+        ihigh = i0 + 2047;
+    }
+    if (ihigh > width - 3)
+    {
+        ihigh = width - 3;  // change from width-1 to width-3 for the same reason as above
+    }
+
+    jlow = j0 - range;
+    if (j0 - jlow > MaxVmvR[lev_idx] - 1) /* clip to conform with the standard */
+    {
+        jlow = j0 - MaxVmvR[lev_idx] + 1;
+    }
+    if (jlow < -13)     // same reason as above
+    {
+        jlow = -13;
+    }
+
+    jhigh = j0 + range - 1;
+    if (jhigh - j0 > MaxVmvR[lev_idx] - 1) /* clip to conform with the standard */
+    {
+        jhigh = j0 + MaxVmvR[lev_idx] - 1;
+    }
+    if (jhigh > height - 3) // same reason as above
+    {
+        jhigh = height - 3;
+    }
+
+    /* find initial motion vector & predicted MV*/
+    AVCCandidateSelection(mvx, mvy, &num_can, i0 >> 4, j0 >> 4, encvid, type_pred, &cmvx, &cmvy);
+
+    imin = i0;
+    jmin = j0; /* needed for fullsearch */
+    ncand = ref + i0 + j0 * lx;
+
+    /* for first row of MB, fullsearch can be used */
+    if (FS_en)
+    {
+        *hp_guess = 0; /* no guess for fast half-pel */
+
+        dmin =  AVCFullSearch(encvid, ref, cur, &imin, &jmin, ilow, ihigh, jlow, jhigh, cmvx, cmvy);
+
+        ncand = ref + imin + jmin * lx;
+    }
+    else
+    {   /*       fullsearch the top row to only upto (0,3) MB */
+        /*       upto 30% complexity saving with the same complexity */
+        if (video->PrevRefFrameNum == 0 && j0 == 0 && i0 <= 64 && type_pred != 1)
+        {
+            *hp_guess = 0; /* no guess for fast half-pel */
+            dmin =  AVCFullSearch(encvid, ref, cur, &imin, &jmin, ilow, ihigh, jlow, jhigh, cmvx, cmvy);
+            ncand = ref + imin + jmin * lx;
+        }
+        else
+        {
+            /************** initialize candidate **************************/
+
+            dmin = 65535;
+
+            /* check if all are equal */
+            if (num_can == ALL_CAND_EQUAL)
+            {
+                i = i0 + mvx[0];
+                j = j0 + mvy[0];
+
+                if (i >= ilow && i <= ihigh && j >= jlow && j <= jhigh)
+                {
+                    cand = ref + i + j * lx;
+
+                    d = (*SAD_Macroblock)(cand, cur, (dmin << 16) | lx, extra_info);
+                    mvcost = MV_COST(lambda_motion, mvshift, i - i0, j - j0, cmvx, cmvy);
+                    d +=  mvcost;
+
+                    if (d < dmin)
+                    {
+                        dmin = d;
+                        imin = i;
+                        jmin = j;
+                        ncand = cand;
+                        min_sad = d - mvcost; // for rate control
+                    }
+                }
+            }
+            else
+            {
+                /************** evaluate unique candidates **********************/
+                for (k = 0; k < num_can; k++)
+                {
+                    i = i0 + mvx[k];
+                    j = j0 + mvy[k];
+
+                    if (i >= ilow && i <= ihigh && j >= jlow && j <= jhigh)
+                    {
+                        cand = ref + i + j * lx;
+                        d = (*SAD_Macroblock)(cand, cur, (dmin << 16) | lx, extra_info);
+                        mvcost = MV_COST(lambda_motion, mvshift, i - i0, j - j0, cmvx, cmvy);
+                        d +=  mvcost;
+
+                        if (d < dmin)
+                        {
+                            dmin = d;
+                            imin = i;
+                            jmin = j;
+                            ncand = cand;
+                            min_sad = d - mvcost; // for rate control
+                        }
+                    }
+                }
+            }
+
+            /******************* local refinement ***************************/
+            center_again = 0;
+            last_loc = new_loc = 0;
+            //          ncand = ref + jmin*lx + imin;  /* center of the search */
+            step = 0;
+            dn[0] = dmin;
+            while (!center_again && step <= max_step)
+            {
+
+                AVCMoveNeighborSAD(dn, last_loc);
+
+                center_again = 1;
+                i = imin;
+                j = jmin - 1;
+                cand = ref + i + j * lx;
+
+                /*  starting from [0,-1] */
+                /* spiral check one step at a time*/
+                for (k = 2; k <= 8; k += 2)
+                {
+                    if (!tab_exclude[last_loc][k]) /* exclude last step computation */
+                    {       /* not already computed */
+                        if (i >= ilow && i <= ihigh && j >= jlow && j <= jhigh)
+                        {
+                            d = (*SAD_Macroblock)(cand, cur, (dmin << 16) | lx, extra_info);
+                            mvcost = MV_COST(lambda_motion, mvshift, i - i0, j - j0, cmvx, cmvy);
+                            d += mvcost;
+
+                            dn[k] = d; /* keep it for half pel use */
+
+                            if (d < dmin)
+                            {
+                                ncand = cand;
+                                dmin = d;
+                                imin = i;
+                                jmin = j;
+                                center_again = 0;
+                                new_loc = k;
+                                min_sad = d - mvcost; // for rate control
+                            }
+                        }
+                    }
+                    if (k == 8)  /* end side search*/
+                    {
+                        if (!center_again)
+                        {
+                            k = -1; /* start diagonal search */
+                            cand -= lx;
+                            j--;
+                        }
+                    }
+                    else
+                    {
+                        next = refine_next[k][0];
+                        i += next;
+                        cand += next;
+                        next = refine_next[k][1];
+                        j += next;
+                        cand += lx * next;
+                    }
+                }
+                last_loc = new_loc;
+                step ++;
+            }
+            if (!center_again)
+                AVCMoveNeighborSAD(dn, last_loc);
+
+            *hp_guess = AVCFindMin(dn);
+
+            encvid->rateCtrl->MADofMB[mbnum] = min_sad / 256.0;
+        }
+    }
+
+    mot16x16[mbnum].sad = dmin;
+    mot16x16[mbnum].x = (imin - i0) << 2;
+    mot16x16[mbnum].y = (jmin - j0) << 2;
+    best_cand[0] = ncand;
+
+    if (rateCtrl->subPelEnable) // always enable half-pel search
+    {
+        /* find half-pel resolution motion vector */
+        min_sad = AVCFindHalfPelMB(encvid, cur, mot16x16 + mbnum, best_cand[0], i0, j0, *hp_guess, cmvx, cmvy);
+
+        encvid->rateCtrl->MADofMB[mbnum] = min_sad / 256.0;
+
+
+        if (encvid->best_qpel_pos == -1)
+        {
+            ncand = encvid->hpel_cand[encvid->best_hpel_pos];
+        }
+        else
+        {
+            ncand = encvid->qpel_cand[encvid->best_qpel_pos];
+        }
+    }
+    else
+    {
+        encvid->rateCtrl->MADofMB[mbnum] = min_sad / 256.0;
+    }
+
+    /** do motion comp here for now */
+    ref = currPic->Sl + i0 + j0 * lx;
+    /* copy from the best result to current Picture */
+    for (j = 0; j < 16; j++)
+    {
+        for (i = 0; i < 16; i++)
+        {
+            *ref++ = *ncand++;
+        }
+        ref += (lx - 16);
+        ncand += 8;
+    }
+
+    return ;
+}
+
+#endif
+
+/*===============================================================================
+    Function:   AVCFullSearch
+    Date:       09/16/2000
+    Purpose:    Perform full-search motion estimation over the range of search
+                region in a spiral-outward manner.
+    Input/Output:   VideoEncData, current Vol, previou Vop, pointer to the left corner of
+                current VOP, current coord (also output), boundaries.
+===============================================================================*/
+int AVCFullSearch(AVCEncObject *encvid, uint8 *prev, uint8 *cur,
+                  int *imin, int *jmin, int ilow, int ihigh, int jlow, int jhigh,
+                  int cmvx, int cmvy)
+{
+    int range = encvid->rateCtrl->mvRange;
+    AVCPictureData *currPic = encvid->common->currPic;
+    uint8 *cand;
+    int i, j, k, l;
+    int d, dmin;
+    int i0 = *imin; /* current position */
+    int j0 = *jmin;
+    int (*SAD_Macroblock)(uint8*, uint8*, int, void*) = encvid->functionPointer->SAD_Macroblock;
+    void *extra_info = encvid->sad_extra_info;
+    int lx = currPic->pitch; /* with padding */
+
+    int offset = i0 + j0 * lx;
+
+    int lambda_motion = encvid->lambda_motion;
+    uint8 *mvbits = encvid->mvbits;
+    int mvshift = 2;
+    int mvcost;
+    int min_sad;
+
+    cand = prev + offset;
+
+    dmin  = (*SAD_Macroblock)(cand, cur, (65535 << 16) | lx, (void*)extra_info);
+    mvcost = MV_COST(lambda_motion, mvshift, 0, 0, cmvx, cmvy);
+    min_sad = dmin;
+    dmin += mvcost;
+
+    /* perform spiral search */
+    for (k = 1; k <= range; k++)
+    {
+
+        i = i0 - k;
+        j = j0 - k;
+
+        cand = prev + i + j * lx;
+
+        for (l = 0; l < 8*k; l++)
+        {
+            /* no need for boundary checking again */
+            if (i >= ilow && i <= ihigh && j >= jlow && j <= jhigh)
+            {
+                d = (*SAD_Macroblock)(cand, cur, (dmin << 16) | lx, (void*)extra_info);
+                mvcost = MV_COST(lambda_motion, mvshift, i - i0, j - j0, cmvx, cmvy);
+                d +=  mvcost;
+
+                if (d < dmin)
+                {
+                    dmin = d;
+                    *imin = i;
+                    *jmin = j;
+                    min_sad = d - mvcost;
+                }
+            }
+
+            if (l < (k << 1))
+            {
+                i++;
+                cand++;
+            }
+            else if (l < (k << 2))
+            {
+                j++;
+                cand += lx;
+            }
+            else if (l < ((k << 2) + (k << 1)))
+            {
+                i--;
+                cand--;
+            }
+            else
+            {
+                j--;
+                cand -= lx;
+            }
+        }
+    }
+
+    encvid->rateCtrl->MADofMB[encvid->common->mbNum] = (min_sad / 256.0); // for rate control
+
+    return dmin;
+}
+
+/*===============================================================================
+    Function:   AVCCandidateSelection
+    Date:       09/16/2000
+    Purpose:    Fill up the list of candidate using spatio-temporal correlation
+                among neighboring blocks.
+    Input/Output:   type_pred = 0: first pass, 1: second pass, or no SCD
+    Modified:   , 09/23/01, get rid of redundant candidates before passing back.
+                , 09/11/07, added return for modified predicted MV, this will be
+                    needed for both fast search and fullsearch.
+===============================================================================*/
+
+void AVCCandidateSelection(int *mvx, int *mvy, int *num_can, int imb, int jmb,
+                           AVCEncObject *encvid, int type_pred, int *cmvx, int *cmvy)
+{
+    AVCCommonObj *video = encvid->common;
+    AVCMV *mot16x16 = encvid->mot16x16;
+    AVCMV *pmot;
+    int mbnum = video->mbNum;
+    int mbwidth = video->PicWidthInMbs;
+    int mbheight = video->PicHeightInMbs;
+    int i, j, same, num1;
+
+    /* this part is for predicted MV */
+    int pmvA_x = 0, pmvA_y = 0, pmvB_x = 0, pmvB_y = 0, pmvC_x = 0, pmvC_y = 0;
+    int availA = 0, availB = 0, availC = 0;
+
+    *num_can = 0;
+
+    if (video->PrevRefFrameNum != 0) // previous frame is an IDR frame
+    {
+        /* Spatio-Temporal Candidate (five candidates) */
+        if (type_pred == 0) /* first pass */
+        {
+            pmot = &mot16x16[mbnum]; /* same coordinate previous frame */
+            mvx[(*num_can)] = (pmot->x) >> 2;
+            mvy[(*num_can)++] = (pmot->y) >> 2;
+            if (imb >= (mbwidth >> 1) && imb > 0)  /*left neighbor previous frame */
+            {
+                pmot = &mot16x16[mbnum-1];
+                mvx[(*num_can)] = (pmot->x) >> 2;
+                mvy[(*num_can)++] = (pmot->y) >> 2;
+            }
+            else if (imb + 1 < mbwidth)   /*right neighbor previous frame */
+            {
+                pmot = &mot16x16[mbnum+1];
+                mvx[(*num_can)] = (pmot->x) >> 2;
+                mvy[(*num_can)++] = (pmot->y) >> 2;
+            }
+
+            if (jmb < mbheight - 1)  /*bottom neighbor previous frame */
+            {
+                pmot = &mot16x16[mbnum+mbwidth];
+                mvx[(*num_can)] = (pmot->x) >> 2;
+                mvy[(*num_can)++] = (pmot->y) >> 2;
+            }
+            else if (jmb > 0)   /*upper neighbor previous frame */
+            {
+                pmot = &mot16x16[mbnum-mbwidth];
+                mvx[(*num_can)] = (pmot->x) >> 2;
+                mvy[(*num_can)++] = (pmot->y) >> 2;
+            }
+
+            if (imb > 0 && jmb > 0)  /* upper-left neighbor current frame*/
+            {
+                pmot = &mot16x16[mbnum-mbwidth-1];
+                mvx[(*num_can)] = (pmot->x) >> 2;
+                mvy[(*num_can)++] = (pmot->y) >> 2;
+            }
+            if (jmb > 0 && imb < mbheight - 1)  /* upper right neighbor current frame*/
+            {
+                pmot = &mot16x16[mbnum-mbwidth+1];
+                mvx[(*num_can)] = (pmot->x) >> 2;
+                mvy[(*num_can)++] = (pmot->y) >> 2;
+            }
+        }
+        else    /* second pass */
+            /* original ST1 algorithm */
+        {
+            pmot = &mot16x16[mbnum]; /* same coordinate previous frame */
+            mvx[(*num_can)] = (pmot->x) >> 2;
+            mvy[(*num_can)++] = (pmot->y) >> 2;
+
+            if (imb > 0)  /*left neighbor current frame */
+            {
+                pmot = &mot16x16[mbnum-1];
+                mvx[(*num_can)] = (pmot->x) >> 2;
+                mvy[(*num_can)++] = (pmot->y) >> 2;
+            }
+            if (jmb > 0)  /*upper neighbor current frame */
+            {
+                pmot = &mot16x16[mbnum-mbwidth];
+                mvx[(*num_can)] = (pmot->x) >> 2;
+                mvy[(*num_can)++] = (pmot->y) >> 2;
+            }
+            if (imb < mbwidth - 1)  /*right neighbor previous frame */
+            {
+                pmot = &mot16x16[mbnum+1];
+                mvx[(*num_can)] = (pmot->x) >> 2;
+                mvy[(*num_can)++] = (pmot->y) >> 2;
+            }
+            if (jmb < mbheight - 1)  /*bottom neighbor previous frame */
+            {
+                pmot = &mot16x16[mbnum+mbwidth];
+                mvx[(*num_can)] = (pmot->x) >> 2;
+                mvy[(*num_can)++] = (pmot->y) >> 2;
+            }
+        }
+
+        /* get predicted MV */
+        if (imb > 0)    /* get MV from left (A) neighbor either on current or previous frame */
+        {
+            availA = 1;
+            pmot = &mot16x16[mbnum-1];
+            pmvA_x = pmot->x;
+            pmvA_y = pmot->y;
+        }
+
+        if (jmb > 0) /* get MV from top (B) neighbor either on current or previous frame */
+        {
+            availB = 1;
+            pmot = &mot16x16[mbnum-mbwidth];
+            pmvB_x = pmot->x;
+            pmvB_y = pmot->y;
+
+            availC = 1;
+
+            if (imb < mbwidth - 1) /* get MV from top-right (C) neighbor of current frame */
+            {
+                pmot = &mot16x16[mbnum-mbwidth+1];
+            }
+            else /* get MV from top-left (D) neighbor of current frame */
+            {
+                pmot = &mot16x16[mbnum-mbwidth-1];
+            }
+            pmvC_x = pmot->x;
+            pmvC_y = pmot->y;
+        }
+
+    }
+    else  /* only Spatial Candidate (four candidates)*/
+    {
+        if (type_pred == 0) /*first pass*/
+        {
+            if (imb > 1)  /* neighbor two blocks away to the left */
+            {
+                pmot = &mot16x16[mbnum-2];
+                mvx[(*num_can)] = (pmot->x) >> 2;
+                mvy[(*num_can)++] = (pmot->y) >> 2;
+            }
+            if (imb > 0 && jmb > 0)  /* upper-left neighbor */
+            {
+                pmot = &mot16x16[mbnum-mbwidth-1];
+                mvx[(*num_can)] = (pmot->x) >> 2;
+                mvy[(*num_can)++] = (pmot->y) >> 2;
+            }
+            if (jmb > 0 && imb < mbheight - 1)  /* upper right neighbor */
+            {
+                pmot = &mot16x16[mbnum-mbwidth+1];
+                mvx[(*num_can)] = (pmot->x) >> 2;
+                mvy[(*num_can)++] = (pmot->y) >> 2;
+            }
+
+            /* get predicted MV */
+            if (imb > 1)    /* get MV from 2nd left (A) neighbor either of current frame */
+            {
+                availA = 1;
+                pmot = &mot16x16[mbnum-2];
+                pmvA_x = pmot->x;
+                pmvA_y = pmot->y;
+            }
+
+            if (jmb > 0 && imb > 0) /* get MV from top-left (B) neighbor of current frame */
+            {
+                availB = 1;
+                pmot = &mot16x16[mbnum-mbwidth-1];
+                pmvB_x = pmot->x;
+                pmvB_y = pmot->y;
+            }
+
+            if (jmb > 0 && imb < mbwidth - 1)
+            {
+                availC = 1;
+                pmot = &mot16x16[mbnum-mbwidth+1];
+                pmvC_x = pmot->x;
+                pmvC_y = pmot->y;
+            }
+        }
+//#ifdef SCENE_CHANGE_DETECTION
+        /* second pass (ST2 algorithm)*/
+        else
+        {
+            if (type_pred == 1) /*  4/7/01 */
+            {
+                if (imb > 0)  /*left neighbor current frame */
+                {
+                    pmot = &mot16x16[mbnum-1];
+                    mvx[(*num_can)] = (pmot->x) >> 2;
+                    mvy[(*num_can)++] = (pmot->y) >> 2;
+                }
+                if (jmb > 0)  /*upper neighbor current frame */
+                {
+                    pmot = &mot16x16[mbnum-mbwidth];
+                    mvx[(*num_can)] = (pmot->x) >> 2;
+                    mvy[(*num_can)++] = (pmot->y) >> 2;
+                }
+                if (imb < mbwidth - 1)  /*right neighbor current frame */
+                {
+                    pmot = &mot16x16[mbnum+1];
+                    mvx[(*num_can)] = (pmot->x) >> 2;
+                    mvy[(*num_can)++] = (pmot->y) >> 2;
+                }
+                if (jmb < mbheight - 1)  /*bottom neighbor current frame */
+                {
+                    pmot = &mot16x16[mbnum+mbwidth];
+                    mvx[(*num_can)] = (pmot->x) >> 2;
+                    mvy[(*num_can)++] = (pmot->y) >> 2;
+                }
+            }
+            //#else
+            else /* original ST1 algorithm */
+            {
+                if (imb > 0)  /*left neighbor current frame */
+                {
+                    pmot = &mot16x16[mbnum-1];
+                    mvx[(*num_can)] = (pmot->x) >> 2;
+                    mvy[(*num_can)++] = (pmot->y) >> 2;
+
+                    if (jmb > 0)  /*upper-left neighbor current frame */
+                    {
+                        pmot = &mot16x16[mbnum-mbwidth-1];
+                        mvx[(*num_can)] = (pmot->x) >> 2;
+                        mvy[(*num_can)++] = (pmot->y) >> 2;
+                    }
+
+                }
+                if (jmb > 0)  /*upper neighbor current frame */
+                {
+                    pmot = &mot16x16[mbnum-mbwidth];
+                    mvx[(*num_can)] = (pmot->x) >> 2;
+                    mvy[(*num_can)++] = (pmot->y) >> 2;
+
+                    if (imb < mbheight - 1)  /*upper-right neighbor current frame */
+                    {
+                        pmot = &mot16x16[mbnum-mbwidth+1];
+                        mvx[(*num_can)] = (pmot->x) >> 2;
+                        mvy[(*num_can)++] = (pmot->y) >> 2;
+                    }
+                }
+            }
+
+            /* get predicted MV */
+            if (imb > 0)    /* get MV from left (A) neighbor either on current or previous frame */
+            {
+                availA = 1;
+                pmot = &mot16x16[mbnum-1];
+                pmvA_x = pmot->x;
+                pmvA_y = pmot->y;
+            }
+
+            if (jmb > 0) /* get MV from top (B) neighbor either on current or previous frame */
+            {
+                availB = 1;
+                pmot = &mot16x16[mbnum-mbwidth];
+                pmvB_x = pmot->x;
+                pmvB_y = pmot->y;
+
+                availC = 1;
+
+                if (imb < mbwidth - 1) /* get MV from top-right (C) neighbor of current frame */
+                {
+                    pmot = &mot16x16[mbnum-mbwidth+1];
+                }
+                else /* get MV from top-left (D) neighbor of current frame */
+                {
+                    pmot = &mot16x16[mbnum-mbwidth-1];
+                }
+                pmvC_x = pmot->x;
+                pmvC_y = pmot->y;
+            }
+        }
+//#endif
+    }
+
+    /*  3/23/01, remove redundant candidate (possible k-mean) */
+    num1 = *num_can;
+    *num_can = 1;
+    for (i = 1; i < num1; i++)
+    {
+        same = 0;
+        j = 0;
+        while (!same && j < *num_can)
+        {
+#if (CANDIDATE_DISTANCE==0)
+            if (mvx[i] == mvx[j] && mvy[i] == mvy[j])
+#else
+            // modified k-mean,  3/24/01, shouldn't be greater than 3
+            if (AVC_ABS(mvx[i] - mvx[j]) + AVC_ABS(mvy[i] - mvy[j]) < CANDIDATE_DISTANCE)
+#endif
+                same = 1;
+            j++;
+        }
+        if (!same)
+        {
+            mvx[*num_can] = mvx[i];
+            mvy[*num_can] = mvy[i];
+            (*num_can)++;
+        }
+    }
+
+    if (num1 == 5 && *num_can == 1)
+        *num_can = ALL_CAND_EQUAL; /* all are equal */
+
+    /* calculate predicted MV */
+
+    if (availA && !(availB || availC))
+    {
+        *cmvx = pmvA_x;
+        *cmvy = pmvA_y;
+    }
+    else
+    {
+        *cmvx = AVC_MEDIAN(pmvA_x, pmvB_x, pmvC_x);
+        *cmvy = AVC_MEDIAN(pmvA_y, pmvB_y, pmvC_y);
+    }
+
+    return ;
+}
+
+
+/*************************************************************
+    Function:   AVCMoveNeighborSAD
+    Date:       3/27/01
+    Purpose:    Move neighboring SAD around when center has shifted
+*************************************************************/
+
+void AVCMoveNeighborSAD(int dn[], int new_loc)
+{
+    int tmp[9];
+    tmp[0] = dn[0];
+    tmp[1] = dn[1];
+    tmp[2] = dn[2];
+    tmp[3] = dn[3];
+    tmp[4] = dn[4];
+    tmp[5] = dn[5];
+    tmp[6] = dn[6];
+    tmp[7] = dn[7];
+    tmp[8] = dn[8];
+    dn[0] = dn[1] = dn[2] = dn[3] = dn[4] = dn[5] = dn[6] = dn[7] = dn[8] = 65536;
+
+    switch (new_loc)
+    {
+        case 0:
+            break;
+        case 1:
+            dn[4] = tmp[2];
+            dn[5] = tmp[0];
+            dn[6] = tmp[8];
+            break;
+        case 2:
+            dn[4] = tmp[3];
+            dn[5] = tmp[4];
+            dn[6] = tmp[0];
+            dn[7] = tmp[8];
+            dn[8] = tmp[1];
+            break;
+        case 3:
+            dn[6] = tmp[4];
+            dn[7] = tmp[0];
+            dn[8] = tmp[2];
+            break;
+        case 4:
+            dn[1] = tmp[2];
+            dn[2] = tmp[3];
+            dn[6] = tmp[5];
+            dn[7] = tmp[6];
+            dn[8] = tmp[0];
+            break;
+        case 5:
+            dn[1] = tmp[0];
+            dn[2] = tmp[4];
+            dn[8] = tmp[6];
+            break;
+        case 6:
+            dn[1] = tmp[8];
+            dn[2] = tmp[0];
+            dn[3] = tmp[4];
+            dn[4] = tmp[5];
+            dn[8] = tmp[7];
+            break;
+        case 7:
+            dn[2] = tmp[8];
+            dn[3] = tmp[0];
+            dn[4] = tmp[6];
+            break;
+        case 8:
+            dn[2] = tmp[1];
+            dn[3] = tmp[2];
+            dn[4] = tmp[0];
+            dn[5] = tmp[6];
+            dn[6] = tmp[7];
+            break;
+    }
+    dn[0] = tmp[new_loc];
+
+    return ;
+}
+
+/*  3/28/01, find minimal of dn[9] */
+
+int AVCFindMin(int dn[])
+{
+    int min, i;
+    int dmin;
+
+    dmin = dn[1];
+    min = 1;
+    for (i = 2; i < 9; i++)
+    {
+        if (dn[i] < dmin)
+        {
+            dmin = dn[i];
+            min = i;
+        }
+    }
+
+    return min;
+}
+
+
+
diff --git a/media/libstagefright/codecs/avc/enc/src/rate_control.cpp b/media/libstagefright/codecs/avc/enc/src/rate_control.cpp
new file mode 100644
index 0000000..15b55fb
--- /dev/null
+++ b/media/libstagefright/codecs/avc/enc/src/rate_control.cpp
@@ -0,0 +1,981 @@
+/* ------------------------------------------------------------------
+ * Copyright (C) 1998-2009 PacketVideo
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
+ * express or implied.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ * -------------------------------------------------------------------
+ */
+#include "avcenc_lib.h"
+#include <math.h>
+
+/* rate control variables */
+#define RC_MAX_QUANT 51
+#define RC_MIN_QUANT 0   //cap to 10 to prevent rate fluctuation    
+
+#define MAD_MIN 1 /* handle the case of devision by zero in RC */
+
+
+/* local functions */
+double QP2Qstep(int QP);
+int Qstep2QP(double Qstep);
+
+double ComputeFrameMAD(AVCCommonObj *video, AVCRateControl *rateCtrl);
+
+void targetBitCalculation(AVCEncObject *encvid, AVCCommonObj *video, AVCRateControl *rateCtrl, MultiPass *pMP);
+
+void calculateQuantizer_Multipass(AVCEncObject *encvid, AVCCommonObj *video,
+                                  AVCRateControl *rateCtrl, MultiPass *pMP);
+
+void updateRC_PostProc(AVCRateControl *rateCtrl, MultiPass *pMP);
+
+void AVCSaveRDSamples(MultiPass *pMP, int counter_samples);
+
+void updateRateControl(AVCRateControl *rateControl, int nal_type);
+
+int GetAvgFrameQP(AVCRateControl *rateCtrl)
+{
+    return rateCtrl->Qc;
+}
+
+AVCEnc_Status RCDetermineFrameNum(AVCEncObject *encvid, AVCRateControl *rateCtrl, uint32 modTime, uint *frameNum)
+{
+    AVCCommonObj *video = encvid->common;
+    AVCSliceHeader *sliceHdr = video->sliceHdr;
+    uint32 modTimeRef = encvid->modTimeRef;
+    int32  currFrameNum ;
+    int  frameInc;
+
+
+    /* check with the buffer fullness to make sure that we have enough bits to encode this frame */
+    /* we can use a threshold to guarantee minimum picture quality */
+    /**********************************/
+
+    /* for now, the default is to encode every frame, To Be Changed */
+    if (rateCtrl->first_frame)
+    {
+        encvid->modTimeRef = modTime;
+        encvid->wrapModTime = 0;
+        encvid->prevFrameNum = 0;
+        encvid->prevProcFrameNum = 0;
+
+        *frameNum = 0;
+
+        /* set frame type to IDR-frame */
+        video->nal_unit_type = AVC_NALTYPE_IDR;
+        sliceHdr->slice_type = AVC_I_ALL_SLICE;
+        video->slice_type = AVC_I_SLICE;
+
+        return AVCENC_SUCCESS;
+    }
+    else
+    {
+        if (modTime < modTimeRef) /* modTime wrapped around */
+        {
+            encvid->wrapModTime += ((uint32)0xFFFFFFFF - modTimeRef) + 1;
+            encvid->modTimeRef = modTimeRef = 0;
+        }
+        modTime += encvid->wrapModTime; /* wrapModTime is non zero after wrap-around */
+
+        currFrameNum = (int32)(((modTime - modTimeRef) * rateCtrl->frame_rate + 200) / 1000); /* add small roundings */
+
+        if (currFrameNum <= (int32)encvid->prevProcFrameNum)
+        {
+            return AVCENC_FAIL;  /* this is a late frame do not encode it */
+        }
+
+        frameInc = currFrameNum - encvid->prevProcFrameNum;
+
+        if (frameInc < rateCtrl->skip_next_frame + 1)
+        {
+            return AVCENC_FAIL;  /* frame skip required to maintain the target bit rate. */
+        }
+
+        RCUpdateBuffer(video, rateCtrl, frameInc - rateCtrl->skip_next_frame);  /* in case more frames dropped */
+
+        *frameNum = currFrameNum;
+
+        /* This part would be similar to DetermineVopType of m4venc */
+        if ((*frameNum >= (uint)rateCtrl->idrPeriod && rateCtrl->idrPeriod > 0) || (*frameNum > video->MaxFrameNum)) /* first frame or IDR*/
+        {
+            /* set frame type to IDR-frame */
+            if (rateCtrl->idrPeriod)
+            {
+                encvid->modTimeRef += (uint32)(rateCtrl->idrPeriod * 1000 / rateCtrl->frame_rate);
+                *frameNum -= rateCtrl->idrPeriod;
+            }
+            else
+            {
+                encvid->modTimeRef += (uint32)(video->MaxFrameNum * 1000 / rateCtrl->frame_rate);
+                *frameNum -= video->MaxFrameNum;
+            }
+
+            video->nal_unit_type = AVC_NALTYPE_IDR;
+            sliceHdr->slice_type = AVC_I_ALL_SLICE;
+            video->slice_type = AVC_I_SLICE;
+            encvid->prevProcFrameNum = *frameNum;
+        }
+        else
+        {
+            video->nal_unit_type = AVC_NALTYPE_SLICE;
+            sliceHdr->slice_type = AVC_P_ALL_SLICE;
+            video->slice_type = AVC_P_SLICE;
+            encvid->prevProcFrameNum = currFrameNum;
+        }
+
+    }
+
+    return AVCENC_SUCCESS;
+}
+
+void RCUpdateBuffer(AVCCommonObj *video, AVCRateControl *rateCtrl, int frameInc)
+{
+    int tmp;
+    MultiPass *pMP = rateCtrl->pMP;
+
+    OSCL_UNUSED_ARG(video);
+
+    if (rateCtrl->rcEnable == TRUE)
+    {
+        if (frameInc > 1)
+        {
+            tmp = rateCtrl->bitsPerFrame * (frameInc - 1);
+            rateCtrl->VBV_fullness -= tmp;
+            pMP->counter_BTsrc += 10 * (frameInc - 1);
+
+            /* Check buffer underflow */
+            if (rateCtrl->VBV_fullness < rateCtrl->low_bound)
+            {
+                rateCtrl->VBV_fullness = rateCtrl->low_bound; // -rateCtrl->Bs/2;
+                rateCtrl->TMN_W = rateCtrl->VBV_fullness - rateCtrl->low_bound;
+                pMP->counter_BTsrc = pMP->counter_BTdst + (int)((OsclFloat)(rateCtrl->Bs / 2 - rateCtrl->low_bound) / 2.0 / (pMP->target_bits_per_frame / 10));
+            }
+        }
+    }
+}
+
+
+AVCEnc_Status InitRateControlModule(AVCHandle *avcHandle)
+{
+    AVCEncObject *encvid = (AVCEncObject*) avcHandle->AVCObject;
+    AVCCommonObj *video = encvid->common;
+    AVCRateControl *rateCtrl = encvid->rateCtrl;
+    double L1, L2, L3, bpp;
+    int qp;
+    int i, j;
+
+    rateCtrl->basicUnit = video->PicSizeInMbs;
+
+    rateCtrl->MADofMB = (double*) avcHandle->CBAVC_Malloc(encvid->avcHandle->userData,
+                        video->PicSizeInMbs * sizeof(double), DEFAULT_ATTR);
+
+    if (!rateCtrl->MADofMB)
+    {
+        goto CLEANUP_RC;
+    }
+
+    if (rateCtrl->rcEnable == TRUE)
+    {
+        rateCtrl->pMP = (MultiPass*) avcHandle->CBAVC_Malloc(encvid->avcHandle->userData, sizeof(MultiPass), DEFAULT_ATTR);
+        if (!rateCtrl->pMP)
+        {
+            goto CLEANUP_RC;
+        }
+        memset(rateCtrl->pMP, 0, sizeof(MultiPass));
+        rateCtrl->pMP->encoded_frames = -1; /* forget about the very first I frame */
+
+        /* RDInfo **pRDSamples */
+        rateCtrl->pMP->pRDSamples = (RDInfo **)avcHandle->CBAVC_Malloc(encvid->avcHandle->userData, (30 * sizeof(RDInfo *)), DEFAULT_ATTR);
+        if (!rateCtrl->pMP->pRDSamples)
+        {
+            goto CLEANUP_RC;
+        }
+
+        for (i = 0; i < 30; i++)
+        {
+            rateCtrl->pMP->pRDSamples[i] = (RDInfo *)avcHandle->CBAVC_Malloc(encvid->avcHandle->userData, (32 * sizeof(RDInfo)), DEFAULT_ATTR);
+            if (!rateCtrl->pMP->pRDSamples[i])
+            {
+                goto CLEANUP_RC;
+            }
+            for (j = 0; j < 32; j++)    memset(&(rateCtrl->pMP->pRDSamples[i][j]), 0, sizeof(RDInfo));
+        }
+        rateCtrl->pMP->frameRange = (int)(rateCtrl->frame_rate * 1.0); /* 1.0s time frame*/
+        rateCtrl->pMP->frameRange = AVC_MAX(rateCtrl->pMP->frameRange, 5);
+        rateCtrl->pMP->frameRange = AVC_MIN(rateCtrl->pMP->frameRange, 30);
+
+        rateCtrl->pMP->framePos = -1;
+
+
+        rateCtrl->bitsPerFrame = (int32)(rateCtrl->bitRate / rateCtrl->frame_rate);
+
+        /* BX rate control */
+        rateCtrl->skip_next_frame = 0; /* must be initialized */
+
+        rateCtrl->Bs = rateCtrl->cpbSize;
+        rateCtrl->TMN_W = 0;
+        rateCtrl->VBV_fullness = (int)(rateCtrl->Bs * 0.5); /* rateCtrl->Bs */
+        rateCtrl->encoded_frames = 0;
+
+        rateCtrl->TMN_TH = rateCtrl->bitsPerFrame;
+
+        rateCtrl->max_BitVariance_num = (int)((OsclFloat)(rateCtrl->Bs - rateCtrl->VBV_fullness) / (rateCtrl->bitsPerFrame / 10.0)) - 5;
+        if (rateCtrl->max_BitVariance_num < 0) rateCtrl->max_BitVariance_num += 5;
+
+        // Set the initial buffer fullness
+        /* According to the spec, the initial buffer fullness needs to be set to 1/3 */
+        rateCtrl->VBV_fullness = (int)(rateCtrl->Bs / 3.0 - rateCtrl->Bs / 2.0); /* the buffer range is [-Bs/2, Bs/2] */
+        rateCtrl->pMP->counter_BTsrc = (int)((rateCtrl->Bs / 2.0 - rateCtrl->Bs / 3.0) / (rateCtrl->bitsPerFrame / 10.0));
+        rateCtrl->TMN_W = (int)(rateCtrl->VBV_fullness + rateCtrl->pMP->counter_BTsrc * (rateCtrl->bitsPerFrame / 10.0));
+
+        rateCtrl->low_bound = -rateCtrl->Bs / 2;
+        rateCtrl->VBV_fullness_offset = 0;
+
+        /* Setting the bitrate and framerate */
+        rateCtrl->pMP->bitrate = rateCtrl->bitRate;
+        rateCtrl->pMP->framerate = rateCtrl->frame_rate;
+        rateCtrl->pMP->target_bits_per_frame = rateCtrl->pMP->bitrate / rateCtrl->pMP->framerate;
+
+        /*compute the initial QP*/
+        bpp = 1.0 * rateCtrl->bitRate / (rateCtrl->frame_rate * (video->PicSizeInMbs << 8));
+        if (video->PicWidthInSamplesL == 176)
+        {
+            L1 = 0.1;
+            L2 = 0.3;
+            L3 = 0.6;
+        }
+        else if (video->PicWidthInSamplesL == 352)
+        {
+            L1 = 0.2;
+            L2 = 0.6;
+            L3 = 1.2;
+        }
+        else
+        {
+            L1 = 0.6;
+            L2 = 1.4;
+            L3 = 2.4;
+        }
+
+        if (rateCtrl->initQP == 0)
+        {
+            if (bpp <= L1)
+                qp = 35;
+            else if (bpp <= L2)
+                qp = 25;
+            else if (bpp <= L3)
+                qp = 20;
+            else
+                qp = 15;
+            rateCtrl->initQP = qp;
+        }
+
+        rateCtrl->Qc = rateCtrl->initQP;
+    }
+
+    return AVCENC_SUCCESS;
+
+CLEANUP_RC:
+
+    CleanupRateControlModule(avcHandle);
+    return AVCENC_MEMORY_FAIL;
+
+}
+
+
+void CleanupRateControlModule(AVCHandle *avcHandle)
+{
+    AVCEncObject *encvid = (AVCEncObject*) avcHandle->AVCObject;
+    AVCRateControl *rateCtrl = encvid->rateCtrl;
+    int i;
+
+    if (rateCtrl->MADofMB)
+    {
+        avcHandle->CBAVC_Free(avcHandle->userData, (int)(rateCtrl->MADofMB));
+    }
+
+    if (rateCtrl->pMP)
+    {
+        if (rateCtrl->pMP->pRDSamples)
+        {
+            for (i = 0; i < 30; i++)
+            {
+                if (rateCtrl->pMP->pRDSamples[i])
+                {
+                    avcHandle->CBAVC_Free(avcHandle->userData, (int)rateCtrl->pMP->pRDSamples[i]);
+                }
+            }
+            avcHandle->CBAVC_Free(avcHandle->userData, (int)rateCtrl->pMP->pRDSamples);
+        }
+        avcHandle->CBAVC_Free(avcHandle->userData, (int)(rateCtrl->pMP));
+    }
+
+    return ;
+}
+
+void RCInitGOP(AVCEncObject *encvid)
+{
+    /* in BX RC, there's no GOP-level RC */
+
+    OSCL_UNUSED_ARG(encvid);
+
+    return ;
+}
+
+
+void RCInitFrameQP(AVCEncObject *encvid)
+{
+    AVCCommonObj *video = encvid->common;
+    AVCRateControl *rateCtrl = encvid->rateCtrl;
+    AVCPicParamSet *picParam = video->currPicParams;
+    MultiPass *pMP = rateCtrl->pMP;
+
+    if (rateCtrl->rcEnable == TRUE)
+    {
+        /* frame layer rate control */
+        if (rateCtrl->encoded_frames == 0)
+        {
+            video->QPy = rateCtrl->Qc = rateCtrl->initQP;
+        }
+        else
+        {
+            calculateQuantizer_Multipass(encvid, video, rateCtrl, pMP);
+            video->QPy = rateCtrl->Qc;
+        }
+
+        rateCtrl->NumberofHeaderBits = 0;
+        rateCtrl->NumberofTextureBits = 0;
+        rateCtrl->numFrameBits = 0; // reset
+
+        /* update pMP->framePos */
+        if (++pMP->framePos == pMP->frameRange) pMP->framePos = 0;
+
+        if (rateCtrl->T == 0)
+        {
+            pMP->counter_BTdst = (int)(rateCtrl->frame_rate * 7.5 + 0.5); /* 0.75s time frame */
+            pMP->counter_BTdst = AVC_MIN(pMP->counter_BTdst, (int)(rateCtrl->max_BitVariance_num / 2 * 0.40)); /* 0.75s time frame may go beyond VBV buffer if we set the buffer size smaller than 0.75s */
+            pMP->counter_BTdst = AVC_MAX(pMP->counter_BTdst, (int)((rateCtrl->Bs / 2 - rateCtrl->VBV_fullness) * 0.30 / (rateCtrl->TMN_TH / 10.0) + 0.5)); /* At least 30% of VBV buffer size/2 */
+            pMP->counter_BTdst = AVC_MIN(pMP->counter_BTdst, 20); /* Limit the target to be smaller than 3C */
+
+            pMP->target_bits = rateCtrl->T = rateCtrl->TMN_TH = (int)(rateCtrl->TMN_TH * (1.0 + pMP->counter_BTdst * 0.1));
+            pMP->diff_counter = pMP->counter_BTdst;
+        }
+
+        /* collect the necessary data: target bits, actual bits, mad and QP */
+        pMP->target_bits = rateCtrl->T;
+        pMP->QP  = video->QPy;
+
+        pMP->mad = (OsclFloat)rateCtrl->totalSAD / video->PicSizeInMbs; //ComputeFrameMAD(video, rateCtrl);
+        if (pMP->mad < MAD_MIN) pMP->mad = MAD_MIN; /* MAD_MIN is defined as 1 in mp4def.h */
+
+        pMP->bitrate = rateCtrl->bitRate; /* calculated in RCVopQPSetting */
+        pMP->framerate = rateCtrl->frame_rate;
+
+        /* first pass encoding */
+        pMP->nRe_Quantized = 0;
+
+    } // rcEnable
+    else
+    {
+        video->QPy = rateCtrl->initQP;
+    }
+
+//  printf(" %d ",video->QPy);
+
+    if (video->CurrPicNum == 0 && encvid->outOfBandParamSet == FALSE)
+    {
+        picParam->pic_init_qs_minus26 = 0;
+        picParam->pic_init_qp_minus26 = video->QPy - 26;
+    }
+
+    // need this for motion estimation
+    encvid->lambda_mode = QP2QUANT[AVC_MAX(0, video->QPy-SHIFT_QP)];
+    encvid->lambda_motion = LAMBDA_FACTOR(encvid->lambda_mode);
+    return ;
+}
+
+/* Mad based variable bit allocation + QP calculation with a new quadratic method */
+void calculateQuantizer_Multipass(AVCEncObject *encvid, AVCCommonObj *video,
+                                  AVCRateControl *rateCtrl, MultiPass *pMP)
+{
+    int prev_actual_bits = 0, curr_target, /*pos=0,*/i, j;
+    OsclFloat Qstep, prev_QP = 0.625;
+
+    OsclFloat curr_mad, prev_mad, curr_RD, prev_RD, average_mad, aver_QP;
+
+    /* Mad based variable bit allocation */
+    targetBitCalculation(encvid, video, rateCtrl, pMP);
+
+    if (rateCtrl->T <= 0 || rateCtrl->totalSAD == 0)
+    {
+        if (rateCtrl->T < 0)    rateCtrl->Qc = RC_MAX_QUANT;
+        return;
+    }
+
+    /* ---------------------------------------------------------------------------------------------------*/
+    /* current frame QP estimation */
+    curr_target = rateCtrl->T;
+    curr_mad = (OsclFloat)rateCtrl->totalSAD / video->PicSizeInMbs;
+    if (curr_mad < MAD_MIN) curr_mad = MAD_MIN; /* MAD_MIN is defined as 1 in mp4def.h */
+    curr_RD  = (OsclFloat)curr_target / curr_mad;
+
+    if (rateCtrl->skip_next_frame == -1) // previous was skipped
+    {
+        i = pMP->framePos;
+        prev_mad = pMP->pRDSamples[i][0].mad;
+        prev_QP = pMP->pRDSamples[i][0].QP;
+        prev_actual_bits = pMP->pRDSamples[i][0].actual_bits;
+    }
+    else
+    {
+        /* Another version of search the optimal point */
+        prev_mad = 0.0;
+        i = 0;
+        while (i < pMP->frameRange && prev_mad < 0.001) /* find first one with nonzero prev_mad */
+        {
+            prev_mad = pMP->pRDSamples[i][0].mad;
+            i++;
+        }
+
+        if (i < pMP->frameRange)
+        {
+            prev_actual_bits = pMP->pRDSamples[i-1][0].actual_bits;
+
+            for (j = 0; i < pMP->frameRange; i++)
+            {
+                if (pMP->pRDSamples[i][0].mad != 0 &&
+                        AVC_ABS(prev_mad - curr_mad) > AVC_ABS(pMP->pRDSamples[i][0].mad - curr_mad))
+                {
+                    prev_mad = pMP->pRDSamples[i][0].mad;
+                    prev_actual_bits = pMP->pRDSamples[i][0].actual_bits;
+                    j = i;
+                }
+            }
+            prev_QP = QP2Qstep(pMP->pRDSamples[j][0].QP);
+
+            for (i = 1; i < pMP->samplesPerFrame[j]; i++)
+            {
+                if (AVC_ABS(prev_actual_bits - curr_target) > AVC_ABS(pMP->pRDSamples[j][i].actual_bits - curr_target))
+                {
+                    prev_actual_bits = pMP->pRDSamples[j][i].actual_bits;
+                    prev_QP = QP2Qstep(pMP->pRDSamples[j][i].QP);
+                }
+            }
+        }
+    }
+
+    // quadratic approximation
+    if (prev_mad > 0.001) // only when prev_mad is greater than 0, otherwise keep using the same QP
+    {
+        prev_RD = (OsclFloat)prev_actual_bits / prev_mad;
+        //rateCtrl->Qc = (Int)(prev_QP * sqrt(prev_actual_bits/curr_target) + 0.4);
+        if (prev_QP == 0.625) // added this to allow getting out of QP = 0 easily
+        {
+            Qstep = (int)(prev_RD / curr_RD + 0.5);
+        }
+        else
+        {
+            //      rateCtrl->Qc =(Int)(prev_QP * M4VENC_SQRT(prev_RD/curr_RD) + 0.9);
+
+            if (prev_RD / curr_RD > 0.5 && prev_RD / curr_RD < 2.0)
+                Qstep = (int)(prev_QP * (sqrt(prev_RD / curr_RD) + prev_RD / curr_RD) / 2.0 + 0.9); /* Quadratic and linear approximation */
+            else
+                Qstep = (int)(prev_QP * (sqrt(prev_RD / curr_RD) + pow(prev_RD / curr_RD, 1.0 / 3.0)) / 2.0 + 0.9);
+        }
+        // lower bound on Qc should be a function of curr_mad
+        // When mad is already low, lower bound on Qc doesn't have to be small.
+        // Note, this doesn't work well for low complexity clip encoded at high bit rate
+        // it doesn't hit the target bit rate due to this QP lower bound.
+        /// if((curr_mad < 8) && (rateCtrl->Qc < 12))   rateCtrl->Qc = 12;
+        //  else    if((curr_mad < 128) && (rateCtrl->Qc < 3)) rateCtrl->Qc = 3;
+
+        rateCtrl->Qc = Qstep2QP(Qstep);
+
+        if (rateCtrl->Qc < RC_MIN_QUANT) rateCtrl->Qc = RC_MIN_QUANT;
+        if (rateCtrl->Qc > RC_MAX_QUANT)    rateCtrl->Qc = RC_MAX_QUANT;
+    }
+
+    /* active bit resource protection */
+    aver_QP = (pMP->encoded_frames == 0 ? 0 : pMP->sum_QP / (OsclFloat)pMP->encoded_frames);
+    average_mad = (pMP->encoded_frames == 0 ? 0 : pMP->sum_mad / (OsclFloat)pMP->encoded_frames); /* this function is called from the scond encoded frame*/
+    if (pMP->diff_counter == 0 &&
+            ((OsclFloat)rateCtrl->Qc <= aver_QP*1.1 || curr_mad <= average_mad*1.1) &&
+            pMP->counter_BTsrc <= (pMP->counter_BTdst + (int)(pMP->framerate*1.0 + 0.5)))
+    {
+        rateCtrl->TMN_TH -= (int)(pMP->target_bits_per_frame / 10.0);
+        rateCtrl->T = rateCtrl->TMN_TH - rateCtrl->TMN_W;
+        pMP->counter_BTsrc++;
+        pMP->diff_counter--;
+    }
+
+}
+
+void targetBitCalculation(AVCEncObject *encvid, AVCCommonObj *video, AVCRateControl *rateCtrl, MultiPass *pMP)
+{
+    OSCL_UNUSED_ARG(encvid);
+    OsclFloat curr_mad;//, average_mad;
+    int diff_counter_BTsrc, diff_counter_BTdst, prev_counter_diff, curr_counter_diff, bound;
+    /* BT = Bit Transfer, for pMP->counter_BTsrc, pMP->counter_BTdst */
+
+    /* some stuff about frame dropping remained here to be done because pMP cannot be inserted into updateRateControl()*/
+    updateRC_PostProc(rateCtrl, pMP);
+
+    /* update pMP->counter_BTsrc and pMP->counter_BTdst to avoid interger overflow */
+    if (pMP->counter_BTsrc > 1000 && pMP->counter_BTdst > 1000)
+    {
+        pMP->counter_BTsrc -= 1000;
+        pMP->counter_BTdst -= 1000;
+    }
+
+    /* ---------------------------------------------------------------------------------------------------*/
+    /* target calculation */
+    curr_mad = (OsclFloat)rateCtrl->totalSAD / video->PicSizeInMbs;
+    if (curr_mad < MAD_MIN) curr_mad = MAD_MIN; /* MAD_MIN is defined as 1 in mp4def.h */
+    diff_counter_BTsrc = diff_counter_BTdst = 0;
+    pMP->diff_counter = 0;
+
+
+    /*1.calculate average mad */
+    pMP->sum_mad += curr_mad;
+    //average_mad = (pMP->encoded_frames < 1 ? curr_mad : pMP->sum_mad/(OsclFloat)(pMP->encoded_frames+1)); /* this function is called from the scond encoded frame*/
+    //pMP->aver_mad = average_mad;
+    if (pMP->encoded_frames >= 0) /* pMP->encoded_frames is set to -1 initially, so forget about the very first I frame */
+        pMP->aver_mad = (pMP->aver_mad * pMP->encoded_frames + curr_mad) / (pMP->encoded_frames + 1);
+
+    if (pMP->overlapped_win_size > 0 && pMP->encoded_frames_prev >= 0)
+        pMP->aver_mad_prev = (pMP->aver_mad_prev * pMP->encoded_frames_prev + curr_mad) / (pMP->encoded_frames_prev + 1);
+
+    /*2.average_mad, mad ==> diff_counter_BTsrc, diff_counter_BTdst */
+    if (pMP->overlapped_win_size == 0)
+    {
+        /* original verison */
+        if (curr_mad > pMP->aver_mad*1.1)
+        {
+            if (curr_mad / (pMP->aver_mad + 0.0001) > 2)
+                diff_counter_BTdst = (int)(sqrt(curr_mad / (pMP->aver_mad + 0.0001)) * 10 + 0.4) - 10;
+            //diff_counter_BTdst = (int)((sqrt(curr_mad/pMP->aver_mad)*2+curr_mad/pMP->aver_mad)/(3*0.1) + 0.4) - 10;
+            else
+                diff_counter_BTdst = (int)(curr_mad / (pMP->aver_mad + 0.0001) * 10 + 0.4) - 10;
+        }
+        else /* curr_mad <= average_mad*1.1 */
+            //diff_counter_BTsrc = 10 - (int)((sqrt(curr_mad/pMP->aver_mad) + pow(curr_mad/pMP->aver_mad, 1.0/3.0))/(2.0*0.1) + 0.4);
+            diff_counter_BTsrc = 10 - (int)(sqrt(curr_mad / (pMP->aver_mad + 0.0001)) * 10 + 0.5);
+
+        /* actively fill in the possible gap */
+        if (diff_counter_BTsrc == 0 && diff_counter_BTdst == 0 &&
+                curr_mad <= pMP->aver_mad*1.1 && pMP->counter_BTsrc < pMP->counter_BTdst)
+            diff_counter_BTsrc = 1;
+
+    }
+    else if (pMP->overlapped_win_size > 0)
+    {
+        /* transition time: use previous average mad "pMP->aver_mad_prev" instead of the current average mad "pMP->aver_mad" */
+        if (curr_mad > pMP->aver_mad_prev*1.1)
+        {
+            if (curr_mad / pMP->aver_mad_prev > 2)
+                diff_counter_BTdst = (int)(sqrt(curr_mad / (pMP->aver_mad_prev + 0.0001)) * 10 + 0.4) - 10;
+            //diff_counter_BTdst = (int)((M4VENC_SQRT(curr_mad/pMP->aver_mad_prev)*2+curr_mad/pMP->aver_mad_prev)/(3*0.1) + 0.4) - 10;
+            else
+                diff_counter_BTdst = (int)(curr_mad / (pMP->aver_mad_prev + 0.0001) * 10 + 0.4) - 10;
+        }
+        else /* curr_mad <= average_mad*1.1 */
+            //diff_counter_BTsrc = 10 - (Int)((sqrt(curr_mad/pMP->aver_mad_prev) + pow(curr_mad/pMP->aver_mad_prev, 1.0/3.0))/(2.0*0.1) + 0.4);
+            diff_counter_BTsrc = 10 - (int)(sqrt(curr_mad / (pMP->aver_mad_prev + 0.0001)) * 10 + 0.5);
+
+        /* actively fill in the possible gap */
+        if (diff_counter_BTsrc == 0 && diff_counter_BTdst == 0 &&
+                curr_mad <= pMP->aver_mad_prev*1.1 && pMP->counter_BTsrc < pMP->counter_BTdst)
+            diff_counter_BTsrc = 1;
+
+        if (--pMP->overlapped_win_size <= 0)    pMP->overlapped_win_size = 0;
+    }
+
+
+    /* if difference is too much, do clipping */
+    /* First, set the upper bound for current bit allocation variance: 80% of available buffer */
+    bound = (int)((rateCtrl->Bs / 2 - rateCtrl->VBV_fullness) * 0.6 / (pMP->target_bits_per_frame / 10)); /* rateCtrl->Bs */
+    diff_counter_BTsrc =  AVC_MIN(diff_counter_BTsrc, bound);
+    diff_counter_BTdst =  AVC_MIN(diff_counter_BTdst, bound);
+
+    /* Second, set another upper bound for current bit allocation: 4-5*bitrate/framerate */
+    bound = 50;
+//  if(video->encParams->RC_Type == CBR_LOWDELAY)
+//  not necessary       bound = 10;  -- For Low delay */
+
+    diff_counter_BTsrc =  AVC_MIN(diff_counter_BTsrc, bound);
+    diff_counter_BTdst =  AVC_MIN(diff_counter_BTdst, bound);
+
+
+    /* Third, check the buffer */
+    prev_counter_diff = pMP->counter_BTdst - pMP->counter_BTsrc;
+    curr_counter_diff = prev_counter_diff + (diff_counter_BTdst - diff_counter_BTsrc);
+
+    if (AVC_ABS(prev_counter_diff) >= rateCtrl->max_BitVariance_num || AVC_ABS(curr_counter_diff) >= rateCtrl->max_BitVariance_num)
+    {   //diff_counter_BTsrc = diff_counter_BTdst = 0;
+
+        if (curr_counter_diff > rateCtrl->max_BitVariance_num && diff_counter_BTdst)
+        {
+            diff_counter_BTdst = (rateCtrl->max_BitVariance_num - prev_counter_diff) + diff_counter_BTsrc;
+            if (diff_counter_BTdst < 0) diff_counter_BTdst = 0;
+        }
+
+        else if (curr_counter_diff < -rateCtrl->max_BitVariance_num && diff_counter_BTsrc)
+        {
+            diff_counter_BTsrc = diff_counter_BTdst - (-rateCtrl->max_BitVariance_num - prev_counter_diff);
+            if (diff_counter_BTsrc < 0) diff_counter_BTsrc = 0;
+        }
+    }
+
+
+    /*3.diff_counter_BTsrc, diff_counter_BTdst ==> TMN_TH */
+    rateCtrl->TMN_TH = (int)(pMP->target_bits_per_frame);
+    pMP->diff_counter = 0;
+
+    if (diff_counter_BTsrc)
+    {
+        rateCtrl->TMN_TH -= (int)(pMP->target_bits_per_frame * diff_counter_BTsrc * 0.1);
+        pMP->diff_counter = -diff_counter_BTsrc;
+    }
+    else if (diff_counter_BTdst)
+    {
+        rateCtrl->TMN_TH += (int)(pMP->target_bits_per_frame * diff_counter_BTdst * 0.1);
+        pMP->diff_counter = diff_counter_BTdst;
+    }
+
+
+    /*4.update pMP->counter_BTsrc, pMP->counter_BTdst */
+    pMP->counter_BTsrc += diff_counter_BTsrc;
+    pMP->counter_BTdst += diff_counter_BTdst;
+
+
+    /*5.target bit calculation */
+    rateCtrl->T = rateCtrl->TMN_TH - rateCtrl->TMN_W;
+
+    return ;
+}
+
+void updateRC_PostProc(AVCRateControl *rateCtrl, MultiPass *pMP)
+{
+    if (rateCtrl->skip_next_frame > 0) /* skip next frame */
+    {
+        pMP->counter_BTsrc += 10 * rateCtrl->skip_next_frame;
+
+    }
+    else if (rateCtrl->skip_next_frame == -1) /* skip current frame */
+    {
+        pMP->counter_BTdst -= pMP->diff_counter;
+        pMP->counter_BTsrc += 10;
+
+        pMP->sum_mad -= pMP->mad;
+        pMP->aver_mad = (pMP->aver_mad * pMP->encoded_frames - pMP->mad) / (pMP->encoded_frames - 1 + 0.0001);
+        pMP->sum_QP  -= pMP->QP;
+        pMP->encoded_frames --;
+    }
+    /* some stuff in update VBV_fullness remains here */
+    //if(rateCtrl->VBV_fullness < -rateCtrl->Bs/2) /* rateCtrl->Bs */
+    if (rateCtrl->VBV_fullness < rateCtrl->low_bound)
+    {
+        rateCtrl->VBV_fullness = rateCtrl->low_bound; // -rateCtrl->Bs/2;
+        rateCtrl->TMN_W = rateCtrl->VBV_fullness - rateCtrl->low_bound;
+        pMP->counter_BTsrc = pMP->counter_BTdst + (int)((OsclFloat)(rateCtrl->Bs / 2 - rateCtrl->low_bound) / 2.0 / (pMP->target_bits_per_frame / 10));
+    }
+}
+
+
+void RCInitChromaQP(AVCEncObject *encvid)
+{
+    AVCCommonObj *video = encvid->common;
+    AVCMacroblock *currMB = video->currMB;
+    int q_bits;
+
+    /* we have to do the same thing for AVC_CLIP3(0,51,video->QSy) */
+
+    video->QPy_div_6 = (currMB->QPy * 43) >> 8;
+    video->QPy_mod_6 = currMB->QPy - 6 * video->QPy_div_6;
+    currMB->QPc = video->QPc = mapQPi2QPc[AVC_CLIP3(0, 51, currMB->QPy + video->currPicParams->chroma_qp_index_offset)];
+    video->QPc_div_6 = (video->QPc * 43) >> 8;
+    video->QPc_mod_6 = video->QPc - 6 * video->QPc_div_6;
+
+    /* pre-calculate this to save computation */
+    q_bits = 4 + video->QPy_div_6;
+    if (video->slice_type == AVC_I_SLICE)
+    {
+        encvid->qp_const = 682 << q_bits;       // intra
+    }
+    else
+    {
+        encvid->qp_const = 342 << q_bits;       // inter
+    }
+
+    q_bits = 4 + video->QPc_div_6;
+    if (video->slice_type == AVC_I_SLICE)
+    {
+        encvid->qp_const_c = 682 << q_bits;    // intra
+    }
+    else
+    {
+        encvid->qp_const_c = 342 << q_bits;    // inter
+    }
+
+    encvid->lambda_mode = QP2QUANT[AVC_MAX(0, currMB->QPy-SHIFT_QP)];
+    encvid->lambda_motion = LAMBDA_FACTOR(encvid->lambda_mode);
+
+    return ;
+}
+
+
+void RCInitMBQP(AVCEncObject *encvid)
+{
+    AVCCommonObj *video =  encvid->common;
+    AVCMacroblock *currMB = video->currMB;
+
+    currMB->QPy = video->QPy; /* set to previous value or picture level */
+
+    RCInitChromaQP(encvid);
+
+}
+
+void RCPostMB(AVCCommonObj *video, AVCRateControl *rateCtrl, int num_header_bits, int num_texture_bits)
+{
+    OSCL_UNUSED_ARG(video);
+    rateCtrl->numMBHeaderBits = num_header_bits;
+    rateCtrl->numMBTextureBits = num_texture_bits;
+    rateCtrl->NumberofHeaderBits += rateCtrl->numMBHeaderBits;
+    rateCtrl->NumberofTextureBits += rateCtrl->numMBTextureBits;
+}
+
+void RCRestoreQP(AVCMacroblock *currMB, AVCCommonObj *video, AVCEncObject *encvid)
+{
+    currMB->QPy = video->QPy; /* use previous QP */
+    RCInitChromaQP(encvid);
+
+    return ;
+}
+
+
+void RCCalculateMAD(AVCEncObject *encvid, AVCMacroblock *currMB, uint8 *orgL, int orgPitch)
+{
+    AVCCommonObj *video = encvid->common;
+    AVCRateControl *rateCtrl = encvid->rateCtrl;
+    uint32 dmin_lx;
+
+    if (rateCtrl->rcEnable == TRUE)
+    {
+        if (currMB->mb_intra)
+        {
+            if (currMB->mbMode == AVC_I16)
+            {
+                dmin_lx = (0xFFFF << 16) | orgPitch;
+                rateCtrl->MADofMB[video->mbNum] = AVCSAD_Macroblock_C(orgL,
+                                                  encvid->pred_i16[currMB->i16Mode], dmin_lx, NULL);
+            }
+            else /* i4 */
+            {
+                rateCtrl->MADofMB[video->mbNum] = encvid->i4_sad / 256.;
+            }
+        }
+        /* for INTER, we have already saved it with the MV search */
+    }
+
+    return ;
+}
+
+
+
+AVCEnc_Status RCUpdateFrame(AVCEncObject *encvid)
+{
+    AVCCommonObj *video = encvid->common;
+    AVCRateControl *rateCtrl = encvid->rateCtrl;
+    AVCEnc_Status status = AVCENC_SUCCESS;
+    MultiPass *pMP = rateCtrl->pMP;
+    int diff_BTCounter;
+    int nal_type = video->nal_unit_type;
+
+    /* update the complexity weight of I, P, B frame */
+
+    if (rateCtrl->rcEnable == TRUE)
+    {
+        pMP->actual_bits = rateCtrl->numFrameBits;
+        pMP->mad = (OsclFloat)rateCtrl->totalSAD / video->PicSizeInMbs; //ComputeFrameMAD(video, rateCtrl);
+
+        AVCSaveRDSamples(pMP, 0);
+
+        pMP->encoded_frames++;
+
+        /* for pMP->samplesPerFrame */
+        pMP->samplesPerFrame[pMP->framePos] = 0;
+
+        pMP->sum_QP += pMP->QP;
+
+        /* update pMP->counter_BTsrc, pMP->counter_BTdst */
+        /* re-allocate the target bit again and then stop encoding */
+        diff_BTCounter = (int)((OsclFloat)(rateCtrl->TMN_TH - rateCtrl->TMN_W - pMP->actual_bits) /
+                               (pMP->bitrate / (pMP->framerate + 0.0001) + 0.0001) / 0.1);
+        if (diff_BTCounter >= 0)
+            pMP->counter_BTsrc += diff_BTCounter; /* pMP->actual_bits is smaller */
+        else
+            pMP->counter_BTdst -= diff_BTCounter; /* pMP->actual_bits is bigger */
+
+        rateCtrl->TMN_TH -= (int)((OsclFloat)pMP->bitrate / (pMP->framerate + 0.0001) * (diff_BTCounter * 0.1));
+        rateCtrl->T = pMP->target_bits = rateCtrl->TMN_TH - rateCtrl->TMN_W;
+        pMP->diff_counter -= diff_BTCounter;
+
+        rateCtrl->Rc = rateCtrl->numFrameBits;  /* Total Bits for current frame */
+        rateCtrl->Hc = rateCtrl->NumberofHeaderBits;    /* Total Bits in Header and Motion Vector */
+
+        /* BX_RC */
+        updateRateControl(rateCtrl, nal_type);
+        if (rateCtrl->skip_next_frame == -1) // skip current frame
+        {
+            status = AVCENC_SKIPPED_PICTURE;
+        }
+    }
+
+    rateCtrl->first_frame = 0;  // reset here after we encode the first frame.
+
+    return status;
+}
+
+void AVCSaveRDSamples(MultiPass *pMP, int counter_samples)
+{
+    /* for pMP->pRDSamples */
+    pMP->pRDSamples[pMP->framePos][counter_samples].QP    = pMP->QP;
+    pMP->pRDSamples[pMP->framePos][counter_samples].actual_bits = pMP->actual_bits;
+    pMP->pRDSamples[pMP->framePos][counter_samples].mad   = pMP->mad;
+    pMP->pRDSamples[pMP->framePos][counter_samples].R_D = (OsclFloat)pMP->actual_bits / (pMP->mad + 0.0001);
+
+    return ;
+}
+
+void updateRateControl(AVCRateControl *rateCtrl, int nal_type)
+{
+    int  frame_bits;
+    MultiPass *pMP = rateCtrl->pMP;
+
+    /* BX rate contro\l */
+    frame_bits = (int)(rateCtrl->bitRate / rateCtrl->frame_rate);
+    rateCtrl->TMN_W += (rateCtrl->Rc - rateCtrl->TMN_TH);
+    rateCtrl->VBV_fullness += (rateCtrl->Rc - frame_bits); //rateCtrl->Rp);
+    //if(rateCtrl->VBV_fullness < 0) rateCtrl->VBV_fullness = -1;
+
+    rateCtrl->encoded_frames++;
+
+    /* frame dropping */
+    rateCtrl->skip_next_frame = 0;
+
+    if ((rateCtrl->VBV_fullness > rateCtrl->Bs / 2) && nal_type != AVC_NALTYPE_IDR) /* skip the current frame */ /* rateCtrl->Bs */
+    {
+        rateCtrl->TMN_W -= (rateCtrl->Rc - rateCtrl->TMN_TH);
+        rateCtrl->VBV_fullness -= rateCtrl->Rc;
+        rateCtrl->skip_next_frame = -1;
+    }
+    else if ((OsclFloat)(rateCtrl->VBV_fullness - rateCtrl->VBV_fullness_offset) > (rateCtrl->Bs / 2 - rateCtrl->VBV_fullness_offset)*0.95) /* skip next frame */
+    {
+        rateCtrl->VBV_fullness -= frame_bits; //rateCtrl->Rp;
+        rateCtrl->skip_next_frame = 1;
+        pMP->counter_BTsrc -= (int)((OsclFloat)(rateCtrl->Bs / 2 - rateCtrl->low_bound) / 2.0 / (pMP->target_bits_per_frame / 10));
+        /* BX_1, skip more than 1 frames  */
+        //while(rateCtrl->VBV_fullness > rateCtrl->Bs*0.475)
+        while ((rateCtrl->VBV_fullness - rateCtrl->VBV_fullness_offset) > (rateCtrl->Bs / 2 - rateCtrl->VBV_fullness_offset)*0.95)
+        {
+            rateCtrl->VBV_fullness -= frame_bits; //rateCtrl->Rp;
+            rateCtrl->skip_next_frame++;
+            pMP->counter_BTsrc -= (int)((OsclFloat)(rateCtrl->Bs / 2 - rateCtrl->low_bound) / 2.0 / (pMP->target_bits_per_frame / 10));
+        }
+
+        /* END BX_1 */
+    }
+}
+
+
+double ComputeFrameMAD(AVCCommonObj *video, AVCRateControl *rateCtrl)
+{
+    double TotalMAD;
+    int i;
+    TotalMAD = 0.0;
+    for (i = 0; i < (int)video->PicSizeInMbs; i++)
+        TotalMAD += rateCtrl->MADofMB[i];
+    TotalMAD /= video->PicSizeInMbs;
+    return TotalMAD;
+}
+
+
+
+
+
+/* convert from QP to Qstep */
+double QP2Qstep(int QP)
+{
+    int i;
+    double Qstep;
+    static const double QP2QSTEP[6] = { 0.625, 0.6875, 0.8125, 0.875, 1.0, 1.125 };
+
+    Qstep = QP2QSTEP[QP % 6];
+    for (i = 0; i < (QP / 6); i++)
+        Qstep *= 2;
+
+    return Qstep;
+}
+
+/* convert from step size to QP */
+int Qstep2QP(double Qstep)
+{
+    int q_per = 0, q_rem = 0;
+
+    //  assert( Qstep >= QP2Qstep(0) && Qstep <= QP2Qstep(51) );
+    if (Qstep < QP2Qstep(0))
+        return 0;
+    else if (Qstep > QP2Qstep(51))
+        return 51;
+
+    while (Qstep > QP2Qstep(5))
+    {
+        Qstep /= 2;
+        q_per += 1;
+    }
+
+    if (Qstep <= (0.625 + 0.6875) / 2)
+    {
+        Qstep = 0.625;
+        q_rem = 0;
+    }
+    else if (Qstep <= (0.6875 + 0.8125) / 2)
+    {
+        Qstep = 0.6875;
+        q_rem = 1;
+    }
+    else if (Qstep <= (0.8125 + 0.875) / 2)
+    {
+        Qstep = 0.8125;
+        q_rem = 2;
+    }
+    else if (Qstep <= (0.875 + 1.0) / 2)
+    {
+        Qstep = 0.875;
+        q_rem = 3;
+    }
+    else if (Qstep <= (1.0 + 1.125) / 2)
+    {
+        Qstep = 1.0;
+        q_rem = 4;
+    }
+    else
+    {
+        Qstep = 1.125;
+        q_rem = 5;
+    }
+
+    return (q_per * 6 + q_rem);
+}
+
+
+
diff --git a/media/libstagefright/codecs/avc/enc/src/residual.cpp b/media/libstagefright/codecs/avc/enc/src/residual.cpp
new file mode 100644
index 0000000..42eb910
--- /dev/null
+++ b/media/libstagefright/codecs/avc/enc/src/residual.cpp
@@ -0,0 +1,389 @@
+/* ------------------------------------------------------------------
+ * Copyright (C) 1998-2009 PacketVideo
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
+ * express or implied.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ * -------------------------------------------------------------------
+ */
+#include "avcenc_lib.h"
+
+AVCEnc_Status EncodeIntraPCM(AVCEncObject *encvid)
+{
+    AVCEnc_Status status = AVCENC_SUCCESS;
+    AVCCommonObj *video = encvid->common;
+    AVCFrameIO  *currInput = encvid->currInput;
+    AVCEncBitstream *stream = encvid->bitstream;
+    int x_position = (video->mb_x << 4);
+    int y_position = (video->mb_y << 4);
+    int orgPitch = currInput->pitch;
+    int offset1 = y_position * orgPitch + x_position;
+    int i, j;
+    int offset;
+    uint8 *pDst, *pSrc;
+    uint code;
+
+    ue_v(stream, 25);
+
+    i = stream->bit_left & 0x7;
+    if (i) /* not byte-aligned */
+    {
+        BitstreamWriteBits(stream, 0, i);
+    }
+
+    pSrc = currInput->YCbCr[0] + offset1;
+    pDst = video->currPic->Sl + offset1;
+    offset = video->PicWidthInSamplesL - 16;
+
+    /* at this point bitstream is byte-aligned */
+    j = 16;
+    while (j > 0)
+    {
+#if (WORD_SIZE==32)
+        for (i = 0; i < 4; i++)
+        {
+            code = *((uint*)pSrc);
+            pSrc += 4;
+            *((uint*)pDst) = code;
+            pDst += 4;
+            status = BitstreamWriteBits(stream, 32, code);
+        }
+#else
+        for (i = 0; i < 8; i++)
+        {
+            code = *((uint*)pSrc);
+            pSrc += 2;
+            *((uint*)pDst) = code;
+            pDst += 2;
+            status = BitstreamWriteBits(stream, 16, code);
+        }
+#endif
+        pDst += offset;
+        pSrc += offset;
+        j--;
+    }
+    if (status != AVCENC_SUCCESS)  /* check only once per line */
+        return status;
+
+    pDst = video->currPic->Scb + ((offset1 + x_position) >> 2);
+    pSrc = currInput->YCbCr[1] + ((offset1 + x_position) >> 2);
+    offset >>= 1;
+
+    j = 8;
+    while (j > 0)
+    {
+#if (WORD_SIZE==32)
+        for (i = 0; i < 2; i++)
+        {
+            code = *((uint*)pSrc);
+            pSrc += 4;
+            *((uint*)pDst) = code;
+            pDst += 4;
+            status = BitstreamWriteBits(stream, 32, code);
+        }
+#else
+        for (i = 0; i < 4; i++)
+        {
+            code = *((uint*)pSrc);
+            pSrc += 2;
+            *((uint*)pDst) = code;
+            pDst += 2;
+            status = BitstreamWriteBits(stream, 16, code);
+        }
+#endif
+        pDst += offset;
+        pSrc += offset;
+        j--;
+    }
+
+    if (status != AVCENC_SUCCESS)  /* check only once per line */
+        return status;
+
+    pDst = video->currPic->Scr + ((offset1 + x_position) >> 2);
+    pSrc = currInput->YCbCr[2] + ((offset1 + x_position) >> 2);
+
+    j = 8;
+    while (j > 0)
+    {
+#if (WORD_SIZE==32)
+        for (i = 0; i < 2; i++)
+        {
+            code = *((uint*)pSrc);
+            pSrc += 4;
+            *((uint*)pDst) = code;
+            pDst += 4;
+            status = BitstreamWriteBits(stream, 32, code);
+        }
+#else
+        for (i = 0; i < 4; i++)
+        {
+            code = *((uint*)pSrc);
+            pSrc += 2;
+            *((uint*)pDst) = code;
+            pDst += 2;
+            status = BitstreamWriteBits(stream, 16, code);
+        }
+#endif
+        pDst += offset;
+        pSrc += offset;
+        j--;
+    }
+
+    return status;
+}
+
+
+AVCEnc_Status enc_residual_block(AVCEncObject *encvid, AVCResidualType type, int cindx, AVCMacroblock *currMB)
+{
+    AVCEnc_Status status = AVCENC_SUCCESS;
+    AVCCommonObj *video = encvid->common;
+    int i, maxNumCoeff, nC;
+    int cdc = 0, cac = 0;
+    int TrailingOnes;
+    AVCEncBitstream *stream = encvid->bitstream;
+    uint trailing_ones_sign_flag;
+    int zerosLeft;
+    int *level, *run;
+    int TotalCoeff;
+    const static int incVlc[] = {0, 3, 6, 12, 24, 48, 32768};  // maximum vlc = 6
+    int escape, numPrefix, sufmask, suffix, shift, sign, value, absvalue, vlcnum, level_two_or_higher;
+    int bindx = blkIdx2blkXY[cindx>>2][cindx&3] ; // raster scan index
+
+    switch (type)
+    {
+        case AVC_Luma:
+            maxNumCoeff = 16;
+            level = encvid->level[cindx];
+            run = encvid->run[cindx];
+            TotalCoeff = currMB->nz_coeff[bindx];
+            break;
+        case AVC_Intra16DC:
+            maxNumCoeff = 16;
+            level = encvid->leveldc;
+            run = encvid->rundc;
+            TotalCoeff = cindx; /* special case */
+            bindx = 0;
+            cindx = 0;
+            break;
+        case AVC_Intra16AC:
+            maxNumCoeff = 15;
+            level = encvid->level[cindx];
+            run = encvid->run[cindx];
+            TotalCoeff = currMB->nz_coeff[bindx];
+            break;
+        case AVC_ChromaDC:  /* how to differentiate Cb from Cr */
+            maxNumCoeff = 4;
+            cdc = 1;
+            if (cindx >= 8)
+            {
+                level = encvid->levelcdc + 4;
+                run = encvid->runcdc + 4;
+                TotalCoeff = cindx - 8;  /* special case */
+            }
+            else
+            {
+                level = encvid->levelcdc;
+                run = encvid->runcdc;
+                TotalCoeff = cindx;  /* special case */
+            }
+            break;
+        case AVC_ChromaAC:
+            maxNumCoeff = 15;
+            cac = 1;
+            level = encvid->level[cindx];
+            run = encvid->run[cindx];
+            cindx -= 16;
+            bindx = 16 + blkIdx2blkXY[cindx>>2][cindx&3];
+            cindx += 16;
+            TotalCoeff = currMB->nz_coeff[bindx];
+            break;
+        default:
+            return AVCENC_FAIL;
+    }
+
+
+    /* find TrailingOnes */
+    TrailingOnes = 0;
+    zerosLeft = 0;
+    i = TotalCoeff - 1;
+    nC = 1;
+    while (i >= 0)
+    {
+        zerosLeft += run[i];
+        if (nC && (level[i] == 1 || level[i] == -1))
+        {
+            TrailingOnes++;
+        }
+        else
+        {
+            nC = 0;
+        }
+        i--;
+    }
+    if (TrailingOnes > 3)
+    {
+        TrailingOnes = 3; /* clip it */
+    }
+
+    if (!cdc)
+    {
+        if (!cac)  /* not chroma */
+        {
+            nC = predict_nnz(video, bindx & 3, bindx >> 2);
+        }
+        else /* chroma ac but not chroma dc */
+        {
+            nC = predict_nnz_chroma(video, bindx & 3, bindx >> 2);
+        }
+
+        status = ce_TotalCoeffTrailingOnes(stream, TrailingOnes, TotalCoeff, nC);
+    }
+    else
+    {
+        nC = -1; /* Chroma DC level */
+        status = ce_TotalCoeffTrailingOnesChromaDC(stream, TrailingOnes, TotalCoeff);
+    }
+
+    /* This part is done quite differently in ReadCoef4x4_CAVLC() */
+    if (TotalCoeff > 0)
+    {
+
+        i = TotalCoeff - 1;
+
+        if (TrailingOnes) /* keep reading the sign of those trailing ones */
+        {
+            nC = TrailingOnes;
+            trailing_ones_sign_flag = 0;
+            while (nC)
+            {
+                trailing_ones_sign_flag <<= 1;
+                trailing_ones_sign_flag |= ((uint32)level[i--] >> 31); /* 0 or positive, 1 for negative */
+                nC--;
+            }
+
+            /* instead of writing one bit at a time, read the whole thing at once */
+            status = BitstreamWriteBits(stream, TrailingOnes, trailing_ones_sign_flag);
+        }
+
+        level_two_or_higher = 1;
+        if (TotalCoeff > 3 && TrailingOnes == 3)
+        {
+            level_two_or_higher = 0;
+        }
+
+        if (TotalCoeff > 10 && TrailingOnes < 3)
+        {
+            vlcnum = 1;
+        }
+        else
+        {
+            vlcnum = 0;
+        }
+
+        /* then do this TotalCoeff-TrailingOnes times */
+        for (i = TotalCoeff - TrailingOnes - 1; i >= 0; i--)
+        {
+            value = level[i];
+            absvalue = (value >= 0) ? value : -value;
+
+            if (level_two_or_higher)
+            {
+                if (value > 0) value--;
+                else    value++;
+                level_two_or_higher = 0;
+            }
+
+            if (value >= 0)
+            {
+                sign = 0;
+            }
+            else
+            {
+                sign = 1;
+                value = -value;
+            }
+
+            if (vlcnum == 0) // VLC1
+            {
+                if (value < 8)
+                {
+                    status = BitstreamWriteBits(stream, value * 2 + sign - 1, 1);
+                }
+                else if (value < 8 + 8)
+                {
+                    status = BitstreamWriteBits(stream, 14 + 1 + 4, (1 << 4) | ((value - 8) << 1) | sign);
+                }
+                else
+                {
+                    status = BitstreamWriteBits(stream, 14 + 2 + 12, (1 << 12) | ((value - 16) << 1) | sign) ;
+                }
+            }
+            else  // VLCN
+            {
+                shift = vlcnum - 1;
+                escape = (15 << shift) + 1;
+                numPrefix = (value - 1) >> shift;
+                sufmask = ~((0xffffffff) << shift);
+                suffix = (value - 1) & sufmask;
+                if (value < escape)
+                {
+                    status = BitstreamWriteBits(stream, numPrefix + vlcnum + 1, (1 << (shift + 1)) | (suffix << 1) | sign);
+                }
+                else
+                {
+                    status = BitstreamWriteBits(stream, 28, (1 << 12) | ((value - escape) << 1) | sign);
+                }
+
+            }
+
+            if (absvalue > incVlc[vlcnum])
+                vlcnum++;
+
+            if (i == TotalCoeff - TrailingOnes - 1 && absvalue > 3)
+                vlcnum = 2;
+        }
+
+        if (status != AVCENC_SUCCESS)  /* occasionally check the bitstream */
+        {
+            return status;
+        }
+        if (TotalCoeff < maxNumCoeff)
+        {
+            if (!cdc)
+            {
+                ce_TotalZeros(stream, zerosLeft, TotalCoeff);
+            }
+            else
+            {
+                ce_TotalZerosChromaDC(stream, zerosLeft, TotalCoeff);
+            }
+        }
+        else
+        {
+            zerosLeft = 0;
+        }
+
+        i = TotalCoeff - 1;
+        while (i > 0) /* don't do the last one */
+        {
+            if (zerosLeft > 0)
+            {
+                ce_RunBefore(stream, run[i], zerosLeft);
+            }
+
+            zerosLeft = zerosLeft - run[i];
+            i--;
+        }
+    }
+
+    return status;
+}
diff --git a/media/libstagefright/codecs/avc/enc/src/sad.cpp b/media/libstagefright/codecs/avc/enc/src/sad.cpp
new file mode 100644
index 0000000..ae7acd2
--- /dev/null
+++ b/media/libstagefright/codecs/avc/enc/src/sad.cpp
@@ -0,0 +1,290 @@
+/* ------------------------------------------------------------------
+ * Copyright (C) 1998-2009 PacketVideo
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
+ * express or implied.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ * -------------------------------------------------------------------
+ */
+#include "avcenc_lib.h"
+#include "sad_inline.h"
+
+#define Cached_lx 176
+
+#ifdef _SAD_STAT
+uint32 num_sad_MB = 0;
+uint32 num_sad_Blk = 0;
+uint32 num_sad_MB_call = 0;
+uint32 num_sad_Blk_call = 0;
+
+#define NUM_SAD_MB_CALL()       num_sad_MB_call++
+#define NUM_SAD_MB()            num_sad_MB++
+#define NUM_SAD_BLK_CALL()      num_sad_Blk_call++
+#define NUM_SAD_BLK()           num_sad_Blk++
+
+#else
+
+#define NUM_SAD_MB_CALL()
+#define NUM_SAD_MB()
+#define NUM_SAD_BLK_CALL()
+#define NUM_SAD_BLK()
+
+#endif
+
+
+/* consist of
+int AVCSAD_Macroblock_C(uint8 *ref,uint8 *blk,int dmin,int lx,void *extra_info)
+int AVCSAD_MB_HTFM_Collect(uint8 *ref,uint8 *blk,int dmin,int lx,void *extra_info)
+int AVCSAD_MB_HTFM(uint8 *ref,uint8 *blk,int dmin,int lx,void *extra_info)
+*/
+
+
+/*==================================================================
+    Function:   SAD_Macroblock
+    Date:       09/07/2000
+    Purpose:    Compute SAD 16x16 between blk and ref.
+    To do:      Uniform subsampling will be inserted later!
+                Hypothesis Testing Fast Matching to be used later!
+    Changes:
+    11/7/00:    implemented MMX
+    1/24/01:    implemented SSE
+==================================================================*/
+/********** C ************/
+int AVCSAD_Macroblock_C(uint8 *ref, uint8 *blk, int dmin_lx, void *extra_info)
+{
+    (void)(extra_info);
+
+    int32 x10;
+    int dmin = (uint32)dmin_lx >> 16;
+    int lx = dmin_lx & 0xFFFF;
+
+    NUM_SAD_MB_CALL();
+
+    x10 = simd_sad_mb(ref, blk, dmin, lx);
+
+    return x10;
+}
+
+#ifdef HTFM   /* HTFM with uniform subsampling implementation 2/28/01 */
+/*===============================================================
+    Function:   AVCAVCSAD_MB_HTFM_Collect and AVCSAD_MB_HTFM
+    Date:       3/2/1
+    Purpose:    Compute the SAD on a 16x16 block using
+                uniform subsampling and hypothesis testing fast matching
+                for early dropout. SAD_MB_HP_HTFM_Collect is to collect
+                the statistics to compute the thresholds to be used in
+                SAD_MB_HP_HTFM.
+    Input/Output:
+    Changes:
+  ===============================================================*/
+
+int AVCAVCSAD_MB_HTFM_Collect(uint8 *ref, uint8 *blk, int dmin_lx, void *extra_info)
+{
+    int i;
+    int sad = 0;
+    uint8 *p1;
+    int lx4 = (dmin_lx << 2) & 0x3FFFC;
+    uint32 cur_word;
+    int saddata[16], tmp, tmp2;    /* used when collecting flag (global) is on */
+    int difmad;
+    int madstar;
+    HTFM_Stat *htfm_stat = (HTFM_Stat*) extra_info;
+    int *abs_dif_mad_avg = &(htfm_stat->abs_dif_mad_avg);
+    uint *countbreak = &(htfm_stat->countbreak);
+    int *offsetRef = htfm_stat->offsetRef;
+
+    madstar = (uint32)dmin_lx >> 20;
+
+    NUM_SAD_MB_CALL();
+
+    blk -= 4;
+    for (i = 0; i < 16; i++)
+    {
+        p1 = ref + offsetRef[i];
+        cur_word = *((uint32*)(blk += 4));
+        tmp = p1[12];
+        tmp2 = (cur_word >> 24) & 0xFF;
+        sad = SUB_SAD(sad, tmp, tmp2);
+        tmp = p1[8];
+        tmp2 = (cur_word >> 16) & 0xFF;
+        sad = SUB_SAD(sad, tmp, tmp2);
+        tmp = p1[4];
+        tmp2 = (cur_word >> 8) & 0xFF;
+        sad = SUB_SAD(sad, tmp, tmp2);
+        tmp = p1[0];
+        p1 += lx4;
+        tmp2 = (cur_word & 0xFF);
+        sad = SUB_SAD(sad, tmp, tmp2);
+
+        cur_word = *((uint32*)(blk += 4));
+        tmp = p1[12];
+        tmp2 = (cur_word >> 24) & 0xFF;
+        sad = SUB_SAD(sad, tmp, tmp2);
+        tmp = p1[8];
+        tmp2 = (cur_word >> 16) & 0xFF;
+        sad = SUB_SAD(sad, tmp, tmp2);
+        tmp = p1[4];
+        tmp2 = (cur_word >> 8) & 0xFF;
+        sad = SUB_SAD(sad, tmp, tmp2);
+        tmp = p1[0];
+        p1 += lx4;
+        tmp2 = (cur_word & 0xFF);
+        sad = SUB_SAD(sad, tmp, tmp2);
+
+        cur_word = *((uint32*)(blk += 4));
+        tmp = p1[12];
+        tmp2 = (cur_word >> 24) & 0xFF;
+        sad = SUB_SAD(sad, tmp, tmp2);
+        tmp = p1[8];
+        tmp2 = (cur_word >> 16) & 0xFF;
+        sad = SUB_SAD(sad, tmp, tmp2);
+        tmp = p1[4];
+        tmp2 = (cur_word >> 8) & 0xFF;
+        sad = SUB_SAD(sad, tmp, tmp2);
+        tmp = p1[0];
+        p1 += lx4;
+        tmp2 = (cur_word & 0xFF);
+        sad = SUB_SAD(sad, tmp, tmp2);
+
+        cur_word = *((uint32*)(blk += 4));
+        tmp = p1[12];
+        tmp2 = (cur_word >> 24) & 0xFF;
+        sad = SUB_SAD(sad, tmp, tmp2);
+        tmp = p1[8];
+        tmp2 = (cur_word >> 16) & 0xFF;
+        sad = SUB_SAD(sad, tmp, tmp2);
+        tmp = p1[4];
+        tmp2 = (cur_word >> 8) & 0xFF;
+        sad = SUB_SAD(sad, tmp, tmp2);
+        tmp = p1[0];
+        p1 += lx4;
+        tmp2 = (cur_word & 0xFF);
+        sad = SUB_SAD(sad, tmp, tmp2);
+
+        NUM_SAD_MB();
+
+        saddata[i] = sad;
+
+        if (i > 0)
+        {
+            if ((uint32)sad > ((uint32)dmin_lx >> 16))
+            {
+                difmad = saddata[0] - ((saddata[1] + 1) >> 1);
+                (*abs_dif_mad_avg) += ((difmad > 0) ? difmad : -difmad);
+                (*countbreak)++;
+                return sad;
+            }
+        }
+    }
+
+    difmad = saddata[0] - ((saddata[1] + 1) >> 1);
+    (*abs_dif_mad_avg) += ((difmad > 0) ? difmad : -difmad);
+    (*countbreak)++;
+    return sad;
+}
+
+int AVCSAD_MB_HTFM(uint8 *ref, uint8 *blk, int dmin_lx, void *extra_info)
+{
+    int sad = 0;
+    uint8 *p1;
+
+    int i;
+    int tmp, tmp2;
+    int lx4 = (dmin_lx << 2) & 0x3FFFC;
+    int sadstar = 0, madstar;
+    int *nrmlz_th = (int*) extra_info;
+    int *offsetRef = (int*) extra_info + 32;
+    uint32 cur_word;
+
+    madstar = (uint32)dmin_lx >> 20;
+
+    NUM_SAD_MB_CALL();
+
+    blk -= 4;
+    for (i = 0; i < 16; i++)
+    {
+        p1 = ref + offsetRef[i];
+        cur_word = *((uint32*)(blk += 4));
+        tmp = p1[12];
+        tmp2 = (cur_word >> 24) & 0xFF;
+        sad = SUB_SAD(sad, tmp, tmp2);
+        tmp = p1[8];
+        tmp2 = (cur_word >> 16) & 0xFF;
+        sad = SUB_SAD(sad, tmp, tmp2);
+        tmp = p1[4];
+        tmp2 = (cur_word >> 8) & 0xFF;
+        sad = SUB_SAD(sad, tmp, tmp2);
+        tmp = p1[0];
+        p1 += lx4;
+        tmp2 = (cur_word & 0xFF);
+        sad = SUB_SAD(sad, tmp, tmp2);
+
+        cur_word = *((uint32*)(blk += 4));
+        tmp = p1[12];
+        tmp2 = (cur_word >> 24) & 0xFF;
+        sad = SUB_SAD(sad, tmp, tmp2);
+        tmp = p1[8];
+        tmp2 = (cur_word >> 16) & 0xFF;
+        sad = SUB_SAD(sad, tmp, tmp2);
+        tmp = p1[4];
+        tmp2 = (cur_word >> 8) & 0xFF;
+        sad = SUB_SAD(sad, tmp, tmp2);
+        tmp = p1[0];
+        p1 += lx4;
+        tmp2 = (cur_word & 0xFF);
+        sad = SUB_SAD(sad, tmp, tmp2);
+
+        cur_word = *((uint32*)(blk += 4));
+        tmp = p1[12];
+        tmp2 = (cur_word >> 24) & 0xFF;
+        sad = SUB_SAD(sad, tmp, tmp2);
+        tmp = p1[8];
+        tmp2 = (cur_word >> 16) & 0xFF;
+        sad = SUB_SAD(sad, tmp, tmp2);
+        tmp = p1[4];
+        tmp2 = (cur_word >> 8) & 0xFF;
+        sad = SUB_SAD(sad, tmp, tmp2);
+        tmp = p1[0];
+        p1 += lx4;
+        tmp2 = (cur_word & 0xFF);
+        sad = SUB_SAD(sad, tmp, tmp2);
+
+        cur_word = *((uint32*)(blk += 4));
+        tmp = p1[12];
+        tmp2 = (cur_word >> 24) & 0xFF;
+        sad = SUB_SAD(sad, tmp, tmp2);
+        tmp = p1[8];
+        tmp2 = (cur_word >> 16) & 0xFF;
+        sad = SUB_SAD(sad, tmp, tmp2);
+        tmp = p1[4];
+        tmp2 = (cur_word >> 8) & 0xFF;
+        sad = SUB_SAD(sad, tmp, tmp2);
+        tmp = p1[0];
+        p1 += lx4;
+        tmp2 = (cur_word & 0xFF);
+        sad = SUB_SAD(sad, tmp, tmp2);
+
+        NUM_SAD_MB();
+
+        sadstar += madstar;
+        if (((uint32)sad <= ((uint32)dmin_lx >> 16)) && (sad <= (sadstar - *nrmlz_th++)))
+            ;
+        else
+            return 65536;
+    }
+
+    return sad;
+}
+#endif /* HTFM */
+
+
+
diff --git a/media/libstagefright/codecs/avc/enc/src/sad_halfpel.cpp b/media/libstagefright/codecs/avc/enc/src/sad_halfpel.cpp
new file mode 100644
index 0000000..faf2198
--- /dev/null
+++ b/media/libstagefright/codecs/avc/enc/src/sad_halfpel.cpp
@@ -0,0 +1,629 @@
+/* ------------------------------------------------------------------
+ * Copyright (C) 1998-2009 PacketVideo
+ *
+ * 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.
+ * -------------------------------------------------------------------
+ */
+/* contains
+int AVCHalfPel1_SAD_MB(uint8 *ref,uint8 *blk,int dmin,int width,int ih,int jh)
+int AVCHalfPel2_SAD_MB(uint8 *ref,uint8 *blk,int dmin,int width)
+int AVCHalfPel1_SAD_Blk(uint8 *ref,uint8 *blk,int dmin,int width,int ih,int jh)
+int AVCHalfPel2_SAD_Blk(uint8 *ref,uint8 *blk,int dmin,int width)
+
+int AVCSAD_MB_HalfPel_C(uint8 *ref,uint8 *blk,int dmin,int width,int rx,int xh,int yh,void *extra_info)
+int AVCSAD_MB_HP_HTFM_Collect(uint8 *ref,uint8 *blk,int dmin,int width,int rx,int xh,int yh,void *extra_info)
+int AVCSAD_MB_HP_HTFM(uint8 *ref,uint8 *blk,int dmin,int width,int rx,int xh,int yh,void *extra_info)
+int AVCSAD_Blk_HalfPel_C(uint8 *ref,uint8 *blk,int dmin,int width,int rx,int xh,int yh,void *extra_info)
+*/
+
+#include "avcenc_lib.h"
+#include "sad_halfpel_inline.h"
+
+#ifdef _SAD_STAT
+uint32 num_sad_HP_MB = 0;
+uint32 num_sad_HP_Blk = 0;
+uint32 num_sad_HP_MB_call = 0;
+uint32 num_sad_HP_Blk_call = 0;
+#define NUM_SAD_HP_MB_CALL()    num_sad_HP_MB_call++
+#define NUM_SAD_HP_MB()         num_sad_HP_MB++
+#define NUM_SAD_HP_BLK_CALL()   num_sad_HP_Blk_call++
+#define NUM_SAD_HP_BLK()        num_sad_HP_Blk++
+#else
+#define NUM_SAD_HP_MB_CALL()
+#define NUM_SAD_HP_MB()
+#define NUM_SAD_HP_BLK_CALL()
+#define NUM_SAD_HP_BLK()
+#endif
+
+
+
+/*===============================================================
+    Function:   SAD_MB_HalfPel
+    Date:       09/17/2000
+    Purpose:    Compute the SAD on the half-pel resolution
+    Input/Output:   hmem is assumed to be a pointer to the starting
+                point of the search in the 33x33 matrix search region
+    Changes:
+    11/7/00:    implemented MMX
+  ===============================================================*/
+/*==================================================================
+    Function:   AVCSAD_MB_HalfPel_C
+    Date:       04/30/2001
+    Purpose:    Compute SAD 16x16 between blk and ref in halfpel
+                resolution,
+    Changes:
+  ==================================================================*/
+/* One component is half-pel */
+int AVCSAD_MB_HalfPel_Cxhyh(uint8 *ref, uint8 *blk, int dmin_rx, void *extra_info)
+{
+    (void)(extra_info);
+
+    int i, j;
+    int sad = 0;
+    uint8 *kk, *p1, *p2, *p3, *p4;
+//  int sumref=0;
+    int temp;
+    int rx = dmin_rx & 0xFFFF;
+
+    NUM_SAD_HP_MB_CALL();
+
+    p1 = ref;
+    p2 = ref + 1;
+    p3 = ref + rx;
+    p4 = ref + rx + 1;
+    kk  = blk;
+
+    for (i = 0; i < 16; i++)
+    {
+        for (j = 0; j < 16; j++)
+        {
+
+            temp = ((p1[j] + p2[j] + p3[j] + p4[j] + 2) >> 2) - *kk++;
+            sad += AVC_ABS(temp);
+        }
+
+        NUM_SAD_HP_MB();
+
+        if (sad > (int)((uint32)dmin_rx >> 16))
+            return sad;
+
+        p1 += rx;
+        p3 += rx;
+        p2 += rx;
+        p4 += rx;
+    }
+    return sad;
+}
+
+int AVCSAD_MB_HalfPel_Cyh(uint8 *ref, uint8 *blk, int dmin_rx, void *extra_info)
+{
+    (void)(extra_info);
+
+    int i, j;
+    int sad = 0;
+    uint8 *kk, *p1, *p2;
+//  int sumref=0;
+    int temp;
+    int rx = dmin_rx & 0xFFFF;
+
+    NUM_SAD_HP_MB_CALL();
+
+    p1 = ref;
+    p2 = ref + rx; /* either left/right or top/bottom pixel */
+    kk  = blk;
+
+    for (i = 0; i < 16; i++)
+    {
+        for (j = 0; j < 16; j++)
+        {
+
+            temp = ((p1[j] + p2[j] + 1) >> 1) - *kk++;
+            sad += AVC_ABS(temp);
+        }
+
+        NUM_SAD_HP_MB();
+
+        if (sad > (int)((uint32)dmin_rx >> 16))
+            return sad;
+        p1 += rx;
+        p2 += rx;
+    }
+    return sad;
+}
+
+int AVCSAD_MB_HalfPel_Cxh(uint8 *ref, uint8 *blk, int dmin_rx, void *extra_info)
+{
+    (void)(extra_info);
+
+    int i, j;
+    int sad = 0;
+    uint8 *kk, *p1;
+    int temp;
+    int rx = dmin_rx & 0xFFFF;
+
+    NUM_SAD_HP_MB_CALL();
+
+    p1 = ref;
+    kk  = blk;
+
+    for (i = 0; i < 16; i++)
+    {
+        for (j = 0; j < 16; j++)
+        {
+
+            temp = ((p1[j] + p1[j+1] + 1) >> 1) - *kk++;
+            sad += AVC_ABS(temp);
+        }
+
+        NUM_SAD_HP_MB();
+
+        if (sad > (int)((uint32)dmin_rx >> 16))
+            return sad;
+        p1 += rx;
+    }
+    return sad;
+}
+
+#ifdef HTFM  /* HTFM with uniform subsampling implementation,  2/28/01 */
+
+//Checheck here
+int AVCAVCSAD_MB_HP_HTFM_Collectxhyh(uint8 *ref, uint8 *blk, int dmin_rx, void *extra_info)
+{
+    int i, j;
+    int sad = 0;
+    uint8 *p1, *p2;
+    int rx = dmin_rx & 0xFFFF;
+    int refwx4 = rx << 2;
+    int saddata[16];      /* used when collecting flag (global) is on */
+    int difmad, tmp, tmp2;
+    int madstar;
+    HTFM_Stat *htfm_stat = (HTFM_Stat*) extra_info;
+    int *abs_dif_mad_avg = &(htfm_stat->abs_dif_mad_avg);
+    UInt *countbreak = &(htfm_stat->countbreak);
+    int *offsetRef = htfm_stat->offsetRef;
+    uint32 cur_word;
+
+    madstar = (uint32)dmin_rx >> 20;
+
+    NUM_SAD_HP_MB_CALL();
+
+    blk -= 4;
+
+    for (i = 0; i < 16; i++) /* 16 stages */
+    {
+        p1 = ref + offsetRef[i];
+        p2 = p1 + rx;
+
+        j = 4;/* 4 lines */
+        do
+        {
+            cur_word = *((uint32*)(blk += 4));
+            tmp = p1[12] + p2[12];
+            tmp2 = p1[13] + p2[13];
+            tmp += tmp2;
+            tmp2 = (cur_word >> 24) & 0xFF;
+            tmp += 2;
+            sad = INTERP2_SUB_SAD(sad, tmp, tmp2);;
+            tmp = p1[8] + p2[8];
+            tmp2 = p1[9] + p2[9];
+            tmp += tmp2;
+            tmp2 = (cur_word >> 16) & 0xFF;
+            tmp += 2;
+            sad = INTERP2_SUB_SAD(sad, tmp, tmp2);;
+            tmp = p1[4] + p2[4];
+            tmp2 = p1[5] + p2[5];
+            tmp += tmp2;
+            tmp2 = (cur_word >> 8) & 0xFF;
+            tmp += 2;
+            sad = INTERP2_SUB_SAD(sad, tmp, tmp2);;
+            tmp2 = p1[1] + p2[1];
+            tmp = p1[0] + p2[0];
+            p1 += refwx4;
+            p2 += refwx4;
+            tmp += tmp2;
+            tmp2 = (cur_word & 0xFF);
+            tmp += 2;
+            sad = INTERP2_SUB_SAD(sad, tmp, tmp2);;
+        }
+        while (--j);
+
+        NUM_SAD_HP_MB();
+
+        saddata[i] = sad;
+
+        if (i > 0)
+        {
+            if (sad > ((uint32)dmin_rx >> 16))
+            {
+                difmad = saddata[0] - ((saddata[1] + 1) >> 1);
+                (*abs_dif_mad_avg) += ((difmad > 0) ? difmad : -difmad);
+                (*countbreak)++;
+                return sad;
+            }
+        }
+    }
+    difmad = saddata[0] - ((saddata[1] + 1) >> 1);
+    (*abs_dif_mad_avg) += ((difmad > 0) ? difmad : -difmad);
+    (*countbreak)++;
+
+    return sad;
+}
+
+int AVCAVCSAD_MB_HP_HTFM_Collectyh(uint8 *ref, uint8 *blk, int dmin_rx, void *extra_info)
+{
+    int i, j;
+    int sad = 0;
+    uint8 *p1, *p2;
+    int rx = dmin_rx & 0xFFFF;
+    int refwx4 = rx << 2;
+    int saddata[16];      /* used when collecting flag (global) is on */
+    int difmad, tmp, tmp2;
+    int madstar;
+    HTFM_Stat *htfm_stat = (HTFM_Stat*) extra_info;
+    int *abs_dif_mad_avg = &(htfm_stat->abs_dif_mad_avg);
+    UInt *countbreak = &(htfm_stat->countbreak);
+    int *offsetRef = htfm_stat->offsetRef;
+    uint32 cur_word;
+
+    madstar = (uint32)dmin_rx >> 20;
+
+    NUM_SAD_HP_MB_CALL();
+
+    blk -= 4;
+
+    for (i = 0; i < 16; i++) /* 16 stages */
+    {
+        p1 = ref + offsetRef[i];
+        p2 = p1 + rx;
+        j = 4;
+        do
+        {
+            cur_word = *((uint32*)(blk += 4));
+            tmp = p1[12];
+            tmp2 = p2[12];
+            tmp++;
+            tmp2 += tmp;
+            tmp = (cur_word >> 24) & 0xFF;
+            sad = INTERP1_SUB_SAD(sad, tmp, tmp2);;
+            tmp = p1[8];
+            tmp2 = p2[8];
+            tmp++;
+            tmp2 += tmp;
+            tmp = (cur_word >> 16) & 0xFF;
+            sad = INTERP1_SUB_SAD(sad, tmp, tmp2);;
+            tmp = p1[4];
+            tmp2 = p2[4];
+            tmp++;
+            tmp2 += tmp;
+            tmp = (cur_word >> 8) & 0xFF;
+            sad = INTERP1_SUB_SAD(sad, tmp, tmp2);;
+            tmp = p1[0];
+            p1 += refwx4;
+            tmp2 = p2[0];
+            p2 += refwx4;
+            tmp++;
+            tmp2 += tmp;
+            tmp = (cur_word & 0xFF);
+            sad = INTERP1_SUB_SAD(sad, tmp, tmp2);;
+        }
+        while (--j);
+
+        NUM_SAD_HP_MB();
+
+        saddata[i] = sad;
+
+        if (i > 0)
+        {
+            if (sad > ((uint32)dmin_rx >> 16))
+            {
+                difmad = saddata[0] - ((saddata[1] + 1) >> 1);
+                (*abs_dif_mad_avg) += ((difmad > 0) ? difmad : -difmad);
+                (*countbreak)++;
+                return sad;
+            }
+        }
+    }
+    difmad = saddata[0] - ((saddata[1] + 1) >> 1);
+    (*abs_dif_mad_avg) += ((difmad > 0) ? difmad : -difmad);
+    (*countbreak)++;
+
+    return sad;
+}
+
+int AVCAVCSAD_MB_HP_HTFM_Collectxh(uint8 *ref, uint8 *blk, int dmin_rx, void *extra_info)
+{
+    int i, j;
+    int sad = 0;
+    uint8 *p1;
+    int rx = dmin_rx & 0xFFFF;
+    int refwx4 = rx << 2;
+    int saddata[16];      /* used when collecting flag (global) is on */
+    int difmad, tmp, tmp2;
+    int madstar;
+    HTFM_Stat *htfm_stat = (HTFM_Stat*) extra_info;
+    int *abs_dif_mad_avg = &(htfm_stat->abs_dif_mad_avg);
+    UInt *countbreak = &(htfm_stat->countbreak);
+    int *offsetRef = htfm_stat->offsetRef;
+    uint32 cur_word;
+
+    madstar = (uint32)dmin_rx >> 20;
+
+    NUM_SAD_HP_MB_CALL();
+
+    blk -= 4;
+
+    for (i = 0; i < 16; i++) /* 16 stages */
+    {
+        p1 = ref + offsetRef[i];
+
+        j = 4; /* 4 lines */
+        do
+        {
+            cur_word = *((uint32*)(blk += 4));
+            tmp = p1[12];
+            tmp2 = p1[13];
+            tmp++;
+            tmp2 += tmp;
+            tmp = (cur_word >> 24) & 0xFF;
+            sad = INTERP1_SUB_SAD(sad, tmp, tmp2);;
+            tmp = p1[8];
+            tmp2 = p1[9];
+            tmp++;
+            tmp2 += tmp;
+            tmp = (cur_word >> 16) & 0xFF;
+            sad = INTERP1_SUB_SAD(sad, tmp, tmp2);;
+            tmp = p1[4];
+            tmp2 = p1[5];
+            tmp++;
+            tmp2 += tmp;
+            tmp = (cur_word >> 8) & 0xFF;
+            sad = INTERP1_SUB_SAD(sad, tmp, tmp2);;
+            tmp = p1[0];
+            tmp2 = p1[1];
+            p1 += refwx4;
+            tmp++;
+            tmp2 += tmp;
+            tmp = (cur_word & 0xFF);
+            sad = INTERP1_SUB_SAD(sad, tmp, tmp2);;
+        }
+        while (--j);
+
+        NUM_SAD_HP_MB();
+
+        saddata[i] = sad;
+
+        if (i > 0)
+        {
+            if (sad > ((uint32)dmin_rx >> 16))
+            {
+                difmad = saddata[0] - ((saddata[1] + 1) >> 1);
+                (*abs_dif_mad_avg) += ((difmad > 0) ? difmad : -difmad);
+                (*countbreak)++;
+                return sad;
+            }
+        }
+    }
+    difmad = saddata[0] - ((saddata[1] + 1) >> 1);
+    (*abs_dif_mad_avg) += ((difmad > 0) ? difmad : -difmad);
+    (*countbreak)++;
+
+    return sad;
+}
+
+int AVCSAD_MB_HP_HTFMxhyh(uint8 *ref, uint8 *blk, int dmin_rx, void *extra_info)
+{
+    int i, j;
+    int sad = 0, tmp, tmp2;
+    uint8 *p1, *p2;
+    int rx = dmin_rx & 0xFFFF;
+    int refwx4 = rx << 2;
+    int sadstar = 0, madstar;
+    int *nrmlz_th = (int*) extra_info;
+    int *offsetRef = nrmlz_th + 32;
+    uint32 cur_word;
+
+    madstar = (uint32)dmin_rx >> 20;
+
+    NUM_SAD_HP_MB_CALL();
+
+    blk -= 4;
+
+    for (i = 0; i < 16; i++) /* 16 stages */
+    {
+        p1 = ref + offsetRef[i];
+        p2 = p1 + rx;
+
+        j = 4; /* 4 lines */
+        do
+        {
+            cur_word = *((uint32*)(blk += 4));
+            tmp = p1[12] + p2[12];
+            tmp2 = p1[13] + p2[13];
+            tmp += tmp2;
+            tmp2 = (cur_word >> 24) & 0xFF;
+            tmp += 2;
+            sad = INTERP2_SUB_SAD(sad, tmp, tmp2);;
+            tmp = p1[8] + p2[8];
+            tmp2 = p1[9] + p2[9];
+            tmp += tmp2;
+            tmp2 = (cur_word >> 16) & 0xFF;
+            tmp += 2;
+            sad = INTERP2_SUB_SAD(sad, tmp, tmp2);;
+            tmp = p1[4] + p2[4];
+            tmp2 = p1[5] + p2[5];
+            tmp += tmp2;
+            tmp2 = (cur_word >> 8) & 0xFF;
+            tmp += 2;
+            sad = INTERP2_SUB_SAD(sad, tmp, tmp2);;
+            tmp2 = p1[1] + p2[1];
+            tmp = p1[0] + p2[0];
+            p1 += refwx4;
+            p2 += refwx4;
+            tmp += tmp2;
+            tmp2 = (cur_word & 0xFF);
+            tmp += 2;
+            sad = INTERP2_SUB_SAD(sad, tmp, tmp2);;
+        }
+        while (--j);
+
+        NUM_SAD_HP_MB();
+
+        sadstar += madstar;
+        if (sad > sadstar - nrmlz_th[i] || sad > ((uint32)dmin_rx >> 16))
+        {
+            return 65536;
+        }
+    }
+
+    return sad;
+}
+
+int AVCSAD_MB_HP_HTFMyh(uint8 *ref, uint8 *blk, int dmin_rx, void *extra_info)
+{
+    int i, j;
+    int sad = 0, tmp, tmp2;
+    uint8 *p1, *p2;
+    int rx = dmin_rx & 0xFFFF;
+    int refwx4 = rx << 2;
+    int sadstar = 0, madstar;
+    int *nrmlz_th = (int*) extra_info;
+    int *offsetRef = nrmlz_th + 32;
+    uint32 cur_word;
+
+    madstar = (uint32)dmin_rx >> 20;
+
+    NUM_SAD_HP_MB_CALL();
+
+    blk -= 4;
+
+    for (i = 0; i < 16; i++) /* 16 stages */
+    {
+        p1 = ref + offsetRef[i];
+        p2 = p1 + rx;
+        j = 4;
+        do
+        {
+            cur_word = *((uint32*)(blk += 4));
+            tmp = p1[12];
+            tmp2 = p2[12];
+            tmp++;
+            tmp2 += tmp;
+            tmp = (cur_word >> 24) & 0xFF;
+            sad = INTERP1_SUB_SAD(sad, tmp, tmp2);;
+            tmp = p1[8];
+            tmp2 = p2[8];
+            tmp++;
+            tmp2 += tmp;
+            tmp = (cur_word >> 16) & 0xFF;
+            sad = INTERP1_SUB_SAD(sad, tmp, tmp2);;
+            tmp = p1[4];
+            tmp2 = p2[4];
+            tmp++;
+            tmp2 += tmp;
+            tmp = (cur_word >> 8) & 0xFF;
+            sad = INTERP1_SUB_SAD(sad, tmp, tmp2);;
+            tmp = p1[0];
+            p1 += refwx4;
+            tmp2 = p2[0];
+            p2 += refwx4;
+            tmp++;
+            tmp2 += tmp;
+            tmp = (cur_word & 0xFF);
+            sad = INTERP1_SUB_SAD(sad, tmp, tmp2);;
+        }
+        while (--j);
+
+        NUM_SAD_HP_MB();
+        sadstar += madstar;
+        if (sad > sadstar - nrmlz_th[i] || sad > ((uint32)dmin_rx >> 16))
+        {
+            return 65536;
+        }
+    }
+
+    return sad;
+}
+
+int AVCSAD_MB_HP_HTFMxh(uint8 *ref, uint8 *blk, int dmin_rx, void *extra_info)
+{
+    int i, j;
+    int sad = 0, tmp, tmp2;
+    uint8 *p1;
+    int rx = dmin_rx & 0xFFFF;
+    int refwx4 = rx << 2;
+    int sadstar = 0, madstar;
+    int *nrmlz_th = (int*) extra_info;
+    int *offsetRef = nrmlz_th + 32;
+    uint32 cur_word;
+
+    madstar = (uint32)dmin_rx >> 20;
+
+    NUM_SAD_HP_MB_CALL();
+
+    blk -= 4;
+
+    for (i = 0; i < 16; i++) /* 16 stages */
+    {
+        p1 = ref + offsetRef[i];
+
+        j = 4;/* 4 lines */
+        do
+        {
+            cur_word = *((uint32*)(blk += 4));
+            tmp = p1[12];
+            tmp2 = p1[13];
+            tmp++;
+            tmp2 += tmp;
+            tmp = (cur_word >> 24) & 0xFF;
+            sad = INTERP1_SUB_SAD(sad, tmp, tmp2);;
+            tmp = p1[8];
+            tmp2 = p1[9];
+            tmp++;
+            tmp2 += tmp;
+            tmp = (cur_word >> 16) & 0xFF;
+            sad = INTERP1_SUB_SAD(sad, tmp, tmp2);;
+            tmp = p1[4];
+            tmp2 = p1[5];
+            tmp++;
+            tmp2 += tmp;
+            tmp = (cur_word >> 8) & 0xFF;
+            sad = INTERP1_SUB_SAD(sad, tmp, tmp2);;
+            tmp = p1[0];
+            tmp2 = p1[1];
+            p1 += refwx4;
+            tmp++;
+            tmp2 += tmp;
+            tmp = (cur_word & 0xFF);
+            sad = INTERP1_SUB_SAD(sad, tmp, tmp2);;
+        }
+        while (--j);
+
+        NUM_SAD_HP_MB();
+
+        sadstar += madstar;
+        if (sad > sadstar - nrmlz_th[i] || sad > ((uint32)dmin_rx >> 16))
+        {
+            return 65536;
+        }
+    }
+
+    return sad;
+}
+
+#endif /* HTFM */
+
+
+
+
+
diff --git a/media/libstagefright/codecs/avc/enc/src/sad_halfpel_inline.h b/media/libstagefright/codecs/avc/enc/src/sad_halfpel_inline.h
new file mode 100644
index 0000000..3a21647
--- /dev/null
+++ b/media/libstagefright/codecs/avc/enc/src/sad_halfpel_inline.h
@@ -0,0 +1,96 @@
+/* ------------------------------------------------------------------
+ * Copyright (C) 1998-2009 PacketVideo
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
+ * express or implied.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ * -------------------------------------------------------------------
+ */
+
+#ifndef _SAD_HALFPEL_INLINE_H_
+#define _SAD_HALFPEL_INLINE_H_
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#if defined(__GNUC__) && defined(__arm__) /* ARM GNU COMPILER  */
+
+    __inline int32 INTERP1_SUB_SAD(int32 sad, int32 tmp, int32 tmp2)
+    {
+        tmp = (tmp2 >> 1) - tmp;
+        if (tmp > 0) sad += tmp;
+        else sad -= tmp;
+
+        return sad;
+    }
+
+    __inline int32 INTERP2_SUB_SAD(int32 sad, int32 tmp, int32 tmp2)
+    {
+        tmp = (tmp >> 2) - tmp2;
+        if (tmp > 0) sad += tmp;
+        else sad -= tmp;
+
+        return sad;
+    }
+
+#elif defined(__CC_ARM)  /* only work with arm v5 */
+
+    __inline int32 INTERP1_SUB_SAD(int32 sad, int32 tmp, int32 tmp2)
+    {
+        __asm
+        {
+            rsbs    tmp, tmp, tmp2, asr #1 ;
+            rsbmi   tmp, tmp, #0 ;
+            add     sad, sad, tmp ;
+        }
+
+        return sad;
+    }
+
+    __inline int32 INTERP2_SUB_SAD(int32 sad, int32 tmp, int32 tmp2)
+    {
+        __asm
+        {
+            rsbs    tmp, tmp2, tmp, asr #2 ;
+            rsbmi   tmp, tmp, #0 ;
+            add     sad, sad, tmp ;
+        }
+
+        return sad;
+    }
+
+#elif defined(__GNUC__) && defined(__arm__) /* ARM GNU COMPILER  */
+
+    __inline int32 INTERP1_SUB_SAD(int32 sad, int32 tmp, int32 tmp2)
+    {
+__asm__ volatile("rsbs	%1, %1, %2, asr #1\n\trsbmi %1, %1, #0\n\tadd  %0, %0, %1": "=r"(sad), "=r"(tmp): "r"(tmp2));
+
+        return sad;
+    }
+
+    __inline int32 INTERP2_SUB_SAD(int32 sad, int32 tmp, int32 tmp2)
+    {
+__asm__ volatile("rsbs	%1, %2, %1, asr #2\n\trsbmi %1, %1, #0\n\tadd	%0, %0, %1": "=r"(sad), "=r"(tmp): "r"(tmp2));
+
+        return sad;
+    }
+
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif //_SAD_HALFPEL_INLINE_H_
+
diff --git a/media/libstagefright/codecs/avc/enc/src/sad_inline.h b/media/libstagefright/codecs/avc/enc/src/sad_inline.h
new file mode 100644
index 0000000..f39794f
--- /dev/null
+++ b/media/libstagefright/codecs/avc/enc/src/sad_inline.h
@@ -0,0 +1,488 @@
+/* ------------------------------------------------------------------
+ * Copyright (C) 1998-2009 PacketVideo
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
+ * express or implied.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ * -------------------------------------------------------------------
+ */
+#ifndef _SAD_INLINE_H_
+#define _SAD_INLINE_H_
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#if defined(__GNUC__) && defined(__arm__) /* ARM GNU COMPILER  */
+
+    __inline int32 SUB_SAD(int32 sad, int32 tmp, int32 tmp2)
+    {
+        tmp = tmp - tmp2;
+        if (tmp > 0) sad += tmp;
+        else sad -= tmp;
+
+        return sad;
+    }
+
+    __inline int32 sad_4pixel(int32 src1, int32 src2, int32 mask)
+    {
+        int32 x7;
+
+        x7 = src2 ^ src1;       /* check odd/even combination */
+        if ((uint32)src2 >= (uint32)src1)
+        {
+            src1 = src2 - src1;     /* subs */
+        }
+        else
+        {
+            src1 = src1 - src2;
+        }
+        x7 = x7 ^ src1;     /* only odd bytes need to add carry */
+        x7 = mask & ((uint32)x7 >> 1);
+        x7 = (x7 << 8) - x7;
+        src1 = src1 + (x7 >> 7); /* add 0xFF to the negative byte, add back carry */
+        src1 = src1 ^(x7 >> 7);   /* take absolute value of negative byte */
+
+        return src1;
+    }
+
+#define NUMBER 3
+#define SHIFT 24
+
+#include "sad_mb_offset.h"
+
+#undef NUMBER
+#define NUMBER 2
+#undef SHIFT
+#define SHIFT 16
+#include "sad_mb_offset.h"
+
+#undef NUMBER
+#define NUMBER 1
+#undef SHIFT
+#define SHIFT 8
+#include "sad_mb_offset.h"
+
+
+    __inline int32 simd_sad_mb(uint8 *ref, uint8 *blk, int dmin, int lx)
+    {
+        int32 x4, x5, x6, x8, x9, x10, x11, x12, x14;
+
+        x9 = 0x80808080; /* const. */
+
+        x8 = (uint32)ref & 0x3;
+        if (x8 == 3)
+            goto SadMBOffset3;
+        if (x8 == 2)
+            goto SadMBOffset2;
+        if (x8 == 1)
+            goto SadMBOffset1;
+
+//  x5 = (x4<<8)-x4; /* x5 = x4*255; */
+        x4 = x5 = 0;
+
+        x6 = 0xFFFF00FF;
+
+        ref -= lx;
+        blk -= 16;
+
+        x8 = 16;
+
+LOOP_SAD0:
+        /****** process 8 pixels ******/
+        x10 = *((uint32*)(ref += lx));
+        x11 = *((uint32*)(ref + 4));
+        x12 = *((uint32*)(blk += 16));
+        x14 = *((uint32*)(blk + 4));
+
+        /* process x11 & x14 */
+        x11 = sad_4pixel(x11, x14, x9);
+
+        /* process x12 & x10 */
+        x10 = sad_4pixel(x10, x12, x9);
+
+        x5 = x5 + x10; /* accumulate low bytes */
+        x10 = x10 & (x6 << 8); /* x10 & 0xFF00FF00 */
+        x4 = x4 + ((uint32)x10 >> 8);  /* accumulate high bytes */
+        x5 = x5 + x11;  /* accumulate low bytes */
+        x11 = x11 & (x6 << 8); /* x11 & 0xFF00FF00 */
+        x4 = x4 + ((uint32)x11 >> 8);  /* accumulate high bytes */
+
+        /****** process 8 pixels ******/
+        x10 = *((uint32*)(ref + 8));
+        x11 = *((uint32*)(ref + 12));
+        x12 = *((uint32*)(blk + 8));
+        x14 = *((uint32*)(blk + 12));
+
+        /* process x11 & x14 */
+        x11 = sad_4pixel(x11, x14, x9);
+
+        /* process x12 & x10 */
+        x10 = sad_4pixel(x10, x12, x9);
+
+        x5 = x5 + x10;  /* accumulate low bytes */
+        x10 = x10 & (x6 << 8); /* x10 & 0xFF00FF00 */
+        x4 = x4 + ((uint32)x10 >> 8); /* accumulate high bytes */
+        x5 = x5 + x11;  /* accumulate low bytes */
+        x11 = x11 & (x6 << 8); /* x11 & 0xFF00FF00 */
+        x4 = x4 + ((uint32)x11 >> 8);  /* accumulate high bytes */
+
+        /****************/
+        x10 = x5 - (x4 << 8); /* extract low bytes */
+        x10 = x10 + x4;     /* add with high bytes */
+        x10 = x10 + (x10 << 16); /* add with lower half word */
+
+        if ((int)((uint32)x10 >> 16) <= dmin) /* compare with dmin */
+        {
+            if (--x8)
+            {
+                goto LOOP_SAD0;
+            }
+
+        }
+
+        return ((uint32)x10 >> 16);
+
+SadMBOffset3:
+
+        return sad_mb_offset3(ref, blk, lx, dmin);
+
+SadMBOffset2:
+
+        return sad_mb_offset2(ref, blk, lx, dmin);
+
+SadMBOffset1:
+
+        return sad_mb_offset1(ref, blk, lx, dmin);
+
+    }
+
+#elif defined(__CC_ARM)  /* only work with arm v5 */
+
+    __inline int32 SUB_SAD(int32 sad, int32 tmp, int32 tmp2)
+    {
+        __asm
+        {
+            rsbs    tmp, tmp, tmp2 ;
+            rsbmi   tmp, tmp, #0 ;
+            add     sad, sad, tmp ;
+        }
+
+        return sad;
+    }
+
+    __inline int32 sad_4pixel(int32 src1, int32 src2, int32 mask)
+    {
+        int32 x7;
+
+        __asm
+        {
+            EOR     x7, src2, src1;     /* check odd/even combination */
+            SUBS    src1, src2, src1;
+            EOR     x7, x7, src1;
+            AND     x7, mask, x7, lsr #1;
+            ORRCC   x7, x7, #0x80000000;
+            RSB     x7, x7, x7, lsl #8;
+            ADD     src1, src1, x7, asr #7;   /* add 0xFF to the negative byte, add back carry */
+            EOR     src1, src1, x7, asr #7;   /* take absolute value of negative byte */
+        }
+
+        return src1;
+    }
+
+    __inline int32 sad_4pixelN(int32 src1, int32 src2, int32 mask)
+    {
+        int32 x7;
+
+        __asm
+        {
+            EOR      x7, src2, src1;        /* check odd/even combination */
+            ADDS     src1, src2, src1;
+            EOR      x7, x7, src1;      /* only odd bytes need to add carry */
+            ANDS     x7, mask, x7, rrx;
+            RSB      x7, x7, x7, lsl #8;
+            SUB      src1, src1, x7, asr #7;  /* add 0xFF to the negative byte, add back carry */
+            EOR      src1, src1, x7, asr #7; /* take absolute value of negative byte */
+        }
+
+        return src1;
+    }
+
+#define sum_accumulate  __asm{      SBC      x5, x5, x10;  /* accumulate low bytes */ \
+        BIC      x10, x6, x10;   /* x10 & 0xFF00FF00 */ \
+        ADD      x4, x4, x10,lsr #8;   /* accumulate high bytes */ \
+        SBC      x5, x5, x11;    /* accumulate low bytes */ \
+        BIC      x11, x6, x11;   /* x11 & 0xFF00FF00 */ \
+        ADD      x4, x4, x11,lsr #8; } /* accumulate high bytes */
+
+
+#define NUMBER 3
+#define SHIFT 24
+#define INC_X8 0x08000001
+
+#include "sad_mb_offset.h"
+
+#undef NUMBER
+#define NUMBER 2
+#undef SHIFT
+#define SHIFT 16
+#undef INC_X8
+#define INC_X8 0x10000001
+#include "sad_mb_offset.h"
+
+#undef NUMBER
+#define NUMBER 1
+#undef SHIFT
+#define SHIFT 8
+#undef INC_X8
+#define INC_X8 0x08000001
+#include "sad_mb_offset.h"
+
+
+    __inline int32 simd_sad_mb(uint8 *ref, uint8 *blk, int dmin, int lx)
+    {
+        int32 x4, x5, x6, x8, x9, x10, x11, x12, x14;
+
+        x9 = 0x80808080; /* const. */
+        x4 = x5 = 0;
+
+        __asm
+        {
+            MOVS    x8, ref, lsl #31 ;
+            BHI     SadMBOffset3;
+            BCS     SadMBOffset2;
+            BMI     SadMBOffset1;
+
+            MVN     x6, #0xFF00;
+        }
+LOOP_SAD0:
+        /****** process 8 pixels ******/
+        x11 = *((int32*)(ref + 12));
+        x10 = *((int32*)(ref + 8));
+        x14 = *((int32*)(blk + 12));
+        x12 = *((int32*)(blk + 8));
+
+        /* process x11 & x14 */
+        x11 = sad_4pixel(x11, x14, x9);
+
+        /* process x12 & x10 */
+        x10 = sad_4pixel(x10, x12, x9);
+
+        x5 = x5 + x10;  /* accumulate low bytes */
+        x10 = x10 & (x6 << 8); /* x10 & 0xFF00FF00 */
+        x4 = x4 + ((uint32)x10 >> 8); /* accumulate high bytes */
+        x5 = x5 + x11;  /* accumulate low bytes */
+        x11 = x11 & (x6 << 8); /* x11 & 0xFF00FF00 */
+        x4 = x4 + ((uint32)x11 >> 8);  /* accumulate high bytes */
+
+        __asm
+        {
+            /****** process 8 pixels ******/
+            LDR     x11, [ref, #4];
+            LDR     x10, [ref], lx ;
+            LDR     x14, [blk, #4];
+            LDR     x12, [blk], #16 ;
+        }
+
+        /* process x11 & x14 */
+        x11 = sad_4pixel(x11, x14, x9);
+
+        /* process x12 & x10 */
+        x10 = sad_4pixel(x10, x12, x9);
+
+        x5 = x5 + x10;  /* accumulate low bytes */
+        x10 = x10 & (x6 << 8); /* x10 & 0xFF00FF00 */
+        x4 = x4 + ((uint32)x10 >> 8); /* accumulate high bytes */
+        x5 = x5 + x11;  /* accumulate low bytes */
+        x11 = x11 & (x6 << 8); /* x11 & 0xFF00FF00 */
+        x4 = x4 + ((uint32)x11 >> 8);  /* accumulate high bytes */
+
+        /****************/
+        x10 = x5 - (x4 << 8); /* extract low bytes */
+        x10 = x10 + x4;     /* add with high bytes */
+        x10 = x10 + (x10 << 16); /* add with lower half word */
+
+        __asm
+        {
+            /****************/
+            RSBS    x11, dmin, x10, lsr #16;
+            ADDLSS  x8, x8, #0x10000001;
+            BLS     LOOP_SAD0;
+        }
+
+        return ((uint32)x10 >> 16);
+
+SadMBOffset3:
+
+        return sad_mb_offset3(ref, blk, lx, dmin, x8);
+
+SadMBOffset2:
+
+        return sad_mb_offset2(ref, blk, lx, dmin, x8);
+
+SadMBOffset1:
+
+        return sad_mb_offset1(ref, blk, lx, dmin, x8);
+    }
+
+
+#elif defined(__GNUC__) && defined(__arm__) /* ARM GNU COMPILER  */
+
+    __inline int32 SUB_SAD(int32 sad, int32 tmp, int32 tmp2)
+    {
+__asm__ volatile("rsbs	%1, %1, %2\n\trsbmi %1, %1, #0\n\tadd	%0, %0, %1": "=r"(sad): "r"(tmp), "r"(tmp2));
+        return sad;
+    }
+
+    __inline int32 sad_4pixel(int32 src1, int32 src2, int32 mask)
+    {
+        int32 x7;
+
+__asm__ volatile("EOR	%1, %2, %0\n\tSUBS  %0, %2, %0\n\tEOR	%1, %1, %0\n\tAND  %1, %3, %1, lsr #1\n\tORRCC	%1, %1, #0x80000000\n\tRSB  %1, %1, %1, lsl #8\n\tADD  %0, %0, %1, asr #7\n\tEOR  %0, %0, %1, asr #7": "=r"(src1), "=&r"(x7): "r"(src2), "r"(mask));
+
+        return src1;
+    }
+
+    __inline int32 sad_4pixelN(int32 src1, int32 src2, int32 mask)
+    {
+        int32 x7;
+
+__asm__ volatile("EOR	%1, %2, %0\n\tADDS  %0, %2, %0\n\tEOR  %1, %1, %0\n\tANDS  %1, %3, %1, rrx\n\tRSB  %1, %1, %1, lsl #8\n\tSUB	%0, %0, %1, asr #7\n\tEOR   %0, %0, %1, asr #7": "=r"(src1), "=&r"(x7): "r"(src2), "r"(mask));
+
+        return src1;
+    }
+
+#define sum_accumulate  __asm__ volatile("SBC  %0, %0, %1\n\tBIC   %1, %4, %1\n\tADD   %2, %2, %1, lsr #8\n\tSBC   %0, %0, %3\n\tBIC   %3, %4, %3\n\tADD   %2, %2, %3, lsr #8": "=&r" (x5), "=&r" (x10), "=&r" (x4), "=&r" (x11): "r" (x6));
+
+#define NUMBER 3
+#define SHIFT 24
+#define INC_X8 0x08000001
+
+#include "sad_mb_offset.h"
+
+#undef NUMBER
+#define NUMBER 2
+#undef SHIFT
+#define SHIFT 16
+#undef INC_X8
+#define INC_X8 0x10000001
+#include "sad_mb_offset.h"
+
+#undef NUMBER
+#define NUMBER 1
+#undef SHIFT
+#define SHIFT 8
+#undef INC_X8
+#define INC_X8 0x08000001
+#include "sad_mb_offset.h"
+
+
+    __inline int32 simd_sad_mb(uint8 *ref, uint8 *blk, int dmin, int lx)
+    {
+        int32 x4, x5, x6, x8, x9, x10, x11, x12, x14;
+
+        x9 = 0x80808080; /* const. */
+        x4 = x5 = 0;
+
+        x8 = (uint32)ref & 0x3;
+        if (x8 == 3)
+            goto SadMBOffset3;
+        if (x8 == 2)
+            goto SadMBOffset2;
+        if (x8 == 1)
+            goto SadMBOffset1;
+
+        x8 = 16;
+///
+__asm__ volatile("MVN	%0, #0xFF00": "=r"(x6));
+
+LOOP_SAD0:
+        /****** process 8 pixels ******/
+        x11 = *((int32*)(ref + 12));
+        x10 = *((int32*)(ref + 8));
+        x14 = *((int32*)(blk + 12));
+        x12 = *((int32*)(blk + 8));
+
+        /* process x11 & x14 */
+        x11 = sad_4pixel(x11, x14, x9);
+
+        /* process x12 & x10 */
+        x10 = sad_4pixel(x10, x12, x9);
+
+        x5 = x5 + x10;  /* accumulate low bytes */
+        x10 = x10 & (x6 << 8); /* x10 & 0xFF00FF00 */
+        x4 = x4 + ((uint32)x10 >> 8); /* accumulate high bytes */
+        x5 = x5 + x11;  /* accumulate low bytes */
+        x11 = x11 & (x6 << 8); /* x11 & 0xFF00FF00 */
+        x4 = x4 + ((uint32)x11 >> 8);  /* accumulate high bytes */
+
+        /****** process 8 pixels ******/
+        x11 = *((int32*)(ref + 4));
+__asm__ volatile("LDR	%0, [%1], %2": "=&r"(x10), "=r"(ref): "r"(lx));
+        //x10 = *((int32*)ref); ref+=lx;
+        x14 = *((int32*)(blk + 4));
+__asm__ volatile("LDR	%0, [%1], #16": "=&r"(x12), "=r"(blk));
+
+        /* process x11 & x14 */
+        x11 = sad_4pixel(x11, x14, x9);
+
+        /* process x12 & x10 */
+        x10 = sad_4pixel(x10, x12, x9);
+
+        x5 = x5 + x10;  /* accumulate low bytes */
+        x10 = x10 & (x6 << 8); /* x10 & 0xFF00FF00 */
+        x4 = x4 + ((uint32)x10 >> 8); /* accumulate high bytes */
+        x5 = x5 + x11;  /* accumulate low bytes */
+        x11 = x11 & (x6 << 8); /* x11 & 0xFF00FF00 */
+        x4 = x4 + ((uint32)x11 >> 8);  /* accumulate high bytes */
+
+        /****************/
+        x10 = x5 - (x4 << 8); /* extract low bytes */
+        x10 = x10 + x4;     /* add with high bytes */
+        x10 = x10 + (x10 << 16); /* add with lower half word */
+
+        /****************/
+
+        if (((uint32)x10 >> 16) <= dmin) /* compare with dmin */
+        {
+            if (--x8)
+            {
+                goto LOOP_SAD0;
+            }
+
+        }
+
+        return ((uint32)x10 >> 16);
+
+SadMBOffset3:
+
+        return sad_mb_offset3(ref, blk, lx, dmin);
+
+SadMBOffset2:
+
+        return sad_mb_offset2(ref, blk, lx, dmin);
+
+SadMBOffset1:
+
+        return sad_mb_offset1(ref, blk, lx, dmin);
+    }
+
+
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // _SAD_INLINE_H_
+
diff --git a/media/libstagefright/codecs/avc/enc/src/sad_mb_offset.h b/media/libstagefright/codecs/avc/enc/src/sad_mb_offset.h
new file mode 100644
index 0000000..d5d4a42
--- /dev/null
+++ b/media/libstagefright/codecs/avc/enc/src/sad_mb_offset.h
@@ -0,0 +1,311 @@
+/* ------------------------------------------------------------------
+ * Copyright (C) 1998-2009 PacketVideo
+ *
+ * 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.
+ * -------------------------------------------------------------------
+ */
+
+#if defined(__GNUC__) && defined(__arm__) /* ARM GNU COMPILER  */
+
+#if (NUMBER==3)
+__inline int32 sad_mb_offset3(uint8 *ref, uint8 *blk, int lx, int dmin)
+#elif (NUMBER==2)
+__inline int32 sad_mb_offset2(uint8 *ref, uint8 *blk, int lx, int dmin)
+#elif (NUMBER==1)
+__inline int32 sad_mb_offset1(uint8 *ref, uint8 *blk, int lx, int dmin)
+#endif
+{
+    int32 x4, x5, x6, x8, x9, x10, x11, x12, x14;
+
+    //  x5 = (x4<<8) - x4;
+    x4 = x5 = 0;
+    x6 = 0xFFFF00FF;
+    x9 = 0x80808080; /* const. */
+    ref -= NUMBER; /* bic ref, ref, #3 */
+    ref -= lx;
+    blk -= 16;
+    x8 = 16;
+
+#if (NUMBER==3)
+LOOP_SAD3:
+#elif (NUMBER==2)
+LOOP_SAD2:
+#elif (NUMBER==1)
+LOOP_SAD1:
+#endif
+    /****** process 8 pixels ******/
+    x10 = *((uint32*)(ref += lx)); /* D C B A */
+    x11 = *((uint32*)(ref + 4));    /* H G F E */
+    x12 = *((uint32*)(ref + 8));    /* L K J I */
+
+    x10 = ((uint32)x10 >> SHIFT); /* 0 0 0 D */
+    x10 = x10 | (x11 << (32 - SHIFT));        /* G F E D */
+    x11 = ((uint32)x11 >> SHIFT); /* 0 0 0 H */
+    x11 = x11 | (x12 << (32 - SHIFT));        /* K J I H */
+
+    x12 = *((uint32*)(blk += 16));
+    x14 = *((uint32*)(blk + 4));
+
+    /* process x11 & x14 */
+    x11 = sad_4pixel(x11, x14, x9);
+
+    /* process x12 & x10 */
+    x10 = sad_4pixel(x10, x12, x9);
+
+    x5 = x5 + x10; /* accumulate low bytes */
+    x10 = x10 & (x6 << 8); /* x10 & 0xFF00FF00 */
+    x4 = x4 + ((uint32)x10 >> 8);  /* accumulate high bytes */
+    x5 = x5 + x11;  /* accumulate low bytes */
+    x11 = x11 & (x6 << 8); /* x11 & 0xFF00FF00 */
+    x4 = x4 + ((uint32)x11 >> 8);  /* accumulate high bytes */
+
+    /****** process 8 pixels ******/
+    x10 = *((uint32*)(ref + 8)); /* D C B A */
+    x11 = *((uint32*)(ref + 12));   /* H G F E */
+    x12 = *((uint32*)(ref + 16));   /* L K J I */
+
+    x10 = ((uint32)x10 >> SHIFT); /* mvn x10, x10, lsr #24  = 0xFF 0xFF 0xFF ~D */
+    x10 = x10 | (x11 << (32 - SHIFT));        /* bic x10, x10, x11, lsl #8 = ~G ~F ~E ~D */
+    x11 = ((uint32)x11 >> SHIFT); /* 0xFF 0xFF 0xFF ~H */
+    x11 = x11 | (x12 << (32 - SHIFT));        /* ~K ~J ~I ~H */
+
+    x12 = *((uint32*)(blk + 8));
+    x14 = *((uint32*)(blk + 12));
+
+    /* process x11 & x14 */
+    x11 = sad_4pixel(x11, x14, x9);
+
+    /* process x12 & x10 */
+    x10 = sad_4pixel(x10, x12, x9);
+
+    x5 = x5 + x10; /* accumulate low bytes */
+    x10 = x10 & (x6 << 8); /* x10 & 0xFF00FF00 */
+    x4 = x4 + ((uint32)x10 >> 8);  /* accumulate high bytes */
+    x5 = x5 + x11;  /* accumulate low bytes */
+    x11 = x11 & (x6 << 8); /* x11 & 0xFF00FF00 */
+    x4 = x4 + ((uint32)x11 >> 8);  /* accumulate high bytes */
+
+    /****************/
+    x10 = x5 - (x4 << 8); /* extract low bytes */
+    x10 = x10 + x4;     /* add with high bytes */
+    x10 = x10 + (x10 << 16); /* add with lower half word */
+
+    if ((int)((uint32)x10 >> 16) <= dmin) /* compare with dmin */
+    {
+        if (--x8)
+        {
+#if (NUMBER==3)
+            goto         LOOP_SAD3;
+#elif (NUMBER==2)
+            goto         LOOP_SAD2;
+#elif (NUMBER==1)
+            goto         LOOP_SAD1;
+#endif
+        }
+
+    }
+
+    return ((uint32)x10 >> 16);
+}
+
+#elif defined(__CC_ARM)  /* only work with arm v5 */
+
+#if (NUMBER==3)
+__inline int32 sad_mb_offset3(uint8 *ref, uint8 *blk, int lx, int dmin, int32 x8)
+#elif (NUMBER==2)
+__inline int32 sad_mb_offset2(uint8 *ref, uint8 *blk, int lx, int dmin, int32 x8)
+#elif (NUMBER==1)
+__inline int32 sad_mb_offset1(uint8 *ref, uint8 *blk, int lx, int dmin, int32 x8)
+#endif
+{
+    int32 x4, x5, x6, x9, x10, x11, x12, x14;
+
+    x9 = 0x80808080; /* const. */
+    x4 = x5 = 0;
+
+    __asm{
+        MVN      x6, #0xff0000;
+#if (NUMBER==3)
+LOOP_SAD3:
+#elif (NUMBER==2)
+LOOP_SAD2:
+#elif (NUMBER==1)
+LOOP_SAD1:
+#endif
+        BIC      ref, ref, #3;
+    }
+    /****** process 8 pixels ******/
+    x11 = *((int32*)(ref + 12));
+    x12 = *((int32*)(ref + 16));
+    x10 = *((int32*)(ref + 8));
+    x14 = *((int32*)(blk + 12));
+
+    __asm{
+        MVN      x10, x10, lsr #SHIFT;
+        BIC      x10, x10, x11, lsl #(32-SHIFT);
+        MVN      x11, x11, lsr #SHIFT;
+        BIC      x11, x11, x12, lsl #(32-SHIFT);
+
+        LDR      x12, [blk, #8];
+    }
+
+    /* process x11 & x14 */
+    x11 = sad_4pixelN(x11, x14, x9);
+
+    /* process x12 & x10 */
+    x10 = sad_4pixelN(x10, x12, x9);
+
+    sum_accumulate;
+
+    __asm{
+        /****** process 8 pixels ******/
+        LDR      x11, [ref, #4];
+        LDR      x12, [ref, #8];
+        LDR  x10, [ref], lx ;
+        LDR  x14, [blk, #4];
+
+        MVN      x10, x10, lsr #SHIFT;
+        BIC      x10, x10, x11, lsl #(32-SHIFT);
+        MVN      x11, x11, lsr #SHIFT;
+        BIC      x11, x11, x12, lsl #(32-SHIFT);
+
+        LDR      x12, [blk], #16;
+    }
+
+    /* process x11 & x14 */
+    x11 = sad_4pixelN(x11, x14, x9);
+
+    /* process x12 & x10 */
+    x10 = sad_4pixelN(x10, x12, x9);
+
+    sum_accumulate;
+
+    /****************/
+    x10 = x5 - (x4 << 8); /* extract low bytes */
+    x10 = x10 + x4;     /* add with high bytes */
+    x10 = x10 + (x10 << 16); /* add with lower half word */
+
+    __asm{
+        RSBS     x11, dmin, x10, lsr #16
+        ADDLSS   x8, x8, #INC_X8
+#if (NUMBER==3)
+        BLS      LOOP_SAD3;
+#elif (NUMBER==2)
+BLS      LOOP_SAD2;
+#elif (NUMBER==1)
+BLS      LOOP_SAD1;
+#endif
+    }
+
+    return ((uint32)x10 >> 16);
+}
+
+#elif defined(__GNUC__) && defined(__arm__) /* ARM GNU COMPILER  */
+
+#if (NUMBER==3)
+__inline int32 sad_mb_offset3(uint8 *ref, uint8 *blk, int lx, int dmin)
+#elif (NUMBER==2)
+__inline int32 sad_mb_offset2(uint8 *ref, uint8 *blk, int lx, int dmin)
+#elif (NUMBER==1)
+__inline int32 sad_mb_offset1(uint8 *ref, uint8 *blk, int lx, int dmin)
+#endif
+{
+    int32 x4, x5, x6, x8, x9, x10, x11, x12, x14;
+
+    x9 = 0x80808080; /* const. */
+    x4 = x5 = 0;
+    x8 = 16; //<<===========*******
+
+__asm__ volatile("MVN	%0, #0xFF0000": "=r"(x6));
+
+#if (NUMBER==3)
+LOOP_SAD3:
+#elif (NUMBER==2)
+LOOP_SAD2:
+#elif (NUMBER==1)
+LOOP_SAD1:
+#endif
+__asm__ volatile("BIC  %0, %0, #3": "=r"(ref));
+    /****** process 8 pixels ******/
+    x11 = *((int32*)(ref + 12));
+    x12 = *((int32*)(ref + 16));
+    x10 = *((int32*)(ref + 8));
+    x14 = *((int32*)(blk + 12));
+
+#if (SHIFT==8)
+__asm__ volatile("MVN   %0, %0, lsr #8\n\tBIC   %0, %0, %1,lsl #24\n\tMVN   %1, %1,lsr #8\n\tBIC   %1, %1, %2,lsl #24": "=&r"(x10), "=&r"(x11): "r"(x12));
+#elif (SHIFT==16)
+__asm__ volatile("MVN   %0, %0, lsr #16\n\tBIC   %0, %0, %1,lsl #16\n\tMVN   %1, %1,lsr #16\n\tBIC   %1, %1, %2,lsl #16": "=&r"(x10), "=&r"(x11): "r"(x12));
+#elif (SHIFT==24)
+__asm__ volatile("MVN   %0, %0, lsr #24\n\tBIC   %0, %0, %1,lsl #8\n\tMVN   %1, %1,lsr #24\n\tBIC   %1, %1, %2,lsl #8": "=&r"(x10), "=&r"(x11): "r"(x12));
+#endif
+
+    x12 = *((int32*)(blk + 8));
+
+    /* process x11 & x14 */
+    x11 = sad_4pixelN(x11, x14, x9);
+
+    /* process x12 & x10 */
+    x10 = sad_4pixelN(x10, x12, x9);
+
+    sum_accumulate;
+
+    /****** process 8 pixels ******/
+    x11 = *((int32*)(ref + 4));
+    x12 = *((int32*)(ref + 8));
+    x10 = *((int32*)ref); ref += lx;
+    x14 = *((int32*)(blk + 4));
+
+#if (SHIFT==8)
+__asm__ volatile("MVN   %0, %0, lsr #8\n\tBIC   %0, %0, %1,lsl #24\n\tMVN   %1, %1,lsr #8\n\tBIC   %1, %1, %2,lsl #24": "=&r"(x10), "=&r"(x11): "r"(x12));
+#elif (SHIFT==16)
+__asm__ volatile("MVN   %0, %0, lsr #16\n\tBIC   %0, %0, %1,lsl #16\n\tMVN   %1, %1,lsr #16\n\tBIC   %1, %1, %2,lsl #16": "=&r"(x10), "=&r"(x11): "r"(x12));
+#elif (SHIFT==24)
+__asm__ volatile("MVN   %0, %0, lsr #24\n\tBIC   %0, %0, %1,lsl #8\n\tMVN   %1, %1,lsr #24\n\tBIC   %1, %1, %2,lsl #8": "=&r"(x10), "=&r"(x11): "r"(x12));
+#endif
+__asm__ volatile("LDR   %0, [%1], #16": "=&r"(x12), "=r"(blk));
+
+    /* process x11 & x14 */
+    x11 = sad_4pixelN(x11, x14, x9);
+
+    /* process x12 & x10 */
+    x10 = sad_4pixelN(x10, x12, x9);
+
+    sum_accumulate;
+
+    /****************/
+    x10 = x5 - (x4 << 8); /* extract low bytes */
+    x10 = x10 + x4;     /* add with high bytes */
+    x10 = x10 + (x10 << 16); /* add with lower half word */
+
+    if (((uint32)x10 >> 16) <= (uint32)dmin) /* compare with dmin */
+    {
+        if (--x8)
+        {
+#if (NUMBER==3)
+            goto         LOOP_SAD3;
+#elif (NUMBER==2)
+goto         LOOP_SAD2;
+#elif (NUMBER==1)
+goto         LOOP_SAD1;
+#endif
+        }
+
+    }
+
+    return ((uint32)x10 >> 16);
+}
+
+#endif
+
diff --git a/media/libstagefright/codecs/avc/enc/src/slice.cpp b/media/libstagefright/codecs/avc/enc/src/slice.cpp
new file mode 100644
index 0000000..f6d066e
--- /dev/null
+++ b/media/libstagefright/codecs/avc/enc/src/slice.cpp
@@ -0,0 +1,1025 @@
+/* ------------------------------------------------------------------
+ * Copyright (C) 1998-2009 PacketVideo
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
+ * express or implied.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ * -------------------------------------------------------------------
+ */
+#include "avcenc_lib.h"
+
+
+AVCEnc_Status AVCEncodeSlice(AVCEncObject *encvid)
+{
+    AVCEnc_Status status = AVCENC_SUCCESS;
+    AVCCommonObj *video = encvid->common;
+    AVCPicParamSet *pps = video->currPicParams;
+    AVCSliceHeader *sliceHdr = video->sliceHdr;
+    AVCMacroblock *currMB ;
+    AVCEncBitstream *stream = encvid->bitstream;
+    uint slice_group_id;
+    int CurrMbAddr, slice_type;
+
+    slice_type = video->slice_type;
+
+    /* set the first mb in slice */
+    video->mbNum = CurrMbAddr = sliceHdr->first_mb_in_slice;// * (1+video->MbaffFrameFlag);
+    slice_group_id = video->MbToSliceGroupMap[CurrMbAddr];
+
+    video->mb_skip_run = 0;
+
+    /* while loop , see subclause 7.3.4 */
+    while (1)
+    {
+        video->mbNum = CurrMbAddr;
+        currMB = video->currMB = &(video->mblock[CurrMbAddr]);
+        currMB->slice_id = video->slice_id;  // for deblocking
+
+        video->mb_x = CurrMbAddr % video->PicWidthInMbs;
+        video->mb_y = CurrMbAddr / video->PicWidthInMbs;
+
+        /* initialize QP for this MB here*/
+        /* calculate currMB->QPy */
+        RCInitMBQP(encvid);
+
+        /* check the availability of neighboring macroblocks */
+        InitNeighborAvailability(video, CurrMbAddr);
+
+        /* Assuming that InitNeighborAvailability has been called prior to this function */
+        video->intraAvailA = video->intraAvailB = video->intraAvailC = video->intraAvailD = 0;
+        /* this is necessary for all subsequent intra search */
+
+        if (!video->currPicParams->constrained_intra_pred_flag)
+        {
+            video->intraAvailA = video->mbAvailA;
+            video->intraAvailB = video->mbAvailB;
+            video->intraAvailC = video->mbAvailC;
+            video->intraAvailD = video->mbAvailD;
+        }
+        else
+        {
+            if (video->mbAvailA)
+            {
+                video->intraAvailA = video->mblock[video->mbAddrA].mb_intra;
+            }
+            if (video->mbAvailB)
+            {
+                video->intraAvailB = video->mblock[video->mbAddrB].mb_intra ;
+            }
+            if (video->mbAvailC)
+            {
+                video->intraAvailC = video->mblock[video->mbAddrC].mb_intra;
+            }
+            if (video->mbAvailD)
+            {
+                video->intraAvailD = video->mblock[video->mbAddrD].mb_intra;
+            }
+        }
+
+        /* encode_one_macroblock() */
+        status = EncodeMB(encvid);
+        if (status != AVCENC_SUCCESS)
+        {
+            break;
+        }
+
+        /* go to next MB */
+        CurrMbAddr++;
+
+        while ((uint)video->MbToSliceGroupMap[CurrMbAddr] != slice_group_id &&
+                (uint)CurrMbAddr < video->PicSizeInMbs)
+        {
+            CurrMbAddr++;
+        }
+
+        if ((uint)CurrMbAddr >= video->PicSizeInMbs)
+        {
+            /* end of slice, return, but before that check to see if there are other slices
+            to be encoded. */
+            encvid->currSliceGroup++;
+            if (encvid->currSliceGroup > (int)pps->num_slice_groups_minus1) /* no more slice group */
+            {
+                status = AVCENC_PICTURE_READY;
+                break;
+            }
+            else
+            {
+                /* find first_mb_num for the next slice */
+                CurrMbAddr = 0;
+                while (video->MbToSliceGroupMap[CurrMbAddr] != encvid->currSliceGroup &&
+                        (uint)CurrMbAddr < video->PicSizeInMbs)
+                {
+                    CurrMbAddr++;
+                }
+                if ((uint)CurrMbAddr >= video->PicSizeInMbs)
+                {
+                    status = AVCENC_SLICE_EMPTY; /* error, one slice group has no MBs in it */
+                }
+
+                video->mbNum = CurrMbAddr;
+                status = AVCENC_SUCCESS;
+                break;
+            }
+        }
+    }
+
+    if (video->mb_skip_run > 0)
+    {
+        /* write skip_run */
+        if (slice_type != AVC_I_SLICE && slice_type != AVC_SI_SLICE)
+        {
+            ue_v(stream, video->mb_skip_run);
+            video->mb_skip_run = 0;
+        }
+        else    /* shouldn't happen */
+        {
+            status = AVCENC_FAIL;
+        }
+    }
+
+    return status;
+}
+
+
+AVCEnc_Status EncodeMB(AVCEncObject *encvid)
+{
+    AVCEnc_Status status = AVCENC_SUCCESS;
+    AVCCommonObj *video = encvid->common;
+    AVCPictureData *currPic = video->currPic;
+    AVCFrameIO  *currInput = encvid->currInput;
+    AVCMacroblock *currMB = video->currMB;
+    AVCMacroblock *MB_A, *MB_B;
+    AVCEncBitstream *stream = encvid->bitstream;
+    AVCRateControl *rateCtrl = encvid->rateCtrl;
+    uint8 *cur, *curL, *curCb, *curCr;
+    uint8 *orgL, *orgCb, *orgCr, *org4;
+    int CurrMbAddr = video->mbNum;
+    int picPitch = currPic->pitch;
+    int orgPitch = currInput->pitch;
+    int x_position = (video->mb_x << 4);
+    int y_position = (video->mb_y << 4);
+    int offset;
+    int b8, b4, blkidx;
+    AVCResidualType  resType;
+    int slice_type;
+    int numcoeff; /* output from residual_block_cavlc */
+    int cost16, cost8;
+
+    int num_bits, start_mb_bits, start_text_bits;
+
+    slice_type = video->slice_type;
+
+    /* now, point to the reconstructed frame */
+    offset = y_position * picPitch + x_position;
+    curL = currPic->Sl + offset;
+    orgL = currInput->YCbCr[0] + offset;
+    offset = (offset + x_position) >> 2;
+    curCb = currPic->Scb + offset;
+    curCr = currPic->Scr + offset;
+    orgCb = currInput->YCbCr[1] + offset;
+    orgCr = currInput->YCbCr[2] + offset;
+
+    if (orgPitch != picPitch)
+    {
+        offset = y_position * (orgPitch - picPitch);
+        orgL += offset;
+        offset >>= 2;
+        orgCb += offset;
+        orgCr += offset;
+    }
+
+    /******* determine MB prediction mode *******/
+    if (encvid->intraSearch[CurrMbAddr])
+    {
+        MBIntraSearch(encvid, CurrMbAddr, curL, picPitch);
+    }
+    /******* This part should be determined somehow ***************/
+    if (currMB->mbMode == AVC_I_PCM)
+    {
+        /* write down mb_type and PCM data */
+        /* and copy from currInput to currPic */
+        status = EncodeIntraPCM(encvid);
+
+
+        return status;
+    }
+
+    /****** for intra prediction, pred is already done *******/
+    /****** for I4, the recon is ready and Xfrm coefs are ready to be encoded *****/
+
+    //RCCalculateMAD(encvid,currMB,orgL,orgPitch); // no need to re-calculate MAD for Intra
+    // not used since totalSAD is used instead
+
+    /* compute the prediction */
+    /* output is video->pred_block */
+    if (!currMB->mb_intra)
+    {
+        AVCMBMotionComp(encvid, video); /* perform prediction and residue calculation */
+        /* we can do the loop here and call dct_luma */
+        video->pred_pitch = picPitch;
+        currMB->CBP = 0;
+        cost16 = 0;
+        cur = curL;
+        org4 = orgL;
+
+        for (b8 = 0; b8 < 4; b8++)
+        {
+            cost8 = 0;
+
+            for (b4 = 0; b4 < 4; b4++)
+            {
+                blkidx = blkIdx2blkXY[b8][b4];
+                video->pred_block = cur;
+                numcoeff = dct_luma(encvid, blkidx, cur, org4, &cost8);
+                currMB->nz_coeff[blkidx] = numcoeff;
+                if (numcoeff)
+                {
+                    video->cbp4x4 |= (1 << blkidx);
+                    currMB->CBP |= (1 << b8);
+                }
+
+                if (b4&1)
+                {
+                    cur += ((picPitch << 2) - 4);
+                    org4 += ((orgPitch << 2) - 4);
+                }
+                else
+                {
+                    cur += 4;
+                    org4 += 4;
+                }
+            }
+
+            /* move the IDCT part out of dct_luma to accommodate the check
+               for coeff_cost. */
+
+            if ((currMB->CBP&(1 << b8)) && (cost8 <= _LUMA_COEFF_COST_))
+            {
+                cost8 = 0; // reset it
+
+                currMB->CBP ^= (1 << b8);
+                blkidx = blkIdx2blkXY[b8][0];
+
+                currMB->nz_coeff[blkidx] = 0;
+                currMB->nz_coeff[blkidx+1] = 0;
+                currMB->nz_coeff[blkidx+4] = 0;
+                currMB->nz_coeff[blkidx+5] = 0;
+            }
+
+            cost16 += cost8;
+
+            if (b8&1)
+            {
+                cur -= 8;
+                org4 -= 8;
+            }
+            else
+            {
+                cur += (8 - (picPitch << 3));
+                org4 += (8 - (orgPitch << 3));
+            }
+        }
+
+        /* after the whole MB, we do another check for coeff_cost */
+        if ((currMB->CBP&0xF) && (cost16 <= _LUMA_MB_COEFF_COST_))
+        {
+            currMB->CBP = 0;  // reset it to zero
+            memset(currMB->nz_coeff, 0, sizeof(uint8)*16);
+        }
+
+        // now we do IDCT
+        MBInterIdct(video, curL, currMB, picPitch);
+
+//      video->pred_block = video->pred + 256;
+    }
+    else    /* Intra prediction */
+    {
+        encvid->numIntraMB++;
+
+        if (currMB->mbMode == AVC_I16) /* do prediction for the whole macroblock */
+        {
+            currMB->CBP = 0;
+            /* get the prediction from encvid->pred_i16 */
+            dct_luma_16x16(encvid, curL, orgL);
+        }
+        video->pred_block = encvid->pred_ic[currMB->intra_chroma_pred_mode];
+    }
+
+    /* chrominance */
+    /* not need to do anything, the result is in encvid->pred_ic
+    chroma dct must be aware that prediction block can come from either intra or inter. */
+
+    dct_chroma(encvid, curCb, orgCb, 0);
+
+    dct_chroma(encvid, curCr, orgCr, 1);
+
+
+    /* 4.1 if there's nothing in there, video->mb_skip_run++ */
+    /* 4.2 if coded, check if there is a run of skipped MB, encodes it,
+            set video->QPyprev = currMB->QPy; */
+
+    /* 5. vlc encode */
+
+    /* check for skipped macroblock, INTER only */
+    if (!currMB->mb_intra)
+    {
+        /* decide whether this MB (for inter MB) should be skipped if there's nothing left. */
+        if (!currMB->CBP && currMB->NumMbPart == 1 && currMB->QPy == video->QPy)
+        {
+            if (currMB->MBPartPredMode[0][0] == AVC_Pred_L0 && currMB->ref_idx_L0[0] == 0)
+            {
+                MB_A = &video->mblock[video->mbAddrA];
+                MB_B = &video->mblock[video->mbAddrB];
+
+                if (!video->mbAvailA || !video->mbAvailB)
+                {
+                    if (currMB->mvL0[0] == 0) /* both mv components are zeros.*/
+                    {
+                        currMB->mbMode = AVC_SKIP;
+                        video->mvd_l0[0][0][0] = 0;
+                        video->mvd_l0[0][0][1] = 0;
+                    }
+                }
+                else
+                {
+                    if ((MB_A->ref_idx_L0[1] == 0 && MB_A->mvL0[3] == 0) ||
+                            (MB_B->ref_idx_L0[2] == 0 && MB_B->mvL0[12] == 0))
+                    {
+                        if (currMB->mvL0[0] == 0) /* both mv components are zeros.*/
+                        {
+                            currMB->mbMode = AVC_SKIP;
+                            video->mvd_l0[0][0][0] = 0;
+                            video->mvd_l0[0][0][1] = 0;
+                        }
+                    }
+                    else if (video->mvd_l0[0][0][0] == 0 && video->mvd_l0[0][0][1] == 0)
+                    {
+                        currMB->mbMode = AVC_SKIP;
+                    }
+                }
+            }
+
+            if (currMB->mbMode == AVC_SKIP)
+            {
+                video->mb_skip_run++;
+
+                /* set parameters */
+                /* not sure whether we need the followings */
+                if (slice_type == AVC_P_SLICE)
+                {
+                    currMB->mbMode = AVC_SKIP;
+                    currMB->MbPartWidth = currMB->MbPartHeight = 16;
+                    currMB->MBPartPredMode[0][0] = AVC_Pred_L0;
+                    currMB->NumMbPart = 1;
+                    currMB->NumSubMbPart[0] = currMB->NumSubMbPart[1] =
+                                                  currMB->NumSubMbPart[2] = currMB->NumSubMbPart[3] = 1;
+                    currMB->SubMbPartWidth[0] = currMB->SubMbPartWidth[1] =
+                                                    currMB->SubMbPartWidth[2] = currMB->SubMbPartWidth[3] = currMB->MbPartWidth;
+                    currMB->SubMbPartHeight[0] = currMB->SubMbPartHeight[1] =
+                                                     currMB->SubMbPartHeight[2] = currMB->SubMbPartHeight[3] = currMB->MbPartHeight;
+
+                }
+                else if (slice_type == AVC_B_SLICE)
+                {
+                    currMB->mbMode = AVC_SKIP;
+                    currMB->MbPartWidth = currMB->MbPartHeight = 8;
+                    currMB->MBPartPredMode[0][0] = AVC_Direct;
+                    currMB->NumMbPart = -1;
+                }
+
+                /* for skipped MB, always look at the first entry in RefPicList */
+                currMB->RefIdx[0] = currMB->RefIdx[1] =
+                                        currMB->RefIdx[2] = currMB->RefIdx[3] = video->RefPicList0[0]->RefIdx;
+
+                /* do not return yet, need to do some copies */
+            }
+        }
+    }
+    /* non-skipped MB */
+
+
+    /************* START ENTROPY CODING *************************/
+
+    start_mb_bits = 32 + (encvid->bitstream->write_pos << 3) - encvid->bitstream->bit_left;
+
+    /* encode mb_type, mb_pred, sub_mb_pred, CBP */
+    if (slice_type != AVC_I_SLICE && slice_type != AVC_SI_SLICE && currMB->mbMode != AVC_SKIP)
+    {
+        //if(!pps->entropy_coding_mode_flag)  ALWAYS true
+        {
+            ue_v(stream, video->mb_skip_run);
+            video->mb_skip_run = 0;
+        }
+    }
+
+    if (currMB->mbMode != AVC_SKIP)
+    {
+        status = EncodeMBHeader(currMB, encvid);
+        if (status != AVCENC_SUCCESS)
+        {
+            return status;
+        }
+    }
+
+    start_text_bits = 32 + (encvid->bitstream->write_pos << 3) - encvid->bitstream->bit_left;
+
+    /**** now decoding part *******/
+    resType = AVC_Luma;
+
+    /* DC transform for luma I16 mode */
+    if (currMB->mbMode == AVC_I16)
+    {
+        /* vlc encode level/run */
+        status = enc_residual_block(encvid, AVC_Intra16DC, encvid->numcoefdc, currMB);
+        if (status != AVCENC_SUCCESS)
+        {
+            return status;
+        }
+        resType = AVC_Intra16AC;
+    }
+
+    /* VLC encoding for luma */
+    for (b8 = 0; b8 < 4; b8++)
+    {
+        if (currMB->CBP&(1 << b8))
+        {
+            for (b4 = 0; b4 < 4; b4++)
+            {
+                /* vlc encode level/run */
+                status = enc_residual_block(encvid, resType, (b8 << 2) + b4, currMB);
+                if (status != AVCENC_SUCCESS)
+                {
+                    return status;
+                }
+            }
+        }
+    }
+
+    /* chroma */
+    if (currMB->CBP & (3 << 4)) /* chroma DC residual present */
+    {
+        for (b8 = 0; b8 < 2; b8++) /* for iCbCr */
+        {
+            /* vlc encode level/run */
+            status = enc_residual_block(encvid, AVC_ChromaDC, encvid->numcoefcdc[b8] + (b8 << 3), currMB);
+            if (status != AVCENC_SUCCESS)
+            {
+                return status;
+            }
+        }
+    }
+
+    if (currMB->CBP & (2 << 4))
+    {
+        /* AC part */
+        for (b8 = 0; b8 < 2; b8++) /* for iCbCr */
+        {
+            for (b4 = 0; b4 < 4; b4++)  /* for each block inside Cb or Cr */
+            {
+                /* vlc encode level/run */
+                status = enc_residual_block(encvid, AVC_ChromaAC, 16 + (b8 << 2) + b4, currMB);
+                if (status != AVCENC_SUCCESS)
+                {
+                    return status;
+                }
+            }
+        }
+    }
+
+
+    num_bits = 32 + (encvid->bitstream->write_pos << 3) - encvid->bitstream->bit_left;
+
+    RCPostMB(video, rateCtrl, start_text_bits - start_mb_bits,
+             num_bits - start_text_bits);
+
+//  num_bits -= start_mb_bits;
+//  fprintf(fdebug,"MB #%d: %d bits\n",CurrMbAddr,num_bits);
+//  fclose(fdebug);
+    return status;
+}
+
+/* copy the content from predBlock back to the reconstructed YUV frame */
+void Copy_MB(uint8 *curL, uint8 *curCb, uint8 *curCr, uint8 *predBlock, int picPitch)
+{
+    int j, offset;
+    uint32 *dst, *dst2, *src;
+
+    dst = (uint32*)curL;
+    src = (uint32*)predBlock;
+
+    offset = (picPitch - 16) >> 2;
+
+    for (j = 0; j < 16; j++)
+    {
+        *dst++ = *src++;
+        *dst++ = *src++;
+        *dst++ = *src++;
+        *dst++ = *src++;
+
+        dst += offset;
+    }
+
+    dst = (uint32*)curCb;
+    dst2 = (uint32*)curCr;
+    offset >>= 1;
+
+    for (j = 0; j < 8; j++)
+    {
+        *dst++ = *src++;
+        *dst++ = *src++;
+        *dst2++ = *src++;
+        *dst2++ = *src++;
+
+        dst += offset;
+        dst2 += offset;
+    }
+    return ;
+}
+
+/* encode mb_type, mb_pred, sub_mb_pred, CBP */
+/* decide whether this MB (for inter MB) should be skipped */
+AVCEnc_Status EncodeMBHeader(AVCMacroblock *currMB, AVCEncObject *encvid)
+{
+    AVCEnc_Status status = AVCENC_SUCCESS;
+    uint mb_type;
+    AVCCommonObj *video = encvid->common;
+    AVCEncBitstream *stream = encvid->bitstream;
+
+    if (currMB->CBP > 47)   /* chroma CBP is 11 */
+    {
+        currMB->CBP -= 16;  /* remove the 5th bit from the right */
+    }
+
+    mb_type = InterpretMBType(currMB, video->slice_type);
+
+    status = ue_v(stream, mb_type);
+
+    if (currMB->mbMode == AVC_P8 || currMB->mbMode == AVC_P8ref0)
+    {
+        status = sub_mb_pred(video, currMB, stream);
+    }
+    else
+    {
+        status = mb_pred(video, currMB, stream) ;
+    }
+
+    if (currMB->mbMode != AVC_I16)
+    {
+        /* decode coded_block_pattern */
+        status = EncodeCBP(currMB, stream);
+    }
+
+    /* calculate currMB->mb_qp_delta = currMB->QPy - video->QPyprev */
+    if (currMB->CBP > 0 || currMB->mbMode == AVC_I16)
+    {
+        status = se_v(stream, currMB->QPy - video->QPy);
+        video->QPy = currMB->QPy; /* = (video->QPyprev + currMB->mb_qp_delta + 52)%52; */
+        // no need video->QPc = currMB->QPc;
+    }
+    else
+    {
+        if (currMB->QPy != video->QPy) // current QP is not the same as previous QP
+        {
+            /* restore these values */
+            RCRestoreQP(currMB, video, encvid);
+        }
+    }
+
+    return status;
+}
+
+
+/* inputs are mbMode, mb_intra, i16Mode, CBP, NumMbPart, MbPartWidth, MbPartHeight */
+uint InterpretMBType(AVCMacroblock *currMB, int slice_type)
+{
+    int CBP_chrom;
+    int mb_type;// part1, part2, part3;
+//  const static int MapParts2Type[2][3][3]={{{4,8,12},{10,6,14},{16,18,20}},
+//  {{5,9,13},{11,7,15},{17,19,21}}};
+
+    if (currMB->mb_intra)
+    {
+        if (currMB->mbMode == AVC_I4)
+        {
+            mb_type = 0;
+        }
+        else if (currMB->mbMode == AVC_I16)
+        {
+            CBP_chrom = (currMB->CBP & 0x30);
+            if (currMB->CBP&0xF)
+            {
+                currMB->CBP |= 0xF;  /* either 0x0 or 0xF */
+                mb_type = 13;
+            }
+            else
+            {
+                mb_type = 1;
+            }
+            mb_type += (CBP_chrom >> 2) + currMB->i16Mode;
+        }
+        else /* if(currMB->mbMode == AVC_I_PCM) */
+        {
+            mb_type = 25;
+        }
+    }
+    else
+    {  /* P-MB *//* note that the order of the enum AVCMBMode cannot be changed
+        since we use it here. */
+        mb_type = currMB->mbMode - AVC_P16;
+    }
+
+    if (slice_type == AVC_P_SLICE)
+    {
+        if (currMB->mb_intra)
+        {
+            mb_type += 5;
+        }
+    }
+    // following codes have not been tested yet, not needed.
+    /*  else if(slice_type == AVC_B_SLICE)
+        {
+            if(currMB->mbMode == AVC_BDirect16)
+            {
+                mb_type = 0;
+            }
+            else if(currMB->mbMode == AVC_P16)
+            {
+                mb_type = currMB->MBPartPredMode[0][0] + 1; // 1 or 2
+            }
+            else if(currMB->mbMode == AVC_P8)
+            {
+                mb_type = 26;
+            }
+            else if(currMB->mbMode == AVC_P8ref0)
+            {
+                mb_type = 27;
+            }
+            else
+            {
+                part1 = currMB->mbMode - AVC_P16x8;
+                part2 = currMB->MBPartPredMode[0][0];
+                part3 = currMB->MBPartPredMode[1][0];
+                mb_type = MapParts2Type[part1][part2][part3];
+            }
+        }
+
+        if(slice_type == AVC_SI_SLICE)
+        {
+            mb_type++;
+        }
+    */
+    return (uint)mb_type;
+}
+
+//const static int mbPart2raster[3][4] = {{0,0,0,0},{1,1,0,0},{1,0,1,0}};
+
+/* see subclause 7.3.5.1 */
+AVCEnc_Status mb_pred(AVCCommonObj *video, AVCMacroblock *currMB, AVCEncBitstream *stream)
+{
+    AVCEnc_Status status = AVCENC_SUCCESS;
+    int mbPartIdx;
+    AVCSliceHeader *sliceHdr = video->sliceHdr;
+    int max_ref_idx;
+    uint code;
+
+    if (currMB->mbMode == AVC_I4 || currMB->mbMode == AVC_I16)
+    {
+        if (currMB->mbMode == AVC_I4)
+        {
+            /* perform prediction to get the actual intra 4x4 pred mode */
+            EncodeIntra4x4Mode(video, currMB, stream);
+            /* output will be in currMB->i4Mode[4][4] */
+        }
+
+        /* assume already set from MBPrediction() */
+        status = ue_v(stream, currMB->intra_chroma_pred_mode);
+    }
+    else if (currMB->MBPartPredMode[0][0] != AVC_Direct)
+    {
+
+        memset(currMB->ref_idx_L0, 0, sizeof(int16)*4);
+
+        /* see subclause 7.4.5.1 for the range of ref_idx_lX */
+        max_ref_idx = sliceHdr->num_ref_idx_l0_active_minus1;
+        /*      if(video->MbaffFrameFlag && currMB->mb_field_decoding_flag)
+                    max_ref_idx = 2*sliceHdr->num_ref_idx_l0_active_minus1 + 1;
+        */
+        /* decode ref index for L0 */
+        if (sliceHdr->num_ref_idx_l0_active_minus1 > 0)
+        {
+            for (mbPartIdx = 0; mbPartIdx < currMB->NumMbPart; mbPartIdx++)
+            {
+                if (/*(sliceHdr->num_ref_idx_l0_active_minus1>0 || currMB->mb_field_decoding_flag) &&*/
+                    currMB->MBPartPredMode[mbPartIdx][0] != AVC_Pred_L1)
+                {
+                    code = currMB->ref_idx_L0[mbPartIdx];
+                    status = te_v(stream, code, max_ref_idx);
+                }
+            }
+        }
+
+        /* see subclause 7.4.5.1 for the range of ref_idx_lX */
+        max_ref_idx = sliceHdr->num_ref_idx_l1_active_minus1;
+        /*      if(video->MbaffFrameFlag && currMB->mb_field_decoding_flag)
+                    max_ref_idx = 2*sliceHdr->num_ref_idx_l1_active_minus1 + 1;
+        */
+        /* decode ref index for L1 */
+        if (sliceHdr->num_ref_idx_l1_active_minus1 > 0)
+        {
+            for (mbPartIdx = 0; mbPartIdx < currMB->NumMbPart; mbPartIdx++)
+            {
+                if (/*(sliceHdr->num_ref_idx_l1_active_minus1>0 || currMB->mb_field_decoding_flag) &&*/
+                    currMB->MBPartPredMode[mbPartIdx][0] != AVC_Pred_L0)
+                {
+                    status = te_v(stream, currMB->ref_idx_L1[mbPartIdx], max_ref_idx);
+                }
+            }
+        }
+
+        /* encode mvd_l0 */
+        for (mbPartIdx = 0; mbPartIdx < currMB->NumMbPart; mbPartIdx++)
+        {
+            if (currMB->MBPartPredMode[mbPartIdx][0] != AVC_Pred_L1)
+            {
+                status = se_v(stream, video->mvd_l0[mbPartIdx][0][0]);
+                status = se_v(stream, video->mvd_l0[mbPartIdx][0][1]);
+            }
+        }
+        /* encode mvd_l1 */
+        for (mbPartIdx = 0; mbPartIdx < currMB->NumMbPart; mbPartIdx++)
+        {
+            if (currMB->MBPartPredMode[mbPartIdx][0] != AVC_Pred_L0)
+            {
+                status = se_v(stream, video->mvd_l1[mbPartIdx][0][0]);
+                status = se_v(stream, video->mvd_l1[mbPartIdx][0][1]);
+            }
+        }
+    }
+
+    return status;
+}
+
+/* see subclause 7.3.5.2 */
+AVCEnc_Status sub_mb_pred(AVCCommonObj *video, AVCMacroblock *currMB, AVCEncBitstream *stream)
+{
+    AVCEnc_Status status = AVCENC_SUCCESS;
+    int mbPartIdx, subMbPartIdx;
+    AVCSliceHeader *sliceHdr = video->sliceHdr;
+    uint max_ref_idx;
+    uint slice_type = video->slice_type;
+    uint sub_mb_type[4];
+
+    /* this should move somewhere else where we don't have to make this check */
+    if (currMB->mbMode == AVC_P8ref0)
+    {
+        memset(currMB->ref_idx_L0, 0, sizeof(int16)*4);
+    }
+
+    /* we have to check the values to make sure they are valid  */
+    /* assign values to currMB->sub_mb_type[] */
+    if (slice_type == AVC_P_SLICE)
+    {
+        InterpretSubMBTypeP(currMB, sub_mb_type);
+    }
+    /* no need to check for B-slice
+        else if(slice_type == AVC_B_SLICE)
+        {
+            InterpretSubMBTypeB(currMB,sub_mb_type);
+        }*/
+
+    for (mbPartIdx = 0; mbPartIdx < 4; mbPartIdx++)
+    {
+        status = ue_v(stream, sub_mb_type[mbPartIdx]);
+    }
+
+    /* see subclause 7.4.5.1 for the range of ref_idx_lX */
+    max_ref_idx = sliceHdr->num_ref_idx_l0_active_minus1;
+    /*  if(video->MbaffFrameFlag && currMB->mb_field_decoding_flag)
+            max_ref_idx = 2*sliceHdr->num_ref_idx_l0_active_minus1 + 1; */
+
+    for (mbPartIdx = 0; mbPartIdx < 4; mbPartIdx++)
+    {
+        if ((sliceHdr->num_ref_idx_l0_active_minus1 > 0 /*|| currMB->mb_field_decoding_flag*/) &&
+                currMB->mbMode != AVC_P8ref0 && /*currMB->subMbMode[mbPartIdx]!=AVC_BDirect8 &&*/
+                currMB->MBPartPredMode[mbPartIdx][0] != AVC_Pred_L1)
+        {
+            status = te_v(stream, currMB->ref_idx_L0[mbPartIdx], max_ref_idx);
+        }
+        /* used in deblocking */
+        currMB->RefIdx[mbPartIdx] = video->RefPicList0[currMB->ref_idx_L0[mbPartIdx]]->RefIdx;
+    }
+    /* see subclause 7.4.5.1 for the range of ref_idx_lX */
+    max_ref_idx = sliceHdr->num_ref_idx_l1_active_minus1;
+    /*  if(video->MbaffFrameFlag && currMB->mb_field_decoding_flag)
+            max_ref_idx = 2*sliceHdr->num_ref_idx_l1_active_minus1 + 1;*/
+
+    if (sliceHdr->num_ref_idx_l1_active_minus1 > 0)
+    {
+        for (mbPartIdx = 0; mbPartIdx < 4; mbPartIdx++)
+        {
+            if (/*(sliceHdr->num_ref_idx_l1_active_minus1>0 || currMB->mb_field_decoding_flag) &&*/
+                /*currMB->subMbMode[mbPartIdx]!=AVC_BDirect8 &&*/
+                currMB->MBPartPredMode[mbPartIdx][0] != AVC_Pred_L0)
+            {
+                status = te_v(stream, currMB->ref_idx_L1[mbPartIdx], max_ref_idx);
+            }
+        }
+    }
+
+    for (mbPartIdx = 0; mbPartIdx < 4; mbPartIdx++)
+    {
+        if (/*currMB->subMbMode[mbPartIdx]!=AVC_BDirect8 &&*/
+            currMB->MBPartPredMode[mbPartIdx][0] != AVC_Pred_L1)
+        {
+            for (subMbPartIdx = 0; subMbPartIdx < currMB->NumSubMbPart[mbPartIdx]; subMbPartIdx++)
+            {
+                status = se_v(stream, video->mvd_l0[mbPartIdx][subMbPartIdx][0]);
+                status = se_v(stream, video->mvd_l0[mbPartIdx][subMbPartIdx][1]);
+            }
+        }
+    }
+
+    for (mbPartIdx = 0; mbPartIdx < 4; mbPartIdx++)
+    {
+        if (/*currMB->subMbMode[mbPartIdx]!=AVC_BDirect8 &&*/
+            currMB->MBPartPredMode[mbPartIdx][0] != AVC_Pred_L0)
+        {
+            for (subMbPartIdx = 0; subMbPartIdx < currMB->NumSubMbPart[mbPartIdx]; subMbPartIdx++)
+            {
+                status = se_v(stream, video->mvd_l1[mbPartIdx][subMbPartIdx][0]);
+                status = se_v(stream, video->mvd_l1[mbPartIdx][subMbPartIdx][1]);
+            }
+        }
+    }
+
+    return status;
+}
+
+/* input is mblock->sub_mb_type[] */
+void InterpretSubMBTypeP(AVCMacroblock *mblock, uint *sub_mb_type)
+{
+    int i;
+    /* see enum AVCMBType declaration */
+    /*const static AVCSubMBMode map2subMbMode[4] = {AVC_8x8,AVC_8x4,AVC_4x8,AVC_4x4};
+    const static int map2subPartWidth[4] = {8,8,4,4};
+    const static int map2subPartHeight[4] = {8,4,8,4};
+    const static int map2numSubPart[4] = {1,2,2,4};*/
+
+    for (i = 0; i < 4 ; i++)
+    {
+        sub_mb_type[i] = mblock->subMbMode[i] - AVC_8x8;
+    }
+
+    return ;
+}
+
+void InterpretSubMBTypeB(AVCMacroblock *mblock, uint *sub_mb_type)
+{
+    int i;
+    /* see enum AVCMBType declaration */
+    /*  const static AVCSubMBMode map2subMbMode[13] = {AVC_BDirect8,AVC_8x8,AVC_8x8,
+            AVC_8x8,AVC_8x4,AVC_4x8,AVC_8x4,AVC_4x8,AVC_8x4,AVC_4x8,AVC_4x4,AVC_4x4,AVC_4x4};
+        const static int map2subPartWidth[13] = {4,8,8,8,8,4,8,4,8,4,4,4,4};
+        const static int map2subPartHeight[13] = {4,8,8,8,4,8,4,8,4,8,4,4,4};
+        const static int map2numSubPart[13] = {4,1,1,1,2,2,2,2,2,2,4,4,4};
+        const static int map2predMode[13] = {3,0,1,2,0,0,1,1,2,2,0,1,2};*/
+
+    for (i = 0; i < 4 ; i++)
+    {
+        if (mblock->subMbMode[i] == AVC_BDirect8)
+        {
+            sub_mb_type[i] = 0;
+        }
+        else if (mblock->subMbMode[i] == AVC_8x8)
+        {
+            sub_mb_type[i] = 1 + mblock->MBPartPredMode[i][0];
+        }
+        else if (mblock->subMbMode[i] == AVC_4x4)
+        {
+            sub_mb_type[i] = 10 + mblock->MBPartPredMode[i][0];
+        }
+        else
+        {
+            sub_mb_type[i] = 4 + (mblock->MBPartPredMode[i][0] << 1) + (mblock->subMbMode[i] - AVC_8x4);
+        }
+    }
+
+    return ;
+}
+
+/* see subclause 8.3.1 */
+AVCEnc_Status EncodeIntra4x4Mode(AVCCommonObj *video, AVCMacroblock *currMB, AVCEncBitstream *stream)
+{
+    int intra4x4PredModeA = 0;
+    int intra4x4PredModeB, predIntra4x4PredMode;
+    int component, SubBlock_indx, block_x, block_y;
+    int dcOnlyPredictionFlag;
+    uint    flag;
+    int     rem = 0;
+    int     mode;
+    int bindx = 0;
+
+    for (component = 0; component < 4; component++) /* partition index */
+    {
+        block_x = ((component & 1) << 1);
+        block_y = ((component >> 1) << 1);
+
+        for (SubBlock_indx = 0; SubBlock_indx < 4; SubBlock_indx++) /* sub-partition index */
+        {
+            dcOnlyPredictionFlag = 0;
+            if (block_x > 0)
+            {
+                intra4x4PredModeA = currMB->i4Mode[(block_y << 2) + block_x - 1 ];
+            }
+            else
+            {
+                if (video->intraAvailA)
+                {
+                    if (video->mblock[video->mbAddrA].mbMode == AVC_I4)
+                    {
+                        intra4x4PredModeA = video->mblock[video->mbAddrA].i4Mode[(block_y << 2) + 3];
+                    }
+                    else
+                    {
+                        intra4x4PredModeA = AVC_I4_DC;
+                    }
+                }
+                else
+                {
+                    dcOnlyPredictionFlag = 1;
+                }
+            }
+
+            if (block_y > 0)
+            {
+                intra4x4PredModeB = currMB->i4Mode[((block_y-1) << 2) + block_x];
+            }
+            else
+            {
+                if (video->intraAvailB)
+                {
+                    if (video->mblock[video->mbAddrB].mbMode == AVC_I4)
+                    {
+                        intra4x4PredModeB = video->mblock[video->mbAddrB].i4Mode[(3 << 2) + block_x];
+                    }
+                    else
+                    {
+                        intra4x4PredModeB = AVC_I4_DC;
+                    }
+                }
+                else
+                {
+                    dcOnlyPredictionFlag = 1;
+                }
+            }
+
+            if (dcOnlyPredictionFlag)
+            {
+                intra4x4PredModeA = intra4x4PredModeB = AVC_I4_DC;
+            }
+
+            predIntra4x4PredMode = AVC_MIN(intra4x4PredModeA, intra4x4PredModeB);
+
+            flag = 0;
+            mode = currMB->i4Mode[(block_y<<2)+block_x];
+
+            if (mode == (AVCIntra4x4PredMode)predIntra4x4PredMode)
+            {
+                flag = 1;
+            }
+            else if (mode < predIntra4x4PredMode)
+            {
+                rem = mode;
+            }
+            else
+            {
+                rem = mode - 1;
+            }
+
+            BitstreamWrite1Bit(stream, flag);
+
+            if (!flag)
+            {
+                BitstreamWriteBits(stream, 3, rem);
+            }
+
+            bindx++;
+            block_y += (SubBlock_indx & 1) ;
+            block_x += (1 - 2 * (SubBlock_indx & 1)) ;
+        }
+    }
+
+    return AVCENC_SUCCESS;
+}
+
+
+
diff --git a/media/libstagefright/codecs/avc/enc/src/vlc_encode.cpp b/media/libstagefright/codecs/avc/enc/src/vlc_encode.cpp
new file mode 100644
index 0000000..222e709
--- /dev/null
+++ b/media/libstagefright/codecs/avc/enc/src/vlc_encode.cpp
@@ -0,0 +1,336 @@
+/* ------------------------------------------------------------------
+ * Copyright (C) 1998-2009 PacketVideo
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
+ * express or implied.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ * -------------------------------------------------------------------
+ */
+#include "avcenc_lib.h"
+
+/**
+See algorithm in subclause 9.1, Table 9-1, Table 9-2. */
+AVCEnc_Status ue_v(AVCEncBitstream *bitstream, uint codeNum)
+{
+    if (AVCENC_SUCCESS != SetEGBitstring(bitstream, codeNum))
+        return AVCENC_FAIL;
+
+    return AVCENC_SUCCESS;
+}
+
+/**
+See subclause 9.1.1, Table 9-3 */
+AVCEnc_Status  se_v(AVCEncBitstream *bitstream, int value)
+{
+    uint codeNum;
+    AVCEnc_Status status;
+
+    if (value <= 0)
+    {
+        codeNum = -value * 2;
+    }
+    else
+    {
+        codeNum = value * 2 - 1;
+    }
+
+    status = ue_v(bitstream, codeNum);
+
+    return status;
+}
+
+AVCEnc_Status te_v(AVCEncBitstream *bitstream, uint value, uint range)
+{
+    AVCEnc_Status status;
+
+    if (range > 1)
+    {
+        return ue_v(bitstream, value);
+    }
+    else
+    {
+        status = BitstreamWrite1Bit(bitstream, 1 - value);
+        return status;
+    }
+}
+
+/**
+See subclause 9.1, Table 9-1, 9-2. */
+// compute leadingZeros and inforbits
+//codeNum = (1<<leadingZeros)-1+infobits;
+AVCEnc_Status SetEGBitstring(AVCEncBitstream *bitstream, uint codeNum)
+{
+    AVCEnc_Status status;
+    int leadingZeros;
+    int infobits;
+
+    if (!codeNum)
+    {
+        status = BitstreamWrite1Bit(bitstream, 1);
+        return status;
+    }
+
+    /* calculate leadingZeros and infobits */
+    leadingZeros = 1;
+    while ((uint)(1 << leadingZeros) < codeNum + 2)
+    {
+        leadingZeros++;
+    }
+    leadingZeros--;
+    infobits = codeNum - (1 << leadingZeros) + 1;
+
+    status = BitstreamWriteBits(bitstream, leadingZeros, 0);
+    infobits |= (1 << leadingZeros);
+    status = BitstreamWriteBits(bitstream, leadingZeros + 1, infobits);
+    return status;
+}
+
+/* see Table 9-4 assignment of codeNum to values of coded_block_pattern. */
+const static uint8 MapCBP2code[48][2] =
+{
+    {3, 0}, {29, 2}, {30, 3}, {17, 7}, {31, 4}, {18, 8}, {37, 17}, {8, 13}, {32, 5}, {38, 18}, {19, 9}, {9, 14},
+    {20, 10}, {10, 15}, {11, 16}, {2, 11}, {16, 1}, {33, 32}, {34, 33}, {21, 36}, {35, 34}, {22, 37}, {39, 44}, {4, 40},
+    {36, 35}, {40, 45}, {23, 38}, {5, 41}, {24, 39}, {6, 42}, {7, 43}, {1, 19}, {41, 6}, {42, 24}, {43, 25}, {25, 20},
+    {44, 26}, {26, 21}, {46, 46}, {12, 28}, {45, 27}, {47, 47}, {27, 22}, {13, 29}, {28, 23}, {14, 30}, {15, 31}, {0, 12}
+};
+
+AVCEnc_Status EncodeCBP(AVCMacroblock *currMB, AVCEncBitstream *stream)
+{
+    AVCEnc_Status status;
+    uint codeNum;
+
+    if (currMB->mbMode == AVC_I4)
+    {
+        codeNum = MapCBP2code[currMB->CBP][0];
+    }
+    else
+    {
+        codeNum = MapCBP2code[currMB->CBP][1];
+    }
+
+    status = ue_v(stream, codeNum);
+
+    return status;
+}
+
+AVCEnc_Status ce_TotalCoeffTrailingOnes(AVCEncBitstream *stream, int TrailingOnes, int TotalCoeff, int nC)
+{
+    const static uint8 totCoeffTrailOne[3][4][17][2] =
+    {
+        {   // 0702
+            {{1, 1}, {6, 5}, {8, 7}, {9, 7}, {10, 7}, {11, 7}, {13, 15}, {13, 11}, {13, 8}, {14, 15}, {14, 11}, {15, 15}, {15, 11}, {16, 15}, {16, 11}, {16, 7}, {16, 4}},
+            {{0, 0}, {2, 1}, {6, 4}, {8, 6}, {9, 6}, {10, 6}, {11, 6}, {13, 14}, {13, 10}, {14, 14}, {14, 10}, {15, 14}, {15, 10}, {15, 1}, {16, 14}, {16, 10}, {16, 6}},
+            {{0, 0}, {0, 0}, {3, 1}, {7, 5}, {8, 5}, {9, 5}, {10, 5}, {11, 5}, {13, 13}, {13, 9}, {14, 13}, {14, 9}, {15, 13}, {15, 9}, {16, 13}, {16, 9}, {16, 5}},
+            {{0, 0}, {0, 0}, {0, 0}, {5, 3}, {6, 3}, {7, 4}, {8, 4}, {9, 4}, {10, 4}, {11, 4}, {13, 12}, {14, 12}, {14, 8}, {15, 12}, {15, 8}, {16, 12}, {16, 8}},
+        },
+        {
+            {{2, 3}, {6, 11}, {6, 7}, {7, 7}, {8, 7}, {8, 4}, {9, 7}, {11, 15}, {11, 11}, {12, 15}, {12, 11}, {12, 8}, {13, 15}, {13, 11}, {13, 7}, {14, 9}, {14, 7}},
+            {{0, 0}, {2, 2}, {5, 7}, {6, 10}, {6, 6}, {7, 6}, {8, 6}, {9, 6}, {11, 14}, {11, 10}, {12, 14}, {12, 10}, {13, 14}, {13, 10}, {14, 11}, {14, 8}, {14, 6}},
+            {{0, 0}, {0, 0}, {3, 3}, {6, 9}, {6, 5}, {7, 5}, {8, 5}, {9, 5}, {11, 13}, {11, 9}, {12, 13}, {12, 9}, {13, 13}, {13, 9}, {13, 6}, {14, 10}, {14, 5}},
+            {{0, 0}, {0, 0}, {0, 0}, {4, 5}, {4, 4}, {5, 6}, {6, 8}, {6, 4}, {7, 4}, {9, 4}, {11, 12}, {11, 8}, {12, 12}, {13, 12}, {13, 8}, {13, 1}, {14, 4}},
+        },
+        {
+            {{4, 15}, {6, 15}, {6, 11}, {6, 8}, {7, 15}, {7, 11}, {7, 9}, {7, 8}, {8, 15}, {8, 11}, {9, 15}, {9, 11}, {9, 8}, {10, 13}, {10, 9}, {10, 5}, {10, 1}},
+            {{0, 0}, {4, 14}, {5, 15}, {5, 12}, {5, 10}, {5, 8}, {6, 14}, {6, 10}, {7, 14}, {8, 14}, {8, 10}, {9, 14}, {9, 10}, {9, 7}, {10, 12}, {10, 8}, {10, 4}},
+            {{0, 0}, {0, 0}, {4, 13}, {5, 14}, {5, 11}, {5, 9}, {6, 13}, {6, 9}, {7, 13}, {7, 10}, {8, 13}, {8, 9}, {9, 13}, {9, 9}, {10, 11}, {10, 7}, {10, 3}},
+            {{0, 0}, {0, 0}, {0, 0}, {4, 12}, {4, 11}, {4, 10}, {4, 9}, {4, 8}, {5, 13}, {6, 12}, {7, 12}, {8, 12}, {8, 8}, {9, 12}, {10, 10}, {10, 6}, {10, 2}}
+        }
+    };
+
+
+    AVCEnc_Status status = AVCENC_SUCCESS;
+    uint code, len;
+    int vlcnum;
+
+    if (TrailingOnes > 3)
+    {
+        return AVCENC_TRAILINGONES_FAIL;
+    }
+
+    if (nC >= 8)
+    {
+        if (TotalCoeff)
+        {
+            code = ((TotalCoeff - 1) << 2) | (TrailingOnes);
+        }
+        else
+        {
+            code = 3;
+        }
+        status = BitstreamWriteBits(stream, 6, code);
+    }
+    else
+    {
+        if (nC < 2)
+        {
+            vlcnum = 0;
+        }
+        else if (nC < 4)
+        {
+            vlcnum = 1;
+        }
+        else
+        {
+            vlcnum = 2;
+        }
+
+        len = totCoeffTrailOne[vlcnum][TrailingOnes][TotalCoeff][0];
+        code = totCoeffTrailOne[vlcnum][TrailingOnes][TotalCoeff][1];
+        status = BitstreamWriteBits(stream, len, code);
+    }
+
+    return status;
+}
+
+AVCEnc_Status ce_TotalCoeffTrailingOnesChromaDC(AVCEncBitstream *stream, int TrailingOnes, int TotalCoeff)
+{
+    const static uint8 totCoeffTrailOneChrom[4][5][2] =
+    {
+        { {2, 1}, {6, 7}, {6, 4}, {6, 3}, {6, 2}},
+        { {0, 0}, {1, 1}, {6, 6}, {7, 3}, {8, 3}},
+        { {0, 0}, {0, 0}, {3, 1}, {7, 2}, {8, 2}},
+        { {0, 0}, {0, 0}, {0, 0}, {6, 5}, {7, 0}},
+    };
+
+    AVCEnc_Status status = AVCENC_SUCCESS;
+    uint code, len;
+
+    len = totCoeffTrailOneChrom[TrailingOnes][TotalCoeff][0];
+    code = totCoeffTrailOneChrom[TrailingOnes][TotalCoeff][1];
+    status = BitstreamWriteBits(stream, len, code);
+
+    return status;
+}
+
+/* see Table 9-7 and 9-8 */
+AVCEnc_Status ce_TotalZeros(AVCEncBitstream *stream, int total_zeros, int TotalCoeff)
+{
+    const static uint8 lenTotalZeros[15][16] =
+    {
+        { 1, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 9},
+        { 3, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 6, 6, 6, 6},
+        { 4, 3, 3, 3, 4, 4, 3, 3, 4, 5, 5, 6, 5, 6},
+        { 5, 3, 4, 4, 3, 3, 3, 4, 3, 4, 5, 5, 5},
+        { 4, 4, 4, 3, 3, 3, 3, 3, 4, 5, 4, 5},
+        { 6, 5, 3, 3, 3, 3, 3, 3, 4, 3, 6},
+        { 6, 5, 3, 3, 3, 2, 3, 4, 3, 6},
+        { 6, 4, 5, 3, 2, 2, 3, 3, 6},
+        { 6, 6, 4, 2, 2, 3, 2, 5},
+        { 5, 5, 3, 2, 2, 2, 4},
+        { 4, 4, 3, 3, 1, 3},
+        { 4, 4, 2, 1, 3},
+        { 3, 3, 1, 2},
+        { 2, 2, 1},
+        { 1, 1},
+    };
+
+    const static uint8 codTotalZeros[15][16] =
+    {
+        {1, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 1},
+        {7, 6, 5, 4, 3, 5, 4, 3, 2, 3, 2, 3, 2, 1, 0},
+        {5, 7, 6, 5, 4, 3, 4, 3, 2, 3, 2, 1, 1, 0},
+        {3, 7, 5, 4, 6, 5, 4, 3, 3, 2, 2, 1, 0},
+        {5, 4, 3, 7, 6, 5, 4, 3, 2, 1, 1, 0},
+        {1, 1, 7, 6, 5, 4, 3, 2, 1, 1, 0},
+        {1, 1, 5, 4, 3, 3, 2, 1, 1, 0},
+        {1, 1, 1, 3, 3, 2, 2, 1, 0},
+        {1, 0, 1, 3, 2, 1, 1, 1, },
+        {1, 0, 1, 3, 2, 1, 1, },
+        {0, 1, 1, 2, 1, 3},
+        {0, 1, 1, 1, 1},
+        {0, 1, 1, 1},
+        {0, 1, 1},
+        {0, 1},
+    };
+    int len, code;
+    AVCEnc_Status status;
+
+    len = lenTotalZeros[TotalCoeff-1][total_zeros];
+    code = codTotalZeros[TotalCoeff-1][total_zeros];
+
+    status = BitstreamWriteBits(stream, len, code);
+
+    return status;
+}
+
+/* see Table 9-9 */
+AVCEnc_Status ce_TotalZerosChromaDC(AVCEncBitstream *stream, int total_zeros, int TotalCoeff)
+{
+    const static uint8 lenTotalZerosChromaDC[3][4] =
+    {
+        { 1, 2, 3, 3, },
+        { 1, 2, 2, 0, },
+        { 1, 1, 0, 0, },
+    };
+
+    const static uint8 codTotalZerosChromaDC[3][4] =
+    {
+        { 1, 1, 1, 0, },
+        { 1, 1, 0, 0, },
+        { 1, 0, 0, 0, },
+    };
+
+    int len, code;
+    AVCEnc_Status status;
+
+    len = lenTotalZerosChromaDC[TotalCoeff-1][total_zeros];
+    code = codTotalZerosChromaDC[TotalCoeff-1][total_zeros];
+
+    status = BitstreamWriteBits(stream, len, code);
+
+    return status;
+}
+
+/* see Table 9-10 */
+AVCEnc_Status ce_RunBefore(AVCEncBitstream *stream, int run_before, int zerosLeft)
+{
+    const static uint8 lenRunBefore[7][16] =
+    {
+        {1, 1},
+        {1, 2, 2},
+        {2, 2, 2, 2},
+        {2, 2, 2, 3, 3},
+        {2, 2, 3, 3, 3, 3},
+        {2, 3, 3, 3, 3, 3, 3},
+        {3, 3, 3, 3, 3, 3, 3, 4, 5, 6, 7, 8, 9, 10, 11},
+    };
+
+    const static uint8 codRunBefore[7][16] =
+    {
+        {1, 0},
+        {1, 1, 0},
+        {3, 2, 1, 0},
+        {3, 2, 1, 1, 0},
+        {3, 2, 3, 2, 1, 0},
+        {3, 0, 1, 3, 2, 5, 4},
+        {7, 6, 5, 4, 3, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1},
+    };
+
+    int len, code;
+    AVCEnc_Status status;
+
+    if (zerosLeft <= 6)
+    {
+        len = lenRunBefore[zerosLeft-1][run_before];
+        code = codRunBefore[zerosLeft-1][run_before];
+    }
+    else
+    {
+        len = lenRunBefore[6][run_before];
+        code = codRunBefore[6][run_before];
+    }
+
+    status = BitstreamWriteBits(stream, len, code);
+
+
+    return status;
+}
diff --git a/media/libstagefright/httplive/M3UParser.cpp b/media/libstagefright/httplive/M3UParser.cpp
index edd8648..17771c4 100644
--- a/media/libstagefright/httplive/M3UParser.cpp
+++ b/media/libstagefright/httplive/M3UParser.cpp
@@ -90,7 +90,7 @@
         out->setTo(baseURL);
         out->append(url);
     } else {
-        char *slashPos = strrchr(baseURL, '/');
+        const char *slashPos = strrchr(baseURL, '/');
 
         if (slashPos > &baseURL[6]) {
             out->setTo(baseURL, slashPos - baseURL);
diff --git a/media/libstagefright/include/AACDecoder.h b/media/libstagefright/include/AACDecoder.h
index f09addd..200f93c 100644
--- a/media/libstagefright/include/AACDecoder.h
+++ b/media/libstagefright/include/AACDecoder.h
@@ -25,6 +25,7 @@
 namespace android {
 
 struct MediaBufferGroup;
+struct MetaData;
 
 struct AACDecoder : public MediaSource {
     AACDecoder(const sp<MediaSource> &source);
@@ -41,6 +42,7 @@
     virtual ~AACDecoder();
 
 private:
+    sp<MetaData>    mMeta;
     sp<MediaSource> mSource;
     bool mStarted;
 
@@ -50,9 +52,11 @@
     void *mDecoderBuf;
     int64_t mAnchorTimeUs;
     int64_t mNumSamplesOutput;
+    status_t mInitCheck;
 
     MediaBuffer *mInputBuffer;
 
+    status_t initCheck();
     AACDecoder(const AACDecoder &);
     AACDecoder &operator=(const AACDecoder &);
 };
diff --git a/media/libstagefright/include/AVCEncoder.h b/media/libstagefright/include/AVCEncoder.h
new file mode 100644
index 0000000..4fe2e30
--- /dev/null
+++ b/media/libstagefright/include/AVCEncoder.h
@@ -0,0 +1,90 @@
+/*
+ * 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.
+ */
+
+#ifndef AVC_ENCODER_H_
+
+#define AVC_ENCODER_H_
+
+#include <media/stagefright/MediaBuffer.h>
+#include <media/stagefright/MediaSource.h>
+#include <utils/Vector.h>
+
+struct tagAVCHandle;
+struct tagAVCEncParam;
+
+namespace android {
+
+struct MediaBuffer;
+struct MediaBufferGroup;
+
+struct AVCEncoder : public MediaSource,
+                    public MediaBufferObserver {
+    AVCEncoder(const sp<MediaSource> &source,
+            const sp<MetaData>& meta);
+
+    virtual status_t start(MetaData *params);
+    virtual status_t stop();
+
+    virtual sp<MetaData> getFormat();
+
+    virtual status_t read(
+            MediaBuffer **buffer, const ReadOptions *options);
+
+    virtual void signalBufferReturned(MediaBuffer *buffer);
+
+    // Callbacks required by the encoder
+    int32_t allocOutputBuffers(unsigned int sizeInMbs, unsigned int numBuffers);
+    void    unbindOutputBuffer(int32_t index);
+    int32_t bindOutputBuffer(int32_t index, uint8_t **yuv);
+
+protected:
+    virtual ~AVCEncoder();
+
+private:
+    sp<MediaSource> mSource;
+    sp<MetaData>    mFormat;
+    sp<MetaData>    mMeta;
+
+    int32_t  mVideoWidth;
+    int32_t  mVideoHeight;
+    int32_t  mVideoFrameRate;
+    int32_t  mVideoBitRate;
+    int32_t  mVideoColorFormat;
+    int64_t  mNumInputFrames;
+    status_t mInitCheck;
+    bool     mStarted;
+    bool     mSpsPpsHeaderReceived;
+    bool     mReadyForNextFrame;
+    int32_t  mIsIDRFrame;  // for set kKeyIsSyncFrame
+
+    tagAVCHandle          *mHandle;
+    tagAVCEncParam        *mEncParams;
+    MediaBuffer           *mInputBuffer;
+    uint8_t               *mInputFrameData;
+    MediaBufferGroup      *mGroup;
+    Vector<MediaBuffer *> mOutputBuffers;
+
+
+    status_t initCheck(const sp<MetaData>& meta);
+    void releaseOutputBuffers();
+
+    AVCEncoder(const AVCEncoder &);
+    AVCEncoder &operator=(const AVCEncoder &);
+};
+
+}  // namespace android
+
+#endif  // AVC_ENCODER_H_
diff --git a/media/libstagefright/rtsp/ARTSPConnection.cpp b/media/libstagefright/rtsp/ARTSPConnection.cpp
index e9162c0..9826990 100644
--- a/media/libstagefright/rtsp/ARTSPConnection.cpp
+++ b/media/libstagefright/rtsp/ARTSPConnection.cpp
@@ -116,7 +116,7 @@
         path->setTo(slashPos);
     }
 
-    char *colonPos = strchr(host->c_str(), ':');
+    const char *colonPos = strchr(host->c_str(), ':');
 
     if (colonPos != NULL) {
         unsigned long x;
diff --git a/media/libstagefright/rtsp/ASessionDescription.cpp b/media/libstagefright/rtsp/ASessionDescription.cpp
index ca4c55e..25b9ce2 100644
--- a/media/libstagefright/rtsp/ASessionDescription.cpp
+++ b/media/libstagefright/rtsp/ASessionDescription.cpp
@@ -164,7 +164,7 @@
     AString format;
     getFormat(index, &format);
 
-    char *lastSpacePos = strrchr(format.c_str(), ' ');
+    const char *lastSpacePos = strrchr(format.c_str(), ' ');
     CHECK(lastSpacePos != NULL);
 
     char *end;
diff --git a/media/libstagefright/rtsp/MyHandler.h b/media/libstagefright/rtsp/MyHandler.h
index 74bb798..719ebf3 100644
--- a/media/libstagefright/rtsp/MyHandler.h
+++ b/media/libstagefright/rtsp/MyHandler.h
@@ -419,7 +419,7 @@
             out->setTo(baseURL);
             out->append(url);
         } else {
-            char *slashPos = strrchr(baseURL, '/');
+            const char *slashPos = strrchr(baseURL, '/');
 
             if (slashPos > &baseURL[6]) {
                 out->setTo(baseURL, slashPos - baseURL);
diff --git a/media/mediaserver/Android.mk b/media/mediaserver/Android.mk
index a92cea8..0559812 100644
--- a/media/mediaserver/Android.mk
+++ b/media/mediaserver/Android.mk
@@ -14,8 +14,8 @@
 base := $(LOCAL_PATH)/../..
 
 LOCAL_C_INCLUDES := \
-    $(base)/libs/audioflinger \
-    $(base)/camera/libcameraservice \
+    $(base)/services/audioflinger \
+    $(base)/services/camera/libcameraservice \
     $(base)/media/libmediaplayerservice
 
 LOCAL_MODULE:= mediaserver
diff --git a/media/mtp/Android.mk b/media/mtp/Android.mk
index 13a6430..40adf18 100644
--- a/media/mtp/Android.mk
+++ b/media/mtp/Android.mk
@@ -13,6 +13,9 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 #
+
+ifneq ($(TARGET_SIMULATOR),true)
+
 LOCAL_PATH:= $(call my-dir)
 
 include $(CLEAR_VARS)
@@ -20,67 +23,26 @@
 LOCAL_SRC_FILES:=                                       \
                   MtpClient.cpp                         \
                   MtpCursor.cpp                         \
-                  MtpDatabase.cpp                       \
                   MtpDataPacket.cpp                     \
                   MtpDebug.cpp                          \
                   MtpDevice.cpp                         \
+                  MtpEventPacket.cpp                    \
                   MtpDeviceInfo.cpp                     \
-                  MtpMediaScanner.cpp                   \
                   MtpObjectInfo.cpp                     \
                   MtpPacket.cpp                         \
                   MtpProperty.cpp                       \
                   MtpRequestPacket.cpp                  \
                   MtpResponsePacket.cpp                 \
                   MtpServer.cpp                         \
-                  MtpSqliteDatabase.cpp                 \
                   MtpStorageInfo.cpp                    \
                   MtpStringBuffer.cpp                   \
                   MtpStorage.cpp                        \
                   MtpUtils.cpp                          \
-                  SqliteDatabase.cpp                    \
-                  SqliteStatement.cpp                   \
 
 LOCAL_MODULE:= libmtp
 
-LOCAL_C_INCLUDES := external/sqlite/dist
-
 LOCAL_CFLAGS := -DMTP_DEVICE -DMTP_HOST
 
 include $(BUILD_STATIC_LIBRARY)
 
-ifneq ($(TARGET_SIMULATOR),true)
-
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES:=                                       \
-                  mtptest.cpp                           \
-
-LOCAL_MODULE:= mtptest
-
-LOCAL_CFLAGS := -DMTP_DEVICE
-
-LOCAL_SHARED_LIBRARIES := libutils libsqlite libstagefright libcutils \
-	libmedia
-
-LOCAL_STATIC_LIBRARIES := libmtp
-
-include $(BUILD_EXECUTABLE)
-
-include $(CLEAR_VARS)
-
-LOCAL_MODULE := scantest
-LOCAL_SRC_FILES:=                                       \
-                  scantest.cpp                          \
-
-
-LOCAL_STATIC_LIBRARIES := libmtp
-
-LOCAL_C_INCLUDES := external/sqlite/dist
-LOCAL_SHARED_LIBRARIES := libutils libsqlite libstagefright libmedia
-
-LOCAL_CFLAGS := -g
-LOCAL_LDFLAGS := -g
-
-include $(BUILD_EXECUTABLE)
-
 endif
diff --git a/media/mtp/MtpDataPacket.cpp b/media/mtp/MtpDataPacket.cpp
index a7e975c..6f9ea24 100644
--- a/media/mtp/MtpDataPacket.cpp
+++ b/media/mtp/MtpDataPacket.cpp
@@ -299,17 +299,28 @@
         putUInt64(*values++);
 }
 
-void MtpDataPacket::putString(const MtpStringBuffer& string)
-{
+void MtpDataPacket::putString(const MtpStringBuffer& string) {
     string.writeToPacket(this);
 }
 
-void MtpDataPacket::putString(const char* s)
-{
+void MtpDataPacket::putString(const char* s) {
     MtpStringBuffer string(s);
     string.writeToPacket(this);
 }
 
+void MtpDataPacket::putString(const uint16_t* string) {
+    int count = 0;
+    for (int i = 0; i < 256; i++) {
+        if (string[i])
+            count++;
+        else
+            break;
+    }
+    putUInt8(count);
+    for (int i = 0; i < count; i++)
+        putUInt16(string[i]);
+}
+
 #ifdef MTP_DEVICE 
 int MtpDataPacket::read(int fd) {
     // first read the header
diff --git a/media/mtp/MtpDataPacket.h b/media/mtp/MtpDataPacket.h
index 146ef64..759c0f9 100644
--- a/media/mtp/MtpDataPacket.h
+++ b/media/mtp/MtpDataPacket.h
@@ -79,6 +79,7 @@
     void                putAUInt64(const uint64_t* values, int count);
     void                putString(const MtpStringBuffer& string);
     void                putString(const char* string);
+    void                putString(const uint16_t* string);
     inline void         putEmptyString() { putUInt16(0); }
     inline void         putEmptyArray() { putUInt32(0); }
 
diff --git a/media/mtp/MtpDatabase.cpp b/media/mtp/MtpDatabase.cpp
deleted file mode 100644
index eabd993..0000000
--- a/media/mtp/MtpDatabase.cpp
+++ /dev/null
@@ -1,81 +0,0 @@
-/*
- * 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.
- */
-
-#define LOG_TAG "MtpDatabase"
-
-#include "MtpDebug.h"
-#include "MtpDatabase.h"
-#include "MtpTypes.h"
-#include "mtp.h"
-
-namespace android {
-
-MtpDatabase::~MtpDatabase() {
-}
-
-uint32_t MtpDatabase::getTableForFile(MtpObjectFormat format) {
-    switch (format) {
-        case MTP_FORMAT_AIFF:
-        case MTP_FORMAT_WAV:
-        case MTP_FORMAT_MP3:
-        case MTP_FORMAT_FLAC:
-        case MTP_FORMAT_UNDEFINED_AUDIO:
-        case MTP_FORMAT_WMA:
-        case MTP_FORMAT_OGG:
-        case MTP_FORMAT_AAC:
-        case MTP_FORMAT_AUDIBLE:
-            return kObjectHandleTableAudio;
-        case MTP_FORMAT_AVI:
-        case MTP_FORMAT_MPEG:
-        case MTP_FORMAT_ASF:
-        case MTP_FORMAT_UNDEFINED_VIDEO:
-        case MTP_FORMAT_WMV:
-        case MTP_FORMAT_MP4_CONTAINER:
-        case MTP_FORMAT_MP2:
-        case MTP_FORMAT_3GP_CONTAINER:
-            return kObjectHandleTableVideo;
-        case MTP_FORMAT_DEFINED:
-        case MTP_FORMAT_EXIF_JPEG:
-        case MTP_FORMAT_TIFF_EP:
-        case MTP_FORMAT_FLASHPIX:
-        case MTP_FORMAT_BMP:
-        case MTP_FORMAT_CIFF:
-        case MTP_FORMAT_GIF:
-        case MTP_FORMAT_JFIF:
-        case MTP_FORMAT_CD:
-        case MTP_FORMAT_PICT:
-        case MTP_FORMAT_PNG:
-        case MTP_FORMAT_TIFF:
-        case MTP_FORMAT_TIFF_IT:
-        case MTP_FORMAT_JP2:
-        case MTP_FORMAT_JPX:
-        case MTP_FORMAT_WINDOWS_IMAGE_FORMAT:
-            return kObjectHandleTableImage;
-        case MTP_FORMAT_ABSTRACT_AUDIO_PLAYLIST:
-        case MTP_FORMAT_ABSTRACT_AV_PLAYLIST:
-        case MTP_FORMAT_ABSTRACT_VIDEO_PLAYLIST:
-        case MTP_FORMAT_WPL_PLAYLIST:
-        case MTP_FORMAT_M3U_PLAYLIST:
-        case MTP_FORMAT_MPL_PLAYLIST:
-        case MTP_FORMAT_ASX_PLAYLIST:
-        case MTP_FORMAT_PLS_PLAYLIST:
-            return kObjectHandleTablePlaylist;
-        default:
-            return kObjectHandleTableFile;
-    }
-}
-
-}  // namespace android
diff --git a/media/mtp/MtpDatabase.h b/media/mtp/MtpDatabase.h
index 0c70d9f..7feb3dc 100644
--- a/media/mtp/MtpDatabase.h
+++ b/media/mtp/MtpDatabase.h
@@ -18,7 +18,6 @@
 #define _MTP_DATABASE_H
 
 #include "MtpTypes.h"
-#include "SqliteDatabase.h"
 
 namespace android {
 
@@ -26,35 +25,27 @@
 
 class MtpDatabase {
 public:
-    virtual ~MtpDatabase();
+    virtual ~MtpDatabase() {}
 
-    static uint32_t                 getTableForFile(MtpObjectFormat format);
-
-    virtual MtpObjectHandle         getObjectHandle(const char* path) = 0;
-    virtual MtpObjectHandle         addFile(const char* path,
+    // called from SendObjectInfo to reserve a database entry for the incoming file
+    virtual MtpObjectHandle         beginSendObject(const char* path,
                                             MtpObjectFormat format,
                                             MtpObjectHandle parent,
                                             MtpStorageID storage,
                                             uint64_t size,
                                             time_t modified) = 0;
 
-    virtual MtpObjectHandle         addAudioFile(MtpObjectHandle id) = 0;
-
-    virtual MtpObjectHandle         addAudioFile(MtpObjectHandle id,
-                                            const char* title,
-                                            const char* artist,
-                                            const char* album,
-                                            const char* albumArtist,
-                                            const char* genre,
-                                            const char* composer,
-                                            const char* mimeType,
-                                            int track,
-                                            int year,
-                                            int duration) = 0;
+    // called to report success or failure of the SendObject file transfer
+    // success should signal a notification of the new object's creation,
+    // failure should remove the database entry created in beginSendObject
+    virtual void                    endSendObject(const char* path,
+                                            MtpObjectHandle handle,
+                                            MtpObjectFormat format,
+                                            bool succeeded) = 0;
 
     virtual MtpObjectHandleList*    getObjectList(MtpStorageID storageID,
-                                    MtpObjectFormat format,
-                                    MtpObjectHandle parent) = 0;
+                                            MtpObjectFormat format,
+                                            MtpObjectHandle parent) = 0;
 
     virtual MtpResponseCode         getObjectProperty(MtpObjectHandle handle,
                                             MtpObjectProperty property,
@@ -68,9 +59,6 @@
                                             int64_t& fileLength) = 0;
     virtual bool                    deleteFile(MtpObjectHandle handle) = 0;
 
-    // helper for media scanner
-    virtual MtpObjectHandle*        getFileList(int& outCount) = 0;
-
     virtual void                    beginTransaction() = 0;
     virtual void                    commitTransaction() = 0;
     virtual void                    rollbackTransaction() = 0;
diff --git a/media/mtp/MtpEventPacket.cpp b/media/mtp/MtpEventPacket.cpp
new file mode 100644
index 0000000..089278e
--- /dev/null
+++ b/media/mtp/MtpEventPacket.cpp
@@ -0,0 +1,65 @@
+/*
+ * 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.
+ */
+
+#define LOG_TAG "MtpEventPacket"
+
+#include <stdio.h>
+#include <sys/types.h>
+#include <fcntl.h>
+#include <sys/ioctl.h>
+
+#include <linux/usb/f_mtp.h>
+
+#include "MtpEventPacket.h"
+
+namespace android {
+
+MtpEventPacket::MtpEventPacket()
+    :   MtpPacket(512)
+{
+}
+
+MtpEventPacket::~MtpEventPacket() {
+}
+
+#ifdef MTP_DEVICE
+int MtpEventPacket::write(int fd) {
+    struct mtp_event    event;
+
+    putUInt32(MTP_CONTAINER_LENGTH_OFFSET, mPacketSize);
+    putUInt16(MTP_CONTAINER_TYPE_OFFSET, MTP_CONTAINER_TYPE_EVENT);
+
+    event.data = mBuffer;
+    event.length = mPacketSize;
+    int ret = ::ioctl(fd, MTP_SEND_EVENT, (unsigned long)&event);
+    return (ret < 0 ? ret : 0);
+}
+#endif
+
+#ifdef MTP_HOST
+    // read our buffer from the given endpoint
+int MtpEventPacket::read(struct usb_endpoint *ep) {
+    int ret = transfer(ep, mBuffer, mBufferSize);
+     if (ret >= 0)
+        mPacketSize = ret;
+    else
+        mPacketSize = 0;
+    return ret;
+}
+#endif
+
+}  // namespace android
+
diff --git a/media/mtp/MtpEventPacket.h b/media/mtp/MtpEventPacket.h
new file mode 100644
index 0000000..30ae869
--- /dev/null
+++ b/media/mtp/MtpEventPacket.h
@@ -0,0 +1,48 @@
+/*
+ * 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.
+ */
+
+#ifndef _MTP_EVENT_PACKET_H
+#define _MTP_EVENT_PACKET_H
+
+#include "MtpPacket.h"
+#include "mtp.h"
+
+namespace android {
+
+class MtpEventPacket : public MtpPacket {
+
+public:
+                        MtpEventPacket();
+    virtual             ~MtpEventPacket();
+
+#ifdef MTP_DEVICE
+    // write our data to the given file descriptor
+    int                 write(int fd);
+#endif
+
+#ifdef MTP_HOST
+    // read our buffer from the given endpoint
+    int                 read(struct usb_endpoint *ep);
+#endif
+
+    inline MtpEventCode     getEventCode() const { return getContainerCode(); }
+    inline void             setEventCode(MtpEventCode code)
+                                                     { return setContainerCode(code); }
+};
+
+}; // namespace android
+
+#endif // _MTP_EVENT_PACKET_H
diff --git a/media/mtp/MtpMediaScanner.cpp b/media/mtp/MtpMediaScanner.cpp
deleted file mode 100644
index ac4c0cf..0000000
--- a/media/mtp/MtpMediaScanner.cpp
+++ /dev/null
@@ -1,381 +0,0 @@
-/*
- * 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.
- */
-
-#define LOG_TAG "MtpMediaScanner"
-
-#include "MtpDebug.h"
-#include "MtpDatabase.h"
-#include "MtpMediaScanner.h"
-#include "mtp.h"
-
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <sys/statfs.h>
-#include <unistd.h>
-#include <dirent.h>
-#include <errno.h>
-#include <string.h>
-#include <stdio.h>
-#include <limits.h>
-
-#include <media/mediascanner.h>
-#include <media/stagefright/StagefrightMediaScanner.h>
-
-namespace android {
-
-class MtpMediaScannerClient : public MediaScannerClient
-{
-public:
-    MtpMediaScannerClient()
-    {
-        reset();
-    }
-
-    virtual ~MtpMediaScannerClient()
-    {
-    }
-
-    // returns true if it succeeded, false if an exception occured in the Java code
-    virtual bool scanFile(const char* path, long long lastModified, long long fileSize)
-    {
-        LOGV("scanFile %s", path);
-        return true;
-    }
-
-    // returns true if it succeeded, false if an exception occured in the Java code
-    virtual bool handleStringTag(const char* name, const char* value)
-    {
-        int temp;
-
-        if (!strcmp(name, "title")) {
-            mTitle = value;
-            mHasTitle = true;
-        } else if  (!strcmp(name, "artist")) {
-            mArtist = value;
-            mHasArtist = true;
-        } else if  (!strcmp(name, "album")) {
-            mAlbum = value;
-            mHasAlbum = true;
-        } else if  (!strcmp(name, "albumartist")) {
-            mAlbumArtist = value;
-            mHasAlbumArtist = true;
-        } else if  (!strcmp(name, "genre")) {
-            // FIXME - handle numeric values here
-            mGenre = value;
-            mHasGenre = true;
-        } else if  (!strcmp(name, "composer")) {
-            mComposer = value;
-            mHasComposer = true;
-        } else if  (!strcmp(name, "tracknumber")) {
-            if (sscanf(value, "%d", &temp) == 1)
-                mTrack = temp;
-        } else if  (!strcmp(name, "discnumber")) {
-            // currently unused
-        } else if  (!strcmp(name, "year") || !strcmp(name, "date")) {
-            if (sscanf(value, "%d", &temp) == 1)
-                mYear = temp;
-        } else if  (!strcmp(name, "duration")) {
-            if (sscanf(value, "%d", &temp) == 1)
-                mDuration = temp;
-        } else {
-            LOGV("handleStringTag %s : %s", name, value);
-        }
-        return true;
-    }
-
-    // returns true if it succeeded, false if an exception occured in the Java code
-    virtual bool setMimeType(const char* mimeType)
-    {
-        mMimeType = mimeType;
-        mHasMimeType = true;
-        return true;
-    }
-
-    // returns true if it succeeded, false if an exception occured in the Java code
-    virtual bool addNoMediaFolder(const char* path)
-    {
-        LOGV("addNoMediaFolder %s", path);
-        return true;
-    }
-
-    void reset()
-    {
-        mHasTitle = false;
-        mHasArtist = false;
-        mHasAlbum = false;
-        mHasAlbumArtist = false;
-        mHasGenre = false;
-        mHasComposer = false;
-        mHasMimeType = false;
-        mTrack = mYear = mDuration = 0;
-    }
-
-    inline const char* getTitle() const { return mHasTitle ? (const char *)mTitle : NULL; }
-    inline const char* getArtist() const { return mHasArtist ? (const char *)mArtist : NULL; }
-    inline const char* getAlbum() const { return mHasAlbum ? (const char *)mAlbum : NULL; }
-    inline const char* getAlbumArtist() const { return mHasAlbumArtist ? (const char *)mAlbumArtist : NULL; }
-    inline const char* getGenre() const { return mHasGenre ? (const char *)mGenre : NULL; }
-    inline const char* getComposer() const { return mHasComposer ? (const char *)mComposer : NULL; }
-    inline const char* getMimeType() const { return mHasMimeType ? (const char *)mMimeType : NULL; }
-    inline int getTrack() const { return mTrack; }
-    inline int getYear() const { return mYear; }
-    inline int getDuration() const { return mDuration; }
-
-private:
-    MtpString   mTitle;
-    MtpString   mArtist;
-    MtpString   mAlbum;
-    MtpString   mAlbumArtist;
-    MtpString   mGenre;
-    MtpString   mComposer;
-    MtpString   mMimeType;
-
-    bool        mHasTitle;
-    bool        mHasArtist;
-    bool        mHasAlbum;
-    bool        mHasAlbumArtist;
-    bool        mHasGenre;
-    bool        mHasComposer;
-    bool        mHasMimeType;
-
-    int         mTrack;
-    int         mYear;
-    int         mDuration;
-};
-
-
-MtpMediaScanner::MtpMediaScanner(MtpStorageID id, const char* filePath, MtpDatabase* db)
-    :   mStorageID(id),
-        mFilePath(filePath),
-        mDatabase(db),
-        mMediaScanner(NULL),
-        mMediaScannerClient(NULL),
-        mFileList(NULL),
-        mFileCount(0)
-{
-    mMediaScanner = new StagefrightMediaScanner;
-    mMediaScannerClient = new MtpMediaScannerClient;
-}
-
-MtpMediaScanner::~MtpMediaScanner() {
-}
-
-bool MtpMediaScanner::scanFiles() {
-    mDatabase->beginTransaction();
-    mFileCount = 0;
-    mFileList = mDatabase->getFileList(mFileCount);
-
-    int ret = scanDirectory(mFilePath, MTP_PARENT_ROOT);
-
-    for (int i = 0; i < mFileCount; i++) {
-        MtpObjectHandle test = mFileList[i];
-        if (! (test & kObjectHandleMarkBit)) {
-            LOGV("delete missing file %08X", test);
-            mDatabase->deleteFile(test);
-        }
-    }
-
-    delete[] mFileList;
-    mFileCount = 0;
-    mDatabase->commitTransaction();
-    return (ret == 0);
-}
-
-
-static const struct MediaFileTypeEntry
-{
-    const char*     extension;
-    MtpObjectFormat format;
-    uint32_t        table;
-} sFileTypes[] =
-{
-    { "MP3",    MTP_FORMAT_MP3,             kObjectHandleTableAudio     },
-    { "M4A",    MTP_FORMAT_UNDEFINED_AUDIO, kObjectHandleTableAudio     },
-    { "WAV",    MTP_FORMAT_WAV,             kObjectHandleTableAudio     },
-    { "AMR",    MTP_FORMAT_UNDEFINED_AUDIO, kObjectHandleTableAudio     },
-    { "AWB",    MTP_FORMAT_UNDEFINED_AUDIO, kObjectHandleTableAudio     },
-    { "WMA",    MTP_FORMAT_WMA,             kObjectHandleTableAudio     },
-    { "OGG",    MTP_FORMAT_OGG,             kObjectHandleTableAudio     },
-    { "OGA",    MTP_FORMAT_UNDEFINED_AUDIO, kObjectHandleTableAudio     },
-    { "AAC",    MTP_FORMAT_AAC,             kObjectHandleTableAudio     },
-    { "MID",    MTP_FORMAT_UNDEFINED_AUDIO, kObjectHandleTableAudio     },
-    { "MIDI",   MTP_FORMAT_UNDEFINED_AUDIO, kObjectHandleTableAudio     },
-    { "XMF",    MTP_FORMAT_UNDEFINED_AUDIO, kObjectHandleTableAudio     },
-    { "RTTTL",  MTP_FORMAT_UNDEFINED_AUDIO, kObjectHandleTableAudio     },
-    { "SMF",    MTP_FORMAT_UNDEFINED_AUDIO, kObjectHandleTableAudio     },
-    { "IMY",    MTP_FORMAT_UNDEFINED_AUDIO, kObjectHandleTableAudio     },
-    { "RTX",    MTP_FORMAT_UNDEFINED_AUDIO, kObjectHandleTableAudio     },
-    { "OTA",    MTP_FORMAT_UNDEFINED_AUDIO, kObjectHandleTableAudio     },
-    { "MPEG",   MTP_FORMAT_UNDEFINED_VIDEO, kObjectHandleTableVideo     },
-    { "MP4",    MTP_FORMAT_UNDEFINED_VIDEO, kObjectHandleTableVideo     },
-    { "M4V",    MTP_FORMAT_UNDEFINED_VIDEO, kObjectHandleTableVideo     },
-    { "3GP",    MTP_FORMAT_UNDEFINED_VIDEO, kObjectHandleTableVideo     },
-    { "3GPP",   MTP_FORMAT_UNDEFINED_VIDEO, kObjectHandleTableVideo     },
-    { "3G2",    MTP_FORMAT_UNDEFINED_VIDEO, kObjectHandleTableVideo     },
-    { "3GPP2",  MTP_FORMAT_UNDEFINED_VIDEO, kObjectHandleTableVideo     },
-    { "WMV",    MTP_FORMAT_UNDEFINED_VIDEO, kObjectHandleTableVideo     },
-    { "ASF",    MTP_FORMAT_UNDEFINED_VIDEO, kObjectHandleTableVideo     },
-    { "JPG",    MTP_FORMAT_EXIF_JPEG,       kObjectHandleTableImage     },
-    { "JPEG",   MTP_FORMAT_EXIF_JPEG,       kObjectHandleTableImage     },
-    { "GIF",    MTP_FORMAT_GIF,             kObjectHandleTableImage     },
-    { "PNG",    MTP_FORMAT_PNG,             kObjectHandleTableImage     },
-    { "BMP",    MTP_FORMAT_BMP,             kObjectHandleTableImage     },
-    { "WBMP",   MTP_FORMAT_BMP,             kObjectHandleTableImage     },
-    { "M3U",    MTP_FORMAT_M3U_PLAYLIST,    kObjectHandleTablePlaylist  },
-    { "PLS",    MTP_FORMAT_PLS_PLAYLIST,    kObjectHandleTablePlaylist  },
-    { "WPL",    MTP_FORMAT_WPL_PLAYLIST,    kObjectHandleTablePlaylist  },
-};
-
-MtpObjectFormat MtpMediaScanner::getFileFormat(const char* path, uint32_t& table)
-{
-    const char* extension = strrchr(path, '.');
-    if (!extension)
-        return MTP_FORMAT_UNDEFINED;
-    extension++; // skip the dot
-
-    for (unsigned i = 0; i < sizeof(sFileTypes) / sizeof(sFileTypes[0]); i++) {
-        if (!strcasecmp(extension, sFileTypes[i].extension)) {
-            table = sFileTypes[i].table;
-            return sFileTypes[i].format;
-        }
-    }
-    table = kObjectHandleTableFile;
-    return MTP_FORMAT_UNDEFINED;
-}
-
-int MtpMediaScanner::scanDirectory(const char* path, MtpObjectHandle parent)
-{
-    char buffer[PATH_MAX];
-    struct dirent* entry;
-
-    unsigned length = strlen(path);
-    if (length > sizeof(buffer) + 2) {
-        LOGE("path too long: %s", path);
-    }
-
-    DIR* dir = opendir(path);
-    if (!dir) {
-        LOGE("opendir %s failed, errno: %d", path, errno);
-        return -1;
-    }
-
-    strncpy(buffer, path, sizeof(buffer));
-    char* fileStart = buffer + length;
-    // make sure we have a trailing slash
-    if (fileStart[-1] != '/') {
-        *(fileStart++) = '/';
-    }
-    int fileNameLength = sizeof(buffer) + fileStart - buffer;
-
-    while ((entry = readdir(dir))) {
-        const char* name = entry->d_name;
-
-        // ignore "." and "..", as well as any files or directories staring with dot
-        if (name[0] == '.') {
-            continue;
-        }
-        if (strlen(name) + 1 > fileNameLength) {
-            LOGE("path too long for %s", name);
-            continue;
-        }
-        strcpy(fileStart, name);
-
-        struct stat statbuf;
-        memset(&statbuf, 0, sizeof(statbuf));
-        stat(buffer, &statbuf);
-
-        if (S_ISDIR(statbuf.st_mode)) {
-            MtpObjectHandle handle = mDatabase->getObjectHandle(buffer);
-            if (handle) {
-                markFile(handle);
-            } else {
-                handle = mDatabase->addFile(buffer, MTP_FORMAT_ASSOCIATION,
-                        parent, mStorageID, 0, statbuf.st_mtime);
-            }
-            scanDirectory(buffer, handle);
-        } else if (S_ISREG(statbuf.st_mode)) {
-            scanFile(buffer, parent, statbuf);
-        }
-    }
-
-    closedir(dir);
-    return 0;
-}
-
-void MtpMediaScanner::scanFile(const char* path, MtpObjectHandle parent, struct stat& statbuf) {
-    uint32_t table;
-    MtpObjectFormat format = getFileFormat(path, table);
-    // don't scan unknown file types
-    if (format == MTP_FORMAT_UNDEFINED)
-        return;
-    MtpObjectHandle handle = mDatabase->getObjectHandle(path);
-    // fixme - rescan if mod date changed
-    if (handle) {
-        markFile(handle);
-    } else {
-        mDatabase->beginTransaction();
-        handle = mDatabase->addFile(path, format, parent, mStorageID,
-                statbuf.st_size, statbuf.st_mtime);
-        if (handle <= 0) {
-            LOGE("addFile failed in MtpMediaScanner::scanFile()");
-            mDatabase->rollbackTransaction();
-            return;
-        }
-
-        if (table == kObjectHandleTableAudio) {
-            mMediaScannerClient->reset();
-            mMediaScanner->processFile(path, NULL, *mMediaScannerClient);
-            handle = mDatabase->addAudioFile(handle,
-                    mMediaScannerClient->getTitle(),
-                    mMediaScannerClient->getArtist(),
-                    mMediaScannerClient->getAlbum(),
-                    mMediaScannerClient->getAlbumArtist(),
-                    mMediaScannerClient->getGenre(),
-                    mMediaScannerClient->getComposer(),
-                    mMediaScannerClient->getMimeType(),
-                    mMediaScannerClient->getTrack(),
-                    mMediaScannerClient->getYear(),
-                    mMediaScannerClient->getDuration());
-        }
-        mDatabase->commitTransaction();
-    }
-}
-
-void MtpMediaScanner::markFile(MtpObjectHandle handle) {
-    if (mFileList) {
-        handle &= kObjectHandleIndexMask;
-        // binary search for the file in mFileList
-        int low = 0;
-        int high = mFileCount;
-        int index;
-
-        while (low < high) {
-            index = (low + high) >> 1;
-            MtpObjectHandle test = (mFileList[index] & kObjectHandleIndexMask);
-            if (handle < test)
-                high = index;       // item is less than index
-            else if (handle > test)
-                low = index + 1;    // item is greater than index
-            else {
-                mFileList[index] |= kObjectHandleMarkBit;
-                return;
-            }
-        }
-        LOGE("file %d not found in mFileList", handle);
-    }
-}
-
-}  // namespace android
diff --git a/media/mtp/MtpMediaScanner.h b/media/mtp/MtpMediaScanner.h
deleted file mode 100644
index 53d5063..0000000
--- a/media/mtp/MtpMediaScanner.h
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
- * 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.
- */
-
-#ifndef _MTP_MEDIA_SCANNER_H
-#define _MTP_MEDIA_SCANNER_H
-
-struct stat;
-
-namespace android {
-
-class MtpDatabase;
-class SqliteStatement;
-class MediaScanner;
-class MtpMediaScannerClient;
-
-class MtpMediaScanner {
-private:
-    MtpStorageID            mStorageID;
-    const char*             mFilePath;
-    MtpDatabase*            mDatabase;
-    MediaScanner*           mMediaScanner;
-    MtpMediaScannerClient*  mMediaScannerClient;
-
-    // for garbage collecting missing files
-    MtpObjectHandle*        mFileList;
-    int                     mFileCount;
-
-public:
-                            MtpMediaScanner(MtpStorageID id, const char* filePath, MtpDatabase* db);
-    virtual                 ~MtpMediaScanner();
-
-    bool                    scanFiles();
-
-private:
-    MtpObjectFormat         getFileFormat(const char* path, uint32_t& table);
-    int                     scanDirectory(const char* path, MtpObjectHandle parent);
-    void                    scanFile(const char* path, MtpObjectHandle parent, struct stat& statbuf);
-    void                    markFile(MtpObjectHandle handle);
-};
-
-}; // namespace android
-
-#endif // _MTP_MEDIA_SCANNER_H
diff --git a/media/mtp/MtpServer.cpp b/media/mtp/MtpServer.cpp
index b9eeec5..163c05b 100644
--- a/media/mtp/MtpServer.cpp
+++ b/media/mtp/MtpServer.cpp
@@ -25,13 +25,13 @@
 #include <cutils/properties.h>
 
 #include "MtpDebug.h"
+#include "MtpDatabase.h"
 #include "MtpProperty.h"
 #include "MtpServer.h"
-#include "MtpSqliteDatabase.h"
 #include "MtpStorage.h"
 #include "MtpStringBuffer.h"
 
-#include "f_mtp.h"
+#include <linux/usb/f_mtp.h>
 
 namespace android {
 
@@ -73,6 +73,11 @@
 //    MTP_OPERATION_SKIP,
 };
 
+static const MtpEventCode kSupportedEventCodes[] = {
+    MTP_EVENT_OBJECT_ADDED,
+    MTP_EVENT_OBJECT_REMOVED,
+};
+
 static const MtpObjectProperty kSupportedObjectProperties[] = {
     MTP_PROPERTY_STORAGE_ID,
     MTP_PROPERTY_OBJECT_FORMAT,
@@ -113,22 +118,19 @@
     // MTP_FORMAT_PLS_PLAYLIST,
 };
 
-MtpServer::MtpServer(int fd, const char* databasePath,
+MtpServer::MtpServer(int fd, MtpDatabase* database,
                     int fileGroup, int filePerm, int directoryPerm)
     :   mFD(fd),
-        mDatabasePath(databasePath),
-        mDatabase(NULL),
+        mDatabase(database),
         mFileGroup(fileGroup),
         mFilePermission(filePerm),
         mDirectoryPermission(directoryPerm),
         mSessionID(0),
         mSessionOpen(false),
         mSendObjectHandle(kInvalidObjectHandle),
+        mSendObjectFormat(0),
         mSendObjectFileSize(0)
 {
-    mDatabase = new MtpSqliteDatabase();
-    mDatabase->open(databasePath, true);
-
     initObjectProperties();
 }
 
@@ -151,13 +153,6 @@
     return NULL;
 }
 
-void MtpServer::scanStorage() {
-    for (int i = 0; i < mStorages.size(); i++) {
-        MtpStorage* storage =  mStorages[i];
-        storage->scanFiles();
-    }
-}
-
 void MtpServer::run() {
     int fd = mFD;
 
@@ -249,6 +244,24 @@
     return NULL;
 }
 
+void MtpServer::sendObjectAdded(MtpObjectHandle handle) {
+    LOGD("sendObjectAdded %d\n", handle);
+    mEvent.setEventCode(MTP_EVENT_OBJECT_ADDED);
+    mEvent.setTransactionID(mRequest.getTransactionID());
+    mEvent.setParameter(1, handle);
+    int ret = mEvent.write(mFD);
+    LOGD("mEvent.write returned %d\n", ret);
+}
+
+void MtpServer::sendObjectRemoved(MtpObjectHandle handle) {
+    LOGD("sendObjectRemoved %d\n", handle);
+    mEvent.setEventCode(MTP_EVENT_OBJECT_REMOVED);
+    mEvent.setTransactionID(mRequest.getTransactionID());
+    mEvent.setParameter(1, handle);
+    int ret = mEvent.write(mFD);
+    LOGD("mEvent.write returned %d\n", ret);
+}
+
 void MtpServer::initObjectProperties() {
     mObjectProperties.push(new MtpProperty(MTP_PROPERTY_STORAGE_ID, MTP_TYPE_UINT16));
     mObjectProperties.push(new MtpProperty(MTP_PROPERTY_OBJECT_FORMAT, MTP_TYPE_UINT16));
@@ -336,7 +349,8 @@
     mData.putUInt16(0); //Functional Mode
     mData.putAUInt16(kSupportedOperationCodes,
             sizeof(kSupportedOperationCodes) / sizeof(uint16_t)); // Operations Supported
-    mData.putEmptyArray(); // Events Supported
+    mData.putAUInt16(kSupportedEventCodes,
+            sizeof(kSupportedEventCodes) / sizeof(uint16_t)); // Events Supported
     mData.putEmptyArray(); // Device Properties Supported
     mData.putEmptyArray(); // Capture Formats
     mData.putAUInt16(kSupportedPlaybackFormats,
@@ -427,6 +441,8 @@
     MtpObjectFormat format = mRequest.getParameter(2);      // 0 for all formats
     MtpObjectHandle parent = mRequest.getParameter(3);      // 0xFFFFFFFF for objects with no parent
                                                             // 0x00000000 for all objects?
+    if (parent == 0xFFFFFFFF)
+        parent = 0;
 
     MtpObjectHandleList* handles = mDatabase->getObjectList(storageID, format, parent);
     mData.putAUInt32(handles);
@@ -488,9 +504,10 @@
         return MTP_RESPONSE_INVALID_STORAGE_ID;
 
     // special case the root
-    if (parent == MTP_PARENT_ROOT)
+    if (parent == MTP_PARENT_ROOT) {
         path = storage->getPath();
-    else {
+        parent = 0;
+    } else {
         int64_t dummy;
         if (!mDatabase->getObjectFilePath(parent, path, dummy))
             return MTP_RESPONSE_INVALID_OBJECT_HANDLE;
@@ -527,15 +544,12 @@
     path += (const char *)name;
 
     mDatabase->beginTransaction();
-    MtpObjectHandle handle = mDatabase->addFile((const char*)path, format, parent, storageID, 
-                                    mSendObjectFileSize, modifiedTime);
+    MtpObjectHandle handle = mDatabase->beginSendObject((const char*)path,
+            format, parent, storageID, mSendObjectFileSize, modifiedTime);
     if (handle == kInvalidObjectHandle) {
         mDatabase->rollbackTransaction();
         return MTP_RESPONSE_GENERAL_ERROR;
     }
-    uint32_t table = MtpDatabase::getTableForFile(format);
-    if (table == kObjectHandleTableAudio)
-        handle = mDatabase->addAudioFile(handle);
     mDatabase->commitTransaction();
 
   if (format == MTP_FORMAT_ASSOCIATION) {
@@ -549,23 +563,29 @@
         mSendObjectFilePath = path;
         // save the handle for the SendObject call, which should follow
         mSendObjectHandle = handle;
+        mSendObjectFormat = format;
     }
 
     mResponse.setParameter(1, storageID);
-    mResponse.setParameter(2, parent);
+    mResponse.setParameter(2, (parent == 0 ? 0xFFFFFFFF: parent));
     mResponse.setParameter(3, handle);
 
     return MTP_RESPONSE_OK;
 }
 
 MtpResponseCode MtpServer::doSendObject() {
+    MtpResponseCode result = MTP_RESPONSE_OK;
+    mode_t mask;
+    int ret;
+
     if (mSendObjectHandle == kInvalidObjectHandle) {
         LOGE("Expected SendObjectInfo before SendObject");
-        return MTP_RESPONSE_NO_VALID_OBJECT_INFO;
+        result = MTP_RESPONSE_NO_VALID_OBJECT_INFO;
+        goto done;
     }
 
     // read the header
-    int ret = mData.readDataHeader(mFD);
+    ret = mData.readDataHeader(mFD);
     // FIXME - check for errors here.
 
     // reset so we don't attempt to send this back
@@ -574,11 +594,12 @@
     mtp_file_range  mfr;
     mfr.fd = open(mSendObjectFilePath, O_RDWR | O_CREAT | O_TRUNC);
     if (mfr.fd < 0) {
-        return MTP_RESPONSE_GENERAL_ERROR;
+        result = MTP_RESPONSE_GENERAL_ERROR;
+        goto done;
     }
     fchown(mfr.fd, getuid(), mFileGroup);
     // set permissions
-    mode_t mask = umask(0);
+    mask = umask(0);
     fchmod(mfr.fd, mFilePermission);
     umask(mask);
 
@@ -589,18 +610,22 @@
     ret = ioctl(mFD, MTP_RECEIVE_FILE, (unsigned long)&mfr);
     close(mfr.fd);
 
-    // FIXME - we need to delete mSendObjectHandle from the database if this fails.
     LOGV("MTP_RECEIVE_FILE returned %d", ret);
-    mSendObjectHandle = kInvalidObjectHandle;
 
     if (ret < 0) {
         unlink(mSendObjectFilePath);
         if (errno == ECANCELED)
-            return MTP_RESPONSE_TRANSACTION_CANCELLED;
+            result = MTP_RESPONSE_TRANSACTION_CANCELLED;
         else
-            return MTP_RESPONSE_GENERAL_ERROR;
+            result = MTP_RESPONSE_GENERAL_ERROR;
     }
-    return MTP_RESPONSE_OK;
+
+done:
+    mDatabase->endSendObject(mSendObjectFilePath, mSendObjectHandle, mSendObjectFormat,
+            result == MTP_RESPONSE_OK);
+    mSendObjectHandle = kInvalidObjectHandle;
+    mSendObjectFormat = 0;
+    return result;
 }
 
 MtpResponseCode MtpServer::doDeleteObject() {
diff --git a/media/mtp/MtpServer.h b/media/mtp/MtpServer.h
index 25635af..aff973a 100644
--- a/media/mtp/MtpServer.h
+++ b/media/mtp/MtpServer.h
@@ -20,15 +20,16 @@
 #include "MtpRequestPacket.h"
 #include "MtpDataPacket.h"
 #include "MtpResponsePacket.h"
+#include "MtpEventPacket.h"
 #include "mtp.h"
 
 #include "MtpUtils.h"
 
 namespace android {
 
-class MtpStorage;
-class MtpSqliteDatabase;
+class MtpDatabase;
 class MtpProperty;
+class MtpStorage;
 
 class MtpServer {
 
@@ -36,10 +37,7 @@
     // file descriptor for MTP kernel driver
     int                 mFD;
 
-    // path to our sqlite3 database
-    const char*         mDatabasePath;
-
-    MtpSqliteDatabase*  mDatabase;
+    MtpDatabase*        mDatabase;
 
     // group to own new files and folders
     int                 mFileGroup;
@@ -55,6 +53,7 @@
     MtpRequestPacket    mRequest;
     MtpDataPacket       mData;
     MtpResponsePacket   mResponse;
+    MtpEventPacket      mEvent;
 
     MtpStorageList      mStorages;
 
@@ -63,23 +62,26 @@
 
     // handle for new object, set by SendObjectInfo and used by SendObject
     MtpObjectHandle     mSendObjectHandle;
+    MtpObjectFormat     mSendObjectFormat;
     MtpString           mSendObjectFilePath;
     size_t              mSendObjectFileSize;
 
 public:
-                        MtpServer(int fd, const char* databasePath,
+                        MtpServer(int fd, MtpDatabase* database,
                                     int fileGroup, int filePerm, int directoryPerm);
     virtual             ~MtpServer();
 
     void                addStorage(const char* filePath);
     inline void         addStorage(MtpStorage* storage) { mStorages.push(storage); }
     MtpStorage*         getStorage(MtpStorageID id);
-    void                scanStorage();
     void                run();
 
     MtpProperty*        getObjectProperty(MtpPropertyCode propCode);
     MtpProperty*        getDeviceProperty(MtpPropertyCode propCode);
 
+    void                sendObjectAdded(MtpObjectHandle handle);
+    void                sendObjectRemoved(MtpObjectHandle handle);
+
 private:
     void                initObjectProperties();
 
diff --git a/media/mtp/MtpSqliteDatabase.cpp b/media/mtp/MtpSqliteDatabase.cpp
deleted file mode 100644
index fa3bdfe..0000000
--- a/media/mtp/MtpSqliteDatabase.cpp
+++ /dev/null
@@ -1,564 +0,0 @@
-/*
- * 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.
- */
-
-#define LOG_TAG "MtpSqliteDatabase"
-
-#include "MtpDebug.h"
-#include "MtpSqliteDatabase.h"
-#include "MtpDataPacket.h"
-#include "MtpUtils.h"
-#include "SqliteDatabase.h"
-#include "SqliteStatement.h"
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <sqlite3.h>
-
-namespace android {
-
-#define FILE_ID_COLUMN                  1
-#define FILE_PATH_COLUMN                2
-#define FILE_FORMAT_COLUMN              3
-#define FILE_PARENT_COLUMN              4
-#define FILE_STORAGE_COLUMN             5
-#define FILE_SIZE_COLUMN                6
-#define FILE_MODIFIED_COLUMN            7
-
-#define AUDIO_ID_COLUMN                 1
-#define AUDIO_TITLE_COLUMN              2
-#define AUDIO_ARTIST_COLUMN             3
-#define AUDIO_ALBUM_COLUMN              4
-#define AUDIO_ALBUM_ARTIST_COLUMN       5
-#define AUDIO_GENRE_COLUMN              6
-#define AUDIO_COMPOSER_COLUMN           7
-#define AUDIO_TRACK_NUMBER_COLUMN       8
-#define AUDIO_YEAR_COLUMN               9
-#define AUDIO_DURATION_COLUMN           10
-#define AUDIO_USE_COUNT_COLUMN          11
-#define AUDIO_SAMPLE_RATE_COLUMN        12
-#define AUDIO_NUM_CHANNELS_COLUMN       13
-#define AUDIO_AUDIO_WAVE_CODEC_COLUMN   14
-#define AUDIO_AUDIO_BIT_RATE_COLUMN     15
-
-#define FILE_TABLE_CREATE    "CREATE TABLE IF NOT EXISTS files ("    \
-                        "_id INTEGER PRIMARY KEY,"              \
-                        "path TEXT,"                            \
-                        "format INTEGER,"                       \
-                        "parent INTEGER,"                       \
-                        "storage INTEGER,"                      \
-                        "size INTEGER,"                         \
-                        "date_modified INTEGER"                \
-                        ");"
-
-#define AUDIO_TABLE_CREATE    "CREATE TABLE IF NOT EXISTS audio ("    \
-                        "id INTEGER PRIMARY KEY,"               \
-                        "title TEXT,"                           \
-                        "artist TEXT,"                          \
-                        "album TEXT,"                           \
-                        "album_artist TEXT,"                    \
-                        "genre TEXT,"                           \
-                        "composer TEXT,"                        \
-                        "track_number INTEGER,"                 \
-                        "year INTEGER,"                         \
-                        "duration INTEGER,"                     \
-                        "use_count INTEGER,"                    \
-                        "sample_rate INTEGER,"                  \
-                        "num_channels INTEGER,"                 \
-                        "audio_wave_codec TEXT,"                \
-                        "audio_bit_rate INTEGER"                \
-                        ");"
-
-#define PATH_INDEX_CREATE "CREATE INDEX IF NOT EXISTS path_index on files(path);"
-
-#define FILE_ID_QUERY   "SELECT _id,format FROM files WHERE path = ?;"
-#define FILE_PATH_QUERY "SELECT path,size FROM files WHERE _id = ?"
-
-#define GET_OBJECT_INFO_QUERY   "SELECT storage,format,parent,path,size,date_modified FROM files WHERE _id = ?;"
-#define FILE_INSERT     "INSERT INTO files VALUES(?,?,?,?,?,?,?);"
-#define FILE_DELETE     "DELETE FROM files WHERE _id = ?;"
-
-#define AUDIO_INSERT    "INSERT INTO audio VALUES(?,?,?,?,?,?,?,?,?,?,?,?,?,?,?);"
-#define AUDIO_DELETE    "DELETE FROM audio WHERE id = ?;"
-
-struct PropertyTableEntry {
-    MtpObjectProperty   property;
-    int                 type;
-    const char*         columnName;
-};
-
-static const PropertyTableEntry   kPropertyTable[] = {
-    {   MTP_PROPERTY_PARENT_OBJECT,     MTP_TYPE_UINT32,    "parent"        },
-    {   MTP_PROPERTY_STORAGE_ID,        MTP_TYPE_UINT32,    "storage"       },
-    {   MTP_PROPERTY_OBJECT_FORMAT,     MTP_TYPE_UINT32,    "format"        },
-    {   MTP_PROPERTY_OBJECT_FILE_NAME,  MTP_TYPE_STR,       "path"          },
-    {   MTP_PROPERTY_OBJECT_SIZE,       MTP_TYPE_UINT64,    "size"          },
-    {   MTP_PROPERTY_DATE_MODIFIED,     MTP_TYPE_STR,       "date_modified" },
-};
-
-static bool getPropertyInfo(MtpObjectProperty property, int& type, const char*& columnName) {
-    int count = sizeof(kPropertyTable) / sizeof(kPropertyTable[0]);
-    const PropertyTableEntry* entry = kPropertyTable;
-    for (int i = 0; i < count; i++, entry++) {
-        if (entry->property == property) {
-            type = entry->type;
-            columnName = entry->columnName;
-            return true;
-        }
-    }
-    return false;
-}
-
-MtpSqliteDatabase::MtpSqliteDatabase()
-    :   mDatabase(NULL),
-        mFileIdQuery(NULL),
-        mFilePathQuery(NULL),
-        mObjectInfoQuery(NULL),
-        mFileInserter(NULL),
-        mFileDeleter(NULL),
-        mAudioInserter(NULL),
-        mAudioDeleter(NULL)
-{
-}
-
-MtpSqliteDatabase::~MtpSqliteDatabase() {
-    delete mDatabase;
-    delete mFileIdQuery;
-    delete mFilePathQuery;
-    delete mObjectInfoQuery;
-    delete mFileInserter;
-    delete mFileDeleter;
-    delete mAudioInserter;
-    delete mAudioDeleter;
-}
-
-bool MtpSqliteDatabase::open(const char* path, bool create) {
-    mDatabase = new SqliteDatabase;
-
-    if (!mDatabase->open(path, create))
-        goto fail;
-
-    // create tables and indices if necessary
-    if (!mDatabase->exec(FILE_TABLE_CREATE)) {
-        LOGE("could not create file table");
-        goto fail;
-    }
-    if (!mDatabase->exec(PATH_INDEX_CREATE)) {
-        LOGE("could not path index on file table");
-        goto fail;
-    }
-    if (!mDatabase->exec(AUDIO_TABLE_CREATE)) {
-        LOGE("could not create file table");
-        goto fail;
-    }
-
-    if (!mFileIdQuery) {
-        mFileIdQuery = new SqliteStatement(mDatabase);
-        if (!mFileIdQuery->prepare(FILE_ID_QUERY)) {
-            LOGE("could not compile FILE_ID_QUERY");
-            goto fail;
-        }
-    }
-    if (!mFilePathQuery) {
-        mFilePathQuery = new SqliteStatement(mDatabase);
-        if (!mFilePathQuery->prepare(FILE_PATH_QUERY)) {
-            LOGE("could not compile FILE_PATH_QUERY");
-            goto fail;
-        }
-    }
-    if (!mObjectInfoQuery) {
-        mObjectInfoQuery = new SqliteStatement(mDatabase);
-        if (!mObjectInfoQuery->prepare(GET_OBJECT_INFO_QUERY)) {
-            LOGE("could not compile GET_OBJECT_INFO_QUERY");
-            goto fail;
-        }
-    }
-    if (!mFileInserter) {
-        mFileInserter = new SqliteStatement(mDatabase);
-        if (!mFileInserter->prepare(FILE_INSERT)) {
-            LOGE("could not compile FILE_INSERT\n");
-            goto fail;
-        }
-    }
-    if (!mFileDeleter) {
-        mFileDeleter = new SqliteStatement(mDatabase);
-        if (!mFileDeleter->prepare(FILE_DELETE)) {
-            LOGE("could not compile FILE_DELETE\n");
-            goto fail;
-        }
-    }
-    if (!mAudioInserter) {
-        mAudioInserter = new SqliteStatement(mDatabase);
-        if (!mAudioInserter->prepare(AUDIO_INSERT)) {
-            LOGE("could not compile AUDIO_INSERT\n");
-            goto fail;
-        }
-    }
-    if (!mAudioDeleter) {
-        mAudioDeleter = new SqliteStatement(mDatabase);
-        if (!mAudioDeleter->prepare(AUDIO_DELETE)) {
-            LOGE("could not compile AUDIO_DELETE\n");
-            goto fail;
-        }
-    }
-
-    return true;
-
-fail:
-    delete mDatabase;
-    delete mFileIdQuery;
-    delete mFilePathQuery;
-    delete mObjectInfoQuery;
-    delete mFileInserter;
-    delete mFileDeleter;
-    delete mAudioInserter;
-    delete mAudioDeleter;
-    mDatabase = NULL;
-    mFileIdQuery = NULL;
-    mFilePathQuery = NULL;
-    mObjectInfoQuery = NULL;
-    mFileInserter = NULL;
-    mFileDeleter = NULL;
-    mAudioInserter = NULL;
-    mAudioDeleter = NULL;
-    return false;
-}
-
-void MtpSqliteDatabase::close() {
-    if (mDatabase) {
-        mDatabase->close();
-        mDatabase = NULL;
-    }
-}
-
-MtpObjectHandle MtpSqliteDatabase::getObjectHandle(const char* path) {
-    mFileIdQuery->reset();
-    mFileIdQuery->bind(1, path);
-    if (mFileIdQuery->step()) {
-        int row = mFileIdQuery->getColumnInt(0);
-        if (row > 0) {
-            MtpObjectFormat format = mFileIdQuery->getColumnInt(1);
-            row |= getTableForFile(format);
-            return row;
-        }
-    }
-
-    return 0;
-}
-
-MtpObjectHandle MtpSqliteDatabase::addFile(const char* path,
-                                    MtpObjectFormat format,
-                                    MtpObjectHandle parent,
-                                    MtpStorageID storage,
-                                    uint64_t size,
-                                    time_t modified) {
-    mFileInserter->bind(FILE_PATH_COLUMN, path);
-    mFileInserter->bind(FILE_FORMAT_COLUMN, format);
-    mFileInserter->bind(FILE_PARENT_COLUMN, parent);
-    mFileInserter->bind(FILE_STORAGE_COLUMN, storage);
-    mFileInserter->bind(FILE_SIZE_COLUMN, size);
-    mFileInserter->bind(FILE_MODIFIED_COLUMN, modified);
-    mFileInserter->step();
-    mFileInserter->reset();
-    int result = mDatabase->lastInsertedRow();
-    return (result <= 0 ? kInvalidObjectHandle : result);
-}
-
-MtpObjectHandle MtpSqliteDatabase::addAudioFile(MtpObjectHandle handle) {
-    mAudioInserter->bind(AUDIO_ID_COLUMN, handle);
-    mAudioInserter->step();
-    mAudioInserter->reset();
-    int result = mDatabase->lastInsertedRow();
-    handle |= kObjectHandleTableAudio;
-    return (result > 0 ? handle : kInvalidObjectHandle);
-}
-
-MtpObjectHandle MtpSqliteDatabase::addAudioFile(MtpObjectHandle handle,
-                                    const char* title,
-                                    const char* artist,
-                                    const char* album,
-                                    const char* albumArtist,
-                                    const char* genre,
-                                    const char* composer,
-                                    const char* mimeType,
-                                    int track,
-                                    int year,
-                                    int duration) {
-    mAudioInserter->bind(AUDIO_ID_COLUMN, handle);
-    if (title) mAudioInserter->bind(AUDIO_TITLE_COLUMN, title);
-    if (artist) mAudioInserter->bind(AUDIO_ARTIST_COLUMN, artist);
-    if (album) mAudioInserter->bind(AUDIO_ALBUM_COLUMN, album);
-    if (albumArtist) mAudioInserter->bind(AUDIO_ALBUM_ARTIST_COLUMN, albumArtist);
-    if (genre) mAudioInserter->bind(AUDIO_GENRE_COLUMN, genre);
-    if (composer) mAudioInserter->bind(AUDIO_COMPOSER_COLUMN, composer);
-    if (track) mAudioInserter->bind(AUDIO_TRACK_NUMBER_COLUMN, track);
-    if (year) mAudioInserter->bind(AUDIO_YEAR_COLUMN, year);
-    if (duration) mAudioInserter->bind(AUDIO_DURATION_COLUMN, duration);
-    mAudioInserter->step();
-    mAudioInserter->reset();
-    int result = mDatabase->lastInsertedRow();
-    if (result <= 0)
-        return kInvalidObjectHandle;
-    result |= kObjectHandleTableAudio;
-    return result;
-}
-
-MtpObjectHandleList* MtpSqliteDatabase::getObjectList(MtpStorageID storageID,
-                                                MtpObjectFormat format,
-                                                MtpObjectHandle parent) {
-    bool                whereStorage = (storageID != 0xFFFFFFFF);
-    bool                whereFormat = (format != 0);
-    bool                whereParent = (parent != 0);
-    char                intBuffer[20];
-
-    MtpString  query("SELECT _id,format FROM files");
-    if (whereStorage || whereFormat || whereParent)
-        query += " WHERE";
-    if (whereStorage) {
-        snprintf(intBuffer, sizeof(intBuffer), "%d", storageID);
-        query += " storage = ";
-        query += intBuffer;
-    }
-    if (whereFormat) {
-        snprintf(intBuffer, sizeof(intBuffer), "%d", format);
-        if (whereStorage)
-            query += " AND";
-        query += " format = ";
-        query += intBuffer;
-    }
-    if (whereParent) {
-        if (parent != MTP_PARENT_ROOT)
-            parent &= kObjectHandleIndexMask;
-        snprintf(intBuffer, sizeof(intBuffer), "%d", parent);
-        if (whereStorage || whereFormat)
-            query += " AND";
-        query += " parent = ";
-        query += intBuffer;
-    }
-    query += ";";
-
-    SqliteStatement stmt(mDatabase);
-    LOGV("%s", (const char *)query);
-    stmt.prepare(query);
-
-    MtpObjectHandleList* list = new MtpObjectHandleList();
-    while (!stmt.isDone()) {
-        if (stmt.step()) {
-            int index = stmt.getColumnInt(0);
-            LOGV("stmt.getColumnInt returned %d", index);
-            if (index > 0) {
-                MtpObjectFormat format = stmt.getColumnInt(1);
-                index |= getTableForFile(format);
-                list->push(index);
-            }
-        }
-    }
-    LOGV("list size: %d", list->size());
-    return list;
-}
-
-
-MtpResponseCode MtpSqliteDatabase::getObjectProperty(MtpObjectHandle handle,
-                                    MtpObjectProperty property,
-                                    MtpDataPacket& packet) {
-    int         type;
-    const char* columnName;
-    char        intBuffer[20];
-
-    if (handle != MTP_PARENT_ROOT)
-        handle &= kObjectHandleIndexMask;
-
-    if (!getPropertyInfo(property, type, columnName))
-        return MTP_RESPONSE_INVALID_OBJECT_PROP_CODE;
-    snprintf(intBuffer, sizeof(intBuffer), "%d", handle);
-
-    MtpString  query("SELECT ");
-    query += columnName;
-    query += " FROM files WHERE _id = ";
-    query += intBuffer;
-    query += ";";
-
-    SqliteStatement stmt(mDatabase);
-    LOGV("%s", (const char *)query);
-    stmt.prepare(query);
-
-    if (!stmt.step())
-        return MTP_RESPONSE_INVALID_OBJECT_HANDLE;
-
-    switch (type) {
-        case MTP_TYPE_INT8:
-            packet.putInt8(stmt.getColumnInt(0));
-            break;
-        case MTP_TYPE_UINT8:
-            packet.putUInt8(stmt.getColumnInt(0));
-            break;
-        case MTP_TYPE_INT16:
-            packet.putInt16(stmt.getColumnInt(0));
-            break;
-        case MTP_TYPE_UINT16:
-            packet.putUInt16(stmt.getColumnInt(0));
-            break;
-        case MTP_TYPE_INT32:
-            packet.putInt32(stmt.getColumnInt(0));
-            break;
-        case MTP_TYPE_UINT32:
-            packet.putUInt32(stmt.getColumnInt(0));
-            break;
-        case MTP_TYPE_INT64:
-            packet.putInt64(stmt.getColumnInt64(0));
-            break;
-        case MTP_TYPE_UINT64:
-            packet.putUInt64(stmt.getColumnInt64(0));
-            break;
-        case MTP_TYPE_STR:
-            packet.putString(stmt.getColumnString(0));
-            break;
-        default:
-            LOGE("unsupported object type\n");
-            return MTP_RESPONSE_INVALID_OBJECT_HANDLE;
-    }
-    return MTP_RESPONSE_OK;
-}
-
-MtpResponseCode MtpSqliteDatabase::getObjectInfo(MtpObjectHandle handle,
-                                        MtpDataPacket& packet) {
-    char    date[20];
-
-    if (handle != MTP_PARENT_ROOT)
-        handle &= kObjectHandleIndexMask;
-
-    mObjectInfoQuery->reset();
-    mObjectInfoQuery->bind(1, handle);
-    if (!mObjectInfoQuery->step())
-        return MTP_RESPONSE_INVALID_OBJECT_HANDLE;
-
-    MtpStorageID storageID = mObjectInfoQuery->getColumnInt(0);
-    MtpObjectFormat format = mObjectInfoQuery->getColumnInt(1);
-    MtpObjectHandle parent = mObjectInfoQuery->getColumnInt(2);
-    // extract name from path.  do we want a separate database entry for this?
-    const char* name = mObjectInfoQuery->getColumnString(3);
-    const char* lastSlash = strrchr(name, '/');
-    if (lastSlash)
-        name = lastSlash + 1;
-    int64_t size = mObjectInfoQuery->getColumnInt64(4);
-    time_t modified = mObjectInfoQuery->getColumnInt(5);
-    int associationType = (format == MTP_FORMAT_ASSOCIATION ?
-                            MTP_ASSOCIATION_TYPE_GENERIC_FOLDER :
-                            MTP_ASSOCIATION_TYPE_UNDEFINED);
-
-    LOGV("storageID: %d, format: %d, parent: %d", storageID, format, parent);
-
-    packet.putUInt32(storageID);
-    packet.putUInt16(format);
-    packet.putUInt16(0);   // protection status
-    packet.putUInt32((size > 0xFFFFFFFFLL ? 0xFFFFFFFF : size));
-    packet.putUInt16(0);   // thumb format
-    packet.putUInt32(0);   // thumb compressed size
-    packet.putUInt32(0);   // thumb pix width
-    packet.putUInt32(0);   // thumb pix height
-    packet.putUInt32(0);   // image pix width
-    packet.putUInt32(0);   // image pix height
-    packet.putUInt32(0);   // image bit depth
-    packet.putUInt32(parent);
-    packet.putUInt16(associationType);
-    packet.putUInt32(0);   // association desc
-    packet.putUInt32(0);   // sequence number
-    packet.putString(name);   // file name
-    packet.putEmptyString();
-    formatDateTime(modified, date, sizeof(date));
-    packet.putString(date);   // date modified
-    packet.putEmptyString();   // keywords
-
-    return MTP_RESPONSE_OK;
-}
-
-bool MtpSqliteDatabase::getObjectFilePath(MtpObjectHandle handle,
-                                    MtpString& filePath,
-                                    int64_t& fileLength) {
-    if (handle != MTP_PARENT_ROOT)
-        handle &= kObjectHandleIndexMask;
-    mFilePathQuery->reset();
-    mFilePathQuery->bind(1, handle);
-    if (!mFilePathQuery->step())
-        return false;
-
-    const char* path = mFilePathQuery->getColumnString(0);
-    if (!path)
-        return false;
-    filePath = path;
-    fileLength = mFilePathQuery->getColumnInt64(1);
-    return true;
-}
-
-bool MtpSqliteDatabase::deleteFile(MtpObjectHandle handle) {
-    uint32_t table = handle & kObjectHandleTableMask;
-    handle &= kObjectHandleIndexMask;
-    mFileDeleter->bind(1, handle);
-    mFileDeleter->step();
-    mFileDeleter->reset();
-    if (table == kObjectHandleTableAudio) {
-        mAudioDeleter->bind(1, handle);
-        mAudioDeleter->step();
-        mAudioDeleter->reset();
-    }
-
-    return true;
-}
-
-MtpObjectHandle* MtpSqliteDatabase::getFileList(int& outCount) {
-    MtpObjectHandle* result = NULL;
-    int count = 0;
-    SqliteStatement stmt(mDatabase);
-    stmt.prepare("SELECT count(*) FROM files;");
-
-    MtpObjectHandleList* list = new MtpObjectHandleList();
-    if (stmt.step())
-        count = stmt.getColumnInt(0);
-
-    if (count > 0) {
-        result = new MtpObjectHandle[count];
-        memset(result, 0, count * sizeof(*result));
-        SqliteStatement stmt2(mDatabase);
-        stmt2.prepare("SELECT _id,format FROM files;");
-
-        for (int i = 0; i < count; i++) {
-            if (!stmt2.step()) {
-                LOGW("getFileList ended early");
-                count = i;
-                break;
-            }
-            MtpObjectHandle handle = stmt2.getColumnInt(0);
-            MtpObjectFormat format = stmt2.getColumnInt(1);
-            handle |= getTableForFile(format);
-            result[i] = handle;
-        }
-    }
-    outCount = count;
-    return result;
-}
-
-void MtpSqliteDatabase::beginTransaction() {
-    mDatabase->beginTransaction();
-}
-
-void MtpSqliteDatabase::commitTransaction() {
-    mDatabase->commitTransaction();
-}
-
-void MtpSqliteDatabase::rollbackTransaction() {
-    mDatabase->rollbackTransaction();
-}
-
-}  // namespace android
diff --git a/media/mtp/MtpSqliteDatabase.h b/media/mtp/MtpSqliteDatabase.h
deleted file mode 100644
index 74626a8..0000000
--- a/media/mtp/MtpSqliteDatabase.h
+++ /dev/null
@@ -1,96 +0,0 @@
-/*
- * 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.
- */
-
-#ifndef _MTP_SQLITE_DATABASE_H
-#define _MTP_SQLITE_DATABASE_H
-
-#include "MtpTypes.h"
-#include "MtpDatabase.h"
-
-class SqliteDatabase;
-
-namespace android {
-
-class MtpDataPacket;
-class SqliteStatement;
-
-class MtpSqliteDatabase : public MtpDatabase {
-private:
-    SqliteDatabase*             mDatabase;
-    SqliteStatement*            mFileIdQuery;
-    SqliteStatement*            mFilePathQuery;
-    SqliteStatement*            mObjectInfoQuery;
-    SqliteStatement*            mFileInserter;
-    SqliteStatement*            mFileDeleter;
-    SqliteStatement*            mAudioInserter;
-    SqliteStatement*            mAudioDeleter;
-
-public:
-                                MtpSqliteDatabase();
-    virtual                     ~MtpSqliteDatabase();
-
-    bool                        open(const char* path, bool create);
-    void                        close();
-
-    virtual MtpObjectHandle     getObjectHandle(const char* path);
-    virtual MtpObjectHandle     addFile(const char* path,
-                                        MtpObjectFormat format,
-                                        MtpObjectHandle parent,
-                                        MtpStorageID storage,
-                                        uint64_t size,
-                                        time_t modified);
-
-    virtual MtpObjectHandle     addAudioFile(MtpObjectHandle id);
-
-    virtual MtpObjectHandle     addAudioFile(MtpObjectHandle id,
-                                            const char* title,
-                                            const char* artist,
-                                            const char* album,
-                                            const char* albumArtist,
-                                            const char* genre,
-                                            const char* composer,
-                                            const char* mimeType,
-                                            int track,
-                                            int year,
-                                            int duration);
-
-    virtual MtpObjectHandleList* getObjectList(MtpStorageID storageID,
-                                            MtpObjectFormat format,
-                                            MtpObjectHandle parent);
-
-    virtual MtpResponseCode     getObjectProperty(MtpObjectHandle handle,
-                                            MtpObjectProperty property,
-                                            MtpDataPacket& packet);
-
-    virtual MtpResponseCode     getObjectInfo(MtpObjectHandle handle,
-                                            MtpDataPacket& packet);
-
-    virtual bool                getObjectFilePath(MtpObjectHandle handle,
-                                            MtpString& filePath,
-                                            int64_t& fileLength);
-    virtual bool                deleteFile(MtpObjectHandle handle);
-
-    // helper for media scanner
-    virtual MtpObjectHandle*    getFileList(int& outCount);
-
-    virtual void                beginTransaction();
-    virtual void                commitTransaction();
-    virtual void                rollbackTransaction();
-};
-
-}; // namespace android
-
-#endif // _MTP_SQLITE_DATABASE_H
diff --git a/media/mtp/MtpStorage.cpp b/media/mtp/MtpStorage.cpp
index 7e89a90..eccf186 100644
--- a/media/mtp/MtpStorage.cpp
+++ b/media/mtp/MtpStorage.cpp
@@ -19,7 +19,6 @@
 #include "MtpDebug.h"
 #include "MtpDatabase.h"
 #include "MtpStorage.h"
-#include "MtpMediaScanner.h"
 
 #include <sys/types.h>
 #include <sys/stat.h>
@@ -78,9 +77,4 @@
     return "Device Storage";
 }
 
-bool MtpStorage::scanFiles() {
-    MtpMediaScanner scanner(mStorageID, mFilePath, mDatabase);
-    return scanner.scanFiles();
-}
-
 }  // namespace android
diff --git a/media/mtp/MtpStorage.h b/media/mtp/MtpStorage.h
index 6097272..b13b926 100644
--- a/media/mtp/MtpStorage.h
+++ b/media/mtp/MtpStorage.h
@@ -22,7 +22,6 @@
 namespace android {
 
 class MtpDatabase;
-class SqliteStatement;
 
 class MtpStorage {
 
@@ -44,8 +43,6 @@
     uint64_t                getFreeSpace();
     const char*             getDescription() const;
     inline const char*      getPath() const { return mFilePath; }
-
-    bool                    scanFiles();
 };
 
 }; // namespace android
diff --git a/media/mtp/MtpTypes.h b/media/mtp/MtpTypes.h
index b7c79b2..2a895a7 100644
--- a/media/mtp/MtpTypes.h
+++ b/media/mtp/MtpTypes.h
@@ -28,6 +28,7 @@
 
 typedef uint16_t MtpOperationCode;
 typedef uint16_t MtpResponseCode;
+typedef uint16_t MtpEventCode;
 typedef uint32_t MtpSessionID;
 typedef uint32_t MtpStorageID;
 typedef uint32_t MtpTransactionID;
@@ -60,16 +61,6 @@
 #define MTP_PARENT_ROOT         0xFFFFFFFF       // parent is root of the storage
 #define kInvalidObjectHandle    0xFFFFFFFF
 
-// MtpObjectHandle bits and masks
-#define kObjectHandleMarkBit        0x80000000      // used for mark & sweep by MtpMediaScanner
-#define kObjectHandleTableMask      0x70000000      // mask for object table
-#define kObjectHandleTableFile      0x00000000      // object is only in the file table
-#define kObjectHandleTableAudio     0x10000000      // object is in the audio table
-#define kObjectHandleTableVideo     0x20000000      // object is in the video table
-#define kObjectHandleTableImage     0x30000000      // object is in the images table
-#define kObjectHandleTablePlaylist  0x40000000      // object is in the playlist table
-#define kObjectHandleIndexMask      0x0FFFFFFF      // mask for object index in file table
-
 class MtpStorage;
 class MtpDevice;
 class MtpProperty;
diff --git a/media/mtp/SqliteDatabase.cpp b/media/mtp/SqliteDatabase.cpp
deleted file mode 100644
index 1de3a41..0000000
--- a/media/mtp/SqliteDatabase.cpp
+++ /dev/null
@@ -1,88 +0,0 @@
-/*
- * 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.
- */
-
-#define LOG_TAG "SqliteDatabase"
-
-#include "MtpDebug.h"
-#include "SqliteDatabase.h"
-#include "SqliteStatement.h"
-
-#include <stdio.h>
-#include <sqlite3.h>
-
-namespace android {
-
-SqliteDatabase::SqliteDatabase()
-    :   mDatabaseHandle(NULL)
-{
-}
-
-SqliteDatabase::~SqliteDatabase() {
-    close();
-}
-
-bool SqliteDatabase::open(const char* path, bool create) {
-    int flags = SQLITE_OPEN_READWRITE;
-    if (create) flags |= SQLITE_OPEN_CREATE;
-    // SQLITE_OPEN_NOMUTEX?
-    int ret = sqlite3_open_v2(path, &mDatabaseHandle, flags, NULL);
-    if (ret) {
-        LOGE("could not open database\n");
-        return false;
-    }
-    return true;
-}
-
-void SqliteDatabase::close() {
-    if (mDatabaseHandle) {
-        sqlite3_close(mDatabaseHandle);
-        mDatabaseHandle = NULL;
-    }
-}
-
-bool SqliteDatabase::exec(const char* sql) {
-    return (sqlite3_exec(mDatabaseHandle, sql, NULL, NULL, NULL) == 0);
-}
-
-int SqliteDatabase::lastInsertedRow() {
-    return sqlite3_last_insert_rowid(mDatabaseHandle);
-}
-
-void SqliteDatabase::beginTransaction() {
-    exec("BEGIN TRANSACTION");
-}
-
-void SqliteDatabase::commitTransaction() {
-    exec("COMMIT TRANSACTION");
-}
-
-void SqliteDatabase::rollbackTransaction() {
-    exec("ROLLBACK TRANSACTION");
-}
-
-int SqliteDatabase::getVersion() {
-    SqliteStatement stmt(this);
-    stmt.prepare("PRAGMA user_version;");
-    stmt.step();
-    return stmt.getColumnInt(0);
-}
-void SqliteDatabase::setVersion(int version) {
-    char    buffer[40];
-    snprintf(buffer, sizeof(buffer), "PRAGMA user_version = %d", version);
-    exec(buffer);
-}
-
-}  // namespace android
diff --git a/media/mtp/SqliteDatabase.h b/media/mtp/SqliteDatabase.h
deleted file mode 100644
index 7d008f9..0000000
--- a/media/mtp/SqliteDatabase.h
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- * 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.
- */
-
-#ifndef _SQLITE_DATABASE_H
-#define _SQLITE_DATABASE_H
-
-typedef struct sqlite3 sqlite3;
-
-namespace android {
-
-class SqliteDatabase {
-private:
-    sqlite3*        mDatabaseHandle;
-
-public:
-                    SqliteDatabase();
-    virtual         ~SqliteDatabase();
-
-    bool            open(const char* path, bool create);
-    void            close();
-
-    bool            exec(const char* sql);
-    int             lastInsertedRow();
-
-    void            beginTransaction();
-    void            commitTransaction();
-    void            rollbackTransaction();
-
-    int             getVersion();
-    void            setVersion(int version);
-
-    inline sqlite3* getDatabaseHandle() const { return mDatabaseHandle; }
-};
-
-}; // namespace android
-
-#endif // _SQLITE_DATABASE_H
diff --git a/media/mtp/SqliteStatement.cpp b/media/mtp/SqliteStatement.cpp
deleted file mode 100644
index adef7ae..0000000
--- a/media/mtp/SqliteStatement.cpp
+++ /dev/null
@@ -1,83 +0,0 @@
-/*
- * 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.
- */
-
-#define LOG_TAG "SqliteStatement"
-
-#include "SqliteStatement.h"
-#include "SqliteDatabase.h"
-
-#include <stdio.h>
-#include <sqlite3.h>
-
-namespace android {
-
-SqliteStatement::SqliteStatement(SqliteDatabase* db)
-    :   mDatabaseHandle(db->getDatabaseHandle()),
-        mStatement(NULL),
-        mDone(false)
-{
-}
-
-SqliteStatement::~SqliteStatement() {
-    finalize();
-}
-
-bool SqliteStatement::prepare(const char* sql) {
-    return (sqlite3_prepare_v2(mDatabaseHandle, sql, -1, &mStatement, NULL) == 0);
-}
-
-bool SqliteStatement::step() {
-    int ret = sqlite3_step(mStatement);
-    if (ret == SQLITE_DONE) {
-        mDone = true;
-        return true;
-    }
-    return (ret == SQLITE_OK || ret == SQLITE_ROW);
-}
-
-void SqliteStatement::reset() {
-    sqlite3_reset(mStatement);
-    mDone = false;
-}
-
-void SqliteStatement::finalize() {
-    if (mStatement) {
-        sqlite3_finalize(mStatement);
-        mStatement = NULL;
-    }
-}
-
-void SqliteStatement::bind(int column, int value) {
-    sqlite3_bind_int(mStatement, column, value);
-}
-
-void SqliteStatement::bind(int column, const char* value) {
-    sqlite3_bind_text(mStatement, column, value, -1, SQLITE_TRANSIENT);
-}
-
-int SqliteStatement::getColumnInt(int column) {
-    return sqlite3_column_int(mStatement, column);
-}
-
-int64_t SqliteStatement::getColumnInt64(int column) {
-    return sqlite3_column_int64(mStatement, column);
-}
-
-const char* SqliteStatement::getColumnString(int column) {
-    return (const char *)sqlite3_column_text(mStatement, column);
-}
-
-}  // namespace android
diff --git a/media/mtp/SqliteStatement.h b/media/mtp/SqliteStatement.h
deleted file mode 100644
index c0ebfff..0000000
--- a/media/mtp/SqliteStatement.h
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
- * 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.
- */
-
-#ifndef _SQLITE_STATEMENT_H
-#define _SQLITE_STATEMENT_H
-
-#include <stdint.h>
-
-typedef struct sqlite3 sqlite3;
-typedef struct sqlite3_stmt sqlite3_stmt;
-
-namespace android {
-
-class SqliteDatabase;
-
-class SqliteStatement {
-private:
-    sqlite3*        mDatabaseHandle;
-    sqlite3_stmt*   mStatement;
-    bool            mDone;
-
-public:
-                    SqliteStatement(SqliteDatabase* db);
-    virtual         ~SqliteStatement();
-
-    bool            prepare(const char* sql);
-    bool            step();
-    void            reset();
-    void            finalize();
-
-    void            bind(int column, int value);
-    void            bind(int column, const char* value);
-
-    int             getColumnInt(int column);
-    int64_t         getColumnInt64(int column);
-    const char*     getColumnString(int column);
-
-    inline bool     isDone() const { return mDone; }
-};
-
-}; // namespace android
-
-#endif // _SQLITE_STATEMENT_H
diff --git a/media/mtp/f_mtp.h b/media/mtp/f_mtp.h
deleted file mode 100644
index c1c9aef..0000000
--- a/media/mtp/f_mtp.h
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * Gadget Function Driver for MTP
- *
- * Copyright (C) 2010 Google, Inc.
- * Author: Mike Lockwood <lockwood@android.com>
- *
- * This software is licensed under the terms of the GNU General Public
- * License version 2, as published by the Free Software Foundation, and
- * may be copied, distributed, and modified under those terms.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- */
-
-#ifndef __LINUX_USB_F_MTP_H
-#define __LINUX_USB_F_MTP_H
-
-/* Constants for MTP_SET_INTERFACE_MODE */
-#define MTP_INTERFACE_MODE_MTP  0
-#define MTP_INTERFACE_MODE_PTP  1
-
-
-struct mtp_file_range {
-	/* file descriptor for file to transfer */
-	int			fd;
-	/* offset in file for start of transfer */
-	loff_t  	offset;
-	/* number of bytes to transfer */
-	size_t		length;
-};
-
-/* Sends the specified file range to the host */
-#define MTP_SEND_FILE              _IOW('M', 0, struct mtp_file_range)
-/* Receives data from the host and writes it to a file.
- * The file is created if it does not exist.
- */
-#define MTP_RECEIVE_FILE           _IOW('M', 1, struct mtp_file_range)
-/* Sets the driver mode to either MTP or PTP */
-#define MTP_SET_INTERFACE_MODE     _IOW('M', 2, int)
-
-#endif /* __LINUX_USB_F_MTP_H */
diff --git a/media/mtp/mtptest.cpp b/media/mtp/mtptest.cpp
deleted file mode 100644
index af0f77f..0000000
--- a/media/mtp/mtptest.cpp
+++ /dev/null
@@ -1,88 +0,0 @@
-/*
- * 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.
- */
-
-#define LOG_TAG "mtp_usb"
-
-#include "MtpDebug.h"
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <sys/types.h>
-#include <fcntl.h>
-#include <sys/ioctl.h>
-
-#include "MtpServer.h"
-#include "MtpStorage.h"
-#include "f_mtp.h"
-#include "private/android_filesystem_config.h"
-
-using namespace android;
-
-static bool enable_usb_function(const char* name, bool enable) {
-    char    path[PATH_MAX];
-
-    snprintf(path, sizeof(path), "/sys/class/usb_composite/%s/enable", name);
-    int fd = open(path, O_RDWR);
-    if (fd < 0) {
-        fprintf(stderr, "could not open %s in enable_usb_function\n", path);
-        return false;
-    }
-    write(fd, enable ? "1" : "0", 2);
-    close(fd);
-    return true;
-}
-
-int main(int argc, char* argv[]) {
-    bool usePTP = false;
-    const char* storagePath = "/sdcard";
-
-    for (int i = 1; i < argc; i++) {
-        const char* arg = argv[i];
-        if (!strcmp(arg, "-p"))
-            usePTP = true;
-        else if (arg[0] == '/')
-            storagePath = arg;
-    }
-
-    int fd = open("/dev/mtp_usb", O_RDWR);
-    printf("open returned %d\n", fd);
-    if (fd < 0) {
-        fprintf(stderr, "could not open MTP driver\n");
-        return -1;
-    }
-
-    if (usePTP) {
-        // set driver mode to PTP
-        int ret = ioctl(fd, MTP_SET_INTERFACE_MODE, MTP_INTERFACE_MODE_PTP);
-        if (ret) {
-            fprintf(stderr, "MTP_SET_INTERFACE_MODE failed\n");
-            return -1;
-        }
-    }
-
-    // disable UMS and enable MTP USB functions
-    enable_usb_function("usb_mass_storage", false);
-    enable_usb_function("mtp", true);
-
-    MtpServer   server(fd, "/data/data/mtp/mtp.db", AID_SDCARD_RW, 0664, 0775);
-    server.addStorage(storagePath);
-    server.scanStorage();
-    server.run();
-
-    close(fd);
-    return 0;
-}
-
diff --git a/media/mtp/scantest.cpp b/media/mtp/scantest.cpp
deleted file mode 100644
index 3702a5d..0000000
--- a/media/mtp/scantest.cpp
+++ /dev/null
@@ -1,38 +0,0 @@
-/*
- * 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.
- */
-
-#include <stdio.h>
-
-#include "MtpSqliteDatabase.h"
-#include "MtpMediaScanner.h"
-
-using namespace android;
-
-int main(int argc, char* argv[]) {
-    if (argc != 2) {
-        fprintf(stderr, "usage: %s <storage path>\n", argv[0]);
-        return -1;
-    }
-
-    MtpSqliteDatabase* database = new MtpSqliteDatabase();
-    database->open("scantest.db", true);
-
-    MtpMediaScanner scanner(1, argv[1], database);
-    scanner.scanFiles();
-    database->close();
-
-    return 0;
-}
diff --git a/native/android/Android.mk b/native/android/Android.mk
index 376c64f..2fe0679 100644
--- a/native/android/Android.mk
+++ b/native/android/Android.mk
@@ -6,17 +6,20 @@
 # our source files
 #
 LOCAL_SRC_FILES:= \
-    activity.cpp \
     input.cpp \
     looper.cpp \
-    native_window.cpp
+    native_activity.cpp \
+    native_window.cpp \
+    sensor.cpp
 
 LOCAL_SHARED_LIBRARIES := \
-    libandroid_runtime \
     libcutils \
     libutils \
     libbinder \
-    libui
+    libui \
+    libgui \
+    libsurfaceflinger_client \
+    libandroid_runtime
 
 LOCAL_C_INCLUDES += \
     frameworks/base/native/include \
diff --git a/native/android/activity.cpp b/native/android/activity.cpp
deleted file mode 100644
index e69de29..0000000
--- a/native/android/activity.cpp
+++ /dev/null
diff --git a/native/android/input.cpp b/native/android/input.cpp
index 015a1ce..a4dde51 100644
--- a/native/android/input.cpp
+++ b/native/android/input.cpp
@@ -22,6 +22,8 @@
 #include <ui/InputTransport.h>
 #include <utils/PollLoop.h>
 
+#include <android_runtime/android_app_NativeActivity.h>
+
 #include <poll.h>
 
 using android::InputEvent;
@@ -186,66 +188,22 @@
 }
 
 void AInputQueue_attachLooper(AInputQueue* queue, ALooper* looper,
-        ALooper_callbackFunc callback, void* data) {
-    queue->setPollLoop(static_cast<android::PollLoop*>(looper));
-    ALooper_setCallback(looper, queue->getConsumer().getChannel()->getReceivePipeFd(),
-            POLLIN, callback, data);
+        ALooper_callbackFunc* callback, void* data) {
+    queue->attachLooper(looper, callback, data);
 }
 
 void AInputQueue_detachLooper(AInputQueue* queue) {
-    queue->getPollLoop()->removeCallback(
-            queue->getConsumer().getChannel()->getReceivePipeFd());
+    queue->detachLooper();
 }
 
 int AInputQueue_hasEvents(AInputQueue* queue) {
-    struct pollfd pfd;
-    
-    pfd.fd = queue->getConsumer().getChannel()->getReceivePipeFd();
-    pfd.events = POLLIN;
-    pfd.revents = 0;
-    
-    int nfd = poll(&pfd, 1, 0);
-    if (nfd <= 0) return nfd;
-    return pfd.revents == POLLIN ? 1 : -1;
+    return queue->hasEvents();
 }
 
 int32_t AInputQueue_getEvent(AInputQueue* queue, AInputEvent** outEvent) {
-    *outEvent = NULL;
-    
-    int32_t res = queue->getConsumer().receiveDispatchSignal();
-    if (res != android::OK) {
-        LOGE("channel '%s' ~ Failed to receive dispatch signal.  status=%d",
-                queue->getConsumer().getChannel()->getName().string(), res);
-        return -1;
-    }
-    
-    InputEvent* myEvent = NULL;
-    res = queue->consume(&myEvent);
-    if (res != android::OK) {
-        LOGW("channel '%s' ~ Failed to consume input event.  status=%d",
-                queue->getConsumer().getChannel()->getName().string(), res);
-        queue->getConsumer().sendFinishedSignal();
-        return -1;
-    }
-    
-    *outEvent = myEvent;
-    return 0;
+    return queue->getEvent(outEvent);
 }
 
-void AInputQueue_finishEvent(AInputQueue* queue, AInputEvent* event,
-        int handled) {
-    if (!handled && ((InputEvent*)event)->getType() == INPUT_EVENT_TYPE_KEY
-            && ((KeyEvent*)event)->hasDefaultAction()) {
-        // The app didn't handle this, but it may have a default action
-        // associated with it.  We need to hand this back to Java to be
-        // executed.
-        queue->doDefaultKey((KeyEvent*)event);
-        return;
-    }
-    
-    int32_t res = queue->getConsumer().sendFinishedSignal();
-    if (res != android::OK) {
-        LOGW("Failed to send finished signal on channel '%s'.  status=%d",
-                queue->getConsumer().getChannel()->getName().string(), res);
-    }
+void AInputQueue_finishEvent(AInputQueue* queue, AInputEvent* event, int handled) {
+    queue->finishEvent(event, handled != 0);
 }
diff --git a/native/android/looper.cpp b/native/android/looper.cpp
index 6e78bbd..1564c47 100644
--- a/native/android/looper.cpp
+++ b/native/android/looper.cpp
@@ -27,22 +27,41 @@
     return PollLoop::getForThread().get();
 }
 
-ALooper* ALooper_prepare() {
+ALooper* ALooper_prepare(int32_t opts) {
+    bool allowFds = (opts&ALOOPER_PREPARE_ALLOW_NON_CALLBACKS) != 0;
     sp<PollLoop> loop = PollLoop::getForThread();
     if (loop == NULL) {
-        loop = new PollLoop();
+        loop = new PollLoop(allowFds);
         PollLoop::setForThread(loop);
     }
+    if (loop->getAllowNonCallbacks() != allowFds) {
+        LOGW("ALooper_prepare again with different ALOOPER_PREPARE_ALLOW_NON_CALLBACKS");
+    }
     return loop.get();
 }
 
-int32_t ALooper_pollOnce(int timeoutMillis) {
+int32_t ALooper_pollOnce(int timeoutMillis, int* outEvents, void** outData) {
     sp<PollLoop> loop = PollLoop::getForThread();
     if (loop == NULL) {
         LOGW("ALooper_pollOnce: No looper for this thread!");
         return -1;
     }
-    return loop->pollOnce(timeoutMillis) ? 1 : 0;
+    return loop->pollOnce(timeoutMillis, outEvents, outData);
+}
+
+int32_t ALooper_pollAll(int timeoutMillis, int* outEvents, void** outData) {
+    sp<PollLoop> loop = PollLoop::getForThread();
+    if (loop == NULL) {
+        LOGW("ALooper_pollOnce: No looper for this thread!");
+        return -1;
+    }
+    
+    int32_t result;
+    while ((result = loop->pollOnce(timeoutMillis, outEvents, outData)) == ALOOPER_POLL_CALLBACK) {
+        ;
+    }
+    
+    return result;
 }
 
 void ALooper_acquire(ALooper* looper) {
@@ -53,11 +72,11 @@
     static_cast<PollLoop*>(looper)->decStrong((void*)ALooper_acquire);
 }
 
-void ALooper_setCallback(ALooper* looper, int fd, int events,
+void ALooper_addFd(ALooper* looper, int fd, int events,
         ALooper_callbackFunc* callback, void* data) {
     static_cast<PollLoop*>(looper)->setLooperCallback(fd, events, callback, data);
 }
 
-int32_t ALooper_removeCallback(ALooper* looper, int fd) {
+int32_t ALooper_removeFd(ALooper* looper, int fd) {
     return static_cast<PollLoop*>(looper)->removeCallback(fd) ? 1 : 0;
 }
diff --git a/native/android/native_activity.cpp b/native/android/native_activity.cpp
new file mode 100644
index 0000000..0c6823a
--- /dev/null
+++ b/native/android/native_activity.cpp
@@ -0,0 +1,39 @@
+/*
+ * 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.
+ */
+
+#define LOG_TAG "native_activity"
+#include <utils/Log.h>
+
+#include <android_runtime/android_app_NativeActivity.h>
+
+using namespace android;
+
+void ANativeActivity_setWindowFormat(ANativeActivity* activity, int32_t format) {
+	android_NativeActivity_setWindowFormat(activity, format);
+}
+
+void ANativeActivity_setWindowFlags(ANativeActivity* activity,
+		uint32_t addFlags, uint32_t removeFlags) {
+	android_NativeActivity_setWindowFlags(activity, addFlags, addFlags|removeFlags);
+}
+
+void ANativeActivity_showSoftInput(ANativeActivity* activity, uint32_t flags) {
+	android_NativeActivity_showSoftInput(activity, flags);
+}
+
+void ANativeActivity_hideSoftInput(ANativeActivity* activity, uint32_t flags) {
+	android_NativeActivity_hideSoftInput(activity, flags);
+}
diff --git a/native/android/native_window.cpp b/native/android/native_window.cpp
index 448cbfc..bada078 100644
--- a/native/android/native_window.cpp
+++ b/native/android/native_window.cpp
@@ -17,10 +17,27 @@
 #define LOG_TAG "Surface"
 #include <utils/Log.h>
 
-#include <android/native_window.h>
+#include <android/native_window_jni.h>
 #include <surfaceflinger/Surface.h>
+#include <android_runtime/android_view_Surface.h>
 
-using android::Surface;
+using namespace android;
+
+ANativeWindow* ANativeWindow_fromSurface(JNIEnv* env, jobject surface) {
+    sp<ANativeWindow> win = android_Surface_getNativeWindow(env, surface);
+    if (win != NULL) {
+        win->incStrong((void*)ANativeWindow_acquire);
+    }
+    return win.get();
+}
+
+void ANativeWindow_acquire(ANativeWindow* window) {
+    window->incStrong((void*)ANativeWindow_acquire);
+}
+
+void ANativeWindow_release(ANativeWindow* window) {
+    window->decStrong((void*)ANativeWindow_acquire);
+}
 
 static int32_t getWindowProp(ANativeWindow* window, int what) {
     int value;
@@ -41,7 +58,40 @@
 }
 
 int32_t ANativeWindow_setBuffersGeometry(ANativeWindow* window, int32_t width,
-        int32_t height, int32_t format) {
-    native_window_set_buffers_geometry(window, width, height, format);
+        int32_t height) {
+    native_window_set_buffers_geometry(window, width, height, 0);
     return 0;
 }
+
+int32_t ANativeWindow_lock(ANativeWindow* window, ANativeWindow_Buffer* outBuffer,
+        ARect* inOutDirtyBounds) {
+    Region dirtyRegion;
+    Region* dirtyParam = NULL;
+    if (inOutDirtyBounds != NULL) {
+        dirtyRegion.set(*(Rect*)inOutDirtyBounds);
+        dirtyParam = &dirtyRegion;
+    }
+    
+    Surface::SurfaceInfo info;
+    status_t res = static_cast<Surface*>(window)->lock(&info, dirtyParam);
+    if (res != OK) {
+        return -1;
+    }
+    
+    outBuffer->width = (int32_t)info.w;
+    outBuffer->height = (int32_t)info.h;
+    outBuffer->stride = (int32_t)info.s;
+    outBuffer->format = (int32_t)info.format;
+    outBuffer->bits = info.bits;
+    
+    if (inOutDirtyBounds != NULL) {
+        *inOutDirtyBounds = dirtyRegion.getBounds();
+    }
+    
+    return 0;
+}
+
+int32_t ANativeWindow_unlockAndPost(ANativeWindow* window) {
+    status_t res = static_cast<Surface*>(window)->unlockAndPost();
+    return res == android::OK ? 0 : -1;
+}
diff --git a/native/android/sensor.cpp b/native/android/sensor.cpp
new file mode 100644
index 0000000..7a3907e
--- /dev/null
+++ b/native/android/sensor.cpp
@@ -0,0 +1,150 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "sensor"
+#include <utils/Log.h>
+
+#include <android/looper.h>
+#include <android/sensor.h>
+
+#include <utils/RefBase.h>
+#include <utils/PollLoop.h>
+#include <utils/Timers.h>
+
+#include <gui/Sensor.h>
+#include <gui/SensorManager.h>
+#include <gui/SensorEventQueue.h>
+
+#include <poll.h>
+
+using android::sp;
+using android::Sensor;
+using android::SensorManager;
+using android::SensorEventQueue;
+using android::String8;
+
+/*****************************************************************************/
+
+ASensorManager* ASensorManager_getInstance()
+{
+    return &SensorManager::getInstance();
+}
+
+int ASensorManager_getSensorList(ASensorManager* manager, ASensor** list)
+{
+    Sensor* l;
+    int c = static_cast<SensorManager*>(manager)->getSensorList(&l);
+    if (list) {
+        *list = l;
+    }
+    return c;
+}
+
+ASensor* ASensorManager_getDefaultSensor(ASensorManager* manager, int type)
+{
+    return static_cast<SensorManager*>(manager)->getDefaultSensor(type);
+}
+
+ASensorEventQueue* ASensorManager_createEventQueue(ASensorManager* manager,
+        ALooper* looper, ALooper_callbackFunc* callback, void* data)
+{
+    sp<SensorEventQueue> queue =
+            static_cast<SensorManager*>(manager)->createEventQueue();
+    if (queue != 0) {
+        ALooper_addFd(looper, queue->getFd(), POLLIN, callback, data);
+        queue->looper = looper;
+        queue->incStrong(manager);
+    }
+    return static_cast<ASensorEventQueue*>(queue.get());
+}
+
+int ASensorManager_destroyEventQueue(ASensorManager* manager,
+        ASensorEventQueue* inQueue)
+{
+    sp<SensorEventQueue> queue = static_cast<SensorEventQueue*>(inQueue);
+    ALooper_removeFd(queue->looper, queue->getFd());
+    queue->decStrong(manager);
+    return 0;
+}
+
+/*****************************************************************************/
+
+int ASensorEventQueue_enableSensor(ASensorEventQueue* queue, ASensor* sensor)
+{
+    return static_cast<SensorEventQueue*>(queue)->enableSensor(
+            static_cast<Sensor*>(sensor));
+}
+
+int ASensorEventQueue_disableSensor(ASensorEventQueue* queue, ASensor* sensor)
+{
+    return static_cast<SensorEventQueue*>(queue)->disableSensor(
+            static_cast<Sensor*>(sensor));
+}
+
+int ASensorEventQueue_setEventRate(ASensorEventQueue* queue, ASensor* sensor,
+        int32_t usec)
+{
+    return static_cast<SensorEventQueue*>(queue)->setEventRate(
+            static_cast<Sensor*>(sensor), us2ns(usec));
+}
+
+int ASensorEventQueue_hasEvents(ASensorEventQueue* queue)
+{
+    struct pollfd pfd;
+    pfd.fd = static_cast<SensorEventQueue*>(queue)->getFd();
+    pfd.events = POLLIN;
+    pfd.revents = 0;
+
+    int nfd = poll(&pfd, 1, 0);
+
+    if (nfd < 0)
+        return -errno;
+
+    if (pfd.revents != POLLIN)
+        return -1;
+
+    return (nfd == 0) ? 0 : 1;
+}
+
+ssize_t ASensorEventQueue_getEvents(ASensorEventQueue* queue,
+                ASensorEvent* events, size_t count)
+{
+    return static_cast<SensorEventQueue*>(queue)->read(events, count);
+}
+
+
+/*****************************************************************************/
+
+const char* ASensor_getName(ASensor* sensor)
+{
+    return static_cast<Sensor*>(sensor)->getName().string();
+}
+
+const char* ASensor_getVendor(ASensor* sensor)
+{
+    return static_cast<Sensor*>(sensor)->getVendor().string();
+}
+
+int ASensor_getType(ASensor* sensor)
+{
+    return static_cast<Sensor*>(sensor)->getType();
+}
+
+float ASensor_getResolution(ASensor* sensor)
+{
+    return static_cast<Sensor*>(sensor)->getResolution();
+}
+
diff --git a/native/include/android/input.h b/native/include/android/input.h
index 75be85a..25dd68e 100644
--- a/native/include/android/input.h
+++ b/native/include/android/input.h
@@ -68,7 +68,10 @@
     INPUT_DEVICE_CLASS_TOUCHSCREEN_MT= 0x00000010,
 
     /* The input device is a directional pad. */
-    INPUT_DEVICE_CLASS_DPAD          = 0x00000020
+    INPUT_DEVICE_CLASS_DPAD          = 0x00000020,
+
+    /* The input device is a gamepad (implies keyboard). */
+    INPUT_DEVICE_CLASS_GAMEPAD       = 0x00000040
 };
 
 /*
@@ -534,10 +537,11 @@
 typedef struct AInputQueue AInputQueue;
 
 /*
- * Add this input queue to a looper for processing.
+ * Add this input queue to a looper for processing.  See
+ * ALooper_addFd() for information on the callback and data params.
  */
 void AInputQueue_attachLooper(AInputQueue* queue, ALooper* looper,
-        ALooper_callbackFunc callback, void* data);
+        ALooper_callbackFunc* callback, void* data);
 
 /*
  * Remove the input queue from the looper it is currently attached to.
diff --git a/native/include/android/keycodes.h b/native/include/android/keycodes.h
index 36855c5..496eccc0 100644
--- a/native/include/android/keycodes.h
+++ b/native/include/android/keycodes.h
@@ -41,114 +41,122 @@
 
 /*
  * Key codes.
- *
- * XXX: The declarations in <ui/KeycodeLabel.h> should be updated to use these instead.
- *      We should probably move this into android/keycodes.h and add some new API for
- *      getting labels so that we can remove the other tables also in KeycodeLabel.h.
  */
 enum {
-    KEYCODE_UNKNOWN         = 0,
-    KEYCODE_SOFT_LEFT       = 1,
-    KEYCODE_SOFT_RIGHT      = 2,
-    KEYCODE_HOME            = 3,
-    KEYCODE_BACK            = 4,
-    KEYCODE_CALL            = 5,
-    KEYCODE_ENDCALL         = 6,
-    KEYCODE_0               = 7,
-    KEYCODE_1               = 8,
-    KEYCODE_2               = 9,
-    KEYCODE_3               = 10,
-    KEYCODE_4               = 11,
-    KEYCODE_5               = 12,
-    KEYCODE_6               = 13,
-    KEYCODE_7               = 14,
-    KEYCODE_8               = 15,
-    KEYCODE_9               = 16,
-    KEYCODE_STAR            = 17,
-    KEYCODE_POUND           = 18,
-    KEYCODE_DPAD_UP         = 19,
-    KEYCODE_DPAD_DOWN       = 20,
-    KEYCODE_DPAD_LEFT       = 21,
-    KEYCODE_DPAD_RIGHT      = 22,
-    KEYCODE_DPAD_CENTER     = 23,
-    KEYCODE_VOLUME_UP       = 24,
-    KEYCODE_VOLUME_DOWN     = 25,
-    KEYCODE_POWER           = 26,
-    KEYCODE_CAMERA          = 27,
-    KEYCODE_CLEAR           = 28,
-    KEYCODE_A               = 29,
-    KEYCODE_B               = 30,
-    KEYCODE_C               = 31,
-    KEYCODE_D               = 32,
-    KEYCODE_E               = 33,
-    KEYCODE_F               = 34,
-    KEYCODE_G               = 35,
-    KEYCODE_H               = 36,
-    KEYCODE_I               = 37,
-    KEYCODE_J               = 38,
-    KEYCODE_K               = 39,
-    KEYCODE_L               = 40,
-    KEYCODE_M               = 41,
-    KEYCODE_N               = 42,
-    KEYCODE_O               = 43,
-    KEYCODE_P               = 44,
-    KEYCODE_Q               = 45,
-    KEYCODE_R               = 46,
-    KEYCODE_S               = 47,
-    KEYCODE_T               = 48,
-    KEYCODE_U               = 49,
-    KEYCODE_V               = 50,
-    KEYCODE_W               = 51,
-    KEYCODE_X               = 52,
-    KEYCODE_Y               = 53,
-    KEYCODE_Z               = 54,
-    KEYCODE_COMMA           = 55,
-    KEYCODE_PERIOD          = 56,
-    KEYCODE_ALT_LEFT        = 57,
-    KEYCODE_ALT_RIGHT       = 58,
-    KEYCODE_SHIFT_LEFT      = 59,
-    KEYCODE_SHIFT_RIGHT     = 60,
-    KEYCODE_TAB             = 61,
-    KEYCODE_SPACE           = 62,
-    KEYCODE_SYM             = 63,
-    KEYCODE_EXPLORER        = 64,
-    KEYCODE_ENVELOPE        = 65,
-    KEYCODE_ENTER           = 66,
-    KEYCODE_DEL             = 67,
-    KEYCODE_GRAVE           = 68,
-    KEYCODE_MINUS           = 69,
-    KEYCODE_EQUALS          = 70,
-    KEYCODE_LEFT_BRACKET    = 71,
-    KEYCODE_RIGHT_BRACKET   = 72,
-    KEYCODE_BACKSLASH       = 73,
-    KEYCODE_SEMICOLON       = 74,
-    KEYCODE_APOSTROPHE      = 75,
-    KEYCODE_SLASH           = 76,
-    KEYCODE_AT              = 77,
-    KEYCODE_NUM             = 78,
-    KEYCODE_HEADSETHOOK     = 79,
-    KEYCODE_FOCUS           = 80,   // *Camera* focus
-    KEYCODE_PLUS            = 81,
-    KEYCODE_MENU            = 82,
-    KEYCODE_NOTIFICATION    = 83,
-    KEYCODE_SEARCH          = 84,
-    KEYCODE_MEDIA_PLAY_PAUSE= 85,
-    KEYCODE_MEDIA_STOP      = 86,
-    KEYCODE_MEDIA_NEXT      = 87,
-    KEYCODE_MEDIA_PREVIOUS  = 88,
-    KEYCODE_MEDIA_REWIND    = 89,
-    KEYCODE_MEDIA_FAST_FORWARD = 90,
-    KEYCODE_MUTE            = 91,
-    KEYCODE_PAGE_UP         = 92,
-    KEYCODE_PAGE_DOWN       = 93
+    AKEYCODE_UNKNOWN         = 0,
+    AKEYCODE_SOFT_LEFT       = 1,
+    AKEYCODE_SOFT_RIGHT      = 2,
+    AKEYCODE_HOME            = 3,
+    AKEYCODE_BACK            = 4,
+    AKEYCODE_CALL            = 5,
+    AKEYCODE_ENDCALL         = 6,
+    AKEYCODE_0               = 7,
+    AKEYCODE_1               = 8,
+    AKEYCODE_2               = 9,
+    AKEYCODE_3               = 10,
+    AKEYCODE_4               = 11,
+    AKEYCODE_5               = 12,
+    AKEYCODE_6               = 13,
+    AKEYCODE_7               = 14,
+    AKEYCODE_8               = 15,
+    AKEYCODE_9               = 16,
+    AKEYCODE_STAR            = 17,
+    AKEYCODE_POUND           = 18,
+    AKEYCODE_DPAD_UP         = 19,
+    AKEYCODE_DPAD_DOWN       = 20,
+    AKEYCODE_DPAD_LEFT       = 21,
+    AKEYCODE_DPAD_RIGHT      = 22,
+    AKEYCODE_DPAD_CENTER     = 23,
+    AKEYCODE_VOLUME_UP       = 24,
+    AKEYCODE_VOLUME_DOWN     = 25,
+    AKEYCODE_POWER           = 26,
+    AKEYCODE_CAMERA          = 27,
+    AKEYCODE_CLEAR           = 28,
+    AKEYCODE_A               = 29,
+    AKEYCODE_B               = 30,
+    AKEYCODE_C               = 31,
+    AKEYCODE_D               = 32,
+    AKEYCODE_E               = 33,
+    AKEYCODE_F               = 34,
+    AKEYCODE_G               = 35,
+    AKEYCODE_H               = 36,
+    AKEYCODE_I               = 37,
+    AKEYCODE_J               = 38,
+    AKEYCODE_K               = 39,
+    AKEYCODE_L               = 40,
+    AKEYCODE_M               = 41,
+    AKEYCODE_N               = 42,
+    AKEYCODE_O               = 43,
+    AKEYCODE_P               = 44,
+    AKEYCODE_Q               = 45,
+    AKEYCODE_R               = 46,
+    AKEYCODE_S               = 47,
+    AKEYCODE_T               = 48,
+    AKEYCODE_U               = 49,
+    AKEYCODE_V               = 50,
+    AKEYCODE_W               = 51,
+    AKEYCODE_X               = 52,
+    AKEYCODE_Y               = 53,
+    AKEYCODE_Z               = 54,
+    AKEYCODE_COMMA           = 55,
+    AKEYCODE_PERIOD          = 56,
+    AKEYCODE_ALT_LEFT        = 57,
+    AKEYCODE_ALT_RIGHT       = 58,
+    AKEYCODE_SHIFT_LEFT      = 59,
+    AKEYCODE_SHIFT_RIGHT     = 60,
+    AKEYCODE_TAB             = 61,
+    AKEYCODE_SPACE           = 62,
+    AKEYCODE_SYM             = 63,
+    AKEYCODE_EXPLORER        = 64,
+    AKEYCODE_ENVELOPE        = 65,
+    AKEYCODE_ENTER           = 66,
+    AKEYCODE_DEL             = 67,
+    AKEYCODE_GRAVE           = 68,
+    AKEYCODE_MINUS           = 69,
+    AKEYCODE_EQUALS          = 70,
+    AKEYCODE_LEFT_BRACKET    = 71,
+    AKEYCODE_RIGHT_BRACKET   = 72,
+    AKEYCODE_BACKSLASH       = 73,
+    AKEYCODE_SEMICOLON       = 74,
+    AKEYCODE_APOSTROPHE      = 75,
+    AKEYCODE_SLASH           = 76,
+    AKEYCODE_AT              = 77,
+    AKEYCODE_NUM             = 78,
+    AKEYCODE_HEADSETHOOK     = 79,
+    AKEYCODE_FOCUS           = 80,   // *Camera* focus
+    AKEYCODE_PLUS            = 81,
+    AKEYCODE_MENU            = 82,
+    AKEYCODE_NOTIFICATION    = 83,
+    AKEYCODE_SEARCH          = 84,
+    AKEYCODE_MEDIA_PLAY_PAUSE= 85,
+    AKEYCODE_MEDIA_STOP      = 86,
+    AKEYCODE_MEDIA_NEXT      = 87,
+    AKEYCODE_MEDIA_PREVIOUS  = 88,
+    AKEYCODE_MEDIA_REWIND    = 89,
+    AKEYCODE_MEDIA_FAST_FORWARD = 90,
+    AKEYCODE_MUTE            = 91,
+    AKEYCODE_PAGE_UP         = 92,
+    AKEYCODE_PAGE_DOWN       = 93,
+    AKEYCODE_PICTSYMBOLS     = 94,
+    AKEYCODE_SWITCH_CHARSET  = 95,
+    AKEYCODE_BUTTON_A        = 96,
+    AKEYCODE_BUTTON_B        = 97,
+    AKEYCODE_BUTTON_C        = 98,
+    AKEYCODE_BUTTON_X        = 99,
+    AKEYCODE_BUTTON_Y        = 100,
+    AKEYCODE_BUTTON_Z        = 101,
+    AKEYCODE_BUTTON_L1       = 102,
+    AKEYCODE_BUTTON_R1       = 103,
+    AKEYCODE_BUTTON_L2       = 104,
+    AKEYCODE_BUTTON_R2       = 105,
+    AKEYCODE_BUTTON_THUMBL   = 106,
+    AKEYCODE_BUTTON_THUMBR   = 107,
+    AKEYCODE_BUTTON_START    = 108,
+    AKEYCODE_BUTTON_SELECT   = 109,
+    AKEYCODE_BUTTON_MODE     = 110,
 
-    /* NOTE: If you add a new keycode here you must also add it to:
-     *  native/include/android/keycodes.h
-     *  frameworks/base/include/ui/KeycodeLabels.h
-     *   frameworks/base/core/java/android/view/KeyEvent.java
-     *   tools/puppet_master/PuppetMaster.nav_keys.py
-     *   frameworks/base/core/res/res/values/attrs.xml
-     */
+    // NOTE: If you add a new keycode here you must also add it to several other files.
+    //       Refer to frameworks/base/core/java/android/view/KeyEvent.java for the full list.
 };
 
 #ifdef __cplusplus
diff --git a/native/include/android/looper.h b/native/include/android/looper.h
index 90a8983..2917216 100644
--- a/native/include/android/looper.h
+++ b/native/include/android/looper.h
@@ -24,25 +24,151 @@
 extern "C" {
 #endif
 
+/**
+ * ALooper
+ *
+ * A looper is the state tracking an event loop for a thread.
+ * Loopers do not define event structures or other such things; rather
+ * they are a lower-level facility to attach one or more discrete objects
+ * listening for an event.  An "event" here is simply data available on
+ * a file descriptor: each attached object has an associated file descriptor,
+ * and waiting for "events" means (internally) polling on all of these file
+ * descriptors until one or more of them have data available.
+ *
+ * A thread can have only one ALooper associated with it.
+ */
 struct ALooper;
 typedef struct ALooper ALooper;
 
+/**
+ * For callback-based event loops, this is the prototype of the function
+ * that is called.  It is given the file descriptor it is associated with,
+ * a bitmask of the poll events that were triggered (typically POLLIN), and
+ * the data pointer that was originally supplied.
+ *
+ * Implementations should return 1 to continue receiving callbacks, or 0
+ * to have this file descriptor and callback unregistered from the looper.
+ */
 typedef int ALooper_callbackFunc(int fd, int events, void* data);
 
+/**
+ * Return the ALooper associated with the calling thread, or NULL if
+ * there is not one.
+ */
 ALooper* ALooper_forThread();
 
-ALooper* ALooper_prepare();
+enum {
+    /**
+     * Option for ALooper_prepare: this ALooper will accept calls to
+     * ALooper_addFd() that do not have a callback (that is provide NULL
+     * for the callback).  In this case the caller of ALooper_pollOnce()
+     * or ALooper_pollAll() MUST check the return from these functions to
+     * discover when data is available on such fds and process it.
+     */
+    ALOOPER_PREPARE_ALLOW_NON_CALLBACKS = 1<<0
+};
 
-int32_t ALooper_pollOnce(int timeoutMillis);
+/**
+ * Prepare an ALooper associated with the calling thread, and return it.
+ * If the thread already has an ALooper, it is returned.  Otherwise, a new
+ * one is created, associated with the thread, and returned.
+ *
+ * The opts may be ALOOPER_PREPARE_ALLOW_NON_CALLBACKS or 0.
+ */
+ALooper* ALooper_prepare(int32_t opts);
 
+enum {
+    /**
+     * Result from ALooper_pollOnce() and ALooper_pollAll(): one or
+     * more callbacks were executed.
+     */
+    ALOOPER_POLL_CALLBACK = -1,
+    
+    /**
+     * Result from ALooper_pollOnce() and ALooper_pollAll(): the
+     * timeout expired.
+     */
+    ALOOPER_POLL_TIMEOUT = -2,
+    
+    /**
+     * Result from ALooper_pollOnce() and ALooper_pollAll(): an error
+     * occurred.
+     */
+    ALOOPER_POLL_ERROR = -3,
+};
+
+/**
+ * Wait for events to be available, with optional timeout in milliseconds.
+ * Invokes callbacks for all file descriptors on which an event occurred.
+ *
+ * If the timeout is zero, returns immediately without blocking.
+ * If the timeout is negative, waits indefinitely until an event appears.
+ *
+ * Returns ALOOPER_POLL_CALLBACK if a callback was invoked.
+ *
+ * Returns ALOOPER_POLL_TIMEOUT if there was no data before the given
+ * timeout expired.
+ *
+ * Returns ALOPER_POLL_ERROR if an error occurred.
+ *
+ * Returns a value >= 0 containing a file descriptor if it has data
+ * and it has no callback function (requiring the caller here to handle it).
+ * In this (and only this) case outEvents and outData will contain the poll
+ * events and data associated with the fd.
+ *
+ * This method does not return until it has finished invoking the appropriate callbacks
+ * for all file descriptors that were signalled.
+ */
+int32_t ALooper_pollOnce(int timeoutMillis, int* outEvents, void** outData);
+
+/**
+ * Like ALooper_pollOnce(), but performs all pending callbacks until all
+ * data has been consumed or a file descriptor is available with no callback.
+ * This function will never return ALOOPER_POLL_CALLBACK.
+ */
+int32_t ALooper_pollAll(int timeoutMillis, int* outEvents, void** outData);
+
+/**
+ * Acquire a reference on the given ALooper object.  This prevents the object
+ * from being deleted until the reference is removed.  This is only needed
+ * to safely hand an ALooper from one thread to another.
+ */
 void ALooper_acquire(ALooper* looper);
 
+/**
+ * Remove a reference that was previously acquired with ALooper_acquire().
+ */
 void ALooper_release(ALooper* looper);
 
-void ALooper_setCallback(ALooper* looper, int fd, int events,
+/**
+ * Add a new file descriptor to be polled by the looper.  If the same file
+ * descriptor was previously added, it is replaced.
+ *
+ * "fd" is the file descriptor to be added.
+ * "events" are the poll events to wake up on.  Typically this is POLLIN.
+ * "callback" is the function to call when there is an event on the file
+ * descriptor.
+ * "id" is an identifier to associated with this file descriptor, or 0.
+ * "data" is a private data pointer to supply to the callback.
+ *
+ * There are two main uses of this function:
+ *
+ * (1) If "callback" is non-NULL, then
+ * this function will be called when there is data on the file descriptor.  It
+ * should execute any events it has pending, appropriately reading from the
+ * file descriptor.
+ *
+ * (2) If "callback" is NULL, the fd will be returned by ALooper_pollOnce
+ * when it has data available, requiring the caller to take care of processing
+ * it.
+ */
+void ALooper_addFd(ALooper* looper, int fd, int events,
         ALooper_callbackFunc* callback, void* data);
 
-int32_t ALooper_removeCallback(ALooper* looper, int fd);
+/**
+ * Remove a previously added file descriptor from the looper.
+ */
+int32_t ALooper_removeFd(ALooper* looper, int fd);
 
 #ifdef __cplusplus
 };
diff --git a/native/include/android/native_activity.h b/native/include/android/native_activity.h
index a31c5af..ea6f05f 100644
--- a/native/include/android/native_activity.h
+++ b/native/include/android/native_activity.h
@@ -147,6 +147,21 @@
     void (*onNativeWindowCreated)(ANativeActivity* activity, ANativeWindow* window);
 
     /**
+     * The drawing window for this native activity has been resized.  You should
+     * retrieve the new size from the window and ensure that your rendering in
+     * it now matches.
+     */
+    void (*onNativeWindowResized)(ANativeActivity* activity, ANativeWindow* window);
+
+    /**
+     * The drawing window for this native activity needs to be redrawn.  To avoid
+     * transient artifacts during screen changes (such resizing after rotation),
+     * applications should not return from this function until they have finished
+     * drawing their window in its current state.
+     */
+    void (*onNativeWindowRedrawNeeded)(ANativeActivity* activity, ANativeWindow* window);
+
+    /**
      * The drawing window for this native activity is going to be destroyed.
      * You MUST ensure that you do not touch the window object after returning
      * from this function: in the common case of drawing to the window from
@@ -170,6 +185,11 @@
     void (*onInputQueueDestroyed)(ANativeActivity* activity, AInputQueue* queue);
 
     /**
+     * The rectangle in the window in which content should be placed has changed.
+     */
+    void (*onContentRectChanged)(ANativeActivity* activity, const ARect* rect);
+
+    /**
      * The system is running low on memory.  Use this callback to release
      * resources you do not need, to help the system avoid killing more
      * important processes.
@@ -192,6 +212,33 @@
  */
 extern ANativeActivity_createFunc ANativeActivity_onCreate;
 
+void ANativeActivity_setWindowFormat(ANativeActivity* activity, int32_t format);
+
+void ANativeActivity_setWindowFlags(ANativeActivity* activity,
+        uint32_t addFlags, uint32_t removeFlags);
+
+/**
+ * Flags for ANativeActivity_showSoftInput; see the Java InputMethodManager
+ * API for documentation.
+ */
+enum {
+    ANATIVEACTIVITY_SHOW_SOFT_INPUT_IMPLICIT = 0x0001,
+    ANATIVEACTIVITY_SHOW_SOFT_INPUT_FORCED = 0x0002,
+};
+
+void ANativeActivity_showSoftInput(ANativeActivity* activity, uint32_t flags);
+
+/**
+ * Flags for ANativeActivity_hideSoftInput; see the Java InputMethodManager
+ * API for documentation.
+ */
+enum {
+    ANATIVEACTIVITY_HIDE_SOFT_INPUT_IMPLICIT_ONLY = 0x0001,
+    ANATIVEACTIVITY_HIDE_SOFT_INPUT_NOT_ALWAYS = 0x0002,
+};
+
+void ANativeActivity_hideSoftInput(ANativeActivity* activity, uint32_t flags);
+
 #ifdef __cplusplus
 };
 #endif
diff --git a/native/include/android/native_window.h b/native/include/android/native_window.h
index 678ba3d..7599d7e 100644
--- a/native/include/android/native_window.h
+++ b/native/include/android/native_window.h
@@ -14,10 +14,11 @@
  * limitations under the License.
  */
 
-
 #ifndef ANDROID_NATIVE_WINDOW_H
 #define ANDROID_NATIVE_WINDOW_H
 
+#include <android/rect.h>
+
 #ifdef __cplusplus
 extern "C" {
 #endif
@@ -34,6 +35,27 @@
 struct ANativeWindow;
 typedef struct ANativeWindow ANativeWindow;
 
+typedef struct ANativeWindow_Buffer {
+    int32_t width;
+    int32_t height;
+    int32_t stride;
+    int32_t format;
+    void* bits;
+    
+    uint32_t reserved[6];
+} ANativeWindow_Buffer;
+
+/**
+ * Acquire a reference on the given ANativeWindow object.  This prevents the object
+ * from being deleted until the reference is removed.
+ */
+void ANativeWindow_acquire(ANativeWindow* window);
+
+/**
+ * Remove a reference that was previously acquired with ANativeWindow_acquire().
+ */
+void ANativeWindow_release(ANativeWindow* window);
+
 /*
  * Return the current width in pixels of the window surface.  Returns a
  * negative value on error.
@@ -60,13 +82,22 @@
  * window's physical size, then it buffer will be scaled to match that size
  * when compositing it to the screen.
  *
- * The format may be one of the window format constants above.
- *
- * For all of these parameters, if 0 is supplied than the window's base
+ * For all of these parameters, if 0 is supplied then the window's base
  * value will come back in force.
  */
-int32_t ANativeWindow_setBuffersGeometry(ANativeWindow* window, int32_t width,
-        int32_t height, int32_t format);
+int32_t ANativeWindow_setBuffersGeometry(ANativeWindow* window, int32_t width, int32_t height);
+
+/**
+ * Lock the window's next drawing surface for writing.
+ */
+int32_t ANativeWindow_lock(ANativeWindow* window, ANativeWindow_Buffer* outBuffer,
+        ARect* inOutDirtyBounds);
+
+/**
+ * Unlock the window's drawing surface after previously locking it,
+ * posting the new buffer to the display.
+ */
+int32_t ANativeWindow_unlockAndPost(ANativeWindow* window);
 
 #ifdef __cplusplus
 };
diff --git a/native/include/android/native_window_jni.h b/native/include/android/native_window_jni.h
new file mode 100644
index 0000000..b9e72ef
--- /dev/null
+++ b/native/include/android/native_window_jni.h
@@ -0,0 +1,40 @@
+/*
+ * 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.
+ */
+
+#ifndef ANDROID_NATIVE_WINDOW_JNI_H
+#define ANDROID_NATIVE_WINDOW_JNI_H
+
+#include <android/native_window.h>
+
+#include <jni.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * Return the ANativeWindow associated with a Java Surface object,
+ * for interacting with it through native code.  This acquires a reference
+ * on the ANativeWindow that is returned; be sure to use ANativeWindow_release()
+ * when done with it so that it doesn't leak.
+ */
+ANativeWindow* ANativeWindow_fromSurface(JNIEnv* env, jobject surface);
+
+#ifdef __cplusplus
+};
+#endif
+
+#endif // ANDROID_NATIVE_WINDOW_H
diff --git a/native/include/android/rect.h b/native/include/android/rect.h
new file mode 100644
index 0000000..3e81f53
--- /dev/null
+++ b/native/include/android/rect.h
@@ -0,0 +1,36 @@
+/*
+ * 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.
+ */
+
+
+#ifndef ANDROID_RECT_H
+#define ANDROID_RECT_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct ARect {
+    int32_t left;
+    int32_t top;
+    int32_t right;
+    int32_t bottom;
+} ARect;
+
+#ifdef __cplusplus
+};
+#endif
+
+#endif // ANDROID_RECT_H
diff --git a/native/include/android/sensor.h b/native/include/android/sensor.h
new file mode 100644
index 0000000..4291d3e
--- /dev/null
+++ b/native/include/android/sensor.h
@@ -0,0 +1,235 @@
+/*
+ * 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.
+ */
+
+
+#ifndef ANDROID_SENSOR_H
+#define ANDROID_SENSOR_H
+
+/******************************************************************
+ *
+ * IMPORTANT NOTICE:
+ *
+ *   This file is part of Android's set of stable system headers
+ *   exposed by the Android NDK (Native Development Kit).
+ *
+ *   Third-party source AND binary code relies on the definitions
+ *   here to be FROZEN ON ALL UPCOMING PLATFORM RELEASES.
+ *
+ *   - DO NOT MODIFY ENUMS (EXCEPT IF YOU ADD NEW 32-BIT VALUES)
+ *   - DO NOT MODIFY CONSTANTS OR FUNCTIONAL MACROS
+ *   - DO NOT CHANGE THE SIGNATURE OF FUNCTIONS IN ANY WAY
+ *   - DO NOT CHANGE THE LAYOUT OR SIZE OF STRUCTURES
+ */
+
+/*
+ * Structures and functions to receive and process sensor events in
+ * native code.
+ *
+ */
+
+#include <sys/types.h>
+
+#include <android/looper.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+/*
+ * Sensor types
+ * (keep in sync with hardware/sensor.h)
+ */
+
+enum {
+    ASENSOR_TYPE_ACCELEROMETER      = 1,
+    ASENSOR_TYPE_MAGNETIC_FIELD     = 2,
+    ASENSOR_TYPE_GYROSCOPE          = 4,
+    ASENSOR_TYPE_LIGHT              = 5,
+    ASENSOR_TYPE_PROXIMITY          = 8
+};
+
+/*
+ * Sensor accuracy measure
+ */
+enum {
+    ASENSOR_STATUS_UNRELIABLE       = 0,
+    ASENSOR_STATUS_ACCURACY_LOW     = 1,
+    ASENSOR_STATUS_ACCURACY_MEDIUM  = 2,
+    ASENSOR_STATUS_ACCURACY_HIGH    = 3
+};
+
+/*
+ * A few useful constants
+ */
+
+/* Earth's gravity in m/s^2 */
+#define ASENSOR_STANDARD_GRAVITY            (9.80665f)
+/* Maximum magnetic field on Earth's surface in uT */
+#define ASENSOR_MAGNETIC_FIELD_EARTH_MAX    (60.0f)
+/* Minimum magnetic field on Earth's surface in uT*/
+#define ASENSOR_MAGNETIC_FIELD_EARTH_MIN    (30.0f)
+
+/*
+ * A sensor event.
+ */
+
+typedef struct ASensorVector {
+    union {
+        float v[3];
+        struct {
+            float x;
+            float y;
+            float z;
+        };
+    };
+    int8_t status;
+    uint8_t reserved[3];
+} ASensorVector;
+
+typedef struct ASensorEvent {
+    int sensor;
+    int32_t reserved0;
+    union {
+        float           data[16];
+        ASensorVector   acceleration;
+        ASensorVector   magnetic;
+        float           temperature;
+        float           distance;
+        float           light;
+    };
+    int64_t timestamp;
+    int32_t reserved1[4];
+} ASensorEvent;
+
+
+struct ASensorManager;
+typedef struct ASensorManager ASensorManager;
+
+struct ASensorEventQueue;
+typedef struct ASensorEventQueue ASensorEventQueue;
+
+struct ASensor;
+typedef struct ASensor ASensor;
+
+/*****************************************************************************/
+
+/*
+ * Get a reference to the sensor manager. ASensorManager is a singleton.
+ *
+ * Example:
+ *
+ *     ASensorManager* sensorManager = ASensorManager_getInstance();
+ *
+ */
+ASensorManager* ASensorManager_getInstance();
+
+
+/*
+ * Returns the list of available sensors.
+ */
+int ASensorManager_getSensorList(ASensorManager* manager, ASensor** list);
+
+/*
+ * Returns the default sensor for the given type, or NULL if no sensor
+ * of that type exist.
+ */
+ASensor* ASensorManager_getDefaultSensor(ASensorManager* manager, int type);
+
+/*
+ * Creates a new sensor event queue and associate it with a looper.
+ */
+ASensorEventQueue* ASensorManager_createEventQueue(ASensorManager* manager,
+        ALooper* looper, ALooper_callbackFunc* callback, void* data);
+
+/*
+ * Destroys the event queue and free all resources associated to it.
+ */
+int ASensorManager_destroyEventQueue(ASensorManager* manager, ASensorEventQueue* queue);
+
+
+/*****************************************************************************/
+
+/*
+ * Enable the selected sensor. Returns a negative error code on failure.
+ */
+int ASensorEventQueue_enableSensor(ASensorEventQueue* queue, ASensor* sensor);
+
+/*
+ * Disable the selected sensor. Returns a negative error code on failure.
+ */
+int ASensorEventQueue_disableSensor(ASensorEventQueue* queue, ASensor* sensor);
+
+/*
+ * Sets the delivery rate of events in microseconds for the given sensor.
+ * Note that this is a hint only, generally event will arrive at a higher
+ * rate.
+ * Returns a negative error code on failure.
+ */
+int ASensorEventQueue_setEventRate(ASensorEventQueue* queue, ASensor* sensor, int32_t usec);
+
+/*
+ * Returns true if there are one or more events available in the
+ * sensor queue.  Returns 1 if the queue has events; 0 if
+ * it does not have events; and a negative value if there is an error.
+ */
+int ASensorEventQueue_hasEvents(ASensorEventQueue* queue);
+
+/*
+ * Returns the next available events from the queue.  Returns a negative
+ * value if no events are available or an error has occurred, otherwise
+ * the number of events returned.
+ *
+ * Examples:
+ *   ASensorEvent event;
+ *   ssize_t numEvent = ASensorEventQueue_getEvents(queue, &event, 1);
+ *
+ *   ASensorEvent eventBuffer[8];
+ *   ssize_t numEvent = ASensorEventQueue_getEvents(queue, eventBuffer, 8);
+ *
+ */
+ssize_t ASensorEventQueue_getEvents(ASensorEventQueue* queue,
+                ASensorEvent* events, size_t count);
+
+
+/*****************************************************************************/
+
+/*
+ * Returns this sensor's name (non localized)
+ */
+const char* ASensor_getName(ASensor* sensor);
+
+/*
+ * Returns this sensor's vendor's name (non localized)
+ */
+const char* ASensor_getVendor(ASensor* sensor);
+
+/*
+ * Return this sensor's type
+ */
+int ASensor_getType(ASensor* sensor);
+
+/*
+ * Returns this sensors's resolution
+ */
+float ASensor_getResolution(ASensor* sensor);
+
+
+#ifdef __cplusplus
+};
+#endif
+
+#endif // ANDROID_SENSOR_H
diff --git a/native/include/android/tts.h b/native/include/android/tts.h
index e5c99f7..fb15108 100644
--- a/native/include/android/tts.h
+++ b/native/include/android/tts.h
@@ -87,6 +87,11 @@
  */
 extern android_tts_engine_t *android_getTtsEngine();
 
+/* Including the old version for legacy support (Froyo compatibility).
+ * This should return the same thing as android_getTtsEngine.
+ */
+extern "C" android_tts_engine_t *getTtsEngine();
+
 // A callback type used to notify the framework of new synthetized
 // audio samples, status will be SYNTH_DONE for the last sample of
 // the last request, of SYNTH_PENDING otherwise.
diff --git a/native/include/android/window.h b/native/include/android/window.h
new file mode 100644
index 0000000..2ab192b
--- /dev/null
+++ b/native/include/android/window.h
@@ -0,0 +1,58 @@
+/*
+ * 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.
+ */
+
+
+#ifndef ANDROID_WINDOW_H
+#define ANDROID_WINDOW_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * Window flags, as per the Java API at android.view.WindowManager.LayoutParams.
+ */
+enum {
+    AWINDOW_FLAG_ALLOW_LOCK_WHILE_SCREEN_ON = 0x00000001,
+    AWINDOW_FLAG_DIM_BEHIND                 = 0x00000002,
+    AWINDOW_FLAG_BLUR_BEHIND                = 0x00000004,
+    AWINDOW_FLAG_NOT_FOCUSABLE              = 0x00000008,
+    AWINDOW_FLAG_NOT_TOUCHABLE              = 0x00000010,
+    AWINDOW_FLAG_NOT_TOUCH_MODAL            = 0x00000020,
+    AWINDOW_FLAG_TOUCHABLE_WHEN_WAKING      = 0x00000040,
+    AWINDOW_FLAG_KEEP_SCREEN_ON             = 0x00000080,
+    AWINDOW_FLAG_LAYOUT_IN_SCREEN           = 0x00000100,
+    AWINDOW_FLAG_LAYOUT_NO_LIMITS           = 0x00000200,
+    AWINDOW_FLAG_FULLSCREEN                 = 0x00000400,
+    AWINDOW_FLAG_FORCE_NOT_FULLSCREEN       = 0x00000800,
+    AWINDOW_FLAG_DITHER                     = 0x00001000,
+    AWINDOW_FLAG_SECURE                     = 0x00002000,
+    AWINDOW_FLAG_SCALED                     = 0x00004000,
+    AWINDOW_FLAG_IGNORE_CHEEK_PRESSES       = 0x00008000,
+    AWINDOW_FLAG_LAYOUT_INSET_DECOR         = 0x00010000,
+    AWINDOW_FLAG_ALT_FOCUSABLE_IM           = 0x00020000,
+    AWINDOW_FLAG_WATCH_OUTSIDE_TOUCH        = 0x00040000,
+    AWINDOW_FLAG_SHOW_WHEN_LOCKED           = 0x00080000,
+    AWINDOW_FLAG_SHOW_WALLPAPER             = 0x00100000,
+    AWINDOW_FLAG_TURN_SCREEN_ON             = 0x00200000,
+    AWINDOW_FLAG_DISMISS_KEYGUARD           = 0x00400000,
+};
+
+#ifdef __cplusplus
+};
+#endif
+
+#endif // ANDROID_WINDOW_H
diff --git a/opengl/java/android/opengl/GLSurfaceView.java b/opengl/java/android/opengl/GLSurfaceView.java
index 2ff231d..41207f7 100644
--- a/opengl/java/android/opengl/GLSurfaceView.java
+++ b/opengl/java/android/opengl/GLSurfaceView.java
@@ -222,6 +222,10 @@
         // underlying surface is created and destroyed
         SurfaceHolder holder = getHolder();
         holder.addCallback(this);
+        // setFormat is done by SurfaceView in SDK 2.3 and newer. Uncomment
+        // this statement if back-porting to 2.2 or older:
+        // holder.setFormat(PixelFormat.RGB_565);
+        //
         // setType is not needed for SDK 2.0 or newer. Uncomment this
         // statement if back-porting this code to older SDKs.
         // holder.setType(SurfaceHolder.SURFACE_TYPE_GPU);
@@ -1103,7 +1107,6 @@
             mRenderer = renderer;
         }
 
-
         @Override
         public void run() {
             setName("GLThread " + getId());
@@ -1154,6 +1157,7 @@
                 boolean sizeChanged = false;
                 boolean wantRenderNotification = false;
                 boolean doRenderNotification = false;
+                boolean askedToReleaseEglContext = false;
                 int w = 0;
                 int h = 0;
                 Runnable event = null;
@@ -1179,6 +1183,17 @@
                                 }
                             }
 
+                            // Do we need to give up the EGL context?
+                            if (mShouldReleaseEglContext) {
+                                if (LOG_SURFACE) {
+                                    Log.i("GLThread", "releasing EGL context because asked to tid=" + getId());
+                                }
+                                stopEglSurfaceLocked();
+                                stopEglContextLocked();
+                                mShouldReleaseEglContext = false;
+                                askedToReleaseEglContext = true;
+                            }
+
                             // Have we lost the EGL context?
                             if (lostEglContext) {
                                 stopEglSurfaceLocked();
@@ -1228,6 +1243,9 @@
                             }
 
                             if (doRenderNotification) {
+                                if (LOG_SURFACE) {
+                                    Log.i("GLThread", "sending render notification tid=" + getId());
+                                }
                                 wantRenderNotification = false;
                                 doRenderNotification = false;
                                 mRenderComplete = true;
@@ -1235,22 +1253,24 @@
                             }
 
                             // Ready to draw?
-                            if ((!mPaused) && mHasSurface
-                                && (mWidth > 0) && (mHeight > 0)
-                                && (mRequestRender || (mRenderMode == RENDERMODE_CONTINUOUSLY))) {
+                            if (readyToDraw()) {
 
                                 // If we don't have an EGL context, try to acquire one.
-                                if ((! mHaveEglContext) && sGLThreadManager.tryAcquireEglContextLocked(this)) {
-                                    try {
-                                        mEglHelper.start();
-                                    } catch (RuntimeException t) {
-                                        sGLThreadManager.releaseEglContextLocked(this);
-                                        throw t;
-                                    }
-                                    mHaveEglContext = true;
-                                    createEglContext = true;
+                                if (! mHaveEglContext) {
+                                    if (askedToReleaseEglContext) {
+                                        askedToReleaseEglContext = false;
+                                    } else if (sGLThreadManager.tryAcquireEglContextLocked(this)) {
+                                        try {
+                                            mEglHelper.start();
+                                        } catch (RuntimeException t) {
+                                            sGLThreadManager.releaseEglContextLocked(this);
+                                            throw t;
+                                        }
+                                        mHaveEglContext = true;
+                                        createEglContext = true;
 
-                                    sGLThreadManager.notifyAll();
+                                        sGLThreadManager.notifyAll();
+                                    }
                                 }
 
                                 if (mHaveEglContext && !mHaveEglSurface) {
@@ -1265,6 +1285,9 @@
                                         w = mWidth;
                                         h = mHeight;
                                         wantRenderNotification = true;
+                                        if (LOG_SURFACE) {
+                                            Log.i("GLThread", "noticing that we want render notification tid=" + getId());
+                                        }
 
                                         if (DRAW_TWICE_AFTER_SIZE_CHANGED) {
                                             // We keep mRequestRender true so that we draw twice after the size changes.
@@ -1284,7 +1307,16 @@
 
                             // By design, this is the only place in a GLThread thread where we wait().
                             if (LOG_THREADS) {
-                                Log.i("GLThread", "waiting tid=" + getId());
+                                Log.i("GLThread", "waiting tid=" + getId()
+                                    + " mHaveEglContext: " + mHaveEglContext
+                                    + " mHaveEglSurface: " + mHaveEglSurface
+                                    + " mPaused: " + mPaused
+                                    + " mHasSurface: " + mHasSurface
+                                    + " mWaitingForSurface: " + mWaitingForSurface
+                                    + " mWidth: " + mWidth
+                                    + " mHeight: " + mHeight
+                                    + " mRequestRender: " + mRequestRender
+                                    + " mRenderMode: " + mRenderMode);
                             }
                             sGLThreadManager.wait();
                         }
@@ -1326,7 +1358,7 @@
                     }
 
                     if (LOG_RENDERER_DRAW_FRAME) {
-                        Log.w("GLThread", "onDrawFrame");
+                        Log.w("GLThread", "onDrawFrame tid=" + getId());
                     }
                     mRenderer.onDrawFrame(gl);
                     if (!mEglHelper.swap()) {
@@ -1352,6 +1384,16 @@
             }
         }
 
+        public boolean ableToDraw() {
+            return mHaveEglContext && mHaveEglSurface && readyToDraw();
+        }
+
+        private boolean readyToDraw() {
+            return (!mPaused) && mHasSurface
+                && (mWidth > 0) && (mHeight > 0)
+                && (mRequestRender || (mRenderMode == RENDERMODE_CONTINUOUSLY));
+        }
+
         public void setRenderMode(int renderMode) {
             if ( !((RENDERMODE_WHEN_DIRTY <= renderMode) && (renderMode <= RENDERMODE_CONTINUOUSLY)) ) {
                 throw new IllegalArgumentException("renderMode");
@@ -1461,9 +1503,10 @@
                 sGLThreadManager.notifyAll();
 
                 // Wait for thread to react to resize and render a frame
-                while (! mExited && !mPaused && !mRenderComplete ) {
+                while (! mExited && !mPaused && !mRenderComplete
+                        && (mGLThread != null && mGLThread.ableToDraw())) {
                     if (LOG_SURFACE) {
-                        Log.i("Main thread", "onWindowResize waiting for render complete.");
+                        Log.i("Main thread", "onWindowResize waiting for render complete from tid=" + mGLThread.getId());
                     }
                     try {
                         sGLThreadManager.wait();
@@ -1490,6 +1533,11 @@
             }
         }
 
+        public void requestReleaseEglContextLocked() {
+            mShouldReleaseEglContext = true;
+            sGLThreadManager.notifyAll();
+        }
+
         /**
          * Queue an "event" to be run on the GL rendering thread.
          * @param r the runnable to be run on the GL rendering thread.
@@ -1514,6 +1562,7 @@
         private boolean mWaitingForSurface;
         private boolean mHaveEglContext;
         private boolean mHaveEglSurface;
+        private boolean mShouldReleaseEglContext;
         private int mWidth;
         private int mHeight;
         private int mRenderMode;
@@ -1598,6 +1647,13 @@
             if (mMultipleGLESContextsAllowed) {
                 return true;
             }
+            // Notify the owning thread that it should release the context.
+            // TODO: implement a fairness policy. Currently
+            // if the owning thread is drawing continuously it will just
+            // reacquire the EGL context.
+            if (mEglOwner != null) {
+                mEglOwner.requestReleaseEglContextLocked();
+            }
             return false;
         }
 
diff --git a/opengl/tests/gl_perf/Android.mk b/opengl/tests/gl_perf/Android.mk
new file mode 100644
index 0000000..37647ca
--- /dev/null
+++ b/opengl/tests/gl_perf/Android.mk
@@ -0,0 +1,20 @@
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES:= \
+	gl2_perf.cpp \
+	filltest.cpp
+
+LOCAL_SHARED_LIBRARIES := \
+	libcutils \
+    libEGL \
+    libGLESv2 \
+    libui
+
+LOCAL_MODULE:= test-opengl-gl2_perf
+
+LOCAL_MODULE_TAGS := optional
+
+LOCAL_CFLAGS := -DGL_GLEXT_PROTOTYPES
+
+include $(BUILD_EXECUTABLE)
diff --git a/opengl/tests/gl_perf/filltest.cpp b/opengl/tests/gl_perf/filltest.cpp
new file mode 100644
index 0000000..eb398ec
--- /dev/null
+++ b/opengl/tests/gl_perf/filltest.cpp
@@ -0,0 +1,385 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <time.h>
+#include <sched.h>
+#include <sys/resource.h>
+#include <string.h>
+
+#include <GLES2/gl2.h>
+#include <GLES2/gl2ext.h>
+#include <utils/Timers.h>
+#include <EGL/egl.h>
+
+
+using namespace android;
+
+static void checkGlError(const char* op) {
+    for (GLint error = glGetError(); error; error
+            = glGetError()) {
+        fprintf(stderr, "after %s() glError (0x%x)\n", op, error);
+    }
+}
+
+GLuint loadShader(GLenum shaderType, const char* pSource) {
+    GLuint shader = glCreateShader(shaderType);
+    if (shader) {
+        glShaderSource(shader, 1, &pSource, NULL);
+        glCompileShader(shader);
+        GLint compiled = 0;
+        glGetShaderiv(shader, GL_COMPILE_STATUS, &compiled);
+        if (!compiled) {
+            GLint infoLen = 0;
+            glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &infoLen);
+            if (infoLen) {
+                char* buf = (char*) malloc(infoLen);
+                if (buf) {
+                    glGetShaderInfoLog(shader, infoLen, NULL, buf);
+                    fprintf(stderr, "Could not compile shader %d:\n%s\n",
+                            shaderType, buf);
+                    free(buf);
+                }
+                glDeleteShader(shader);
+                shader = 0;
+            }
+        }
+    }
+    return shader;
+}
+
+enum {
+    A_POS,
+    A_COLOR,
+    A_TEX0,
+    A_TEX1
+};
+
+GLuint createProgram(const char* pVertexSource, const char* pFragmentSource) {
+    GLuint vertexShader = loadShader(GL_VERTEX_SHADER, pVertexSource);
+    if (!vertexShader) {
+        return 0;
+    }
+
+    GLuint pixelShader = loadShader(GL_FRAGMENT_SHADER, pFragmentSource);
+    if (!pixelShader) {
+        return 0;
+    }
+
+    GLuint program = glCreateProgram();
+    if (program) {
+        glAttachShader(program, vertexShader);
+        checkGlError("glAttachShader v");
+        glAttachShader(program, pixelShader);
+        checkGlError("glAttachShader p");
+
+        glBindAttribLocation(program, A_POS, "a_pos");
+        glBindAttribLocation(program, A_COLOR, "a_color");
+        glBindAttribLocation(program, A_TEX0, "a_tex0");
+        glBindAttribLocation(program, A_TEX1, "a_tex1");
+        glLinkProgram(program);
+        GLint linkStatus = GL_FALSE;
+        glGetProgramiv(program, GL_LINK_STATUS, &linkStatus);
+        if (linkStatus != GL_TRUE) {
+            GLint bufLength = 0;
+            glGetProgramiv(program, GL_INFO_LOG_LENGTH, &bufLength);
+            if (bufLength) {
+                char* buf = (char*) malloc(bufLength);
+                if (buf) {
+                    glGetProgramInfoLog(program, bufLength, NULL, buf);
+                    printf("Could not link program:\n%s\n", buf);
+                    free(buf);
+                }
+            }
+            glDeleteProgram(program);
+            program = 0;
+        }
+    }
+    checkGlError("createProgram");
+    glUseProgram(program);
+    return program;
+}
+
+uint64_t getTime() {
+    struct timespec t;
+    clock_gettime(CLOCK_MONOTONIC, &t);
+    return t.tv_nsec + ((uint64_t)t.tv_sec * 1000 * 1000 * 1000);
+}
+
+uint64_t gTime;
+void startTimer() {
+    gTime = getTime();
+}
+
+void endTimer(const char *str, int w, int h, double dc, int count) {
+    uint64_t t2 = getTime();
+    double delta = ((double)(t2 - gTime)) / 1000000000;
+    double pixels = dc * (w * h) * count;
+    double mpps = pixels / delta / 1000000;
+    double dc60 = pixels / delta / (w * h) / 60;
+
+    printf("%s, %f, %f\n", str, mpps, dc60);
+}
+
+static const char gVertexShader[] =
+    "attribute vec4 a_pos;\n"
+    "attribute vec4 a_color;\n"
+    "attribute vec2 a_tex0;\n"
+    "attribute vec2 a_tex1;\n"
+    "varying vec4 v_color;\n"
+    "varying vec2 v_tex0;\n"
+    "varying vec2 v_tex1;\n"
+
+    "void main() {\n"
+    "    v_color = a_color;\n"
+    "    v_tex0 = a_tex0;\n"
+    "    v_tex1 = a_tex1;\n"
+    "    gl_Position = a_pos;\n"
+    "}\n";
+
+static const char gShaderPrefix[] =
+    "precision mediump float;\n"
+    "uniform vec4 u_color;\n"
+    "uniform vec4 u_0;\n"
+    "uniform vec4 u_1;\n"
+    "uniform vec4 u_2;\n"
+    "uniform vec4 u_3;\n"
+    "varying vec4 v_color;\n"
+    "varying vec2 v_tex0;\n"
+    "varying vec2 v_tex1;\n"
+    "uniform sampler2D u_tex0;\n"
+    "uniform sampler2D u_tex1;\n"
+    "void main() {\n";
+
+static const char gShaderPostfix[] =
+    "  gl_FragColor = c;\n"
+    "}\n";
+
+
+static char * append(char *d, const char *s) {
+    size_t len = strlen(s);
+    memcpy(d, s, len);
+    return d + len;
+}
+
+static char * genShader(
+    bool useVarColor,
+    int texCount,
+    bool modulateFirstTex,
+    int extraMath)
+{
+    char *str = (char *)calloc(16 * 1024, 1);
+    char *tmp = append(str, gShaderPrefix);
+
+    if (modulateFirstTex || !texCount) {
+        if (useVarColor) {
+            tmp = append(tmp, "  vec4 c = v_color;\n");
+        } else {
+            tmp = append(tmp, "  vec4 c = u_color;\n");
+        }
+    } else {
+        tmp = append(tmp, "  vec4 c = texture2D(u_tex0, v_tex0);\n");
+    }
+
+    if (modulateFirstTex && texCount) {
+        tmp = append(tmp, "  c *= texture2D(u_tex0, v_tex0);\n");
+    }
+    if (texCount > 1) {
+        tmp = append(tmp, "  c *= texture2D(u_tex1, v_tex1);\n");
+    }
+
+    if (extraMath > 0) {
+        tmp = append(tmp, "  c *= u_0;\n");
+    }
+    if (extraMath > 1) {
+        tmp = append(tmp, "  c *= u_1;\n");
+    }
+    if (extraMath > 2) {
+        tmp = append(tmp, "  c *= u_2;\n");
+    }
+    if (extraMath > 3) {
+        tmp = append(tmp, "  c *= u_3;\n");
+    }
+
+
+    tmp = append(tmp, gShaderPostfix);
+    tmp[0] = 0;
+
+    //printf("%s", str);
+    return str;
+}
+
+static void setupVA() {
+    static const float vtx[] = {
+        -2.0f,-1.0f,
+         1.0f,-1.0f,
+        -2.0f, 1.0f,
+         1.0f, 1.0f };
+    static const float color[] = {
+        1.0f,0.0f,1.0f,1.0f,
+        0.0f,0.0f,1.0f,1.0f,
+        1.0f,1.0f,0.0f,1.0f,
+        1.0f,1.0f,1.0f,1.0f };
+    static const float tex0[] = {
+        0.0f,0.0f,
+        1.0f,0.0f,
+        1.0f,1.0f,
+        0.0f,1.0f };
+    static const float tex1[] = {
+        1.0f,0.0f,
+        1.0f,1.0f,
+        0.0f,1.0f,
+        0.0f,0.0f };
+
+    glEnableVertexAttribArray(A_POS);
+    glEnableVertexAttribArray(A_COLOR);
+    glEnableVertexAttribArray(A_TEX0);
+    glEnableVertexAttribArray(A_TEX1);
+
+    glVertexAttribPointer(A_POS, 2, GL_FLOAT, false, 8, vtx);
+    glVertexAttribPointer(A_COLOR, 4, GL_FLOAT, false, 16, color);
+    glVertexAttribPointer(A_TEX0, 2, GL_FLOAT, false, 8, tex0);
+    glVertexAttribPointer(A_TEX1, 2, GL_FLOAT, false, 8, tex1);
+}
+
+//////////////////////////
+
+void ptSwap();
+
+static void doLoop(uint32_t w, uint32_t h, const char *str) {
+    glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT);
+    glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
+    ptSwap();
+    glFinish();
+
+    startTimer();
+    glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT);
+    for (int ct=0; ct < 100; ct++) {
+        glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
+    }
+    ptSwap();
+    glFinish();
+    endTimer(str, w, h, 1, 100);
+}
+
+static void doSingleTest(uint32_t w, uint32_t h,
+                         bool useVarColor,
+                         int texCount,
+                         bool modulateFirstTex,
+                         int extraMath,
+                         int tex0, int tex1) {
+    char *pgmTxt = genShader(useVarColor, texCount, modulateFirstTex, extraMath);
+    int pgm = createProgram(gVertexShader, pgmTxt);
+    if (!pgm) {
+        printf("error running test\n");
+        return;
+    }
+    int loc = glGetUniformLocation(pgm, "u_tex0");
+    //printf("loc = %i \n", loc);
+    if (loc >= 0) glUniform1i(loc, 0);
+    loc = glGetUniformLocation(pgm, "u_tex1");
+    if (loc >= 0) glUniform1i(loc, 1);
+
+    loc = glGetUniformLocation(pgm, "u_color");
+    if (loc >= 0) glUniform4f(loc, 1.f, 0.4f, 0.6f, 0.8f);
+
+    loc = glGetUniformLocation(pgm, "u_0");
+    if (loc >= 0) glUniform4f(loc, 1.f, 0.4f, 0.6f, 0.8f);
+
+    loc = glGetUniformLocation(pgm, "u_1");
+    if (loc >= 0) glUniform4f(loc, 0.7f, 0.8f, 0.6f, 0.8f);
+
+    loc = glGetUniformLocation(pgm, "u_2");
+    if (loc >= 0) glUniform4f(loc, 0.9f, 0.6f, 0.7f, 1.0f);
+
+    loc = glGetUniformLocation(pgm, "u_3");
+    if (loc >= 0) glUniform4f(loc, 0.88f, 0.2f, 0.4f, 0.2f);
+
+    glActiveTexture(GL_TEXTURE0);
+    glBindTexture(GL_TEXTURE_2D, tex0);
+    glActiveTexture(GL_TEXTURE1);
+    glBindTexture(GL_TEXTURE_2D, tex1);
+    glActiveTexture(GL_TEXTURE0);
+
+    char str2[1024];
+
+    glBlendFunc(GL_ONE, GL_ONE);
+    glDisable(GL_BLEND);
+    sprintf(str2, "%i, %i, %i, %i, %i, 0",
+            useVarColor, texCount, modulateFirstTex, extraMath, tex0);
+    doLoop(w, h, str2);
+
+    glEnable(GL_BLEND);
+    sprintf(str2, "%i, %i, %i, %i, %i, 1",
+            useVarColor, texCount, modulateFirstTex, extraMath, tex0);
+    doLoop(w, h, str2);
+}
+
+void genTextures() {
+    uint32_t *m = (uint32_t *)malloc(1024*1024*4);
+    for (int y=0; y < 1024; y++){
+        for (int x=0; x < 1024; x++){
+            m[y*1024 + x] = 0xff0000ff | ((x & 0xff) << 8) | (y << 16);
+        }
+    }
+    glBindTexture(GL_TEXTURE_2D, 1);
+    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 1024, 1024, 0, GL_RGBA, GL_UNSIGNED_BYTE, m);
+    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
+    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
+
+    for (int y=0; y < 16; y++){
+        for (int x=0; x < 16; x++){
+            m[y*16 + x] = 0xff0000ff | (x<<12) | (y<<20);
+        }
+    }
+    glBindTexture(GL_TEXTURE_2D, 2);
+    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 16, 16, 0, GL_RGBA, GL_UNSIGNED_BYTE, m);
+    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
+    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
+
+}
+
+bool doTest(uint32_t w, uint32_t h) {
+    setupVA();
+    genTextures();
+
+    printf("\nvarColor, texCount, modulate, extraMath, texSize, blend, Mpps, DC60\n");
+
+    for (int texCount = 0; texCount < 3; texCount++) {
+        for (int extraMath = 0; extraMath < 5; extraMath++) {
+
+            doSingleTest(w, h, false, texCount, false, extraMath, 1, 1);
+            doSingleTest(w, h, true, texCount, false, extraMath, 1, 1);
+            if (texCount) {
+                doSingleTest(w, h, false, texCount, true, extraMath, 1, 1);
+                doSingleTest(w, h, true, texCount, true, extraMath, 1, 1);
+
+                doSingleTest(w, h, false, texCount, false, extraMath, 2, 2);
+                doSingleTest(w, h, true, texCount, false, extraMath, 2, 2);
+                doSingleTest(w, h, false, texCount, true, extraMath, 2, 2);
+                doSingleTest(w, h, true, texCount, true, extraMath, 2, 2);
+            }
+        }
+    }
+
+    exit(0);
+    return true;
+}
diff --git a/opengl/tests/gl_perf/gl2_perf.cpp b/opengl/tests/gl_perf/gl2_perf.cpp
new file mode 100644
index 0000000..9dfcf1c
--- /dev/null
+++ b/opengl/tests/gl_perf/gl2_perf.cpp
@@ -0,0 +1,136 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <time.h>
+#include <sched.h>
+#include <sys/resource.h>
+
+#include <EGL/egl.h>
+#include <GLES2/gl2.h>
+#include <GLES2/gl2ext.h>
+
+#include <utils/Timers.h>
+
+#include <ui/FramebufferNativeWindow.h>
+#include <ui/EGLUtils.h>
+
+using namespace android;
+
+
+static void checkEglError(const char* op, EGLBoolean returnVal = EGL_TRUE) {
+    if (returnVal != EGL_TRUE) {
+        fprintf(stderr, "%s() returned %d\n", op, returnVal);
+    }
+
+    for (EGLint error = eglGetError(); error != EGL_SUCCESS; error
+            = eglGetError()) {
+        fprintf(stderr, "after %s() eglError %s (0x%x)\n", op, EGLUtils::strerror(error),
+                error);
+    }
+}
+
+static void checkGlError(const char* op) {
+    for (GLint error = glGetError(); error; error
+            = glGetError()) {
+        fprintf(stderr, "after %s() glError (0x%x)\n", op, error);
+    }
+}
+
+bool doTest(uint32_t w, uint32_t h);
+
+static EGLDisplay dpy;
+static EGLSurface surface;
+
+int main(int argc, char** argv) {
+    EGLBoolean returnValue;
+    EGLConfig myConfig = {0};
+
+    EGLint context_attribs[] = { EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE };
+    EGLint s_configAttribs[] = {
+            EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
+            EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
+            EGL_NONE };
+    EGLint majorVersion;
+    EGLint minorVersion;
+    EGLContext context;
+    EGLint w, h;
+
+
+    checkEglError("<init>");
+    dpy = eglGetDisplay(EGL_DEFAULT_DISPLAY);
+    checkEglError("eglGetDisplay");
+    if (dpy == EGL_NO_DISPLAY) {
+        printf("eglGetDisplay returned EGL_NO_DISPLAY.\n");
+        return 0;
+    }
+
+    returnValue = eglInitialize(dpy, &majorVersion, &minorVersion);
+    checkEglError("eglInitialize", returnValue);
+    if (returnValue != EGL_TRUE) {
+        printf("eglInitialize failed\n");
+        return 0;
+    }
+
+    EGLNativeWindowType window = android_createDisplaySurface();

+    returnValue = EGLUtils::selectConfigForNativeWindow(dpy, s_configAttribs, window, &myConfig);
+    if (returnValue) {
+        printf("EGLUtils::selectConfigForNativeWindow() returned %d", returnValue);
+        return 0;
+    }
+
+    checkEglError("EGLUtils::selectConfigForNativeWindow");
+
+    surface = eglCreateWindowSurface(dpy, myConfig, window, NULL);
+    checkEglError("eglCreateWindowSurface");
+    if (surface == EGL_NO_SURFACE) {
+        printf("gelCreateWindowSurface failed.\n");
+        return 0;
+    }
+
+    context = eglCreateContext(dpy, myConfig, EGL_NO_CONTEXT, context_attribs);
+    checkEglError("eglCreateContext");
+    if (context == EGL_NO_CONTEXT) {
+        printf("eglCreateContext failed\n");
+        return 0;
+    }
+    returnValue = eglMakeCurrent(dpy, surface, surface, context);
+    checkEglError("eglMakeCurrent", returnValue);
+    if (returnValue != EGL_TRUE) {
+        return 0;
+    }
+    eglQuerySurface(dpy, surface, EGL_WIDTH, &w);
+    checkEglError("eglQuerySurface");
+    eglQuerySurface(dpy, surface, EGL_HEIGHT, &h);
+    checkEglError("eglQuerySurface");
+    GLint dim = w < h ? w : h;
+
+    glViewport(0, 0, w, h);
+
+    for (;;) {
+        doTest(w, h);
+        eglSwapBuffers(dpy, surface);
+        checkEglError("eglSwapBuffers");
+    }
+
+    return 0;
+}
+
+void ptSwap() {
+    eglSwapBuffers(dpy, surface);
+}
+
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java b/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
index cd4f96d..7395233 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
@@ -49,6 +49,7 @@
 import org.xmlpull.v1.XmlPullParserException;
 
 import java.io.IOException;
+import java.util.HashSet;
 import java.util.List;
 
 /**
@@ -67,11 +68,29 @@
 
     private Context mContext;
 
+    private static final HashSet<String> mValidTables = new HashSet<String>();
+
+    static {
+        mValidTables.add("system");
+        mValidTables.add("secure");
+        mValidTables.add("bluetooth_devices");
+        mValidTables.add("bookmarks");
+
+        // These are old.
+        mValidTables.add("favorites");
+        mValidTables.add("gservices");
+        mValidTables.add("old_favorites");
+    }
+
     public DatabaseHelper(Context context) {
         super(context, DATABASE_NAME, null, DATABASE_VERSION);
         mContext = context;
     }
 
+    public static boolean isValidTable(String name) {
+        return mValidTables.contains(name);
+    }
+
     private void createSecureTable(SQLiteDatabase db) {
         db.execSQL("CREATE TABLE secure (" +
                 "_id INTEGER PRIMARY KEY AUTOINCREMENT," +
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
index 1019fa8..6a5290e 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
@@ -83,6 +83,9 @@
         SqlArguments(Uri url, String where, String[] args) {
             if (url.getPathSegments().size() == 1) {
                 this.table = url.getPathSegments().get(0);
+                if (!DatabaseHelper.isValidTable(this.table)) {
+                    throw new IllegalArgumentException("Bad root path: " + this.table);
+                }
                 this.where = where;
                 this.args = args;
             } else if (url.getPathSegments().size() != 2) {
@@ -91,6 +94,9 @@
                 throw new UnsupportedOperationException("WHERE clause not supported: " + url);
             } else {
                 this.table = url.getPathSegments().get(0);
+                if (!DatabaseHelper.isValidTable(this.table)) {
+                    throw new IllegalArgumentException("Bad root path: " + this.table);
+                }
                 if ("system".equals(this.table) || "secure".equals(this.table)) {
                     this.where = Settings.NameValueTable.NAME + "=?";
                     this.args = new String[] { url.getPathSegments().get(1) };
@@ -105,6 +111,9 @@
         SqlArguments(Uri url) {
             if (url.getPathSegments().size() == 1) {
                 this.table = url.getPathSegments().get(0);
+                if (!DatabaseHelper.isValidTable(this.table)) {
+                    throw new IllegalArgumentException("Bad root path: " + this.table);
+                }
                 this.where = null;
                 this.args = null;
             } else {
diff --git a/packages/SystemUI/AndroidManifest.xml b/packages/SystemUI/AndroidManifest.xml
index 75045d7..6d77a3a 100644
--- a/packages/SystemUI/AndroidManifest.xml
+++ b/packages/SystemUI/AndroidManifest.xml
@@ -12,7 +12,12 @@
         android:icon="@drawable/ic_launcher_settings">
                  
         <service
-            android:name=".statusbar.StatusBarService"
+            android:name=".statusbar.PhoneStatusBarService"
+            android:exported="false"
+            />
+
+        <service
+            android:name=".statusbar.tablet.TabletStatusBarService"
             android:exported="false"
             />
 
diff --git a/packages/SystemUI/res/drawable/notification_dragger.png b/packages/SystemUI/res/drawable/notification_dragger.png
new file mode 100644
index 0000000..fad1f32
--- /dev/null
+++ b/packages/SystemUI/res/drawable/notification_dragger.png
Binary files differ
diff --git a/packages/SystemUI/res/layout-xlarge/status_bar.xml b/packages/SystemUI/res/layout-xlarge/status_bar.xml
new file mode 100644
index 0000000..1e93bee
--- /dev/null
+++ b/packages/SystemUI/res/layout-xlarge/status_bar.xml
@@ -0,0 +1,155 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/* apps/common/assets/default/default/skins/StatusBar.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License"); 
+** you may not use this file except in compliance with the License. 
+** You may obtain a copy of the License at 
+**
+**     http://www.apache.org/licenses/LICENSE-2.0 
+**
+** Unless required by applicable law or agreed to in writing, software 
+** distributed under the License is distributed on an "AS IS" BASIS, 
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+** See the License for the specific language governing permissions and 
+** limitations under the License.
+*/
+-->
+
+<!--    android:background="@drawable/status_bar_closed_default_background" -->
+<FrameLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:systemui="http://schemas.android.com/apk/res/com.android.systemui"
+    android:background="@drawable/status_bar_background"
+    android:orientation="vertical"
+    android:focusable="true"
+    android:descendantFocusability="afterDescendants"
+    >
+
+    <RelativeLayout android:id="@+id/icons"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:orientation="horizontal">
+            
+<!--
+        <LinearLayout android:id="@+id/statusIcons"
+            android:layout_width="wrap_content"
+            android:layout_height="match_parent"
+            android:layout_alignParentRight="true"
+            android:paddingRight="6dip"
+            android:gravity="center_vertical"
+            android:orientation="horizontal"/>    
+-->
+
+        <com.android.systemui.statusbar.tablet.NotificationIconArea
+            android:id="@+id/notificationIcons"
+            android:layout_width="wrap_content"
+            android:layout_height="match_parent"
+            android:layout_alignParentLeft="true"
+            android:layout_marginLeft="10dp"
+            android:paddingLeft="6dip"
+            android:gravity="center_vertical"
+            android:orientation="horizontal"
+            />  
+            
+        <RelativeLayout android:id="@+id/icons"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_centerInParent="true"
+            >
+
+            <com.android.systemui.statusbar.Clock
+                android:textAppearance="@*android:style/TextAppearance.StatusBar.Icon"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_centerHorizontal="true"
+                android:singleLine="true"
+                android:textSize="16sp"
+                android:textStyle="bold"
+                />
+        </RelativeLayout>
+
+        <com.android.systemui.statusbar.KeyButtonView android:id="@+id/back"
+            android:layout_width="wrap_content"
+            android:layout_height="@*android:dimen/status_bar_height"
+            android:layout_toLeftOf="@+id/menu"
+            android:layout_marginRight="10dp"
+            android:src="@drawable/status_bar_back"
+            systemui:keyCode="4"
+            />
+        <com.android.systemui.statusbar.KeyButtonView android:id="@+id/menu"
+            android:layout_width="wrap_content"
+            android:layout_height="@*android:dimen/status_bar_height"
+            android:layout_toLeftOf="@+id/home"
+            android:src="@drawable/status_bar_menu"
+            android:layout_marginRight="10dp"
+            systemui:keyCode="82"
+            />
+        <com.android.systemui.statusbar.KeyButtonView android:id="@+id/home"
+            android:layout_width="wrap_content"
+            android:layout_height="@*android:dimen/status_bar_height"
+            android:layout_alignParentRight="true"
+            android:layout_marginRight="10dp"
+            android:src="@drawable/status_bar_home"
+            systemui:keyCode="3"
+            />
+            
+    </RelativeLayout>
+<!--
+        
+    <LinearLayout android:id="@+id/ticker"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:paddingLeft="6dip"
+        android:animationCache="false"
+        android:orientation="horizontal" >
+        <ImageSwitcher android:id="@+id/tickerIcon"
+            android:layout_width="wrap_content"
+            android:layout_height="match_parent"
+            android:layout_marginRight="8dip"
+            >
+            <com.android.systemui.statusbar.AnimatedImageView
+                android:layout_width="25dip"
+                android:layout_height="25dip"
+                />
+            <com.android.systemui.statusbar.AnimatedImageView
+                android:layout_width="25dip"
+                android:layout_height="25dip"
+                />
+        </ImageSwitcher>
+        <com.android.systemui.statusbar.TickerView android:id="@+id/tickerText"
+            android:layout_width="0dip"
+            android:layout_weight="1"
+            android:layout_height="wrap_content"
+            android:paddingTop="2dip"
+            android:paddingRight="10dip">
+            <TextView
+                android:textAppearance="@*android:style/TextAppearance.StatusBar.Ticker"
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:singleLine="true"
+                />
+            <TextView
+                android:textAppearance="@*android:style/TextAppearance.StatusBar.Ticker"
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:singleLine="true"
+                />
+        </com.android.systemui.statusbar.TickerView>
+    </LinearLayout>
+
+    <com.android.systemui.statusbar.DateView android:id="@+id/date"
+        android:textAppearance="@*android:style/TextAppearance.StatusBar.Icon"
+        android:layout_width="wrap_content"
+        android:layout_height="match_parent"
+        android:singleLine="true"
+        android:gravity="center_vertical|left"
+        android:paddingLeft="6px"
+        android:paddingRight="6px"
+        android:background="@drawable/status_bar_background"
+        />
+-->
+</FrameLayout>
+
diff --git a/packages/SystemUI/res/layout/status_bar.xml b/packages/SystemUI/res/layout/status_bar.xml
index 4667149..2f1b36e8 100644
--- a/packages/SystemUI/res/layout/status_bar.xml
+++ b/packages/SystemUI/res/layout/status_bar.xml
@@ -60,33 +60,6 @@
             android:textStyle="bold"
             android:gravity="center_vertical|left"
             />
-
-        <LinearLayout android:id="@+id/buttons"
-            android:layout_width="wrap_content"
-            android:layout_height="match_parent"
-            android:paddingLeft="6dip"
-            android:orientation="horizontal" >
-
-            <com.android.systemui.statusbar.KeyButtonView android:id="@+id/back"
-                android:layout_width="wrap_content"
-                android:layout_height="@*android:dimen/status_bar_height"
-                android:src="@drawable/status_bar_back"
-                systemui:keyCode="4"
-                />
-            <com.android.systemui.statusbar.KeyButtonView android:id="@+id/menu"
-                android:layout_width="wrap_content"
-                android:layout_height="@*android:dimen/status_bar_height"
-                android:src="@drawable/status_bar_menu"
-                systemui:keyCode="82"
-                />
-            <com.android.systemui.statusbar.KeyButtonView android:id="@+id/home"
-                android:layout_width="wrap_content"
-                android:layout_height="@*android:dimen/status_bar_height"
-                android:src="@drawable/status_bar_home"
-                systemui:keyCode="3"
-                />
-        </LinearLayout>
-            
     </LinearLayout>
         
     <LinearLayout android:id="@+id/ticker"
diff --git a/packages/SystemUI/res/layout/unused.xml b/packages/SystemUI/res/layout/unused.xml
deleted file mode 100644
index 05a7d7d..0000000
--- a/packages/SystemUI/res/layout/unused.xml
+++ /dev/null
@@ -1,4 +0,0 @@
-<Unused
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    android:id="@+id/buttons">
-</Unused>
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/CloseDragHandle.java b/packages/SystemUI/src/com/android/systemui/statusbar/CloseDragHandle.java
index f45caf51..0f6723e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/CloseDragHandle.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/CloseDragHandle.java
@@ -23,7 +23,7 @@
 
 
 public class CloseDragHandle extends LinearLayout {
-    StatusBarService mService;
+    PhoneStatusBarService mService;
 
     public CloseDragHandle(Context context, AttributeSet attrs) {
         super(context, attrs);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
index f9347b1..2c0af65 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
@@ -32,7 +32,7 @@
  * coalescing these calls so they don't stack up.  For the calls
  * are coalesced, note that they are all idempotent.
  */
-class CommandQueue extends IStatusBar.Stub {
+public class CommandQueue extends IStatusBar.Stub {
     private static final String TAG = "StatusBar.CommandQueue";
 
     private static final int MSG_MASK = 0xffff0000;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandedView.java b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandedView.java
index 3d85f27..a2d4b95 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandedView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandedView.java
@@ -27,7 +27,7 @@
 
 
 public class ExpandedView extends LinearLayout {
-    StatusBarService mService;
+    PhoneStatusBarService mService;
     int mPrevHeight = -1;
 
     public ExpandedView(Context context, AttributeSet attrs) {
@@ -53,7 +53,7 @@
              //Slog.d(StatusBarService.TAG, "height changed old=" + mPrevHeight
              //     + " new=" + height);
              mPrevHeight = height;
-             mService.updateExpandedViewPos(StatusBarService.EXPANDED_LEAVE_ALONE);
+             mService.updateExpandedViewPos(PhoneStatusBarService.EXPANDED_LEAVE_ALONE);
          }
      }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/PhoneStatusBarService.java b/packages/SystemUI/src/com/android/systemui/statusbar/PhoneStatusBarService.java
new file mode 100644
index 0000000..eff9a1d
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/PhoneStatusBarService.java
@@ -0,0 +1,1552 @@
+/*
+ * 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 com.android.systemui.statusbar;
+
+import android.app.Service;
+import android.app.ActivityManagerNative;
+import android.app.Dialog;
+import android.app.Notification;
+import android.app.PendingIntent;
+import android.app.Service;
+import android.app.StatusBarManager;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.pm.PackageManager;
+import android.content.res.Resources;
+import android.graphics.PixelFormat;
+import android.graphics.Rect;
+import android.graphics.drawable.Drawable;
+import android.net.Uri;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.os.Binder;
+import android.os.Handler;
+import android.os.Message;
+import android.os.SystemClock;
+import android.util.Slog;
+import android.util.Log;
+import android.view.Display;
+import android.view.Gravity;
+import android.view.KeyEvent;
+import android.view.LayoutInflater;
+import android.view.MotionEvent;
+import android.view.VelocityTracker;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.Window;
+import android.view.WindowManager;
+import android.view.WindowManagerImpl;
+import android.view.animation.Animation;
+import android.view.animation.AnimationUtils;
+import android.widget.ImageView;
+import android.widget.LinearLayout;
+import android.widget.RemoteViews;
+import android.widget.ScrollView;
+import android.widget.TextView;
+import android.widget.FrameLayout;
+
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Set;
+
+import com.android.internal.statusbar.IStatusBar;
+import com.android.internal.statusbar.IStatusBarService;
+import com.android.internal.statusbar.StatusBarIcon;
+import com.android.internal.statusbar.StatusBarIconList;
+import com.android.internal.statusbar.StatusBarNotification;
+
+import com.android.systemui.R;
+import com.android.systemui.statusbar.policy.StatusBarPolicy;
+
+
+
+public class PhoneStatusBarService extends StatusBarService {
+    static final String TAG = "PhoneStatusBarService";
+    static final boolean SPEW = false;
+
+    public static final String ACTION_STATUSBAR_START
+            = "com.android.internal.policy.statusbar.START";
+
+    static final int EXPANDED_LEAVE_ALONE = -10000;
+    static final int EXPANDED_FULL_OPEN = -10001;
+
+    private static final int MSG_ANIMATE = 1000;
+    private static final int MSG_ANIMATE_REVEAL = 1001;
+    private static final int MSG_SHOW_INTRUDER = 1002;
+    private static final int MSG_HIDE_INTRUDER = 1003;
+
+    // will likely move to a resource or other tunable param at some point
+    private static final int INTRUDER_ALERT_DECAY_MS = 10000;
+
+    StatusBarPolicy mIconPolicy;
+
+    int mIconSize;
+    Display mDisplay;
+
+    StatusBarView mStatusBarView;
+    int mPixelFormat;
+    H mHandler = new H();
+    Object mQueueLock = new Object();
+
+    // icons
+    LinearLayout mIcons;
+    IconMerger mNotificationIcons;
+    LinearLayout mStatusIcons;
+
+    // expanded notifications
+    Dialog mExpandedDialog;
+    ExpandedView mExpandedView;
+    WindowManager.LayoutParams mExpandedParams;
+    ScrollView mScrollView;
+    View mNotificationLinearLayout;
+    View mExpandedContents;
+    // top bar
+    TextView mNoNotificationsTitle;
+    TextView mClearButton;
+    // drag bar
+    CloseDragHandle mCloseView;
+    // ongoing
+    NotificationData mOngoing = new NotificationData();
+    TextView mOngoingTitle;
+    LinearLayout mOngoingItems;
+    // latest
+    NotificationData mLatest = new NotificationData();
+    TextView mLatestTitle;
+    LinearLayout mLatestItems;
+    // position
+    int[] mPositionTmp = new int[2];
+    boolean mExpanded;
+    boolean mExpandedVisible;
+
+    // the date view
+    DateView mDateView;
+
+    // for immersive activities
+    private View mIntruderAlertView;
+
+    // the tracker view
+    TrackingView mTrackingView;
+    WindowManager.LayoutParams mTrackingParams;
+    int mTrackingPosition; // the position of the top of the tracking view.
+    private boolean mPanelSlightlyVisible;
+
+    // ticker
+    private Ticker mTicker;
+    private View mTickerView;
+    private boolean mTicking;
+
+    // Tracking finger for opening/closing.
+    int mEdgeBorder; // corresponds to R.dimen.status_bar_edge_ignore
+    boolean mTracking;
+    VelocityTracker mVelocityTracker;
+
+    static final int ANIM_FRAME_DURATION = (1000/60);
+
+    boolean mAnimating;
+    long mCurAnimationTime;
+    float mDisplayHeight;
+    float mAnimY;
+    float mAnimVel;
+    float mAnimAccel;
+    long mAnimLastTime;
+    boolean mAnimatingReveal = false;
+    int mViewDelta;
+    int[] mAbsPos = new int[2];
+
+    // for disabling the status bar
+    int mDisabled = 0;
+
+    private class ExpandedDialog extends Dialog {
+        ExpandedDialog(Context context) {
+            super(context, com.android.internal.R.style.Theme_Light_NoTitleBar);
+        }
+
+        @Override
+        public boolean dispatchKeyEvent(KeyEvent event) {
+            boolean down = event.getAction() == KeyEvent.ACTION_DOWN;
+            switch (event.getKeyCode()) {
+            case KeyEvent.KEYCODE_BACK:
+                if (!down) {
+                    animateCollapse();
+                }
+                return true;
+            }
+            return super.dispatchKeyEvent(event);
+        }
+    }
+
+    @Override
+    public void onCreate() {
+        mDisplay = ((WindowManager)getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay();
+
+        super.onCreate();
+
+        addIntruderView();
+
+        // Lastly, call to the icon policy to install/update all the icons.
+        mIconPolicy = new StatusBarPolicy(this);
+    }
+
+    @Override
+    public void onDestroy() {
+        // we're never destroyed
+    }
+
+    // ================================================================================
+    // Constructing the view
+    // ================================================================================
+    protected View makeStatusBarView() {
+        final Context context = this;
+
+        Resources res = context.getResources();
+
+        mIconSize = res.getDimensionPixelSize(com.android.internal.R.dimen.status_bar_icon_size);
+
+        ExpandedView expanded = (ExpandedView)View.inflate(context,
+                R.layout.status_bar_expanded, null);
+        expanded.mService = this;
+
+        mIntruderAlertView = View.inflate(context, R.layout.intruder_alert, null);
+        mIntruderAlertView.setVisibility(View.GONE);
+        mIntruderAlertView.setClickable(true);
+
+        StatusBarView sb = (StatusBarView)View.inflate(context, R.layout.status_bar, null);
+        sb.mService = this;
+
+        // figure out which pixel-format to use for the status bar.
+        mPixelFormat = PixelFormat.TRANSLUCENT;
+        Drawable bg = sb.getBackground();
+        if (bg != null) {
+            mPixelFormat = bg.getOpacity();
+        }
+
+        mStatusBarView = sb;
+        mStatusIcons = (LinearLayout)sb.findViewById(R.id.statusIcons);
+        mNotificationIcons = (IconMerger)sb.findViewById(R.id.notificationIcons);
+        mIcons = (LinearLayout)sb.findViewById(R.id.icons);
+        mTickerView = sb.findViewById(R.id.ticker);
+        mDateView = (DateView)sb.findViewById(R.id.date);
+
+        mExpandedDialog = new ExpandedDialog(context);
+        mExpandedView = expanded;
+        mExpandedContents = expanded.findViewById(R.id.notificationLinearLayout);
+        mOngoingTitle = (TextView)expanded.findViewById(R.id.ongoingTitle);
+        mOngoingItems = (LinearLayout)expanded.findViewById(R.id.ongoingItems);
+        mLatestTitle = (TextView)expanded.findViewById(R.id.latestTitle);
+        mLatestItems = (LinearLayout)expanded.findViewById(R.id.latestItems);
+        mNoNotificationsTitle = (TextView)expanded.findViewById(R.id.noNotificationsTitle);
+        mClearButton = (TextView)expanded.findViewById(R.id.clear_all_button);
+        mClearButton.setOnClickListener(mClearButtonListener);
+        mScrollView = (ScrollView)expanded.findViewById(R.id.scroll);
+        mNotificationLinearLayout = expanded.findViewById(R.id.notificationLinearLayout);
+
+        mOngoingTitle.setVisibility(View.GONE);
+        mLatestTitle.setVisibility(View.GONE);
+
+        mTicker = new MyTicker(context, sb);
+
+        TickerView tickerView = (TickerView)sb.findViewById(R.id.tickerText);
+        tickerView.mTicker = mTicker;
+
+        mTrackingView = (TrackingView)View.inflate(context, R.layout.status_bar_tracking, null);
+        mTrackingView.mService = this;
+        mCloseView = (CloseDragHandle)mTrackingView.findViewById(R.id.close);
+        mCloseView.mService = this;
+
+        mEdgeBorder = res.getDimensionPixelSize(R.dimen.status_bar_edge_ignore);
+
+        // the more notifications icon
+        StatusBarIconView moreView = new StatusBarIconView(this, "more");
+        moreView.set(new StatusBarIcon(null, R.drawable.stat_notify_more, 0));
+        mNotificationIcons.addMoreView(moreView,
+                new LinearLayout.LayoutParams(mIconSize, mIconSize));
+
+        // set the inital view visibility
+        setAreThereNotifications();
+        mDateView.setVisibility(View.INVISIBLE);
+
+        // receive broadcasts
+        IntentFilter filter = new IntentFilter();
+        filter.addAction(Intent.ACTION_CONFIGURATION_CHANGED);
+        filter.addAction(Intent.ACTION_CLOSE_SYSTEM_DIALOGS);
+        filter.addAction(Intent.ACTION_SCREEN_OFF);
+        context.registerReceiver(mBroadcastReceiver, filter);
+
+        return sb;
+    }
+
+    protected int getStatusBarGravity() {
+        return Gravity.TOP | Gravity.FILL_HORIZONTAL;
+    }
+
+    private void addIntruderView() {
+        final Resources res = getResources();
+        final int height= res.getDimensionPixelSize(com.android.internal.R.dimen.status_bar_height);
+
+        WindowManager.LayoutParams lp = new WindowManager.LayoutParams(
+                ViewGroup.LayoutParams.MATCH_PARENT,
+                ViewGroup.LayoutParams.WRAP_CONTENT,
+                WindowManager.LayoutParams.TYPE_STATUS_BAR_PANEL,
+                WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN
+                    | WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS
+                    | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
+                    | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
+                    | WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM,
+                PixelFormat.TRANSLUCENT);
+        lp.gravity = Gravity.TOP | Gravity.FILL_HORIZONTAL;
+        lp.y += height * 1.5; // FIXME
+        lp.setTitle("IntruderAlert");
+        lp.windowAnimations = com.android.internal.R.style.Animation_StatusBar_IntruderAlert;
+
+        WindowManagerImpl.getDefault().addView(mIntruderAlertView, lp);
+    }
+
+    public void addIcon(String slot, int index, int viewIndex, StatusBarIcon icon) {
+        if (SPEW) Slog.d(TAG, "addIcon slot=" + slot + " index=" + index + " viewIndex=" + viewIndex
+                + " icon=" + icon);
+        StatusBarIconView view = new StatusBarIconView(this, slot);
+        view.set(icon);
+        mStatusIcons.addView(view, viewIndex, new LinearLayout.LayoutParams(mIconSize, mIconSize));
+    }
+
+    public void updateIcon(String slot, int index, int viewIndex,
+            StatusBarIcon old, StatusBarIcon icon) {
+        if (SPEW) Slog.d(TAG, "updateIcon slot=" + slot + " index=" + index + " viewIndex=" + viewIndex
+                + " old=" + old + " icon=" + icon);
+        StatusBarIconView view = (StatusBarIconView)mStatusIcons.getChildAt(viewIndex);
+        view.set(icon);
+    }
+
+    public void removeIcon(String slot, int index, int viewIndex) {
+        if (SPEW) Slog.d(TAG, "removeIcon slot=" + slot + " index=" + index + " viewIndex=" + viewIndex);
+        mStatusIcons.removeViewAt(viewIndex);
+    }
+
+    public void addNotification(IBinder key, StatusBarNotification notification) {
+        StatusBarIconView iconView = addNotificationViews(key, notification);
+        if (iconView == null) return;
+
+        boolean immersive = false;
+        try {
+            immersive = ActivityManagerNative.getDefault().isTopActivityImmersive();
+            Slog.d(TAG, "Top activity is " + (immersive?"immersive":"not immersive"));
+        } catch (RemoteException ex) {
+        }
+        if (immersive) {
+            if ((notification.notification.flags & Notification.FLAG_HIGH_PRIORITY) != 0) {
+                Slog.d(TAG, "Presenting high-priority notification in immersive activity");
+                // @@@ special new transient ticker mode
+                // 1. Populate mIntruderAlertView
+
+                ImageView alertIcon = (ImageView) mIntruderAlertView.findViewById(R.id.alertIcon);
+                TextView alertText = (TextView) mIntruderAlertView.findViewById(R.id.alertText);
+                alertIcon.setImageDrawable(StatusBarIconView.getIcon(
+                    alertIcon.getContext(),
+                    iconView.getStatusBarIcon()));
+                alertText.setText(notification.notification.tickerText);
+
+                View button = mIntruderAlertView.findViewById(R.id.intruder_alert_content);
+                button.setOnClickListener(
+                    new Launcher(notification.notification.contentIntent,
+                        notification.pkg, notification.tag, notification.id));
+
+                // 2. Animate mIntruderAlertView in
+                mHandler.sendEmptyMessage(MSG_SHOW_INTRUDER);
+
+                // 3. Set alarm to age the notification off (TODO)
+                mHandler.removeMessages(MSG_HIDE_INTRUDER);
+                mHandler.sendEmptyMessageDelayed(MSG_HIDE_INTRUDER, INTRUDER_ALERT_DECAY_MS);
+            }
+        } else if (notification.notification.fullScreenIntent != null) {
+            // not immersive & a full-screen alert should be shown
+            Slog.d(TAG, "Notification has fullScreenIntent and activity is not immersive;"
+                    + " sending fullScreenIntent");
+            try {
+                notification.notification.fullScreenIntent.send();
+            } catch (PendingIntent.CanceledException e) {
+            }
+        } else {
+            // usual case: status bar visible & not immersive
+
+            // show the ticker
+            tick(notification);
+        }
+
+        // Recalculate the position of the sliding windows and the titles.
+        setAreThereNotifications();
+        updateExpandedViewPos(EXPANDED_LEAVE_ALONE);
+    }
+
+    public void updateNotification(IBinder key, StatusBarNotification notification) {
+        Slog.d(TAG, "updateNotification key=" + key + " notification=" + notification);
+
+        NotificationData oldList;
+        int oldIndex = mOngoing.findEntry(key);
+        if (oldIndex >= 0) {
+            oldList = mOngoing;
+        } else {
+            oldIndex = mLatest.findEntry(key);
+            if (oldIndex < 0) {
+                Slog.w(TAG, "updateNotification for unknown key: " + key);
+                return;
+            }
+            oldList = mLatest;
+        }
+        final NotificationData.Entry oldEntry = oldList.getEntryAt(oldIndex);
+        final StatusBarNotification oldNotification = oldEntry.notification;
+        final RemoteViews oldContentView = oldNotification.notification.contentView;
+
+        final RemoteViews contentView = notification.notification.contentView;
+
+        if (false) {
+            Slog.d(TAG, "old notification: when=" + oldNotification.notification.when
+                    + " ongoing=" + oldNotification.isOngoing()
+                    + " expanded=" + oldEntry.expanded
+                    + " contentView=" + oldContentView);
+            Slog.d(TAG, "new notification: when=" + notification.notification.when
+                    + " ongoing=" + oldNotification.isOngoing()
+                    + " contentView=" + contentView);
+        }
+
+        // Can we just reapply the RemoteViews in place?  If when didn't change, the order
+        // didn't change.
+        if (notification.notification.when == oldNotification.notification.when
+                && notification.isOngoing() == oldNotification.isOngoing()
+                && oldEntry.expanded != null
+                && contentView != null && oldContentView != null
+                && contentView.getPackage() != null
+                && oldContentView.getPackage() != null
+                && oldContentView.getPackage().equals(contentView.getPackage())
+                && oldContentView.getLayoutId() == contentView.getLayoutId()) {
+            if (SPEW) Slog.d(TAG, "reusing notification");
+            oldEntry.notification = notification;
+            try {
+                // Reapply the RemoteViews
+                contentView.reapply(this, oldEntry.content);
+                // update the contentIntent
+                final PendingIntent contentIntent = notification.notification.contentIntent;
+                if (contentIntent != null) {
+                    oldEntry.content.setOnClickListener(new Launcher(contentIntent,
+                                notification.pkg, notification.tag, notification.id));
+                }
+                // Update the icon.
+                final StatusBarIcon ic = new StatusBarIcon(notification.pkg,
+                        notification.notification.icon, notification.notification.iconLevel,
+                        notification.notification.number);
+                if (!oldEntry.icon.set(ic)) {
+                    handleNotificationError(key, notification, "Couldn't update icon: " + ic);
+                    return;
+                }
+            }
+            catch (RuntimeException e) {
+                // It failed to add cleanly.  Log, and remove the view from the panel.
+                Slog.w(TAG, "Couldn't reapply views for package " + contentView.getPackage(), e);
+                removeNotificationViews(key);
+                addNotificationViews(key, notification);
+            }
+        } else {
+            if (SPEW) Slog.d(TAG, "not reusing notification");
+            removeNotificationViews(key);
+            addNotificationViews(key, notification);
+        }
+
+        // Restart the ticker if it's still running
+        tick(notification);
+
+        // Recalculate the position of the sliding windows and the titles.
+        setAreThereNotifications();
+        updateExpandedViewPos(EXPANDED_LEAVE_ALONE);
+    }
+
+    public void removeNotification(IBinder key) {
+        if (SPEW) Slog.d(TAG, "removeNotification key=" + key);
+        StatusBarNotification old = removeNotificationViews(key);
+
+        if (old != null) {
+            // Cancel the ticker if it's still running
+            mTicker.removeEntry(old);
+
+            // Recalculate the position of the sliding windows and the titles.
+            setAreThereNotifications();
+            updateExpandedViewPos(EXPANDED_LEAVE_ALONE);
+        }
+    }
+
+    private int chooseIconIndex(boolean isOngoing, int viewIndex) {
+        final int latestSize = mLatest.size();
+        if (isOngoing) {
+            return latestSize + (mOngoing.size() - viewIndex);
+        } else {
+            return latestSize - viewIndex;
+        }
+    }
+
+    View[] makeNotificationView(StatusBarNotification notification, ViewGroup parent) {
+        Notification n = notification.notification;
+        RemoteViews remoteViews = n.contentView;
+        if (remoteViews == null) {
+            return null;
+        }
+
+        // create the row view
+        LayoutInflater inflater = (LayoutInflater)getSystemService(Context.LAYOUT_INFLATER_SERVICE);
+        View row = inflater.inflate(R.layout.status_bar_latest_event, parent, false);
+
+        // bind the click event to the content area
+        ViewGroup content = (ViewGroup)row.findViewById(R.id.content);
+        content.setDescendantFocusability(ViewGroup.FOCUS_BLOCK_DESCENDANTS);
+        content.setOnFocusChangeListener(mFocusChangeListener);
+        PendingIntent contentIntent = n.contentIntent;
+        if (contentIntent != null) {
+            content.setOnClickListener(new Launcher(contentIntent, notification.pkg,
+                        notification.tag, notification.id));
+        }
+
+        View expanded = null;
+        Exception exception = null;
+        try {
+            expanded = remoteViews.apply(this, content);
+        }
+        catch (RuntimeException e) {
+            exception = e;
+        }
+        if (expanded == null) {
+            String ident = notification.pkg + "/0x" + Integer.toHexString(notification.id);
+            Slog.e(TAG, "couldn't inflate view for notification " + ident, exception);
+            return null;
+        } else {
+            content.addView(expanded);
+            row.setDrawingCacheEnabled(true);
+        }
+
+        return new View[] { row, content, expanded };
+    }
+
+    StatusBarIconView addNotificationViews(IBinder key, StatusBarNotification notification) {
+        NotificationData list;
+        ViewGroup parent;
+        final boolean isOngoing = notification.isOngoing();
+        if (isOngoing) {
+            list = mOngoing;
+            parent = mOngoingItems;
+        } else {
+            list = mLatest;
+            parent = mLatestItems;
+        }
+        // Construct the expanded view.
+        final View[] views = makeNotificationView(notification, parent);
+        if (views == null) {
+            handleNotificationError(key, notification, "Couldn't expand RemoteViews for: "
+                    + notification);
+            return null;
+        }
+        final View row = views[0];
+        final View content = views[1];
+        final View expanded = views[2];
+        // Construct the icon.
+        final StatusBarIconView iconView = new StatusBarIconView(this,
+                notification.pkg + "/0x" + Integer.toHexString(notification.id));
+        final StatusBarIcon ic = new StatusBarIcon(notification.pkg, notification.notification.icon,
+                    notification.notification.iconLevel, notification.notification.number);
+        if (!iconView.set(ic)) {
+            handleNotificationError(key, notification, "Coulding create icon: " + ic);
+            return null;
+        }
+        // Add the expanded view.
+        final int viewIndex = list.add(key, notification, row, content, expanded, iconView);
+        parent.addView(row, viewIndex);
+        // Add the icon.
+        final int iconIndex = chooseIconIndex(isOngoing, viewIndex);
+        mNotificationIcons.addView(iconView, iconIndex,
+                new LinearLayout.LayoutParams(mIconSize, mIconSize));
+        return iconView;
+    }
+
+    StatusBarNotification removeNotificationViews(IBinder key) {
+        NotificationData.Entry entry = mOngoing.remove(key);
+        if (entry == null) {
+            entry = mLatest.remove(key);
+            if (entry == null) {
+                Slog.w(TAG, "removeNotification for unknown key: " + key);
+                return null;
+            }
+        }
+        // Remove the expanded view.
+        ((ViewGroup)entry.row.getParent()).removeView(entry.row);
+        // Remove the icon.
+        ((ViewGroup)entry.icon.getParent()).removeView(entry.icon);
+
+        return entry.notification;
+    }
+
+    private void setAreThereNotifications() {
+        boolean ongoing = mOngoing.hasVisibleItems();
+        boolean latest = mLatest.hasVisibleItems();
+
+        // (no ongoing notifications are clearable)
+        if (mLatest.hasClearableItems()) {
+            mClearButton.setVisibility(View.VISIBLE);
+        } else {
+            mClearButton.setVisibility(View.INVISIBLE);
+        }
+
+        mOngoingTitle.setVisibility(ongoing ? View.VISIBLE : View.GONE);
+        mLatestTitle.setVisibility(latest ? View.VISIBLE : View.GONE);
+
+        if (ongoing || latest) {
+            mNoNotificationsTitle.setVisibility(View.GONE);
+        } else {
+            mNoNotificationsTitle.setVisibility(View.VISIBLE);
+        }
+    }
+
+
+    /**
+     * State is one or more of the DISABLE constants from StatusBarManager.
+     */
+    public void disable(int state) {
+        final int old = mDisabled;
+        final int diff = state ^ old;
+        mDisabled = state;
+
+        if ((diff & StatusBarManager.DISABLE_EXPAND) != 0) {
+            if ((state & StatusBarManager.DISABLE_EXPAND) != 0) {
+                Slog.d(TAG, "DISABLE_EXPAND: yes");
+                animateCollapse();
+            }
+        }
+        if ((diff & StatusBarManager.DISABLE_NOTIFICATION_ICONS) != 0) {
+            if ((state & StatusBarManager.DISABLE_NOTIFICATION_ICONS) != 0) {
+                Slog.d(TAG, "DISABLE_NOTIFICATION_ICONS: yes");
+                if (mTicking) {
+                    mTicker.halt();
+                } else {
+                    setNotificationIconVisibility(false, com.android.internal.R.anim.fade_out);
+                }
+            } else {
+                Slog.d(TAG, "DISABLE_NOTIFICATION_ICONS: no");
+                if (!mExpandedVisible) {
+                    setNotificationIconVisibility(true, com.android.internal.R.anim.fade_in);
+                }
+            }
+        } else if ((diff & StatusBarManager.DISABLE_NOTIFICATION_TICKER) != 0) {
+            if (mTicking && (state & StatusBarManager.DISABLE_NOTIFICATION_TICKER) != 0) {
+                Slog.d(TAG, "DISABLE_NOTIFICATION_TICKER: yes");
+                mTicker.halt();
+            }
+        }
+    }
+
+    /**
+     * All changes to the status bar and notifications funnel through here and are batched.
+     */
+    private class H extends Handler {
+        public void handleMessage(Message m) {
+            switch (m.what) {
+                case MSG_ANIMATE:
+                    doAnimation();
+                    break;
+                case MSG_ANIMATE_REVEAL:
+                    doRevealAnimation();
+                    break;
+                case MSG_SHOW_INTRUDER:
+                    setIntruderAlertVisibility(true);
+                    break;
+                case MSG_HIDE_INTRUDER:
+                    setIntruderAlertVisibility(false);
+                    break;
+            }
+        }
+    }
+
+    View.OnFocusChangeListener mFocusChangeListener = new View.OnFocusChangeListener() {
+        public void onFocusChange(View v, boolean hasFocus) {
+            // Because 'v' is a ViewGroup, all its children will be (un)selected
+            // too, which allows marqueeing to work.
+            v.setSelected(hasFocus);
+        }
+    };
+
+    private void makeExpandedVisible() {
+        if (SPEW) Slog.d(TAG, "Make expanded visible: expanded visible=" + mExpandedVisible);
+        if (mExpandedVisible) {
+            return;
+        }
+        mExpandedVisible = true;
+        visibilityChanged(true);
+
+        updateExpandedViewPos(EXPANDED_LEAVE_ALONE);
+        mExpandedParams.flags &= ~WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
+        mExpandedParams.flags |= WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM;
+        mExpandedDialog.getWindow().setAttributes(mExpandedParams);
+        mExpandedView.requestFocus(View.FOCUS_FORWARD);
+        mTrackingView.setVisibility(View.VISIBLE);
+
+        if (!mTicking) {
+            setDateViewVisibility(true, com.android.internal.R.anim.fade_in);
+        }
+    }
+
+    public void animateExpand() {
+        if (SPEW) Slog.d(TAG, "Animate expand: expanded=" + mExpanded);
+        if ((mDisabled & StatusBarManager.DISABLE_EXPAND) != 0) {
+            return ;
+        }
+        if (mExpanded) {
+            return;
+        }
+
+        prepareTracking(0, true);
+        performFling(0, 2000.0f, true);
+    }
+
+    public void animateCollapse() {
+        if (SPEW) {
+            Slog.d(TAG, "animateCollapse(): mExpanded=" + mExpanded
+                    + " mExpandedVisible=" + mExpandedVisible
+                    + " mExpanded=" + mExpanded
+                    + " mAnimating=" + mAnimating
+                    + " mAnimY=" + mAnimY
+                    + " mAnimVel=" + mAnimVel);
+        }
+
+        if (!mExpandedVisible) {
+            return;
+        }
+
+        int y;
+        if (mAnimating) {
+            y = (int)mAnimY;
+        } else {
+            y = mDisplay.getHeight()-1;
+        }
+        // Let the fling think that we're open so it goes in the right direction
+        // and doesn't try to re-open the windowshade.
+        mExpanded = true;
+        prepareTracking(y, false);
+        performFling(y, -2000.0f, true);
+    }
+
+    void performExpand() {
+        if (SPEW) Slog.d(TAG, "performExpand: mExpanded=" + mExpanded);
+        if ((mDisabled & StatusBarManager.DISABLE_EXPAND) != 0) {
+            return ;
+        }
+        if (mExpanded) {
+            return;
+        }
+
+        mExpanded = true;
+        makeExpandedVisible();
+        updateExpandedViewPos(EXPANDED_FULL_OPEN);
+
+        if (false) postStartTracing();
+    }
+
+    void performCollapse() {
+        if (SPEW) Slog.d(TAG, "performCollapse: mExpanded=" + mExpanded
+                + " mExpandedVisible=" + mExpandedVisible);
+
+        if (!mExpandedVisible) {
+            return;
+        }
+        mExpandedVisible = false;
+        visibilityChanged(false);
+        mExpandedParams.flags |= WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
+        mExpandedParams.flags &= ~WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM;
+        mExpandedDialog.getWindow().setAttributes(mExpandedParams);
+        mTrackingView.setVisibility(View.GONE);
+
+        if ((mDisabled & StatusBarManager.DISABLE_NOTIFICATION_ICONS) == 0) {
+            setNotificationIconVisibility(true, com.android.internal.R.anim.fade_in);
+        }
+        setDateViewVisibility(false, com.android.internal.R.anim.fade_out);
+
+        if (!mExpanded) {
+            return;
+        }
+        mExpanded = false;
+    }
+
+    void doAnimation() {
+        if (mAnimating) {
+            if (SPEW) Slog.d(TAG, "doAnimation");
+            if (SPEW) Slog.d(TAG, "doAnimation before mAnimY=" + mAnimY);
+            incrementAnim();
+            if (SPEW) Slog.d(TAG, "doAnimation after  mAnimY=" + mAnimY);
+            if (mAnimY >= mDisplay.getHeight()-1) {
+                if (SPEW) Slog.d(TAG, "Animation completed to expanded state.");
+                mAnimating = false;
+                updateExpandedViewPos(EXPANDED_FULL_OPEN);
+                performExpand();
+            }
+            else if (mAnimY < mStatusBarView.getHeight()) {
+                if (SPEW) Slog.d(TAG, "Animation completed to collapsed state.");
+                mAnimating = false;
+                updateExpandedViewPos(0);
+                performCollapse();
+            }
+            else {
+                updateExpandedViewPos((int)mAnimY);
+                mCurAnimationTime += ANIM_FRAME_DURATION;
+                mHandler.sendMessageAtTime(mHandler.obtainMessage(MSG_ANIMATE), mCurAnimationTime);
+            }
+        }
+    }
+
+    void stopTracking() {
+        mTracking = false;
+        mVelocityTracker.recycle();
+        mVelocityTracker = null;
+    }
+
+    void incrementAnim() {
+        long now = SystemClock.uptimeMillis();
+        float t = ((float)(now - mAnimLastTime)) / 1000;            // ms -> s
+        final float y = mAnimY;
+        final float v = mAnimVel;                                   // px/s
+        final float a = mAnimAccel;                                 // px/s/s
+        mAnimY = y + (v*t) + (0.5f*a*t*t);                          // px
+        mAnimVel = v + (a*t);                                       // px/s
+        mAnimLastTime = now;                                        // ms
+        //Slog.d(TAG, "y=" + y + " v=" + v + " a=" + a + " t=" + t + " mAnimY=" + mAnimY
+        //        + " mAnimAccel=" + mAnimAccel);
+    }
+
+    void doRevealAnimation() {
+        final int h = mCloseView.getHeight() + mStatusBarView.getHeight();
+        if (mAnimatingReveal && mAnimating && mAnimY < h) {
+            incrementAnim();
+            if (mAnimY >= h) {
+                mAnimY = h;
+                updateExpandedViewPos((int)mAnimY);
+            } else {
+                updateExpandedViewPos((int)mAnimY);
+                mCurAnimationTime += ANIM_FRAME_DURATION;
+                mHandler.sendMessageAtTime(mHandler.obtainMessage(MSG_ANIMATE_REVEAL),
+                        mCurAnimationTime);
+            }
+        }
+    }
+
+    void prepareTracking(int y, boolean opening) {
+        mTracking = true;
+        mVelocityTracker = VelocityTracker.obtain();
+        if (opening) {
+            mAnimAccel = 2000.0f;
+            mAnimVel = 200;
+            mAnimY = mStatusBarView.getHeight();
+            updateExpandedViewPos((int)mAnimY);
+            mAnimating = true;
+            mAnimatingReveal = true;
+            mHandler.removeMessages(MSG_ANIMATE);
+            mHandler.removeMessages(MSG_ANIMATE_REVEAL);
+            long now = SystemClock.uptimeMillis();
+            mAnimLastTime = now;
+            mCurAnimationTime = now + ANIM_FRAME_DURATION;
+            mAnimating = true;
+            mHandler.sendMessageAtTime(mHandler.obtainMessage(MSG_ANIMATE_REVEAL),
+                    mCurAnimationTime);
+            makeExpandedVisible();
+        } else {
+            // it's open, close it?
+            if (mAnimating) {
+                mAnimating = false;
+                mHandler.removeMessages(MSG_ANIMATE);
+            }
+            updateExpandedViewPos(y + mViewDelta);
+        }
+    }
+
+    void performFling(int y, float vel, boolean always) {
+        mAnimatingReveal = false;
+        mDisplayHeight = mDisplay.getHeight();
+
+        mAnimY = y;
+        mAnimVel = vel;
+
+        //Slog.d(TAG, "starting with mAnimY=" + mAnimY + " mAnimVel=" + mAnimVel);
+
+        if (mExpanded) {
+            if (!always && (
+                    vel > 200.0f
+                    || (y > (mDisplayHeight-25) && vel > -200.0f))) {
+                // We are expanded, but they didn't move sufficiently to cause
+                // us to retract.  Animate back to the expanded position.
+                mAnimAccel = 2000.0f;
+                if (vel < 0) {
+                    mAnimVel = 0;
+                }
+            }
+            else {
+                // We are expanded and are now going to animate away.
+                mAnimAccel = -2000.0f;
+                if (vel > 0) {
+                    mAnimVel = 0;
+                }
+            }
+        } else {
+            if (always || (
+                    vel > 200.0f
+                    || (y > (mDisplayHeight/2) && vel > -200.0f))) {
+                // We are collapsed, and they moved enough to allow us to
+                // expand.  Animate in the notifications.
+                mAnimAccel = 2000.0f;
+                if (vel < 0) {
+                    mAnimVel = 0;
+                }
+            }
+            else {
+                // We are collapsed, but they didn't move sufficiently to cause
+                // us to retract.  Animate back to the collapsed position.
+                mAnimAccel = -2000.0f;
+                if (vel > 0) {
+                    mAnimVel = 0;
+                }
+            }
+        }
+        //Slog.d(TAG, "mAnimY=" + mAnimY + " mAnimVel=" + mAnimVel
+        //        + " mAnimAccel=" + mAnimAccel);
+
+        long now = SystemClock.uptimeMillis();
+        mAnimLastTime = now;
+        mCurAnimationTime = now + ANIM_FRAME_DURATION;
+        mAnimating = true;
+        mHandler.removeMessages(MSG_ANIMATE);
+        mHandler.removeMessages(MSG_ANIMATE_REVEAL);
+        mHandler.sendMessageAtTime(mHandler.obtainMessage(MSG_ANIMATE), mCurAnimationTime);
+        stopTracking();
+    }
+
+    boolean interceptTouchEvent(MotionEvent event) {
+        if (SPEW) {
+            Slog.d(TAG, "Touch: rawY=" + event.getRawY() + " event=" + event + " mDisabled="
+                + mDisabled);
+        }
+
+        if ((mDisabled & StatusBarManager.DISABLE_EXPAND) != 0) {
+            return false;
+        }
+
+        final int statusBarSize = mStatusBarView.getHeight();
+        final int hitSize = statusBarSize*2;
+        if (event.getAction() == MotionEvent.ACTION_DOWN) {
+            final int y = (int)event.getRawY();
+
+            if (!mExpanded) {
+                mViewDelta = statusBarSize - y;
+            } else {
+                mTrackingView.getLocationOnScreen(mAbsPos);
+                mViewDelta = mAbsPos[1] + mTrackingView.getHeight() - y;
+            }
+            if ((!mExpanded && y < hitSize) ||
+                    (mExpanded && y > (mDisplay.getHeight()-hitSize))) {
+
+                // We drop events at the edge of the screen to make the windowshade come
+                // down by accident less, especially when pushing open a device with a keyboard
+                // that rotates (like g1 and droid)
+                int x = (int)event.getRawX();
+                final int edgeBorder = mEdgeBorder;
+                if (x >= edgeBorder && x < mDisplay.getWidth() - edgeBorder) {
+                    prepareTracking(y, !mExpanded);// opening if we're not already fully visible
+                    mVelocityTracker.addMovement(event);
+                }
+            }
+        } else if (mTracking) {
+            mVelocityTracker.addMovement(event);
+            final int minY = statusBarSize + mCloseView.getHeight();
+            if (event.getAction() == MotionEvent.ACTION_MOVE) {
+                int y = (int)event.getRawY();
+                if (mAnimatingReveal && y < minY) {
+                    // nothing
+                } else  {
+                    mAnimatingReveal = false;
+                    updateExpandedViewPos(y + mViewDelta);
+                }
+            } else if (event.getAction() == MotionEvent.ACTION_UP) {
+                mVelocityTracker.computeCurrentVelocity(1000);
+
+                float yVel = mVelocityTracker.getYVelocity();
+                boolean negative = yVel < 0;
+
+                float xVel = mVelocityTracker.getXVelocity();
+                if (xVel < 0) {
+                    xVel = -xVel;
+                }
+                if (xVel > 150.0f) {
+                    xVel = 150.0f; // limit how much we care about the x axis
+                }
+
+                float vel = (float)Math.hypot(yVel, xVel);
+                if (negative) {
+                    vel = -vel;
+                }
+
+                performFling((int)event.getRawY(), vel, false);
+            }
+
+        }
+        return false;
+    }
+
+    private class Launcher implements View.OnClickListener {
+        private PendingIntent mIntent;
+        private String mPkg;
+        private String mTag;
+        private int mId;
+
+        Launcher(PendingIntent intent, String pkg, String tag, int id) {
+            mIntent = intent;
+            mPkg = pkg;
+            mTag = tag;
+            mId = id;
+        }
+
+        public void onClick(View v) {
+            try {
+                // The intent we are sending is for the application, which
+                // won't have permission to immediately start an activity after
+                // the user switches to home.  We know it is safe to do at this
+                // point, so make sure new activity switches are now allowed.
+                ActivityManagerNative.getDefault().resumeAppSwitches();
+            } catch (RemoteException e) {
+            }
+
+            if (mIntent != null) {
+                int[] pos = new int[2];
+                v.getLocationOnScreen(pos);
+                Intent overlay = new Intent();
+                overlay.setSourceBounds(
+                        new Rect(pos[0], pos[1], pos[0]+v.getWidth(), pos[1]+v.getHeight()));
+                try {
+                    mIntent.send(PhoneStatusBarService.this, 0, overlay);
+                } catch (PendingIntent.CanceledException e) {
+                    // the stack trace isn't very helpful here.  Just log the exception message.
+                    Slog.w(TAG, "Sending contentIntent failed: " + e);
+                }
+            }
+
+            try {
+                mBarService.onNotificationClick(mPkg, mTag, mId);
+            } catch (RemoteException ex) {
+                // system process is dead if we're here.
+            }
+
+            // close the shade if it was open
+            animateCollapse();
+
+            // If this click was on the intruder alert, hide that instead
+            mHandler.sendEmptyMessage(MSG_HIDE_INTRUDER);
+        }
+    }
+
+    private void tick(StatusBarNotification n) {
+        // Show the ticker if one is requested. Also don't do this
+        // until status bar window is attached to the window manager,
+        // because...  well, what's the point otherwise?  And trying to
+        // run a ticker without being attached will crash!
+        if (n.notification.tickerText != null && mStatusBarView.getWindowToken() != null) {
+            if (0 == (mDisabled & (StatusBarManager.DISABLE_NOTIFICATION_ICONS
+                            | StatusBarManager.DISABLE_NOTIFICATION_TICKER))) {
+                mTicker.addEntry(n);
+            }
+        }
+    }
+
+    /**
+     * Cancel this notification and tell the StatusBarManagerService / NotificationManagerService
+     * about the failure.
+     *
+     * WARNING: this will call back into us.  Don't hold any locks.
+     */
+    void handleNotificationError(IBinder key, StatusBarNotification n, String message) {
+        removeNotification(key);
+        try {
+            mBarService.onNotificationError(n.pkg, n.tag, n.id, n.uid, n.initialPid, message);
+        } catch (RemoteException ex) {
+            // The end is nigh.
+        }
+    }
+
+    private class MyTicker extends Ticker {
+        MyTicker(Context context, StatusBarView sb) {
+            super(context, sb);
+        }
+
+        @Override
+        void tickerStarting() {
+            mTicking = true;
+            mIcons.setVisibility(View.GONE);
+            mTickerView.setVisibility(View.VISIBLE);
+            mTickerView.startAnimation(loadAnim(com.android.internal.R.anim.push_up_in, null));
+            mIcons.startAnimation(loadAnim(com.android.internal.R.anim.push_up_out, null));
+            if (mExpandedVisible) {
+                setDateViewVisibility(false, com.android.internal.R.anim.push_up_out);
+            }
+        }
+
+        @Override
+        void tickerDone() {
+            mIcons.setVisibility(View.VISIBLE);
+            mTickerView.setVisibility(View.GONE);
+            mIcons.startAnimation(loadAnim(com.android.internal.R.anim.push_down_in, null));
+            mTickerView.startAnimation(loadAnim(com.android.internal.R.anim.push_down_out,
+                        mTickingDoneListener));
+            if (mExpandedVisible) {
+                setDateViewVisibility(true, com.android.internal.R.anim.push_down_in);
+            }
+        }
+
+        void tickerHalting() {
+            mIcons.setVisibility(View.VISIBLE);
+            mTickerView.setVisibility(View.GONE);
+            mIcons.startAnimation(loadAnim(com.android.internal.R.anim.fade_in, null));
+            mTickerView.startAnimation(loadAnim(com.android.internal.R.anim.fade_out,
+                        mTickingDoneListener));
+            if (mExpandedVisible) {
+                setDateViewVisibility(true, com.android.internal.R.anim.fade_in);
+            }
+        }
+    }
+
+    Animation.AnimationListener mTickingDoneListener = new Animation.AnimationListener() {;
+        public void onAnimationEnd(Animation animation) {
+            mTicking = false;
+        }
+        public void onAnimationRepeat(Animation animation) {
+        }
+        public void onAnimationStart(Animation animation) {
+        }
+    };
+
+    private Animation loadAnim(int id, Animation.AnimationListener listener) {
+        Animation anim = AnimationUtils.loadAnimation(PhoneStatusBarService.this, id);
+        if (listener != null) {
+            anim.setAnimationListener(listener);
+        }
+        return anim;
+    }
+
+    public String viewInfo(View v) {
+        return "(" + v.getLeft() + "," + v.getTop() + ")(" + v.getRight() + "," + v.getBottom()
+                + " " + v.getWidth() + "x" + v.getHeight() + ")";
+    }
+
+    protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+        if (checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
+                != PackageManager.PERMISSION_GRANTED) {
+            pw.println("Permission Denial: can't dump StatusBar from from pid="
+                    + Binder.getCallingPid()
+                    + ", uid=" + Binder.getCallingUid());
+            return;
+        }
+
+        synchronized (mQueueLock) {
+            pw.println("Current Status Bar state:");
+            pw.println("  mExpanded=" + mExpanded
+                    + ", mExpandedVisible=" + mExpandedVisible);
+            pw.println("  mTicking=" + mTicking);
+            pw.println("  mTracking=" + mTracking);
+            pw.println("  mAnimating=" + mAnimating
+                    + ", mAnimY=" + mAnimY + ", mAnimVel=" + mAnimVel
+                    + ", mAnimAccel=" + mAnimAccel);
+            pw.println("  mCurAnimationTime=" + mCurAnimationTime
+                    + " mAnimLastTime=" + mAnimLastTime);
+            pw.println("  mDisplayHeight=" + mDisplayHeight
+                    + " mAnimatingReveal=" + mAnimatingReveal
+                    + " mViewDelta=" + mViewDelta);
+            pw.println("  mDisplayHeight=" + mDisplayHeight);
+            pw.println("  mExpandedParams: " + mExpandedParams);
+            pw.println("  mExpandedView: " + viewInfo(mExpandedView));
+            pw.println("  mExpandedDialog: " + mExpandedDialog);
+            pw.println("  mTrackingParams: " + mTrackingParams);
+            pw.println("  mTrackingView: " + viewInfo(mTrackingView));
+            pw.println("  mOngoingTitle: " + viewInfo(mOngoingTitle));
+            pw.println("  mOngoingItems: " + viewInfo(mOngoingItems));
+            pw.println("  mLatestTitle: " + viewInfo(mLatestTitle));
+            pw.println("  mLatestItems: " + viewInfo(mLatestItems));
+            pw.println("  mNoNotificationsTitle: " + viewInfo(mNoNotificationsTitle));
+            pw.println("  mCloseView: " + viewInfo(mCloseView));
+            pw.println("  mTickerView: " + viewInfo(mTickerView));
+            pw.println("  mScrollView: " + viewInfo(mScrollView)
+                    + " scroll " + mScrollView.getScrollX() + "," + mScrollView.getScrollY());
+            pw.println("mNotificationLinearLayout: " + viewInfo(mNotificationLinearLayout));
+        }
+        /*
+        synchronized (mNotificationData) {
+            int N = mNotificationData.ongoingCount();
+            pw.println("  ongoingCount.size=" + N);
+            for (int i=0; i<N; i++) {
+                StatusBarNotification n = mNotificationData.getOngoing(i);
+                pw.println("    [" + i + "] key=" + n.key + " view=" + n.view);
+                pw.println("           data=" + n.data);
+            }
+            N = mNotificationData.latestCount();
+            pw.println("  ongoingCount.size=" + N);
+            for (int i=0; i<N; i++) {
+                StatusBarNotification n = mNotificationData.getLatest(i);
+                pw.println("    [" + i + "] key=" + n.key + " view=" + n.view);
+                pw.println("           data=" + n.data);
+            }
+        }
+        */
+
+        if (false) {
+            pw.println("see the logcat for a dump of the views we have created.");
+            // must happen on ui thread
+            mHandler.post(new Runnable() {
+                    public void run() {
+                        mStatusBarView.getLocationOnScreen(mAbsPos);
+                        Slog.d(TAG, "mStatusBarView: ----- (" + mAbsPos[0] + "," + mAbsPos[1]
+                                + ") " + mStatusBarView.getWidth() + "x"
+                                + mStatusBarView.getHeight());
+                        mStatusBarView.debug();
+
+                        mExpandedView.getLocationOnScreen(mAbsPos);
+                        Slog.d(TAG, "mExpandedView: ----- (" + mAbsPos[0] + "," + mAbsPos[1]
+                                + ") " + mExpandedView.getWidth() + "x"
+                                + mExpandedView.getHeight());
+                        mExpandedView.debug();
+
+                        mTrackingView.getLocationOnScreen(mAbsPos);
+                        Slog.d(TAG, "mTrackingView: ----- (" + mAbsPos[0] + "," + mAbsPos[1]
+                                + ") " + mTrackingView.getWidth() + "x"
+                                + mTrackingView.getHeight());
+                        mTrackingView.debug();
+                    }
+                });
+        }
+    }
+
+    void onBarViewAttached() {
+        WindowManager.LayoutParams lp;
+        int pixelFormat;
+        Drawable bg;
+
+        /// ---------- Tracking View --------------
+        pixelFormat = PixelFormat.RGBX_8888;
+        bg = mTrackingView.getBackground();
+        if (bg != null) {
+            pixelFormat = bg.getOpacity();
+        }
+
+        lp = new WindowManager.LayoutParams(
+                ViewGroup.LayoutParams.MATCH_PARENT,
+                ViewGroup.LayoutParams.MATCH_PARENT,
+                WindowManager.LayoutParams.TYPE_STATUS_BAR_PANEL,
+                WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN
+                | WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS
+                | WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM,
+                pixelFormat);
+//        lp.token = mStatusBarView.getWindowToken();
+        lp.gravity = Gravity.TOP | Gravity.FILL_HORIZONTAL;
+        lp.setTitle("TrackingView");
+        lp.y = mTrackingPosition;
+        mTrackingParams = lp;
+
+        WindowManagerImpl.getDefault().addView(mTrackingView, lp);
+    }
+
+    void onTrackingViewAttached() {
+        WindowManager.LayoutParams lp;
+        int pixelFormat;
+        Drawable bg;
+
+        /// ---------- Expanded View --------------
+        pixelFormat = PixelFormat.TRANSLUCENT;
+
+        final int disph = mDisplay.getHeight();
+        lp = mExpandedDialog.getWindow().getAttributes();
+        lp.width = ViewGroup.LayoutParams.MATCH_PARENT;
+        lp.height = getExpandedHeight();
+        lp.x = 0;
+        mTrackingPosition = lp.y = -disph; // sufficiently large negative
+        lp.type = WindowManager.LayoutParams.TYPE_STATUS_BAR_PANEL;
+        lp.flags = WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN
+                | WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS
+                | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
+                | WindowManager.LayoutParams.FLAG_DITHER
+                | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
+        lp.format = pixelFormat;
+        lp.gravity = Gravity.TOP | Gravity.FILL_HORIZONTAL;
+        lp.setTitle("StatusBarExpanded");
+        mExpandedDialog.getWindow().setAttributes(lp);
+        mExpandedDialog.getWindow().setFormat(pixelFormat);
+        mExpandedParams = lp;
+
+        mExpandedDialog.getWindow().requestFeature(Window.FEATURE_NO_TITLE);
+        mExpandedDialog.setContentView(mExpandedView,
+                new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
+                                           ViewGroup.LayoutParams.MATCH_PARENT));
+        mExpandedDialog.getWindow().setBackgroundDrawable(null);
+        mExpandedDialog.show();
+        FrameLayout hack = (FrameLayout)mExpandedView.getParent();
+    }
+
+    void setDateViewVisibility(boolean visible, int anim) {
+        mDateView.setUpdates(visible);
+        mDateView.setVisibility(visible ? View.VISIBLE : View.INVISIBLE);
+        mDateView.startAnimation(loadAnim(anim, null));
+    }
+
+    void setNotificationIconVisibility(boolean visible, int anim) {
+        int old = mNotificationIcons.getVisibility();
+        int v = visible ? View.VISIBLE : View.INVISIBLE;
+        if (old != v) {
+            mNotificationIcons.setVisibility(v);
+            mNotificationIcons.startAnimation(loadAnim(anim, null));
+        }
+    }
+
+    void updateExpandedViewPos(int expandedPosition) {
+        if (SPEW) {
+            Slog.d(TAG, "updateExpandedViewPos before expandedPosition=" + expandedPosition
+                    + " mTrackingParams.y=" + mTrackingParams.y
+                    + " mTrackingPosition=" + mTrackingPosition);
+        }
+
+        int h = mStatusBarView.getHeight();
+        int disph = mDisplay.getHeight();
+
+        // If the expanded view is not visible, make sure they're still off screen.
+        // Maybe the view was resized.
+        if (!mExpandedVisible) {
+            if (mTrackingView != null) {
+                mTrackingPosition = -disph;
+                if (mTrackingParams != null) {
+                    mTrackingParams.y = mTrackingPosition;
+                    WindowManagerImpl.getDefault().updateViewLayout(mTrackingView, mTrackingParams);
+                }
+            }
+            if (mExpandedParams != null) {
+                mExpandedParams.y = -disph;
+                mExpandedDialog.getWindow().setAttributes(mExpandedParams);
+            }
+            return;
+        }
+
+        // tracking view...
+        int pos;
+        if (expandedPosition == EXPANDED_FULL_OPEN) {
+            pos = h;
+        }
+        else if (expandedPosition == EXPANDED_LEAVE_ALONE) {
+            pos = mTrackingPosition;
+        }
+        else {
+            if (expandedPosition <= disph) {
+                pos = expandedPosition;
+            } else {
+                pos = disph;
+            }
+            pos -= disph-h;
+        }
+        mTrackingPosition = mTrackingParams.y = pos;
+        mTrackingParams.height = disph-h;
+        WindowManagerImpl.getDefault().updateViewLayout(mTrackingView, mTrackingParams);
+
+        if (mExpandedParams != null) {
+            mCloseView.getLocationInWindow(mPositionTmp);
+            final int closePos = mPositionTmp[1];
+
+            mExpandedContents.getLocationInWindow(mPositionTmp);
+            final int contentsBottom = mPositionTmp[1] + mExpandedContents.getHeight();
+
+            mExpandedParams.y = pos + mTrackingView.getHeight()
+                    - (mTrackingParams.height-closePos) - contentsBottom;
+            int max = h;
+            if (mExpandedParams.y > max) {
+                mExpandedParams.y = max;
+            }
+            int min = mTrackingPosition;
+            if (mExpandedParams.y < min) {
+                mExpandedParams.y = min;
+            }
+
+            boolean visible = (mTrackingPosition + mTrackingView.getHeight()) > h;
+            if (!visible) {
+                // if the contents aren't visible, move the expanded view way off screen
+                // because the window itself extends below the content view.
+                mExpandedParams.y = -disph;
+            }
+            mExpandedDialog.getWindow().setAttributes(mExpandedParams);
+
+            // As long as this isn't just a repositioning that's not supposed to affect
+            // the user's perception of what's showing, call to say that the visibility
+            // has changed. (Otherwise, someone else will call to do that).
+            if (expandedPosition != EXPANDED_LEAVE_ALONE) {
+                if (SPEW) Slog.d(TAG, "updateExpandedViewPos visibilityChanged(" + visible + ")");
+                visibilityChanged(visible);
+            }
+        }
+
+        if (SPEW) {
+            Slog.d(TAG, "updateExpandedViewPos after  expandedPosition=" + expandedPosition
+                    + " mTrackingParams.y=" + mTrackingParams.y
+                    + " mTrackingPosition=" + mTrackingPosition
+                    + " mExpandedParams.y=" + mExpandedParams.y
+                    + " mExpandedParams.height=" + mExpandedParams.height);
+        }
+    }
+
+    int getExpandedHeight() {
+        return mDisplay.getHeight() - mStatusBarView.getHeight() - mCloseView.getHeight();
+    }
+
+    void updateExpandedHeight() {
+        if (mExpandedView != null) {
+            mExpandedParams.height = getExpandedHeight();
+            mExpandedDialog.getWindow().setAttributes(mExpandedParams);
+        }
+    }
+
+    /**
+     * The LEDs are turned o)ff when the notification panel is shown, even just a little bit.
+     * This was added last-minute and is inconsistent with the way the rest of the notifications
+     * are handled, because the notification isn't really cancelled.  The lights are just
+     * turned off.  If any other notifications happen, the lights will turn back on.  Steve says
+     * this is what he wants. (see bug 1131461)
+     */
+    void visibilityChanged(boolean visible) {
+        if (mPanelSlightlyVisible != visible) {
+            mPanelSlightlyVisible = visible;
+            try {
+                mBarService.onPanelRevealed();
+            } catch (RemoteException ex) {
+                // Won't fail unless the world has ended.
+            }
+        }
+    }
+
+    void performDisableActions(int net) {
+        int old = mDisabled;
+        int diff = net ^ old;
+        mDisabled = net;
+
+        // act accordingly
+        if ((diff & StatusBarManager.DISABLE_EXPAND) != 0) {
+            if ((net & StatusBarManager.DISABLE_EXPAND) != 0) {
+                Slog.d(TAG, "DISABLE_EXPAND: yes");
+                animateCollapse();
+            }
+        }
+        if ((diff & StatusBarManager.DISABLE_NOTIFICATION_ICONS) != 0) {
+            if ((net & StatusBarManager.DISABLE_NOTIFICATION_ICONS) != 0) {
+                Slog.d(TAG, "DISABLE_NOTIFICATION_ICONS: yes");
+                if (mTicking) {
+                    mNotificationIcons.setVisibility(View.INVISIBLE);
+                    mTicker.halt();
+                } else {
+                    setNotificationIconVisibility(false, com.android.internal.R.anim.fade_out);
+                }
+            } else {
+                Slog.d(TAG, "DISABLE_NOTIFICATION_ICONS: no");
+                if (!mExpandedVisible) {
+                    setNotificationIconVisibility(true, com.android.internal.R.anim.fade_in);
+                }
+            }
+        } else if ((diff & StatusBarManager.DISABLE_NOTIFICATION_TICKER) != 0) {
+            if (mTicking && (net & StatusBarManager.DISABLE_NOTIFICATION_TICKER) != 0) {
+                mTicker.halt();
+            }
+        }
+    }
+
+    private View.OnClickListener mClearButtonListener = new View.OnClickListener() {
+        public void onClick(View v) {
+            try {
+                mBarService.onClearAllNotifications();
+            } catch (RemoteException ex) {
+                // system process is dead if we're here.
+            }
+            animateCollapse();
+        }
+    };
+
+    private BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
+        public void onReceive(Context context, Intent intent) {
+            String action = intent.getAction();
+            if (Intent.ACTION_CLOSE_SYSTEM_DIALOGS.equals(action)
+                    || Intent.ACTION_SCREEN_OFF.equals(action)) {
+                //collapse();
+            }
+            else if (Intent.ACTION_CONFIGURATION_CHANGED.equals(action)) {
+                updateResources();
+            }
+        }
+    };
+
+    private void setIntruderAlertVisibility(boolean vis) {
+        mIntruderAlertView.setVisibility(vis ? View.VISIBLE : View.GONE);
+    }
+
+    /**
+     * Reload some of our resources when the configuration changes.
+     *
+     * We don't reload everything when the configuration changes -- we probably
+     * should, but getting that smooth is tough.  Someday we'll fix that.  In the
+     * meantime, just update the things that we know change.
+     */
+    void updateResources() {
+        Resources res = getResources();
+
+        mClearButton.setText(getText(R.string.status_bar_clear_all_button));
+        mOngoingTitle.setText(getText(R.string.status_bar_ongoing_events_title));
+        mLatestTitle.setText(getText(R.string.status_bar_latest_events_title));
+        mNoNotificationsTitle.setText(getText(R.string.status_bar_no_notifications_title));
+
+        mEdgeBorder = res.getDimensionPixelSize(R.dimen.status_bar_edge_ignore);
+
+        if (false) Slog.v(TAG, "updateResources");
+    }
+
+    //
+    // tracing
+    //
+
+    void postStartTracing() {
+        mHandler.postDelayed(mStartTracing, 3000);
+    }
+
+    void vibrate() {
+        android.os.Vibrator vib = (android.os.Vibrator)getSystemService(Context.VIBRATOR_SERVICE);
+        vib.vibrate(250);
+    }
+
+    Runnable mStartTracing = new Runnable() {
+        public void run() {
+            vibrate();
+            SystemClock.sleep(250);
+            Slog.d(TAG, "startTracing");
+            android.os.Debug.startMethodTracing("/data/statusbar-traces/trace");
+            mHandler.postDelayed(mStopTracing, 10000);
+        }
+    };
+
+    Runnable mStopTracing = new Runnable() {
+        public void run() {
+            android.os.Debug.stopMethodTracing();
+            Slog.d(TAG, "stopTracing");
+            vibrate();
+        }
+    };
+}
+
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarService.java b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarService.java
index 0d02447..a64c3e7 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarService.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarService.java
@@ -17,194 +17,53 @@
 package com.android.systemui.statusbar;
 
 import android.app.Service;
+import android.content.Context;
+import android.content.Intent;
+import android.content.res.Resources;
+import android.graphics.PixelFormat;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.util.Slog;
+import android.util.Log;
+import android.view.Gravity;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.WindowManager;
+import android.view.WindowManagerImpl;
+
+import java.util.ArrayList;
+
 import com.android.internal.statusbar.IStatusBar;
 import com.android.internal.statusbar.IStatusBarService;
 import com.android.internal.statusbar.StatusBarIcon;
 import com.android.internal.statusbar.StatusBarIconList;
 import com.android.internal.statusbar.StatusBarNotification;
 
-import android.app.ActivityManagerNative;
-import android.app.Dialog;
-import android.app.Notification;
-import android.app.PendingIntent;
-import android.app.Service;
-import android.app.StatusBarManager;
-import android.content.BroadcastReceiver;
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.content.pm.PackageManager;
-import android.content.res.Resources;
-import android.graphics.PixelFormat;
-import android.graphics.Rect;
-import android.graphics.drawable.Drawable;
-import android.net.Uri;
-import android.os.IBinder;
-import android.os.RemoteException;
-import android.os.Binder;
-import android.os.Handler;
-import android.os.Message;
-import android.os.ServiceManager;
-import android.os.SystemClock;
-import android.util.Slog;
-import android.util.Log;
-import android.view.Display;
-import android.view.Gravity;
-import android.view.KeyEvent;
-import android.view.LayoutInflater;
-import android.view.MotionEvent;
-import android.view.VelocityTracker;
-import android.view.View;
-import android.view.ViewGroup;
-import android.view.Window;
-import android.view.WindowManager;
-import android.view.WindowManagerImpl;
-import android.view.animation.Animation;
-import android.view.animation.AnimationUtils;
-import android.widget.ImageView;
-import android.widget.LinearLayout;
-import android.widget.RemoteViews;
-import android.widget.ScrollView;
-import android.widget.TextView;
-import android.widget.FrameLayout;
-
-import java.io.FileDescriptor;
-import java.io.PrintWriter;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.Set;
-
 import com.android.systemui.R;
-import com.android.systemui.statusbar.policy.StatusBarPolicy;
 
-
-
-public class StatusBarService extends Service implements CommandQueue.Callbacks {
+public abstract class StatusBarService extends Service implements CommandQueue.Callbacks {
     static final String TAG = "StatusBarService";
-    static final boolean SPEW = false;
 
-    public static final String ACTION_STATUSBAR_START
-            = "com.android.internal.policy.statusbar.START";
+    protected CommandQueue mCommandQueue;
+    protected IStatusBarService mBarService;
 
-    static final int EXPANDED_LEAVE_ALONE = -10000;
-    static final int EXPANDED_FULL_OPEN = -10001;
+    // Up-call methods
+    protected abstract View makeStatusBarView();
+    protected abstract int getStatusBarGravity();
 
-    private static final int MSG_ANIMATE = 1000;
-    private static final int MSG_ANIMATE_REVEAL = 1001;
-    private static final int MSG_SHOW_INTRUDER = 1002;
-    private static final int MSG_HIDE_INTRUDER = 1003;
-
-    // will likely move to a resource or other tunable param at some point
-    private static final int INTRUDER_ALERT_DECAY_MS = 10000;
-
-    static final int POSITION_TOP = 0;
-    static final int POSITION_BOTTOM = 1;
-
-    StatusBarPolicy mIconPolicy;
-
-    CommandQueue mCommandQueue;
-    IStatusBarService mBarService;
-
-    int mIconSize;
-    Display mDisplay;
-    int mPosition;
-
-    StatusBarView mStatusBarView;
-    int mPixelFormat;
-    H mHandler = new H();
-    Object mQueueLock = new Object();
-
-    // icons
-    LinearLayout mIcons;
-    IconMerger mNotificationIcons;
-    LinearLayout mStatusIcons;
-
-    // expanded notifications
-    Dialog mExpandedDialog;
-    ExpandedView mExpandedView;
-    WindowManager.LayoutParams mExpandedParams;
-    ScrollView mScrollView;
-    View mNotificationLinearLayout;
-    View mExpandedContents;
-    // top bar
-    TextView mNoNotificationsTitle;
-    TextView mClearButton;
-    // drag bar
-    CloseDragHandle mCloseView;
-    // ongoing
-    NotificationData mOngoing = new NotificationData();
-    TextView mOngoingTitle;
-    LinearLayout mOngoingItems;
-    // latest
-    NotificationData mLatest = new NotificationData();
-    TextView mLatestTitle;
-    LinearLayout mLatestItems;
-    // position
-    int[] mPositionTmp = new int[2];
-    boolean mExpanded;
-    boolean mExpandedVisible;
-
-    // the date view
-    DateView mDateView;
-
-    // the tracker view
-    TrackingView mTrackingView;
-    WindowManager.LayoutParams mTrackingParams;
-    int mTrackingPosition; // the position of the top of the tracking view.
-    private boolean mPanelSlightlyVisible;
-
-    // ticker
-    private Ticker mTicker;
-    private View mTickerView;
-    private boolean mTicking;
-
-    // Tracking finger for opening/closing.
-    int mEdgeBorder; // corresponds to R.dimen.status_bar_edge_ignore
-    boolean mTracking;
-    VelocityTracker mVelocityTracker;
-
-    static final int ANIM_FRAME_DURATION = (1000/60);
-
-    boolean mAnimating;
-    long mCurAnimationTime;
-    float mDisplayHeight;
-    float mAnimY;
-    float mAnimVel;
-    float mAnimAccel;
-    long mAnimLastTime;
-    boolean mAnimatingReveal = false;
-    int mViewDelta;
-    int[] mAbsPos = new int[2];
-
-    // for disabling the status bar
-    int mDisabled = 0;
-
-    private class ExpandedDialog extends Dialog {
-        ExpandedDialog(Context context) {
-            super(context, com.android.internal.R.style.Theme_Light_NoTitleBar);
-        }
-
-        @Override
-        public boolean dispatchKeyEvent(KeyEvent event) {
-            boolean down = event.getAction() == KeyEvent.ACTION_DOWN;
-            switch (event.getKeyCode()) {
-            case KeyEvent.KEYCODE_BACK:
-                if (!down) {
-                    animateCollapse();
-                }
-                return true;
-            }
-            return super.dispatchKeyEvent(event);
-        }
+    /**
+     * Nobody binds to us.
+     */
+    @Override
+    public IBinder onBind(Intent intent) {
+        return null;
     }
 
     @Override
     public void onCreate() {
         // First set up our views and stuff.
-        final Resources res = getResources();
-        mPosition = res.getInteger(R.integer.config_status_bar_position);
-        mDisplay = ((WindowManager)getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay();
-        makeStatusBarView(this);
+        View sb = makeStatusBarView();
 
         // Connect in to the status bar manager service
         StatusBarIconList iconList = new StatusBarIconList();
@@ -242,1379 +101,22 @@
         }
 
         // Put up the view
-        addStatusBarView();
-
-        // Lastly, call to the icon policy to install/update all the icons.
-        mIconPolicy = new StatusBarPolicy(this);
-    }
-
-    @Override
-    public void onDestroy() {
-        // we're never destroyed
-    }
-
-    // for immersive activities
-    private View mIntruderAlertView;
-
-    /**
-     * Nobody binds to us.
-     */
-    @Override
-    public IBinder onBind(Intent intent) {
-        return null;
-    }
-
-    // ================================================================================
-    // Constructing the view
-    // ================================================================================
-    private void makeStatusBarView(Context context) {
-        Resources res = context.getResources();
-
-        mIconSize = res.getDimensionPixelSize(com.android.internal.R.dimen.status_bar_icon_size);
-
-        ExpandedView expanded = (ExpandedView)View.inflate(context,
-                R.layout.status_bar_expanded, null);
-        expanded.mService = this;
-
-        mIntruderAlertView = View.inflate(context, R.layout.intruder_alert, null);
-        mIntruderAlertView.setVisibility(View.GONE);
-        mIntruderAlertView.setClickable(true);
-
-        StatusBarView sb = (StatusBarView)View.inflate(context, R.layout.status_bar, null);
-        sb.mService = this;
-
-        // figure out which pixel-format to use for the status bar.
-        mPixelFormat = PixelFormat.TRANSLUCENT;
-        Drawable bg = sb.getBackground();
-        if (bg != null) {
-            mPixelFormat = bg.getOpacity();
-        }
-
-        mStatusBarView = sb;
-        mStatusIcons = (LinearLayout)sb.findViewById(R.id.statusIcons);
-        mNotificationIcons = (IconMerger)sb.findViewById(R.id.notificationIcons);
-        mIcons = (LinearLayout)sb.findViewById(R.id.icons);
-        mTickerView = sb.findViewById(R.id.ticker);
-        mDateView = (DateView)sb.findViewById(R.id.date);
-
-        mExpandedDialog = new ExpandedDialog(context);
-        mExpandedView = expanded;
-        mExpandedContents = expanded.findViewById(R.id.notificationLinearLayout);
-        mOngoingTitle = (TextView)expanded.findViewById(R.id.ongoingTitle);
-        mOngoingItems = (LinearLayout)expanded.findViewById(R.id.ongoingItems);
-        mLatestTitle = (TextView)expanded.findViewById(R.id.latestTitle);
-        mLatestItems = (LinearLayout)expanded.findViewById(R.id.latestItems);
-        mNoNotificationsTitle = (TextView)expanded.findViewById(R.id.noNotificationsTitle);
-        mClearButton = (TextView)expanded.findViewById(R.id.clear_all_button);
-        mClearButton.setOnClickListener(mClearButtonListener);
-        mScrollView = (ScrollView)expanded.findViewById(R.id.scroll);
-        mNotificationLinearLayout = expanded.findViewById(R.id.notificationLinearLayout);
-
-        mOngoingTitle.setVisibility(View.GONE);
-        mLatestTitle.setVisibility(View.GONE);
-
-        mTicker = new MyTicker(context, sb);
-
-        TickerView tickerView = (TickerView)sb.findViewById(R.id.tickerText);
-        tickerView.mTicker = mTicker;
-
-        mTrackingView = (TrackingView)View.inflate(context, R.layout.status_bar_tracking, null);
-        mTrackingView.mService = this;
-        mCloseView = (CloseDragHandle)mTrackingView.findViewById(R.id.close);
-        mCloseView.mService = this;
-
-        mEdgeBorder = res.getDimensionPixelSize(R.dimen.status_bar_edge_ignore);
-
-        // the more notifications icon
-        StatusBarIconView moreView = new StatusBarIconView(this, "more");
-        moreView.set(new StatusBarIcon(null, R.drawable.stat_notify_more, 0));
-        mNotificationIcons.addMoreView(moreView,
-                new LinearLayout.LayoutParams(mIconSize, mIconSize));
-
-        // set the inital view visibility
-        setAreThereNotifications();
-        mDateView.setVisibility(View.INVISIBLE);
-
-        // receive broadcasts
-        IntentFilter filter = new IntentFilter();
-        filter.addAction(Intent.ACTION_CONFIGURATION_CHANGED);
-        filter.addAction(Intent.ACTION_CLOSE_SYSTEM_DIALOGS);
-        filter.addAction(Intent.ACTION_SCREEN_OFF);
-        context.registerReceiver(mBroadcastReceiver, filter);
-    }
-
-    protected void addStatusBarView() {
-        Resources res = getResources();
+        final Resources res = getResources();
         final int height= res.getDimensionPixelSize(com.android.internal.R.dimen.status_bar_height);
 
-        final StatusBarView view = mStatusBarView;
-        WindowManager.LayoutParams lp = new WindowManager.LayoutParams(
+        final WindowManager.LayoutParams lp = new WindowManager.LayoutParams(
                 ViewGroup.LayoutParams.MATCH_PARENT,
                 height,
                 WindowManager.LayoutParams.TYPE_STATUS_BAR,
                 WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
                     | WindowManager.LayoutParams.FLAG_TOUCHABLE_WHEN_WAKING,
                 PixelFormat.RGBX_8888);
-        if (mPosition == POSITION_TOP) {
-            lp.gravity = Gravity.TOP | Gravity.FILL_HORIZONTAL;
-        } else {
-            lp.gravity = Gravity.BOTTOM | Gravity.FILL_HORIZONTAL;
-        }
+        lp.gravity = getStatusBarGravity();
         lp.setTitle("StatusBar");
         // TODO lp.windowAnimations = R.style.Animation_StatusBar;
+        WindowManagerImpl.getDefault().addView(sb, lp);
 
-        WindowManagerImpl.getDefault().addView(view, lp);
-
-        lp = new WindowManager.LayoutParams(
-                ViewGroup.LayoutParams.MATCH_PARENT,
-                ViewGroup.LayoutParams.WRAP_CONTENT,
-                WindowManager.LayoutParams.TYPE_STATUS_BAR_PANEL,
-                WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN
-                    | WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS
-                    | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
-                    | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
-                    | WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM,
-                PixelFormat.TRANSLUCENT);
-        if (mPosition == POSITION_TOP) {
-            lp.gravity = Gravity.TOP | Gravity.FILL_HORIZONTAL;
-        } else {
-            lp.gravity = Gravity.BOTTOM | Gravity.FILL_HORIZONTAL;
-        }
-        lp.y += height * 1.5; // FIXME
-        lp.setTitle("IntruderAlert");
-        lp.windowAnimations = com.android.internal.R.style.Animation_StatusBar_IntruderAlert;
-
-        WindowManagerImpl.getDefault().addView(mIntruderAlertView, lp);
+        Slog.d(TAG, "Added status bar view w/ gravity 0x" + Integer.toHexString(lp.gravity));
     }
-
-    public void addIcon(String slot, int index, int viewIndex, StatusBarIcon icon) {
-        if (SPEW) Slog.d(TAG, "addIcon slot=" + slot + " index=" + index + " viewIndex=" + viewIndex
-                + " icon=" + icon);
-        StatusBarIconView view = new StatusBarIconView(this, slot);
-        view.set(icon);
-        mStatusIcons.addView(view, viewIndex, new LinearLayout.LayoutParams(mIconSize, mIconSize));
-    }
-
-    public void updateIcon(String slot, int index, int viewIndex,
-            StatusBarIcon old, StatusBarIcon icon) {
-        if (SPEW) Slog.d(TAG, "updateIcon slot=" + slot + " index=" + index + " viewIndex=" + viewIndex
-                + " old=" + old + " icon=" + icon);
-        StatusBarIconView view = (StatusBarIconView)mStatusIcons.getChildAt(viewIndex);
-        view.set(icon);
-    }
-
-    public void removeIcon(String slot, int index, int viewIndex) {
-        if (SPEW) Slog.d(TAG, "removeIcon slot=" + slot + " index=" + index + " viewIndex=" + viewIndex);
-        mStatusIcons.removeViewAt(viewIndex);
-    }
-
-    public void addNotification(IBinder key, StatusBarNotification notification) {
-        StatusBarIconView iconView = addNotificationViews(key, notification);
-        if (iconView == null) return;
-
-        boolean immersive = false;
-        try {
-            immersive = ActivityManagerNative.getDefault().isTopActivityImmersive();
-            Slog.d(TAG, "Top activity is " + (immersive?"immersive":"not immersive"));
-        } catch (RemoteException ex) {
-        }
-        if (immersive) {
-            if ((notification.notification.flags & Notification.FLAG_HIGH_PRIORITY) != 0) {
-                Slog.d(TAG, "Presenting high-priority notification in immersive activity");
-                // @@@ special new transient ticker mode
-                // 1. Populate mIntruderAlertView
-
-                ImageView alertIcon = (ImageView) mIntruderAlertView.findViewById(R.id.alertIcon);
-                TextView alertText = (TextView) mIntruderAlertView.findViewById(R.id.alertText);
-                alertIcon.setImageDrawable(StatusBarIconView.getIcon(
-                    alertIcon.getContext(),
-                    iconView.getStatusBarIcon()));
-                alertText.setText(notification.notification.tickerText);
-
-                View button = mIntruderAlertView.findViewById(R.id.intruder_alert_content);
-                button.setOnClickListener(
-                    new Launcher(notification.notification.contentIntent,
-                        notification.pkg, notification.tag, notification.id));
-
-                // 2. Animate mIntruderAlertView in
-                mHandler.sendEmptyMessage(MSG_SHOW_INTRUDER);
-
-                // 3. Set alarm to age the notification off (TODO)
-                mHandler.removeMessages(MSG_HIDE_INTRUDER);
-                mHandler.sendEmptyMessageDelayed(MSG_HIDE_INTRUDER, INTRUDER_ALERT_DECAY_MS);
-            }
-        } else if (notification.notification.fullScreenIntent != null) {
-            // not immersive & a full-screen alert should be shown
-            Slog.d(TAG, "Notification has fullScreenIntent and activity is not immersive;"
-                    + " sending fullScreenIntent");
-            try {
-                notification.notification.fullScreenIntent.send();
-            } catch (PendingIntent.CanceledException e) {
-            }
-        } else {
-            // usual case: status bar visible & not immersive
-
-            // show the ticker
-            tick(notification);
-        }
-
-        // Recalculate the position of the sliding windows and the titles.
-        setAreThereNotifications();
-        updateExpandedViewPos(EXPANDED_LEAVE_ALONE);
-    }
-
-    public void updateNotification(IBinder key, StatusBarNotification notification) {
-        Slog.d(TAG, "updateNotification key=" + key + " notification=" + notification);
-
-        NotificationData oldList;
-        int oldIndex = mOngoing.findEntry(key);
-        if (oldIndex >= 0) {
-            oldList = mOngoing;
-        } else {
-            oldIndex = mLatest.findEntry(key);
-            if (oldIndex < 0) {
-                Slog.w(TAG, "updateNotification for unknown key: " + key);
-                return;
-            }
-            oldList = mLatest;
-        }
-        final NotificationData.Entry oldEntry = oldList.getEntryAt(oldIndex);
-        final StatusBarNotification oldNotification = oldEntry.notification;
-        final RemoteViews oldContentView = oldNotification.notification.contentView;
-
-        final RemoteViews contentView = notification.notification.contentView;
-
-        if (false) {
-            Slog.d(TAG, "old notification: when=" + oldNotification.notification.when
-                    + " ongoing=" + oldNotification.isOngoing()
-                    + " expanded=" + oldEntry.expanded
-                    + " contentView=" + oldContentView);
-            Slog.d(TAG, "new notification: when=" + notification.notification.when
-                    + " ongoing=" + oldNotification.isOngoing()
-                    + " contentView=" + contentView);
-        }
-
-        // Can we just reapply the RemoteViews in place?  If when didn't change, the order
-        // didn't change.
-        if (notification.notification.when == oldNotification.notification.when
-                && notification.isOngoing() == oldNotification.isOngoing()
-                && oldEntry.expanded != null
-                && contentView != null && oldContentView != null
-                && contentView.getPackage() != null
-                && oldContentView.getPackage() != null
-                && oldContentView.getPackage().equals(contentView.getPackage())
-                && oldContentView.getLayoutId() == contentView.getLayoutId()) {
-            if (SPEW) Slog.d(TAG, "reusing notification");
-            oldEntry.notification = notification;
-            try {
-                // Reapply the RemoteViews
-                contentView.reapply(this, oldEntry.content);
-                // update the contentIntent
-                final PendingIntent contentIntent = notification.notification.contentIntent;
-                if (contentIntent != null) {
-                    oldEntry.content.setOnClickListener(new Launcher(contentIntent,
-                                notification.pkg, notification.tag, notification.id));
-                }
-                // Update the icon.
-                final StatusBarIcon ic = new StatusBarIcon(notification.pkg,
-                        notification.notification.icon, notification.notification.iconLevel,
-                        notification.notification.number);
-                if (!oldEntry.icon.set(ic)) {
-                    handleNotificationError(key, notification, "Couldn't update icon: " + ic);
-                    return;
-                }
-            }
-            catch (RuntimeException e) {
-                // It failed to add cleanly.  Log, and remove the view from the panel.
-                Slog.w(TAG, "Couldn't reapply views for package " + contentView.getPackage(), e);
-                removeNotificationViews(key);
-                addNotificationViews(key, notification);
-            }
-        } else {
-            if (SPEW) Slog.d(TAG, "not reusing notification");
-            removeNotificationViews(key);
-            addNotificationViews(key, notification);
-        }
-
-        // Restart the ticker if it's still running
-        tick(notification);
-
-        // Recalculate the position of the sliding windows and the titles.
-        setAreThereNotifications();
-        updateExpandedViewPos(EXPANDED_LEAVE_ALONE);
-    }
-
-    public void removeNotification(IBinder key) {
-        if (SPEW) Slog.d(TAG, "removeNotification key=" + key);
-        StatusBarNotification old = removeNotificationViews(key);
-
-        if (old != null) {
-            // Cancel the ticker if it's still running
-            mTicker.removeEntry(old);
-
-            // Recalculate the position of the sliding windows and the titles.
-            setAreThereNotifications();
-            updateExpandedViewPos(EXPANDED_LEAVE_ALONE);
-        }
-    }
-
-    private int chooseIconIndex(boolean isOngoing, int viewIndex) {
-        final int latestSize = mLatest.size();
-        if (isOngoing) {
-            return latestSize + (mOngoing.size() - viewIndex);
-        } else {
-            return latestSize - viewIndex;
-        }
-    }
-
-    View[] makeNotificationView(StatusBarNotification notification, ViewGroup parent) {
-        Notification n = notification.notification;
-        RemoteViews remoteViews = n.contentView;
-        if (remoteViews == null) {
-            return null;
-        }
-
-        // create the row view
-        LayoutInflater inflater = (LayoutInflater)getSystemService(Context.LAYOUT_INFLATER_SERVICE);
-        View row = inflater.inflate(R.layout.status_bar_latest_event, parent, false);
-
-        // bind the click event to the content area
-        ViewGroup content = (ViewGroup)row.findViewById(R.id.content);
-        content.setDescendantFocusability(ViewGroup.FOCUS_BLOCK_DESCENDANTS);
-        content.setOnFocusChangeListener(mFocusChangeListener);
-        PendingIntent contentIntent = n.contentIntent;
-        if (contentIntent != null) {
-            content.setOnClickListener(new Launcher(contentIntent, notification.pkg,
-                        notification.tag, notification.id));
-        }
-
-        View expanded = null;
-        Exception exception = null;
-        try {
-            expanded = remoteViews.apply(this, content);
-        }
-        catch (RuntimeException e) {
-            exception = e;
-        }
-        if (expanded == null) {
-            String ident = notification.pkg + "/0x" + Integer.toHexString(notification.id);
-            Slog.e(TAG, "couldn't inflate view for notification " + ident, exception);
-            return null;
-        } else {
-            content.addView(expanded);
-            row.setDrawingCacheEnabled(true);
-        }
-
-        return new View[] { row, content, expanded };
-    }
-
-    StatusBarIconView addNotificationViews(IBinder key, StatusBarNotification notification) {
-        NotificationData list;
-        ViewGroup parent;
-        final boolean isOngoing = notification.isOngoing();
-        if (isOngoing) {
-            list = mOngoing;
-            parent = mOngoingItems;
-        } else {
-            list = mLatest;
-            parent = mLatestItems;
-        }
-        // Construct the expanded view.
-        final View[] views = makeNotificationView(notification, parent);
-        if (views == null) {
-            handleNotificationError(key, notification, "Couldn't expand RemoteViews for: "
-                    + notification);
-            return null;
-        }
-        final View row = views[0];
-        final View content = views[1];
-        final View expanded = views[2];
-        // Construct the icon.
-        final StatusBarIconView iconView = new StatusBarIconView(this,
-                notification.pkg + "/0x" + Integer.toHexString(notification.id));
-        final StatusBarIcon ic = new StatusBarIcon(notification.pkg, notification.notification.icon,
-                    notification.notification.iconLevel, notification.notification.number);
-        if (!iconView.set(ic)) {
-            handleNotificationError(key, notification, "Coulding create icon: " + ic);
-            return null;
-        }
-        // Add the expanded view.
-        final int viewIndex = list.add(key, notification, row, content, expanded, iconView);
-        parent.addView(row, viewIndex);
-        // Add the icon.
-        final int iconIndex = chooseIconIndex(isOngoing, viewIndex);
-        mNotificationIcons.addView(iconView, iconIndex,
-                new LinearLayout.LayoutParams(mIconSize, mIconSize));
-        return iconView;
-    }
-
-    StatusBarNotification removeNotificationViews(IBinder key) {
-        NotificationData.Entry entry = mOngoing.remove(key);
-        if (entry == null) {
-            entry = mLatest.remove(key);
-            if (entry == null) {
-                Slog.w(TAG, "removeNotification for unknown key: " + key);
-                return null;
-            }
-        }
-        // Remove the expanded view.
-        ((ViewGroup)entry.row.getParent()).removeView(entry.row);
-        // Remove the icon.
-        ((ViewGroup)entry.icon.getParent()).removeView(entry.icon);
-
-        return entry.notification;
-    }
-
-    private void setAreThereNotifications() {
-        boolean ongoing = mOngoing.hasVisibleItems();
-        boolean latest = mLatest.hasVisibleItems();
-
-        // (no ongoing notifications are clearable)
-        if (mLatest.hasClearableItems()) {
-            mClearButton.setVisibility(View.VISIBLE);
-        } else {
-            mClearButton.setVisibility(View.INVISIBLE);
-        }
-
-        mOngoingTitle.setVisibility(ongoing ? View.VISIBLE : View.GONE);
-        mLatestTitle.setVisibility(latest ? View.VISIBLE : View.GONE);
-
-        if (ongoing || latest) {
-            mNoNotificationsTitle.setVisibility(View.GONE);
-        } else {
-            mNoNotificationsTitle.setVisibility(View.VISIBLE);
-        }
-    }
-
-
-    /**
-     * State is one or more of the DISABLE constants from StatusBarManager.
-     */
-    public void disable(int state) {
-        final int old = mDisabled;
-        final int diff = state ^ old;
-        mDisabled = state;
-
-        if ((diff & StatusBarManager.DISABLE_EXPAND) != 0) {
-            if ((state & StatusBarManager.DISABLE_EXPAND) != 0) {
-                Slog.d(TAG, "DISABLE_EXPAND: yes");
-                animateCollapse();
-            }
-        }
-        if ((diff & StatusBarManager.DISABLE_NOTIFICATION_ICONS) != 0) {
-            if ((state & StatusBarManager.DISABLE_NOTIFICATION_ICONS) != 0) {
-                Slog.d(TAG, "DISABLE_NOTIFICATION_ICONS: yes");
-                if (mTicking) {
-                    mTicker.halt();
-                } else {
-                    setNotificationIconVisibility(false, com.android.internal.R.anim.fade_out);
-                }
-            } else {
-                Slog.d(TAG, "DISABLE_NOTIFICATION_ICONS: no");
-                if (!mExpandedVisible) {
-                    setNotificationIconVisibility(true, com.android.internal.R.anim.fade_in);
-                }
-            }
-        } else if ((diff & StatusBarManager.DISABLE_NOTIFICATION_TICKER) != 0) {
-            if (mTicking && (state & StatusBarManager.DISABLE_NOTIFICATION_TICKER) != 0) {
-                Slog.d(TAG, "DISABLE_NOTIFICATION_TICKER: yes");
-                mTicker.halt();
-            }
-        }
-    }
-
-    /**
-     * All changes to the status bar and notifications funnel through here and are batched.
-     */
-    private class H extends Handler {
-        public void handleMessage(Message m) {
-            switch (m.what) {
-                case MSG_ANIMATE:
-                    doAnimation();
-                    break;
-                case MSG_ANIMATE_REVEAL:
-                    doRevealAnimation();
-                    break;
-                case MSG_SHOW_INTRUDER:
-                    setIntruderAlertVisibility(true);
-                    break;
-                case MSG_HIDE_INTRUDER:
-                    setIntruderAlertVisibility(false);
-                    break;
-            }
-        }
-    }
-
-    View.OnFocusChangeListener mFocusChangeListener = new View.OnFocusChangeListener() {
-        public void onFocusChange(View v, boolean hasFocus) {
-            // Because 'v' is a ViewGroup, all its children will be (un)selected
-            // too, which allows marqueeing to work.
-            v.setSelected(hasFocus);
-        }
-    };
-
-    private void makeExpandedVisible() {
-        if (SPEW) Slog.d(TAG, "Make expanded visible: expanded visible=" + mExpandedVisible);
-        if (mExpandedVisible) {
-            return;
-        }
-        mExpandedVisible = true;
-        visibilityChanged(true);
-
-        updateExpandedViewPos(EXPANDED_LEAVE_ALONE);
-        mExpandedParams.flags &= ~WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
-        mExpandedParams.flags |= WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM;
-        mExpandedDialog.getWindow().setAttributes(mExpandedParams);
-        mExpandedView.requestFocus(View.FOCUS_FORWARD);
-        mTrackingView.setVisibility(View.VISIBLE);
-
-        if (!mTicking) {
-            setDateViewVisibility(true, com.android.internal.R.anim.fade_in);
-        }
-    }
-
-    public void animateExpand() {
-        if (SPEW) Slog.d(TAG, "Animate expand: expanded=" + mExpanded);
-        if ((mDisabled & StatusBarManager.DISABLE_EXPAND) != 0) {
-            return ;
-        }
-        if (mExpanded) {
-            return;
-        }
-
-        prepareTracking(0, true);
-        performFling(0, 2000.0f, true);
-    }
-
-    public void animateCollapse() {
-        if (SPEW) {
-            Slog.d(TAG, "animateCollapse(): mExpanded=" + mExpanded
-                    + " mExpandedVisible=" + mExpandedVisible
-                    + " mExpanded=" + mExpanded
-                    + " mAnimating=" + mAnimating
-                    + " mAnimY=" + mAnimY
-                    + " mAnimVel=" + mAnimVel);
-        }
-
-        if (!mExpandedVisible) {
-            return;
-        }
-
-        int y;
-        if (mAnimating) {
-            y = (int)mAnimY;
-        } else {
-            y = mDisplay.getHeight()-1;
-        }
-        // Let the fling think that we're open so it goes in the right direction
-        // and doesn't try to re-open the windowshade.
-        mExpanded = true;
-        prepareTracking(y, false);
-        performFling(y, -2000.0f, true);
-    }
-
-    void performExpand() {
-        if (SPEW) Slog.d(TAG, "performExpand: mExpanded=" + mExpanded);
-        if ((mDisabled & StatusBarManager.DISABLE_EXPAND) != 0) {
-            return ;
-        }
-        if (mExpanded) {
-            return;
-        }
-
-        mExpanded = true;
-        makeExpandedVisible();
-        updateExpandedViewPos(EXPANDED_FULL_OPEN);
-
-        if (false) postStartTracing();
-    }
-
-    void performCollapse() {
-        if (SPEW) Slog.d(TAG, "performCollapse: mExpanded=" + mExpanded
-                + " mExpandedVisible=" + mExpandedVisible);
-
-        if (!mExpandedVisible) {
-            return;
-        }
-        mExpandedVisible = false;
-        visibilityChanged(false);
-        mExpandedParams.flags |= WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
-        mExpandedParams.flags &= ~WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM;
-        mExpandedDialog.getWindow().setAttributes(mExpandedParams);
-        mTrackingView.setVisibility(View.GONE);
-
-        if ((mDisabled & StatusBarManager.DISABLE_NOTIFICATION_ICONS) == 0) {
-            setNotificationIconVisibility(true, com.android.internal.R.anim.fade_in);
-        }
-        setDateViewVisibility(false, com.android.internal.R.anim.fade_out);
-
-        if (!mExpanded) {
-            return;
-        }
-        mExpanded = false;
-    }
-
-    void doAnimation() {
-        if (mAnimating) {
-            if (SPEW) Slog.d(TAG, "doAnimation");
-            if (SPEW) Slog.d(TAG, "doAnimation before mAnimY=" + mAnimY);
-            incrementAnim();
-            if (SPEW) Slog.d(TAG, "doAnimation after  mAnimY=" + mAnimY);
-            if (mAnimY >= mDisplay.getHeight()-1) {
-                if (SPEW) Slog.d(TAG, "Animation completed to expanded state.");
-                mAnimating = false;
-                updateExpandedViewPos(EXPANDED_FULL_OPEN);
-                performExpand();
-            }
-            else if (mAnimY < mStatusBarView.getHeight()) {
-                if (SPEW) Slog.d(TAG, "Animation completed to collapsed state.");
-                mAnimating = false;
-                updateExpandedViewPos(0);
-                performCollapse();
-            }
-            else {
-                updateExpandedViewPos((int)mAnimY);
-                mCurAnimationTime += ANIM_FRAME_DURATION;
-                mHandler.sendMessageAtTime(mHandler.obtainMessage(MSG_ANIMATE), mCurAnimationTime);
-            }
-        }
-    }
-
-    void stopTracking() {
-        mTracking = false;
-        mVelocityTracker.recycle();
-        mVelocityTracker = null;
-    }
-
-    void incrementAnim() {
-        long now = SystemClock.uptimeMillis();
-        float t = ((float)(now - mAnimLastTime)) / 1000;            // ms -> s
-        final float y = mAnimY;
-        final float v = mAnimVel;                                   // px/s
-        final float a = mAnimAccel;                                 // px/s/s
-        mAnimY = y + (v*t) + (0.5f*a*t*t);                          // px
-        mAnimVel = v + (a*t);                                       // px/s
-        mAnimLastTime = now;                                        // ms
-        //Slog.d(TAG, "y=" + y + " v=" + v + " a=" + a + " t=" + t + " mAnimY=" + mAnimY
-        //        + " mAnimAccel=" + mAnimAccel);
-    }
-
-    void doRevealAnimation() {
-        final int h = mCloseView.getHeight() + mStatusBarView.getHeight();
-        if (mAnimatingReveal && mAnimating && mAnimY < h) {
-            incrementAnim();
-            if (mAnimY >= h) {
-                mAnimY = h;
-                updateExpandedViewPos((int)mAnimY);
-            } else {
-                updateExpandedViewPos((int)mAnimY);
-                mCurAnimationTime += ANIM_FRAME_DURATION;
-                mHandler.sendMessageAtTime(mHandler.obtainMessage(MSG_ANIMATE_REVEAL),
-                        mCurAnimationTime);
-            }
-        }
-    }
-
-    void prepareTracking(int y, boolean opening) {
-        mTracking = true;
-        mVelocityTracker = VelocityTracker.obtain();
-        if (opening) {
-            mAnimAccel = 2000.0f;
-            mAnimVel = 200;
-            mAnimY = mStatusBarView.getHeight();
-            updateExpandedViewPos((int)mAnimY);
-            mAnimating = true;
-            mAnimatingReveal = true;
-            mHandler.removeMessages(MSG_ANIMATE);
-            mHandler.removeMessages(MSG_ANIMATE_REVEAL);
-            long now = SystemClock.uptimeMillis();
-            mAnimLastTime = now;
-            mCurAnimationTime = now + ANIM_FRAME_DURATION;
-            mAnimating = true;
-            mHandler.sendMessageAtTime(mHandler.obtainMessage(MSG_ANIMATE_REVEAL),
-                    mCurAnimationTime);
-            makeExpandedVisible();
-        } else {
-            // it's open, close it?
-            if (mAnimating) {
-                mAnimating = false;
-                mHandler.removeMessages(MSG_ANIMATE);
-            }
-            updateExpandedViewPos(y + mViewDelta);
-        }
-    }
-
-    void performFling(int y, float vel, boolean always) {
-        mAnimatingReveal = false;
-        mDisplayHeight = mDisplay.getHeight();
-
-        mAnimY = y;
-        mAnimVel = vel;
-
-        //Slog.d(TAG, "starting with mAnimY=" + mAnimY + " mAnimVel=" + mAnimVel);
-
-        if (mExpanded) {
-            if (!always && (
-                    vel > 200.0f
-                    || (y > (mDisplayHeight-25) && vel > -200.0f))) {
-                // We are expanded, but they didn't move sufficiently to cause
-                // us to retract.  Animate back to the expanded position.
-                mAnimAccel = 2000.0f;
-                if (vel < 0) {
-                    mAnimVel = 0;
-                }
-            }
-            else {
-                // We are expanded and are now going to animate away.
-                mAnimAccel = -2000.0f;
-                if (vel > 0) {
-                    mAnimVel = 0;
-                }
-            }
-        } else {
-            if (always || (
-                    vel > 200.0f
-                    || (y > (mDisplayHeight/2) && vel > -200.0f))) {
-                // We are collapsed, and they moved enough to allow us to
-                // expand.  Animate in the notifications.
-                mAnimAccel = 2000.0f;
-                if (vel < 0) {
-                    mAnimVel = 0;
-                }
-            }
-            else {
-                // We are collapsed, but they didn't move sufficiently to cause
-                // us to retract.  Animate back to the collapsed position.
-                mAnimAccel = -2000.0f;
-                if (vel > 0) {
-                    mAnimVel = 0;
-                }
-            }
-        }
-        //Slog.d(TAG, "mAnimY=" + mAnimY + " mAnimVel=" + mAnimVel
-        //        + " mAnimAccel=" + mAnimAccel);
-
-        long now = SystemClock.uptimeMillis();
-        mAnimLastTime = now;
-        mCurAnimationTime = now + ANIM_FRAME_DURATION;
-        mAnimating = true;
-        mHandler.removeMessages(MSG_ANIMATE);
-        mHandler.removeMessages(MSG_ANIMATE_REVEAL);
-        mHandler.sendMessageAtTime(mHandler.obtainMessage(MSG_ANIMATE), mCurAnimationTime);
-        stopTracking();
-    }
-
-    boolean interceptTouchEvent(MotionEvent event) {
-        if (SPEW) {
-            Slog.d(TAG, "Touch: rawY=" + event.getRawY() + " event=" + event + " mDisabled="
-                + mDisabled);
-        }
-
-        if ((mDisabled & StatusBarManager.DISABLE_EXPAND) != 0) {
-            return false;
-        }
-
-        final int statusBarSize = mStatusBarView.getHeight();
-        final int hitSize = statusBarSize*2;
-        if (event.getAction() == MotionEvent.ACTION_DOWN) {
-            final int y = (int)event.getRawY();
-
-            if (!mExpanded) {
-                mViewDelta = statusBarSize - y;
-            } else {
-                mTrackingView.getLocationOnScreen(mAbsPos);
-                mViewDelta = mAbsPos[1] + mTrackingView.getHeight() - y;
-            }
-            if ((!mExpanded && y < hitSize) ||
-                    (mExpanded && y > (mDisplay.getHeight()-hitSize))) {
-
-                // We drop events at the edge of the screen to make the windowshade come
-                // down by accident less, especially when pushing open a device with a keyboard
-                // that rotates (like g1 and droid)
-                int x = (int)event.getRawX();
-                final int edgeBorder = mEdgeBorder;
-                if (x >= edgeBorder && x < mDisplay.getWidth() - edgeBorder) {
-                    prepareTracking(y, !mExpanded);// opening if we're not already fully visible
-                    mVelocityTracker.addMovement(event);
-                }
-            }
-        } else if (mTracking) {
-            mVelocityTracker.addMovement(event);
-            final int minY = statusBarSize + mCloseView.getHeight();
-            if (event.getAction() == MotionEvent.ACTION_MOVE) {
-                int y = (int)event.getRawY();
-                if (mAnimatingReveal && y < minY) {
-                    // nothing
-                } else  {
-                    mAnimatingReveal = false;
-                    updateExpandedViewPos(y + mViewDelta);
-                }
-            } else if (event.getAction() == MotionEvent.ACTION_UP) {
-                mVelocityTracker.computeCurrentVelocity(1000);
-
-                float yVel = mVelocityTracker.getYVelocity();
-                boolean negative = yVel < 0;
-
-                float xVel = mVelocityTracker.getXVelocity();
-                if (xVel < 0) {
-                    xVel = -xVel;
-                }
-                if (xVel > 150.0f) {
-                    xVel = 150.0f; // limit how much we care about the x axis
-                }
-
-                float vel = (float)Math.hypot(yVel, xVel);
-                if (negative) {
-                    vel = -vel;
-                }
-
-                performFling((int)event.getRawY(), vel, false);
-            }
-
-        }
-        return false;
-    }
-
-    private class Launcher implements View.OnClickListener {
-        private PendingIntent mIntent;
-        private String mPkg;
-        private String mTag;
-        private int mId;
-
-        Launcher(PendingIntent intent, String pkg, String tag, int id) {
-            mIntent = intent;
-            mPkg = pkg;
-            mTag = tag;
-            mId = id;
-        }
-
-        public void onClick(View v) {
-            try {
-                // The intent we are sending is for the application, which
-                // won't have permission to immediately start an activity after
-                // the user switches to home.  We know it is safe to do at this
-                // point, so make sure new activity switches are now allowed.
-                ActivityManagerNative.getDefault().resumeAppSwitches();
-            } catch (RemoteException e) {
-            }
-
-            if (mIntent != null) {
-                int[] pos = new int[2];
-                v.getLocationOnScreen(pos);
-                Intent overlay = new Intent();
-                overlay.setSourceBounds(
-                        new Rect(pos[0], pos[1], pos[0]+v.getWidth(), pos[1]+v.getHeight()));
-                try {
-                    mIntent.send(StatusBarService.this, 0, overlay);
-                } catch (PendingIntent.CanceledException e) {
-                    // the stack trace isn't very helpful here.  Just log the exception message.
-                    Slog.w(TAG, "Sending contentIntent failed: " + e);
-                }
-            }
-
-            try {
-                mBarService.onNotificationClick(mPkg, mTag, mId);
-            } catch (RemoteException ex) {
-                // system process is dead if we're here.
-            }
-
-            // close the shade if it was open
-            animateCollapse();
-
-            // If this click was on the intruder alert, hide that instead
-            mHandler.sendEmptyMessage(MSG_HIDE_INTRUDER);
-        }
-    }
-
-    private void tick(StatusBarNotification n) {
-        // Show the ticker if one is requested. Also don't do this
-        // until status bar window is attached to the window manager,
-        // because...  well, what's the point otherwise?  And trying to
-        // run a ticker without being attached will crash!
-        if (n.notification.tickerText != null && mStatusBarView.getWindowToken() != null) {
-            if (0 == (mDisabled & (StatusBarManager.DISABLE_NOTIFICATION_ICONS
-                            | StatusBarManager.DISABLE_NOTIFICATION_TICKER))) {
-                mTicker.addEntry(n);
-            }
-        }
-    }
-
-    /**
-     * Cancel this notification and tell the StatusBarManagerService / NotificationManagerService
-     * about the failure.
-     *
-     * WARNING: this will call back into us.  Don't hold any locks.
-     */
-    void handleNotificationError(IBinder key, StatusBarNotification n, String message) {
-        removeNotification(key);
-        try {
-            mBarService.onNotificationError(n.pkg, n.tag, n.id, n.uid, n.initialPid, message);
-        } catch (RemoteException ex) {
-            // The end is nigh.
-        }
-    }
-
-    private class MyTicker extends Ticker {
-        MyTicker(Context context, StatusBarView sb) {
-            super(context, sb);
-        }
-
-        @Override
-        void tickerStarting() {
-            mTicking = true;
-            mIcons.setVisibility(View.GONE);
-            mTickerView.setVisibility(View.VISIBLE);
-            mTickerView.startAnimation(loadAnim(com.android.internal.R.anim.push_up_in, null));
-            mIcons.startAnimation(loadAnim(com.android.internal.R.anim.push_up_out, null));
-            if (mExpandedVisible) {
-                setDateViewVisibility(false, com.android.internal.R.anim.push_up_out);
-            }
-        }
-
-        @Override
-        void tickerDone() {
-            mIcons.setVisibility(View.VISIBLE);
-            mTickerView.setVisibility(View.GONE);
-            mIcons.startAnimation(loadAnim(com.android.internal.R.anim.push_down_in, null));
-            mTickerView.startAnimation(loadAnim(com.android.internal.R.anim.push_down_out,
-                        mTickingDoneListener));
-            if (mExpandedVisible) {
-                setDateViewVisibility(true, com.android.internal.R.anim.push_down_in);
-            }
-        }
-
-        void tickerHalting() {
-            mIcons.setVisibility(View.VISIBLE);
-            mTickerView.setVisibility(View.GONE);
-            mIcons.startAnimation(loadAnim(com.android.internal.R.anim.fade_in, null));
-            mTickerView.startAnimation(loadAnim(com.android.internal.R.anim.fade_out,
-                        mTickingDoneListener));
-            if (mExpandedVisible) {
-                setDateViewVisibility(true, com.android.internal.R.anim.fade_in);
-            }
-        }
-    }
-
-    Animation.AnimationListener mTickingDoneListener = new Animation.AnimationListener() {;
-        public void onAnimationEnd(Animation animation) {
-            mTicking = false;
-        }
-        public void onAnimationRepeat(Animation animation) {
-        }
-        public void onAnimationStart(Animation animation) {
-        }
-    };
-
-    private Animation loadAnim(int id, Animation.AnimationListener listener) {
-        Animation anim = AnimationUtils.loadAnimation(StatusBarService.this, id);
-        if (listener != null) {
-            anim.setAnimationListener(listener);
-        }
-        return anim;
-    }
-
-    public String viewInfo(View v) {
-        return "(" + v.getLeft() + "," + v.getTop() + ")(" + v.getRight() + "," + v.getBottom()
-                + " " + v.getWidth() + "x" + v.getHeight() + ")";
-    }
-
-    protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
-        if (checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
-                != PackageManager.PERMISSION_GRANTED) {
-            pw.println("Permission Denial: can't dump StatusBar from from pid="
-                    + Binder.getCallingPid()
-                    + ", uid=" + Binder.getCallingUid());
-            return;
-        }
-
-        synchronized (mQueueLock) {
-            pw.println("Current Status Bar state:");
-            pw.println("  mExpanded=" + mExpanded
-                    + ", mExpandedVisible=" + mExpandedVisible);
-            pw.println("  mTicking=" + mTicking);
-            pw.println("  mTracking=" + mTracking);
-            pw.println("  mAnimating=" + mAnimating
-                    + ", mAnimY=" + mAnimY + ", mAnimVel=" + mAnimVel
-                    + ", mAnimAccel=" + mAnimAccel);
-            pw.println("  mCurAnimationTime=" + mCurAnimationTime
-                    + " mAnimLastTime=" + mAnimLastTime);
-            pw.println("  mDisplayHeight=" + mDisplayHeight
-                    + " mAnimatingReveal=" + mAnimatingReveal
-                    + " mViewDelta=" + mViewDelta);
-            pw.println("  mDisplayHeight=" + mDisplayHeight);
-            pw.println("  mExpandedParams: " + mExpandedParams);
-            pw.println("  mExpandedView: " + viewInfo(mExpandedView));
-            pw.println("  mExpandedDialog: " + mExpandedDialog);
-            pw.println("  mTrackingParams: " + mTrackingParams);
-            pw.println("  mTrackingView: " + viewInfo(mTrackingView));
-            pw.println("  mOngoingTitle: " + viewInfo(mOngoingTitle));
-            pw.println("  mOngoingItems: " + viewInfo(mOngoingItems));
-            pw.println("  mLatestTitle: " + viewInfo(mLatestTitle));
-            pw.println("  mLatestItems: " + viewInfo(mLatestItems));
-            pw.println("  mNoNotificationsTitle: " + viewInfo(mNoNotificationsTitle));
-            pw.println("  mCloseView: " + viewInfo(mCloseView));
-            pw.println("  mTickerView: " + viewInfo(mTickerView));
-            pw.println("  mScrollView: " + viewInfo(mScrollView)
-                    + " scroll " + mScrollView.getScrollX() + "," + mScrollView.getScrollY());
-            pw.println("mNotificationLinearLayout: " + viewInfo(mNotificationLinearLayout));
-        }
-        /*
-        synchronized (mNotificationData) {
-            int N = mNotificationData.ongoingCount();
-            pw.println("  ongoingCount.size=" + N);
-            for (int i=0; i<N; i++) {
-                StatusBarNotification n = mNotificationData.getOngoing(i);
-                pw.println("    [" + i + "] key=" + n.key + " view=" + n.view);
-                pw.println("           data=" + n.data);
-            }
-            N = mNotificationData.latestCount();
-            pw.println("  ongoingCount.size=" + N);
-            for (int i=0; i<N; i++) {
-                StatusBarNotification n = mNotificationData.getLatest(i);
-                pw.println("    [" + i + "] key=" + n.key + " view=" + n.view);
-                pw.println("           data=" + n.data);
-            }
-        }
-        */
-
-        if (false) {
-            pw.println("see the logcat for a dump of the views we have created.");
-            // must happen on ui thread
-            mHandler.post(new Runnable() {
-                    public void run() {
-                        mStatusBarView.getLocationOnScreen(mAbsPos);
-                        Slog.d(TAG, "mStatusBarView: ----- (" + mAbsPos[0] + "," + mAbsPos[1]
-                                + ") " + mStatusBarView.getWidth() + "x"
-                                + mStatusBarView.getHeight());
-                        mStatusBarView.debug();
-
-                        mExpandedView.getLocationOnScreen(mAbsPos);
-                        Slog.d(TAG, "mExpandedView: ----- (" + mAbsPos[0] + "," + mAbsPos[1]
-                                + ") " + mExpandedView.getWidth() + "x"
-                                + mExpandedView.getHeight());
-                        mExpandedView.debug();
-
-                        mTrackingView.getLocationOnScreen(mAbsPos);
-                        Slog.d(TAG, "mTrackingView: ----- (" + mAbsPos[0] + "," + mAbsPos[1]
-                                + ") " + mTrackingView.getWidth() + "x"
-                                + mTrackingView.getHeight());
-                        mTrackingView.debug();
-                    }
-                });
-        }
-    }
-
-    void onBarViewAttached() {
-        WindowManager.LayoutParams lp;
-        int pixelFormat;
-        Drawable bg;
-
-        /// ---------- Tracking View --------------
-        pixelFormat = PixelFormat.RGBX_8888;
-        bg = mTrackingView.getBackground();
-        if (bg != null) {
-            pixelFormat = bg.getOpacity();
-        }
-
-        lp = new WindowManager.LayoutParams(
-                ViewGroup.LayoutParams.MATCH_PARENT,
-                ViewGroup.LayoutParams.MATCH_PARENT,
-                WindowManager.LayoutParams.TYPE_STATUS_BAR_PANEL,
-                WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN
-                | WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS
-                | WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM,
-                pixelFormat);
-//        lp.token = mStatusBarView.getWindowToken();
-        lp.gravity = Gravity.TOP | Gravity.FILL_HORIZONTAL;
-        lp.setTitle("TrackingView");
-        lp.y = mTrackingPosition;
-        mTrackingParams = lp;
-
-        WindowManagerImpl.getDefault().addView(mTrackingView, lp);
-    }
-
-    void onTrackingViewAttached() {
-        WindowManager.LayoutParams lp;
-        int pixelFormat;
-        Drawable bg;
-
-        /// ---------- Expanded View --------------
-        pixelFormat = PixelFormat.TRANSLUCENT;
-
-        final int disph = mDisplay.getHeight();
-        lp = mExpandedDialog.getWindow().getAttributes();
-        lp.width = ViewGroup.LayoutParams.MATCH_PARENT;
-        lp.height = getExpandedHeight();
-        lp.x = 0;
-        mTrackingPosition = lp.y = -disph; // sufficiently large negative
-        lp.type = WindowManager.LayoutParams.TYPE_STATUS_BAR_PANEL;
-        lp.flags = WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN
-                | WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS
-                | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
-                | WindowManager.LayoutParams.FLAG_DITHER
-                | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
-        lp.format = pixelFormat;
-        lp.gravity = Gravity.TOP | Gravity.FILL_HORIZONTAL;
-        lp.setTitle("StatusBarExpanded");
-        mExpandedDialog.getWindow().setAttributes(lp);
-        mExpandedDialog.getWindow().setFormat(pixelFormat);
-        mExpandedParams = lp;
-
-        mExpandedDialog.getWindow().requestFeature(Window.FEATURE_NO_TITLE);
-        mExpandedDialog.setContentView(mExpandedView,
-                new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
-                                           ViewGroup.LayoutParams.MATCH_PARENT));
-        mExpandedDialog.getWindow().setBackgroundDrawable(null);
-        mExpandedDialog.show();
-        FrameLayout hack = (FrameLayout)mExpandedView.getParent();
-    }
-
-    void setDateViewVisibility(boolean visible, int anim) {
-        mDateView.setUpdates(visible);
-        mDateView.setVisibility(visible ? View.VISIBLE : View.INVISIBLE);
-        mDateView.startAnimation(loadAnim(anim, null));
-    }
-
-    void setNotificationIconVisibility(boolean visible, int anim) {
-        int old = mNotificationIcons.getVisibility();
-        int v = visible ? View.VISIBLE : View.INVISIBLE;
-        if (old != v) {
-            mNotificationIcons.setVisibility(v);
-            mNotificationIcons.startAnimation(loadAnim(anim, null));
-        }
-    }
-
-    void updateExpandedViewPos(int expandedPosition) {
-        if (SPEW) {
-            Slog.d(TAG, "updateExpandedViewPos before expandedPosition=" + expandedPosition
-                    + " mTrackingParams.y=" + mTrackingParams.y
-                    + " mTrackingPosition=" + mTrackingPosition);
-        }
-
-        int h = mStatusBarView.getHeight();
-        int disph = mDisplay.getHeight();
-
-        // If the expanded view is not visible, make sure they're still off screen.
-        // Maybe the view was resized.
-        if (!mExpandedVisible) {
-            if (mTrackingView != null) {
-                mTrackingPosition = -disph;
-                if (mTrackingParams != null) {
-                    mTrackingParams.y = mTrackingPosition;
-                    WindowManagerImpl.getDefault().updateViewLayout(mTrackingView, mTrackingParams);
-                }
-            }
-            if (mExpandedParams != null) {
-                mExpandedParams.y = -disph;
-                mExpandedDialog.getWindow().setAttributes(mExpandedParams);
-            }
-            return;
-        }
-
-        // tracking view...
-        int pos;
-        if (expandedPosition == EXPANDED_FULL_OPEN) {
-            pos = h;
-        }
-        else if (expandedPosition == EXPANDED_LEAVE_ALONE) {
-            pos = mTrackingPosition;
-        }
-        else {
-            if (expandedPosition <= disph) {
-                pos = expandedPosition;
-            } else {
-                pos = disph;
-            }
-            pos -= disph-h;
-        }
-        mTrackingPosition = mTrackingParams.y = pos;
-        mTrackingParams.height = disph-h;
-        WindowManagerImpl.getDefault().updateViewLayout(mTrackingView, mTrackingParams);
-
-        if (mExpandedParams != null) {
-            mCloseView.getLocationInWindow(mPositionTmp);
-            final int closePos = mPositionTmp[1];
-
-            mExpandedContents.getLocationInWindow(mPositionTmp);
-            final int contentsBottom = mPositionTmp[1] + mExpandedContents.getHeight();
-
-            mExpandedParams.y = pos + mTrackingView.getHeight()
-                    - (mTrackingParams.height-closePos) - contentsBottom;
-            int max = h;
-            if (mExpandedParams.y > max) {
-                mExpandedParams.y = max;
-            }
-            int min = mTrackingPosition;
-            if (mExpandedParams.y < min) {
-                mExpandedParams.y = min;
-            }
-
-            boolean visible = (mTrackingPosition + mTrackingView.getHeight()) > h;
-            if (!visible) {
-                // if the contents aren't visible, move the expanded view way off screen
-                // because the window itself extends below the content view.
-                mExpandedParams.y = -disph;
-            }
-            mExpandedDialog.getWindow().setAttributes(mExpandedParams);
-
-            // As long as this isn't just a repositioning that's not supposed to affect
-            // the user's perception of what's showing, call to say that the visibility
-            // has changed. (Otherwise, someone else will call to do that).
-            if (expandedPosition != EXPANDED_LEAVE_ALONE) {
-                if (SPEW) Slog.d(TAG, "updateExpandedViewPos visibilityChanged(" + visible + ")");
-                visibilityChanged(visible);
-            }
-        }
-
-        if (SPEW) {
-            Slog.d(TAG, "updateExpandedViewPos after  expandedPosition=" + expandedPosition
-                    + " mTrackingParams.y=" + mTrackingParams.y
-                    + " mTrackingPosition=" + mTrackingPosition
-                    + " mExpandedParams.y=" + mExpandedParams.y
-                    + " mExpandedParams.height=" + mExpandedParams.height);
-        }
-    }
-
-    int getExpandedHeight() {
-        return mDisplay.getHeight() - mStatusBarView.getHeight() - mCloseView.getHeight();
-    }
-
-    void updateExpandedHeight() {
-        if (mExpandedView != null) {
-            mExpandedParams.height = getExpandedHeight();
-            mExpandedDialog.getWindow().setAttributes(mExpandedParams);
-        }
-    }
-
-    /**
-     * The LEDs are turned o)ff when the notification panel is shown, even just a little bit.
-     * This was added last-minute and is inconsistent with the way the rest of the notifications
-     * are handled, because the notification isn't really cancelled.  The lights are just
-     * turned off.  If any other notifications happen, the lights will turn back on.  Steve says
-     * this is what he wants. (see bug 1131461)
-     */
-    void visibilityChanged(boolean visible) {
-        if (mPanelSlightlyVisible != visible) {
-            mPanelSlightlyVisible = visible;
-            try {
-                mBarService.onPanelRevealed();
-            } catch (RemoteException ex) {
-                // Won't fail unless the world has ended.
-            }
-        }
-    }
-
-    void performDisableActions(int net) {
-        int old = mDisabled;
-        int diff = net ^ old;
-        mDisabled = net;
-
-        // act accordingly
-        if ((diff & StatusBarManager.DISABLE_EXPAND) != 0) {
-            if ((net & StatusBarManager.DISABLE_EXPAND) != 0) {
-                Slog.d(TAG, "DISABLE_EXPAND: yes");
-                animateCollapse();
-            }
-        }
-        if ((diff & StatusBarManager.DISABLE_NOTIFICATION_ICONS) != 0) {
-            if ((net & StatusBarManager.DISABLE_NOTIFICATION_ICONS) != 0) {
-                Slog.d(TAG, "DISABLE_NOTIFICATION_ICONS: yes");
-                if (mTicking) {
-                    mNotificationIcons.setVisibility(View.INVISIBLE);
-                    mTicker.halt();
-                } else {
-                    setNotificationIconVisibility(false, com.android.internal.R.anim.fade_out);
-                }
-            } else {
-                Slog.d(TAG, "DISABLE_NOTIFICATION_ICONS: no");
-                if (!mExpandedVisible) {
-                    setNotificationIconVisibility(true, com.android.internal.R.anim.fade_in);
-                }
-            }
-        } else if ((diff & StatusBarManager.DISABLE_NOTIFICATION_TICKER) != 0) {
-            if (mTicking && (net & StatusBarManager.DISABLE_NOTIFICATION_TICKER) != 0) {
-                mTicker.halt();
-            }
-        }
-    }
-
-    private View.OnClickListener mClearButtonListener = new View.OnClickListener() {
-        public void onClick(View v) {
-            try {
-                mBarService.onClearAllNotifications();
-            } catch (RemoteException ex) {
-                // system process is dead if we're here.
-            }
-            animateCollapse();
-        }
-    };
-
-    private BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
-        public void onReceive(Context context, Intent intent) {
-            String action = intent.getAction();
-            if (Intent.ACTION_CLOSE_SYSTEM_DIALOGS.equals(action)
-                    || Intent.ACTION_SCREEN_OFF.equals(action)) {
-                //collapse();
-            }
-            else if (Intent.ACTION_CONFIGURATION_CHANGED.equals(action)) {
-                updateResources();
-            }
-        }
-    };
-
-    private void setIntruderAlertVisibility(boolean vis) {
-        mIntruderAlertView.setVisibility(vis ? View.VISIBLE : View.GONE);
-    }
-
-    /**
-     * Reload some of our resources when the configuration changes.
-     *
-     * We don't reload everything when the configuration changes -- we probably
-     * should, but getting that smooth is tough.  Someday we'll fix that.  In the
-     * meantime, just update the things that we know change.
-     */
-    void updateResources() {
-        Resources res = getResources();
-
-        mClearButton.setText(getText(R.string.status_bar_clear_all_button));
-        mOngoingTitle.setText(getText(R.string.status_bar_ongoing_events_title));
-        mLatestTitle.setText(getText(R.string.status_bar_latest_events_title));
-        mNoNotificationsTitle.setText(getText(R.string.status_bar_no_notifications_title));
-
-        mEdgeBorder = res.getDimensionPixelSize(R.dimen.status_bar_edge_ignore);
-
-        if (false) Slog.v(TAG, "updateResources");
-    }
-
-    //
-    // tracing
-    //
-
-    void postStartTracing() {
-        mHandler.postDelayed(mStartTracing, 3000);
-    }
-
-    void vibrate() {
-        android.os.Vibrator vib = (android.os.Vibrator)getSystemService(Context.VIBRATOR_SERVICE);
-        vib.vibrate(250);
-    }
-
-    Runnable mStartTracing = new Runnable() {
-        public void run() {
-            vibrate();
-            SystemClock.sleep(250);
-            Slog.d(TAG, "startTracing");
-            android.os.Debug.startMethodTracing("/data/statusbar-traces/trace");
-            mHandler.postDelayed(mStopTracing, 10000);
-        }
-    };
-
-    Runnable mStopTracing = new Runnable() {
-        public void run() {
-            android.os.Debug.stopMethodTracing();
-            Slog.d(TAG, "stopTracing");
-            vibrate();
-        }
-    };
 }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarView.java
index 57452af..20fc41f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarView.java
@@ -35,13 +35,12 @@
 
     static final int DIM_ANIM_TIME = 400;
     
-    StatusBarService mService;
+    PhoneStatusBarService mService;
     boolean mTracking;
     int mStartX, mStartY;
     ViewGroup mNotificationIcons;
     ViewGroup mStatusIcons;
     View mDate;
-    View mButtonArea;
     FixedSizeDrawable mBackground;
     
     boolean mNightMode = false;
@@ -65,8 +64,6 @@
         mBackground = new FixedSizeDrawable(mDate.getBackground());
         mBackground.setFixedBounds(0, 0, 0, 0);
         mDate.setBackgroundDrawable(mBackground);
-
-        mButtonArea = findViewById(R.id.buttons);
     }
 
     @Override
@@ -101,7 +98,7 @@
     @Override
     protected void onSizeChanged(int w, int h, int oldw, int oldh) {
         super.onSizeChanged(w, h, oldw, oldh);
-        mService.updateExpandedViewPos(StatusBarService.EXPANDED_LEAVE_ALONE);
+        mService.updateExpandedViewPos(PhoneStatusBarService.EXPANDED_LEAVE_ALONE);
     }
 
     @Override
@@ -132,10 +129,6 @@
 
         mDate.layout(mDate.getLeft(), mDate.getTop(), newDateRight, mDate.getBottom());
         mBackground.setFixedBounds(-mDate.getLeft(), -mDate.getTop(), (r-l), (b-t));
-
-        if (mButtonArea != null) {
-            mButtonArea.getHitRect(mButtonBounds);
-        }
     }
 
     @Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/TrackingView.java b/packages/SystemUI/src/com/android/systemui/statusbar/TrackingView.java
index 9108eee..c59eb6a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/TrackingView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/TrackingView.java
@@ -26,7 +26,7 @@
 
 public class TrackingView extends LinearLayout {
     final Display mDisplay;
-    StatusBarService mService;
+    PhoneStatusBarService mService;
     boolean mTracking;
     int mStartX, mStartY;
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/NotificationIconArea.java b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/NotificationIconArea.java
new file mode 100644
index 0000000..7835d42
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/NotificationIconArea.java
@@ -0,0 +1,74 @@
+/*
+ * 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 com.android.systemui.statusbar.tablet;
+
+import android.content.Context;
+import android.content.res.Resources;
+import android.os.Handler;
+import android.util.AttributeSet;
+import android.util.Slog;
+import android.view.View;
+import android.widget.LinearLayout;
+import android.widget.ImageView;
+
+import com.android.systemui.R;
+
+
+public class NotificationIconArea extends LinearLayout {
+    private static final String TAG = "NotificationIconArea";
+
+    MoreView mMoreView;
+    IconLayout mIconLayout;
+    DraggerView mDraggerView;
+
+    public NotificationIconArea(Context context, AttributeSet attrs) {
+        super(context, attrs);
+
+        mMoreView = new MoreView(context);
+        addView(mMoreView, new LinearLayout.LayoutParams(
+                    LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT));
+
+        mIconLayout = new IconLayout(context);
+        addView(mIconLayout, new LinearLayout.LayoutParams(
+                    LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT));
+
+        mDraggerView = new DraggerView(context);
+        addView(mDraggerView, new LinearLayout.LayoutParams(
+                    LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT));
+    }
+
+    class MoreView extends ImageView {
+        public MoreView(Context context) {
+            super(context);
+            setImageResource(R.drawable.stat_notify_more);
+        }
+    }
+
+    class IconLayout extends LinearLayout {
+        public IconLayout(Context context) {
+            super(context);
+        }
+    }
+
+    class DraggerView extends ImageView {
+        public DraggerView(Context context) {
+            super(context);
+            setImageResource(R.drawable.notification_dragger);
+        }
+    }
+}
+
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBarService.java b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBarService.java
new file mode 100644
index 0000000..24d3c39
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBarService.java
@@ -0,0 +1,102 @@
+/*
+ * 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 com.android.systemui.statusbar.tablet;
+
+import android.app.Service;
+import android.content.Context;
+import android.content.Intent;
+import android.content.res.Resources;
+import android.os.IBinder;
+import android.view.Gravity;
+import android.view.View;
+import android.widget.LinearLayout;
+
+import com.android.internal.statusbar.StatusBarIcon;
+import com.android.internal.statusbar.StatusBarIconList;
+import com.android.internal.statusbar.StatusBarNotification;
+
+import com.android.systemui.statusbar.*;
+import com.android.systemui.R;
+
+public class TabletStatusBarService extends StatusBarService {
+
+    View mStatusBarView;
+    NotificationIconArea mNotificationIconArea;
+
+    int mIconSize;
+    
+
+    @Override
+    public void onCreate() {
+        super.onCreate();
+    }
+
+    protected View makeStatusBarView() {
+        Resources res = getResources();
+
+        mIconSize = res.getDimensionPixelSize(com.android.internal.R.dimen.status_bar_icon_size);
+
+        final View sb = View.inflate(this, R.layout.status_bar, null);
+        mStatusBarView = sb;
+
+        // the more notifications icon
+        mNotificationIconArea = (NotificationIconArea)sb.findViewById(R.id.notificationIcons);
+
+        return sb;
+    }
+
+    protected int getStatusBarGravity() {
+        return Gravity.BOTTOM | Gravity.FILL_HORIZONTAL;
+    }
+
+    public void addIcon(String slot, int index, int viewIndex, StatusBarIcon icon) {
+        // TODO
+    }
+
+    public void updateIcon(String slot, int index, int viewIndex,
+            StatusBarIcon old, StatusBarIcon icon) {
+        // TODO
+    }
+
+    public void removeIcon(String slot, int index, int viewIndex) {
+        // TODO
+    }
+
+    public void addNotification(IBinder key, StatusBarNotification notification) {
+        // TODO
+    }
+
+    public void updateNotification(IBinder key, StatusBarNotification notification) {
+        // TODO
+    }
+
+    public void removeNotification(IBinder key) {
+        // TODO
+    }
+
+    public void disable(int state) {
+        // TODO
+    }
+
+    public void animateExpand() {
+        // TODO
+    }
+
+    public void animateCollapse() {
+        // TODO
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/usb/StorageNotification.java b/packages/SystemUI/src/com/android/systemui/usb/StorageNotification.java
index f8abc5a..b9e915a4 100644
--- a/packages/SystemUI/src/com/android/systemui/usb/StorageNotification.java
+++ b/packages/SystemUI/src/com/android/systemui/usb/StorageNotification.java
@@ -244,27 +244,12 @@
             intent.setClass(mContext, com.android.systemui.usb.UsbStorageActivity.class);
             intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
 
-            final boolean adbOn = 1 == Settings.Secure.getInt(
-                mContext.getContentResolver(),
-                Settings.Secure.ADB_ENABLED,
-                0);
-
             PendingIntent pi = PendingIntent.getActivity(mContext, 0, intent, 0);
             setUsbStorageNotification(
                     com.android.internal.R.string.usb_storage_notification_title,
                     com.android.internal.R.string.usb_storage_notification_message,
                     com.android.internal.R.drawable.stat_sys_data_usb,
                     false, true, pi);
-
-            if (POP_UMS_ACTIVITY_ON_CONNECT && !adbOn) {
-                // We assume that developers don't want to enable UMS every
-                // time they attach a device to a USB host. The average user,
-                // however, is looking to charge the phone (in which case this
-                // is harmless) or transfer files (in which case this coaches
-                // the user about how to complete that task and saves several
-                // steps).
-                mContext.startActivity(intent);
-            }
         } else {
             setUsbStorageNotification(0, 0, 0, false, false, null);
         }
@@ -313,6 +298,23 @@
             }
 
             mUsbStorageNotification.setLatestEventInfo(mContext, title, message, pi);
+            final boolean adbOn = 1 == Settings.Secure.getInt(
+                mContext.getContentResolver(),
+                Settings.Secure.ADB_ENABLED,
+                0);
+
+            if (POP_UMS_ACTIVITY_ON_CONNECT && !adbOn) {
+                // Pop up a full-screen alert to coach the user through enabling UMS. The average
+                // user has attached the device to USB either to charge the phone (in which case
+                // this is harmless) or transfer files, and in the latter case this alert saves
+                // several steps (as well as subtly indicates that you shouldn't mix UMS with other
+                // activities on the device).
+                //
+                // If ADB is enabled, however, we suppress this dialog (under the assumption that a
+                // developer (a) knows how to enable UMS, and (b) is probably using USB to install
+                // builds or use adb commands.
+                mUsbStorageNotification.fullScreenIntent = pi;
+            }
         }
     
         final int notificationId = mUsbStorageNotification.icon;
diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindow.java b/policy/src/com/android/internal/policy/impl/PhoneWindow.java
index 5c56d3c..070d1e8 100644
--- a/policy/src/com/android/internal/policy/impl/PhoneWindow.java
+++ b/policy/src/com/android/internal/policy/impl/PhoneWindow.java
@@ -27,6 +27,7 @@
 import com.android.internal.view.menu.ContextMenuBuilder;
 import com.android.internal.view.menu.MenuBuilder;
 import com.android.internal.view.menu.MenuDialogHelper;
+import com.android.internal.view.menu.MenuPopupHelper;
 import com.android.internal.view.menu.MenuView;
 import com.android.internal.view.menu.SubMenuBuilder;
 import com.android.internal.widget.ActionBarView;
@@ -77,9 +78,12 @@
 import android.view.inputmethod.InputMethodManager;
 import android.widget.FrameLayout;
 import android.widget.ImageView;
+import android.widget.ListPopupWindow;
 import android.widget.ProgressBar;
 import android.widget.TextView;
 
+import java.lang.ref.WeakReference;
+
 /**
  * Android-specific Window.
  * <p>
@@ -96,7 +100,7 @@
      * Simple callback used by the context menu and its submenus. The options
      * menu submenus do not use this (their behavior is more complex).
      */
-    ContextMenuCallback mContextMenuCallback = new ContextMenuCallback(FEATURE_CONTEXT_MENU);
+    DialogMenuCallback mContextMenuCallback = new DialogMenuCallback(FEATURE_CONTEXT_MENU);
 
     // This is the top-level view of the window, containing the window decor.
     private DecorView mDecor;
@@ -105,7 +109,7 @@
     // mDecor itself, or a child of mDecor where the contents go.
     private ViewGroup mContentParent;
 
-    SurfaceHolder.Callback mTakeSurfaceCallback;
+    SurfaceHolder.Callback2 mTakeSurfaceCallback;
     BaseSurfaceHolder mSurfaceHolder;
     
     InputQueue.Callback mTakeInputQueueCallback;
@@ -251,7 +255,7 @@
     }
 
     @Override
-    public void takeSurface(SurfaceHolder.Callback callback) {
+    public void takeSurface(SurfaceHolder.Callback2 callback) {
         mTakeSurfaceCallback = callback;
     }
     
@@ -280,7 +284,7 @@
         if (mTitleView != null) {
             mTitleView.setText(title);
         } else if (mActionBar != null) {
-            mActionBar.setTitle(title);
+            mActionBar.setWindowTitle(title);
         }
         mTitle = title;
     }
@@ -808,8 +812,20 @@
             return true;
         }
 
-        // The window manager will give us a valid window token
-        new MenuDialogHelper(subMenu).show(null);
+        final Menu parentMenu = subMenu.getRootMenu();
+        final PanelFeatureState panel = findMenuPanel(parentMenu);
+
+        /*
+         * Use the panel open state to determine whether this is coming from an open panel
+         * or an action button. If it's an open panel we want to use MenuDialogHelper.
+         * If it's closed we want to grab the relevant view and create a popup anchored to it.
+         */
+        if (panel.isOpen) {
+            // The window manager will give us a valid window token
+            new MenuDialogHelper(subMenu).show(null);
+        } else {
+            new MenuPopupHelper(getContext(), subMenu).show();
+        }
 
         return true;
     }
@@ -2069,7 +2085,7 @@
             }
         }
 
-        public android.view.SurfaceHolder.Callback willYouTakeTheSurface() {
+        public android.view.SurfaceHolder.Callback2 willYouTakeTheSurface() {
             return mFeatureId < 0 ? mTakeSurfaceCallback : null;
         }
         
@@ -2318,7 +2334,7 @@
             } else {
                 mActionBar = (ActionBarView) findViewById(com.android.internal.R.id.action_bar);
                 if (mActionBar != null && mActionBar.getTitle() == null) {
-                    mActionBar.setTitle(mTitle);
+                    mActionBar.setWindowTitle(mTitle);
                 }
             }
         }
@@ -2797,11 +2813,11 @@
      * <li> Calls back to the callback's onMenuItemSelected when an item is
      * selected.
      */
-    private final class ContextMenuCallback implements MenuBuilder.Callback {
+    private final class DialogMenuCallback implements MenuBuilder.Callback {
         private int mFeatureId;
         private MenuDialogHelper mSubMenuHelper;
 
-        public ContextMenuCallback(int featureId) {
+        public DialogMenuCallback(int featureId) {
             mFeatureId = featureId;
         }
 
diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
index 43bd26d..767f38d 100755
--- a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
+++ b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
@@ -60,7 +60,6 @@
 import android.view.KeyEvent;
 import android.view.MotionEvent;
 import android.view.WindowOrientationListener;
-import android.view.RawInputEvent;
 import android.view.Surface;
 import android.view.View;
 import android.view.ViewConfiguration;
@@ -153,8 +152,6 @@
     static final int APPLICATION_MEDIA_OVERLAY_SUBLAYER = -1;
     static final int APPLICATION_PANEL_SUBLAYER = 1;
     static final int APPLICATION_SUB_PANEL_SUBLAYER = 2;
-
-    static final float SLIDE_TOUCH_EVENT_SIZE_LIMIT = 0.6f;
     
     // Debugging: set this to have the system act like there is no hard keyboard.
     static final boolean KEYBOARD_ALWAYS_HIDDEN = false;
@@ -164,6 +161,10 @@
     static public final String SYSTEM_DIALOG_REASON_RECENT_APPS = "recentapps";
     static public final String SYSTEM_DIALOG_REASON_HOME_KEY = "homekey";
 
+    // Useful scan codes.
+    private static final int SW_LID = 0x00;
+    private static final int BTN_MOUSE = 0x110;
+    
     final Object mLock = new Object();
     
     Context mContext;
@@ -690,7 +691,7 @@
     
     void readLidState() {
         try {
-            int sw = mWindowManager.getSwitchState(RawInputEvent.SW_LID);
+            int sw = mWindowManager.getSwitchState(SW_LID);
             if (sw >= 0) {
                 mLidOpen = sw == 0;
             }
@@ -727,19 +728,6 @@
                 : Configuration.KEYBOARDHIDDEN_YES;
     }
     
-    public boolean isCheekPressedAgainstScreen(MotionEvent ev) {
-        if(ev.getSize() > SLIDE_TOUCH_EVENT_SIZE_LIMIT) {
-            return true;
-        }
-        int size = ev.getHistorySize();
-        for(int i = 0; i < size; i++) {
-            if(ev.getHistoricalSize(i) > SLIDE_TOUCH_EVENT_SIZE_LIMIT) {
-                return true;
-            }
-        }
-        return false;
-    }
-    
     public void dispatchedPointerEventLw(MotionEvent ev, int targetX, int targetY) {
         if (mPointerLocationView == null) {
             return;
@@ -1034,19 +1022,22 @@
         };
 
     /** {@inheritDoc} */
-    public boolean interceptKeyTi(WindowState win, int code, int metaKeys, boolean down, 
-            int repeatCount, int flags) {
-        boolean keyguardOn = keyguardOn();
+    @Override
+    public boolean interceptKeyBeforeDispatching(WindowState win, int action, int flags,
+            int keyCode, 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);
 
         if (false) {
-            Log.d(TAG, "interceptKeyTi code=" + code + " down=" + down + " repeatCount="
+            Log.d(TAG, "interceptKeyTi keyCode=" + keyCode + " down=" + down + " repeatCount="
                     + repeatCount + " keyguardOn=" + keyguardOn + " mHomePressed=" + mHomePressed);
         }
 
         // Clear a pending HOME longpress if the user releases Home
         // TODO: This could probably be inside the next bit of logic, but that code
         // turned out to be a bit fragile so I'm doing it here explicitly, for now.
-        if ((code == KeyEvent.KEYCODE_HOME) && !down) {
+        if ((keyCode == KeyEvent.KEYCODE_HOME) && !down) {
             mHandler.removeCallbacks(mHomeLongPress);
         }
 
@@ -1056,11 +1047,11 @@
             
             // If we have released the home key, and didn't do anything else
             // while it was pressed, then it is time to go home!
-            if (code == KeyEvent.KEYCODE_HOME) {
+            if (keyCode == KeyEvent.KEYCODE_HOME) {
                 if (!down) {
                     mHomePressed = false;
                     
-                    if ((flags&KeyEvent.FLAG_CANCELED) == 0) {
+                    if (! canceled) {
                         // If an incoming call is ringing, HOME is totally disabled.
                         // (The user is already on the InCallScreen at this point,
                         // and his ONLY options are to answer or reject the call.)
@@ -1094,7 +1085,7 @@
         // can never break it, although if keyguard is on, we do let
         // it handle it, because that gives us the correct 5 second
         // timeout.
-        if (code == KeyEvent.KEYCODE_HOME) {
+        if (keyCode == KeyEvent.KEYCODE_HOME) {
 
             // If a system window has focus, then it doesn't make sense
             // right now to interact with applications.
@@ -1122,17 +1113,17 @@
                 mHomePressed = true;
             }
             return true;
-        } else if (code == KeyEvent.KEYCODE_MENU) {
+        } else if (keyCode == KeyEvent.KEYCODE_MENU) {
             // Hijack modified menu keys for debugging features
             final int chordBug = KeyEvent.META_SHIFT_ON;
 
             if (down && repeatCount == 0) {
-                if (mEnableShiftMenuBugReports && (metaKeys & chordBug) == chordBug) {
+                if (mEnableShiftMenuBugReports && (metaState & chordBug) == chordBug) {
                     Intent intent = new Intent(Intent.ACTION_BUG_REPORT);
                     mContext.sendOrderedBroadcast(intent, null);
                     return true;
                 } else if (SHOW_PROCESSES_ON_ALT_MENU &&
-                        (metaKeys & KeyEvent.META_ALT_ON) == KeyEvent.META_ALT_ON) {
+                        (metaState & KeyEvent.META_ALT_ON) == KeyEvent.META_ALT_ON) {
                     Intent service = new Intent();
                     service.setClassName(mContext, "com.android.server.LoadAverageService");
                     ContentResolver res = mContext.getContentResolver();
@@ -1148,7 +1139,7 @@
                     return true;
                 }
             }
-        } else if (code == KeyEvent.KEYCODE_SEARCH) {
+        } else if (keyCode == KeyEvent.KEYCODE_SEARCH) {
             if (down) {
                 if (repeatCount == 0) {
                     mSearchKeyPressed = true;
@@ -1167,7 +1158,7 @@
         // Shortcuts are invoked through Search+key, so intercept those here
         if (mSearchKeyPressed) {
             if (down && repeatCount == 0 && !keyguardOn) {
-                Intent shortcutIntent = mShortcutManager.getIntent(code, metaKeys);
+                Intent shortcutIntent = mShortcutManager.getIntent(keyCode, metaState);
                 if (shortcutIntent != null) {
                     shortcutIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
                     mContext.startActivity(shortcutIntent);
@@ -1613,42 +1604,6 @@
     }
 
     /** {@inheritDoc} */
-    public boolean preprocessInputEventTq(RawInputEvent event) {
-        switch (event.type) {
-            case RawInputEvent.EV_SW:
-                if (event.keycode == RawInputEvent.SW_LID) {
-                    // lid changed state
-                    mLidOpen = event.value == 0;
-                    boolean awakeNow = mKeyguardMediator.doLidChangeTq(mLidOpen);
-                    updateRotation(Surface.FLAGS_ORIENTATION_ANIMATION_DISABLE);
-                    if (awakeNow) {
-                        // If the lid opening and we don't have to keep the
-                        // keyguard up, then we can turn on the screen
-                        // immediately.
-                        mKeyguardMediator.pokeWakelock();
-                    } else if (keyguardIsShowingTq()) {
-                        if (mLidOpen) {
-                            // If we are opening the lid and not hiding the
-                            // keyguard, then we need to have it turn on the
-                            // screen once it is shown.
-                            mKeyguardMediator.onWakeKeyWhenKeyguardShowingTq(
-                                    KeyEvent.KEYCODE_POWER);
-                        }
-                    } else {
-                        // Light up the keyboard if we are sliding up.
-                        if (mLidOpen) {
-                            mPowerManager.userActivity(SystemClock.uptimeMillis(), false,
-                                    LocalPowerManager.BUTTON_EVENT);
-                        } else {
-                            mPowerManager.userActivity(SystemClock.uptimeMillis(), false,
-                                    LocalPowerManager.OTHER_EVENT);
-                        }
-                    }
-                }
-        }
-        return false;
-    }
-    
     public void notifyLidSwitchChanged(long whenNanos, boolean lidOpen) {
         // lid changed state
         mLidOpen = lidOpen;
@@ -1679,26 +1634,6 @@
         }
     }
 
-    
-    /** {@inheritDoc} */
-    public boolean isAppSwitchKeyTqTiLwLi(int keycode) {
-        return keycode == KeyEvent.KEYCODE_HOME
-                || keycode == KeyEvent.KEYCODE_ENDCALL;
-    }
-    
-    /** {@inheritDoc} */
-    public boolean isMovementKeyTi(int keycode) {
-        switch (keycode) {
-            case KeyEvent.KEYCODE_DPAD_UP:
-            case KeyEvent.KEYCODE_DPAD_DOWN:
-            case KeyEvent.KEYCODE_DPAD_LEFT:
-            case KeyEvent.KEYCODE_DPAD_RIGHT:
-                return true;
-        }
-        return false;
-    }
-
-
     /**
      * @return Whether a telephone call is in progress right now.
      */
@@ -1769,60 +1704,63 @@
     }
  
     /** {@inheritDoc} */
-    public int interceptKeyTq(RawInputEvent event, boolean screenIsOn) {
+    @Override
+    public int interceptKeyBeforeQueueing(long whenNanos, int keyCode, boolean down,
+            int policyFlags, boolean isScreenOn) {
         int result = ACTION_PASS_TO_USER;
-        final boolean isWakeKey = isWakeKeyTq(event);
+        
+        final boolean isWakeKey = (policyFlags
+                & (WindowManagerPolicy.FLAG_WAKE | WindowManagerPolicy.FLAG_WAKE_DROPPED)) != 0;
+        
         // 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.
         // This will prevent any keys other than the power button from waking the screen
         // when the keyguard is hidden by another activity.
-        final boolean keyguardActive = (screenIsOn ?
+        final boolean keyguardActive = (isScreenOn ?
                                         mKeyguardMediator.isShowingAndNotHidden() :
                                         mKeyguardMediator.isShowing());
 
         if (false) {
-            Log.d(TAG, "interceptKeyTq event=" + event + " keycode=" + event.keycode
-                  + " screenIsOn=" + screenIsOn + " keyguardActive=" + keyguardActive);
+            Log.d(TAG, "interceptKeyTq keycode=" + keyCode
+                  + " screenIsOn=" + isScreenOn + " keyguardActive=" + keyguardActive);
         }
 
         if (keyguardActive) {
-            if (screenIsOn) {
+            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;
 
-                final boolean isKeyDown =
-                        (event.type == RawInputEvent.EV_KEY) && (event.value != 0);
-                if (isWakeKey && isKeyDown) {
+                if (isWakeKey && down) {
 
                     // 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(event.keycode)
-                            && (event.keycode == KeyEvent.KEYCODE_VOLUME_DOWN
-                                || event.keycode == KeyEvent.KEYCODE_VOLUME_UP)) {
+                    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, event.keycode);
+                            handleVolumeKey(AudioManager.STREAM_VOICE_CALL, keyCode);
                         } else if (isMusicActive()) {
-                            handleVolumeKey(AudioManager.STREAM_MUSIC, event.keycode);
+                            handleVolumeKey(AudioManager.STREAM_MUSIC, keyCode);
                         }
                     }
                 }
             }
-        } else if (!screenIsOn) {
+        } 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() && event.type == RawInputEvent.EV_KEY &&
-                     (event.keycode == KeyEvent.KEYCODE_VOLUME_DOWN
-                                || event.keycode == KeyEvent.KEYCODE_VOLUME_UP)) {
+            if (isInCall() &&
+                     (keyCode == KeyEvent.KEYCODE_VOLUME_DOWN
+                                || keyCode == KeyEvent.KEYCODE_VOLUME_UP)) {
                 result &= ~ACTION_PASS_TO_USER;
-                handleVolumeKey(AudioManager.STREAM_VOICE_CALL, event.keycode);
+                handleVolumeKey(AudioManager.STREAM_VOICE_CALL, keyCode);
             }
             if (isWakeKey) {
                 // a wake key has a sole purpose of waking the device; don't pass
@@ -1832,156 +1770,151 @@
             }
         }
 
-        int type = event.type;
-        int code = event.keycode;
-        boolean down = event.value != 0;
-
-        if (type == RawInputEvent.EV_KEY) {
-            if (code == KeyEvent.KEYCODE_ENDCALL
-                    || code == 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 (code == KeyEvent.KEYCODE_ENDCALL) {
+        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();
-                            } else if (code == 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();
-                                }
                             }
-                        } catch (RemoteException ex) {
-                            Log.w(TAG, "ITelephony threw RemoteException" + ex);
                         }
-                    } else {
-                        Log.w(TAG, "!!! Unable to find ITelephony interface !!!");
-                    }
-
-                    if (!screenIsOn
-                            || (handled && code != KeyEvent.KEYCODE_POWER)
-                            || (handled && hungUp && code == 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;
+                    } catch (RemoteException ex) {
+                        Log.w(TAG, "ITelephony threw RemoteException" + ex);
                     }
                 } else {
-                    mHandler.removeCallbacks(mPowerLongPress);
-                    if (mShouldTurnOffOnKeyUp) {
-                        mShouldTurnOffOnKeyUp = false;
-                        boolean gohome, sleeps;
-                        if (code == 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 (keyguardActive
-                                || (sleeps && !gohome)
-                                || (gohome && !goHome() && sleeps)) {
-                            // they must already be on the keyguad or home screen,
-                            // go to sleep instead
-                            Log.d(TAG, "I'm tired mEndcallBehavior=0x"
-                                    + Integer.toHexString(mEndcallBehavior));
-                            result &= ~ACTION_POKE_USER_ACTIVITY;
-                            result |= ACTION_GO_TO_SLEEP;
-                        }
-                        result &= ~ACTION_PASS_TO_USER;
-                    }
+                    Log.w(TAG, "!!! Unable to find ITelephony interface !!!");
                 }
-            } else if (isMediaKey(code)) {
-                // 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.
-                    KeyEvent keyEvent = new KeyEvent(event.when, event.when,
-                            down ? KeyEvent.ACTION_DOWN : KeyEvent.ACTION_UP,
-                            code, 0);
-                    mBroadcastWakeLock.acquire();
-                    mHandler.post(new PassHeadsetKey(keyEvent));
+
+                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 if (code == 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();
-
-                                // And *don't* pass this key thru to the current activity
-                                // (which is presumably the InCallScreen.)
-                                result &= ~ACTION_PASS_TO_USER;
-                            }
-                        } else {
-                            Log.w(TAG, "CALL button: Unable to find ITelephony interface");
-                        }
-                    } catch (RemoteException ex) {
-                        Log.w(TAG, "CALL button: RemoteException from getPhoneInterface()", ex);
+            } 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 (keyguardActive
+                            || (sleeps && !gohome)
+                            || (gohome && !goHome() && sleeps)) {
+                        // they must already be on the keyguad or home screen,
+                        // go to sleep instead
+                        Log.d(TAG, "I'm tired mEndcallBehavior=0x"
+                                + Integer.toHexString(mEndcallBehavior));
+                        result &= ~ACTION_POKE_USER_ACTIVITY;
+                        result |= ACTION_GO_TO_SLEEP;
+                    }
+                    result &= ~ACTION_PASS_TO_USER;
                 }
-            } else if ((code == KeyEvent.KEYCODE_VOLUME_UP)
-                       || (code == 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.
+            }
+        } 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.)
 
-                // 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();
+            // 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();
 
-                                // 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");
+                            // 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, "VOLUME button: RemoteException from getPhoneInterface()", 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);
                 }
             }
         }
@@ -2031,35 +1964,6 @@
     };
 
     /** {@inheritDoc} */
-    public boolean isWakeRelMovementTq(int device, int classes,
-            RawInputEvent event) {
-        // if it's tagged with one of the wake bits, it wakes up the device
-        return ((event.flags & (FLAG_WAKE | FLAG_WAKE_DROPPED)) != 0);
-    }
-
-    /** {@inheritDoc} */
-    public boolean isWakeAbsMovementTq(int device, int classes,
-            RawInputEvent event) {
-        // if it's tagged with one of the wake bits, it wakes up the device
-        return ((event.flags & (FLAG_WAKE | FLAG_WAKE_DROPPED)) != 0);
-    }
-
-    /**
-     * Given the current state of the world, should this key wake up the device?
-     */
-    protected boolean isWakeKeyTq(RawInputEvent event) {
-        // There are not key maps for trackball devices, but we'd still
-        // like to have pressing it wake the device up, so force it here.
-        int keycode = event.keycode;
-        int flags = event.flags;
-        if (keycode == RawInputEvent.BTN_MOUSE) {
-            flags |= WindowManagerPolicy.FLAG_WAKE;
-        }
-        return (flags
-                & (WindowManagerPolicy.FLAG_WAKE | WindowManagerPolicy.FLAG_WAKE_DROPPED)) != 0;
-    }
-
-    /** {@inheritDoc} */
     public void screenTurnedOff(int why) {
         EventLog.writeEvent(70000, 0);
         mKeyguardMediator.onScreenTurnedOff(why);
@@ -2172,7 +2076,7 @@
             int menuState = mWindowManager.getKeycodeState(KeyEvent.KEYCODE_MENU);
             int sState = mWindowManager.getKeycodeState(KeyEvent.KEYCODE_S);
             int dpadState = mWindowManager.getDPadKeycodeState(KeyEvent.KEYCODE_DPAD_CENTER);
-            int trackballState = mWindowManager.getTrackballScancodeState(RawInputEvent.BTN_MOUSE);
+            int trackballState = mWindowManager.getTrackballScancodeState(BTN_MOUSE);
             mSafeMode = menuState > 0 || sState > 0 || dpadState > 0 || trackballState > 0;
             performHapticFeedbackLw(null, mSafeMode
                     ? HapticFeedbackConstants.SAFE_MODE_ENABLED
@@ -2420,13 +2324,6 @@
         return true;
     }
     
-    public void keyFeedbackFromInput(KeyEvent event) {
-        if (event.getAction() == KeyEvent.ACTION_DOWN
-                && (event.getFlags()&KeyEvent.FLAG_VIRTUAL_HARD_KEY) != 0) {
-            performHapticFeedbackLw(null, HapticFeedbackConstants.VIRTUAL_KEY, false);
-        }
-    }
-    
     public void screenOnStoppedLw() {
         if (!mKeyguardMediator.isShowingAndNotHidden() && mPowerManager.isScreenOn()) {
             long curTime = SystemClock.uptimeMillis();
diff --git a/libs/audioflinger/A2dpAudioInterface.cpp b/services/audioflinger/A2dpAudioInterface.cpp
similarity index 100%
rename from libs/audioflinger/A2dpAudioInterface.cpp
rename to services/audioflinger/A2dpAudioInterface.cpp
diff --git a/libs/audioflinger/A2dpAudioInterface.h b/services/audioflinger/A2dpAudioInterface.h
similarity index 100%
rename from libs/audioflinger/A2dpAudioInterface.h
rename to services/audioflinger/A2dpAudioInterface.h
diff --git a/libs/audioflinger/Android.mk b/services/audioflinger/Android.mk
similarity index 100%
rename from libs/audioflinger/Android.mk
rename to services/audioflinger/Android.mk
diff --git a/libs/audioflinger/AudioBufferProvider.h b/services/audioflinger/AudioBufferProvider.h
similarity index 100%
rename from libs/audioflinger/AudioBufferProvider.h
rename to services/audioflinger/AudioBufferProvider.h
diff --git a/libs/audioflinger/AudioDumpInterface.cpp b/services/audioflinger/AudioDumpInterface.cpp
similarity index 100%
rename from libs/audioflinger/AudioDumpInterface.cpp
rename to services/audioflinger/AudioDumpInterface.cpp
diff --git a/libs/audioflinger/AudioDumpInterface.h b/services/audioflinger/AudioDumpInterface.h
similarity index 100%
rename from libs/audioflinger/AudioDumpInterface.h
rename to services/audioflinger/AudioDumpInterface.h
diff --git a/libs/audioflinger/AudioFlinger.cpp b/services/audioflinger/AudioFlinger.cpp
similarity index 98%
rename from libs/audioflinger/AudioFlinger.cpp
rename to services/audioflinger/AudioFlinger.cpp
index e6f46ce..771d885 100644
--- a/libs/audioflinger/AudioFlinger.cpp
+++ b/services/audioflinger/AudioFlinger.cpp
@@ -17,8 +17,7 @@
 
 
 #define LOG_TAG "AudioFlinger"
-//
-#define LOG_NDEBUG 0
+//#define LOG_NDEBUG 0
 
 #include <math.h>
 #include <signal.h>
@@ -5085,15 +5084,53 @@
     }
 }
 
+void AudioFlinger::EffectModule::updateState() {
+    Mutex::Autolock _l(mLock);
+
+    switch (mState) {
+    case RESTART:
+        reset_l();
+        // FALL THROUGH
+
+    case STARTING:
+        // clear auxiliary effect input buffer for next accumulation
+        if ((mDescriptor.flags & EFFECT_FLAG_TYPE_MASK) == EFFECT_FLAG_TYPE_AUXILIARY) {
+            memset(mConfig.inputCfg.buffer.raw,
+                   0,
+                   mConfig.inputCfg.buffer.frameCount*sizeof(int32_t));
+        }
+        start_l();
+        mState = ACTIVE;
+        break;
+    case STOPPING:
+        stop_l();
+        mDisableWaitCnt = mMaxDisableWaitCnt;
+        mState = STOPPED;
+        break;
+    case STOPPED:
+        // mDisableWaitCnt is forced to 1 by process() when the engine indicates the end of the
+        // turn off sequence.
+        if (--mDisableWaitCnt == 0) {
+            reset_l();
+            mState = IDLE;
+        }
+        break;
+    default: //IDLE , ACTIVE
+        break;
+    }
+}
+
 void AudioFlinger::EffectModule::process()
 {
     Mutex::Autolock _l(mLock);
 
-    if (mEffectInterface == NULL || mConfig.inputCfg.buffer.raw == NULL || mConfig.outputCfg.buffer.raw == NULL) {
+    if (mEffectInterface == NULL ||
+            mConfig.inputCfg.buffer.raw == NULL ||
+            mConfig.outputCfg.buffer.raw == NULL) {
         return;
     }
 
-    if (mState != IDLE) {
+    if (mState == ACTIVE || mState == STOPPING || mState == STOPPED) {
         // do 32 bit to 16 bit conversion for auxiliary effect input buffer
         if ((mDescriptor.flags & EFFECT_FLAG_TYPE_MASK) == EFFECT_FLAG_TYPE_AUXILIARY) {
             AudioMixer::ditherAndClamp(mConfig.inputCfg.buffer.s32,
@@ -5101,33 +5138,15 @@
                                         mConfig.inputCfg.buffer.frameCount);
         }
 
-        // TODO: handle effects with buffer provider
-        if (mState != ACTIVE) {
-            switch (mState) {
-            case RESET:
-                reset_l();
-                mState = STARTING;
-                // clear auxiliary effect input buffer for next accumulation
-                if ((mDescriptor.flags & EFFECT_FLAG_TYPE_MASK) == EFFECT_FLAG_TYPE_AUXILIARY) {
-                    memset(mConfig.inputCfg.buffer.raw, 0, mConfig.inputCfg.buffer.frameCount*sizeof(int32_t));
-                }
-                return;
-            case STARTING:
-                start_l();
-                mState = ACTIVE;
-                break;
-            case STOPPING:
-                mState = STOPPED;
-                break;
-            case STOPPED:
-                stop_l();
-                mState = IDLE;
-                return;
-            }
-        }
-
         // do the actual processing in the effect engine
-        (*mEffectInterface)->process(mEffectInterface, &mConfig.inputCfg.buffer, &mConfig.outputCfg.buffer);
+        int ret = (*mEffectInterface)->process(mEffectInterface,
+                                               &mConfig.inputCfg.buffer,
+                                               &mConfig.outputCfg.buffer);
+
+        // force transition to IDLE state when engine is ready
+        if (mState == STOPPED && ret == -ENODATA) {
+            mDisableWaitCnt = 1;
+        }
 
         // clear auxiliary effect input buffer for next accumulation
         if ((mDescriptor.flags & EFFECT_FLAG_TYPE_MASK) == EFFECT_FLAG_TYPE_AUXILIARY) {
@@ -5216,6 +5235,10 @@
     if (status == 0) {
         status = cmdStatus;
     }
+
+    mMaxDisableWaitCnt = (MAX_DISABLE_TIME_MS * mConfig.outputCfg.samplingRate) /
+            (1000 * mConfig.outputCfg.buffer.frameCount);
+
     return status;
 }
 
@@ -5292,21 +5315,19 @@
         switch (mState) {
         // going from disabled to enabled
         case IDLE:
-            mState = RESET;
+            mState = STARTING;
+            break;
+        case STOPPED:
+            mState = RESTART;
             break;
         case STOPPING:
             mState = ACTIVE;
             break;
-        case STOPPED:
-            mState = STARTING;
-            break;
 
         // going from enabled to disabled
-        case RESET:
-            mState = IDLE;
-            break;
+        case RESTART:
         case STARTING:
-            mState = STOPPED;
+            mState = IDLE;
             break;
         case ACTIVE:
             mState = STOPPING;
@@ -5325,7 +5346,7 @@
 bool AudioFlinger::EffectModule::isEnabled()
 {
     switch (mState) {
-    case RESET:
+    case RESTART:
     case STARTING:
     case ACTIVE:
         return true;
@@ -5772,6 +5793,9 @@
     for (size_t i = 0; i < size; i++) {
         mEffects[i]->process();
     }
+    for (size_t i = 0; i < size; i++) {
+        mEffects[i]->updateState();
+    }
     // if no track is active, input buffer must be cleared here as the mixer process
     // will not do it
     if (mSessionId > 0 && activeTracks() == 0) {
@@ -6044,11 +6068,4 @@
     return BnAudioFlinger::onTransact(code, data, reply, flags);
 }
 
-// ----------------------------------------------------------------------------
-
-void AudioFlinger::instantiate() {
-    defaultServiceManager()->addService(
-            String16("media.audio_flinger"), new AudioFlinger());
-}
-
 }; // namespace android
diff --git a/libs/audioflinger/AudioFlinger.h b/services/audioflinger/AudioFlinger.h
similarity index 98%
rename from libs/audioflinger/AudioFlinger.h
rename to services/audioflinger/AudioFlinger.h
index ec3d7f1..7013d76 100644
--- a/libs/audioflinger/AudioFlinger.h
+++ b/services/audioflinger/AudioFlinger.h
@@ -31,10 +31,12 @@
 #include <utils/Atomic.h>
 #include <utils/Errors.h>
 #include <utils/threads.h>
-#include <binder/MemoryDealer.h>
 #include <utils/SortedVector.h>
 #include <utils/Vector.h>
 
+#include <binder/BinderService.h>
+#include <binder/MemoryDealer.h>
+
 #include <hardware_legacy/AudioHardwareInterface.h>
 
 #include "AudioBufferProvider.h"
@@ -58,10 +60,13 @@
 
 static const nsecs_t kStandbyTimeInNsecs = seconds(3);
 
-class AudioFlinger : public BnAudioFlinger
+class AudioFlinger :
+    public BinderService<AudioFlinger>,
+    public BnAudioFlinger
 {
+    friend class BinderService<AudioFlinger>;
 public:
-    static void instantiate();
+    static char const* getServiceName() { return "media.audio_flinger"; }
 
     virtual     status_t    dump(int fd, const Vector<String16>& args);
 
@@ -905,7 +910,7 @@
 
         enum effect_state {
             IDLE,
-            RESET,
+            RESTART,
             STARTING,
             ACTIVE,
             STOPPING,
@@ -914,6 +919,7 @@
 
         int         id() { return mId; }
         void process();
+        void updateState();
         status_t command(int cmdCode, int cmdSize, void *pCmdData, int *replySize, void *pReplyData);
 
         void reset_l();
@@ -948,6 +954,9 @@
 
     protected:
 
+        // Maximum time allocated to effect engines to complete the turn off sequence
+        static const uint32_t MAX_DISABLE_TIME_MS = 10000;
+
         EffectModule(const EffectModule&);
         EffectModule& operator = (const EffectModule&);
 
@@ -973,6 +982,9 @@
         status_t mStatus;               // initialization status
         uint32_t mState;                // current activation state (effect_state)
         Vector< wp<EffectHandle> > mHandles;    // list of client handles
+        uint32_t mMaxDisableWaitCnt;    // maximum grace period before forcing an effect off after
+                                        // sending disable command.
+        uint32_t mDisableWaitCnt;       // current process() calls count during disable period.
     };
 
     // The EffectHandle class implements the IEffect interface. It provides resources
diff --git a/libs/audioflinger/AudioHardwareGeneric.cpp b/services/audioflinger/AudioHardwareGeneric.cpp
similarity index 100%
rename from libs/audioflinger/AudioHardwareGeneric.cpp
rename to services/audioflinger/AudioHardwareGeneric.cpp
diff --git a/libs/audioflinger/AudioHardwareGeneric.h b/services/audioflinger/AudioHardwareGeneric.h
similarity index 100%
rename from libs/audioflinger/AudioHardwareGeneric.h
rename to services/audioflinger/AudioHardwareGeneric.h
diff --git a/libs/audioflinger/AudioHardwareInterface.cpp b/services/audioflinger/AudioHardwareInterface.cpp
similarity index 100%
rename from libs/audioflinger/AudioHardwareInterface.cpp
rename to services/audioflinger/AudioHardwareInterface.cpp
diff --git a/libs/audioflinger/AudioHardwareStub.cpp b/services/audioflinger/AudioHardwareStub.cpp
similarity index 100%
rename from libs/audioflinger/AudioHardwareStub.cpp
rename to services/audioflinger/AudioHardwareStub.cpp
diff --git a/libs/audioflinger/AudioHardwareStub.h b/services/audioflinger/AudioHardwareStub.h
similarity index 100%
rename from libs/audioflinger/AudioHardwareStub.h
rename to services/audioflinger/AudioHardwareStub.h
diff --git a/libs/audioflinger/AudioMixer.cpp b/services/audioflinger/AudioMixer.cpp
similarity index 100%
rename from libs/audioflinger/AudioMixer.cpp
rename to services/audioflinger/AudioMixer.cpp
diff --git a/libs/audioflinger/AudioMixer.h b/services/audioflinger/AudioMixer.h
similarity index 100%
rename from libs/audioflinger/AudioMixer.h
rename to services/audioflinger/AudioMixer.h
diff --git a/libs/audioflinger/AudioPolicyManagerBase.cpp b/services/audioflinger/AudioPolicyManagerBase.cpp
similarity index 100%
rename from libs/audioflinger/AudioPolicyManagerBase.cpp
rename to services/audioflinger/AudioPolicyManagerBase.cpp
diff --git a/libs/audioflinger/AudioPolicyService.cpp b/services/audioflinger/AudioPolicyService.cpp
similarity index 100%
rename from libs/audioflinger/AudioPolicyService.cpp
rename to services/audioflinger/AudioPolicyService.cpp
diff --git a/libs/audioflinger/AudioPolicyService.h b/services/audioflinger/AudioPolicyService.h
similarity index 100%
rename from libs/audioflinger/AudioPolicyService.h
rename to services/audioflinger/AudioPolicyService.h
diff --git a/libs/audioflinger/AudioResampler.cpp b/services/audioflinger/AudioResampler.cpp
similarity index 100%
rename from libs/audioflinger/AudioResampler.cpp
rename to services/audioflinger/AudioResampler.cpp
diff --git a/libs/audioflinger/AudioResampler.h b/services/audioflinger/AudioResampler.h
similarity index 100%
rename from libs/audioflinger/AudioResampler.h
rename to services/audioflinger/AudioResampler.h
diff --git a/libs/audioflinger/AudioResamplerCubic.cpp b/services/audioflinger/AudioResamplerCubic.cpp
similarity index 100%
rename from libs/audioflinger/AudioResamplerCubic.cpp
rename to services/audioflinger/AudioResamplerCubic.cpp
diff --git a/libs/audioflinger/AudioResamplerCubic.h b/services/audioflinger/AudioResamplerCubic.h
similarity index 100%
rename from libs/audioflinger/AudioResamplerCubic.h
rename to services/audioflinger/AudioResamplerCubic.h
diff --git a/libs/audioflinger/AudioResamplerSinc.cpp b/services/audioflinger/AudioResamplerSinc.cpp
similarity index 100%
rename from libs/audioflinger/AudioResamplerSinc.cpp
rename to services/audioflinger/AudioResamplerSinc.cpp
diff --git a/libs/audioflinger/AudioResamplerSinc.h b/services/audioflinger/AudioResamplerSinc.h
similarity index 100%
rename from libs/audioflinger/AudioResamplerSinc.h
rename to services/audioflinger/AudioResamplerSinc.h
diff --git a/camera/libcameraservice/Android.mk b/services/camera/libcameraservice/Android.mk
similarity index 100%
rename from camera/libcameraservice/Android.mk
rename to services/camera/libcameraservice/Android.mk
diff --git a/camera/libcameraservice/CameraHardwareStub.cpp b/services/camera/libcameraservice/CameraHardwareStub.cpp
similarity index 100%
rename from camera/libcameraservice/CameraHardwareStub.cpp
rename to services/camera/libcameraservice/CameraHardwareStub.cpp
diff --git a/camera/libcameraservice/CameraHardwareStub.h b/services/camera/libcameraservice/CameraHardwareStub.h
similarity index 100%
rename from camera/libcameraservice/CameraHardwareStub.h
rename to services/camera/libcameraservice/CameraHardwareStub.h
diff --git a/camera/libcameraservice/CameraService.cpp b/services/camera/libcameraservice/CameraService.cpp
similarity index 99%
rename from camera/libcameraservice/CameraService.cpp
rename to services/camera/libcameraservice/CameraService.cpp
index 10668a4..c786f94 100644
--- a/camera/libcameraservice/CameraService.cpp
+++ b/services/camera/libcameraservice/CameraService.cpp
@@ -192,11 +192,6 @@
     return mClient[cameraId].promote();
 }
 
-void CameraService::instantiate() {
-    defaultServiceManager()->addService(String16("media.camera"),
-        new CameraService());
-}
-
 status_t CameraService::onTransact(
     uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) {
     // Permission checks
diff --git a/camera/libcameraservice/CameraService.h b/services/camera/libcameraservice/CameraService.h
similarity index 97%
rename from camera/libcameraservice/CameraService.h
rename to services/camera/libcameraservice/CameraService.h
index 8193e77..b0b2d7a 100644
--- a/camera/libcameraservice/CameraService.h
+++ b/services/camera/libcameraservice/CameraService.h
@@ -19,6 +19,8 @@
 #ifndef ANDROID_SERVERS_CAMERA_CAMERASERVICE_H
 #define ANDROID_SERVERS_CAMERA_CAMERASERVICE_H
 
+#include <binder/BinderService.h>
+
 #include <camera/ICameraService.h>
 #include <camera/CameraHardwareInterface.h>
 
@@ -30,11 +32,14 @@
 class MemoryHeapBase;
 class MediaPlayer;
 
-class CameraService: public BnCameraService
+class CameraService :
+    public BinderService<CameraService>,
+    public BnCameraService
 {
     class Client;
+    friend class BinderService<CameraService>;
 public:
-    static void         instantiate();
+    static char const* getServiceName() { return "media.camera"; }
 
                         CameraService();
     virtual             ~CameraService();
diff --git a/camera/libcameraservice/CannedJpeg.h b/services/camera/libcameraservice/CannedJpeg.h
similarity index 100%
rename from camera/libcameraservice/CannedJpeg.h
rename to services/camera/libcameraservice/CannedJpeg.h
diff --git a/camera/libcameraservice/FakeCamera.cpp b/services/camera/libcameraservice/FakeCamera.cpp
similarity index 100%
rename from camera/libcameraservice/FakeCamera.cpp
rename to services/camera/libcameraservice/FakeCamera.cpp
diff --git a/camera/libcameraservice/FakeCamera.h b/services/camera/libcameraservice/FakeCamera.h
similarity index 100%
rename from camera/libcameraservice/FakeCamera.h
rename to services/camera/libcameraservice/FakeCamera.h
diff --git a/camera/tests/CameraServiceTest/Android.mk b/services/camera/tests/CameraServiceTest/Android.mk
similarity index 100%
rename from camera/tests/CameraServiceTest/Android.mk
rename to services/camera/tests/CameraServiceTest/Android.mk
diff --git a/camera/tests/CameraServiceTest/CameraServiceTest.cpp b/services/camera/tests/CameraServiceTest/CameraServiceTest.cpp
similarity index 100%
rename from camera/tests/CameraServiceTest/CameraServiceTest.cpp
rename to services/camera/tests/CameraServiceTest/CameraServiceTest.cpp
diff --git a/services/java/com/android/server/ConnectivityService.java b/services/java/com/android/server/ConnectivityService.java
index 9ff7de6..9c504fe 100644
--- a/services/java/com/android/server/ConnectivityService.java
+++ b/services/java/com/android/server/ConnectivityService.java
@@ -26,6 +26,7 @@
 import android.net.IConnectivityManager;
 import android.net.MobileDataStateTracker;
 import android.net.NetworkInfo;
+import android.net.NetworkProperties;
 import android.net.NetworkStateTracker;
 import android.net.wifi.WifiStateTracker;
 import android.net.NetworkUtils;
@@ -51,7 +52,10 @@
 import java.io.FileWriter;
 import java.io.IOException;
 import java.io.PrintWriter;
+import java.net.InetAddress;
+import java.net.UnknownHostException;
 import java.util.ArrayList;
+import java.util.Collection;
 import java.util.List;
 
 /**
@@ -741,6 +745,7 @@
      * specified host is to be routed
      * @param hostAddress the IP address of the host to which the route is
      * desired
+     * todo - deprecate (only v4!)
      * @return {@code true} on success, {@code false} on failure
      */
     public boolean requestRouteToHost(int networkType, int hostAddress) {
@@ -757,7 +762,11 @@
             }
             return false;
         }
-        return addHostRoute(tracker, hostAddress);
+        try {
+            InetAddress addr = InetAddress.getByAddress(NetworkUtils.v4IntToArray(hostAddress));
+            return addHostRoute(tracker, addr);
+        } catch (UnknownHostException e) {}
+        return false;
     }
 
     /**
@@ -765,22 +774,25 @@
      * host via the mobile data network.
      * @param hostAddress the IP address of the host to which the route is desired,
      * in network byte order.
+     * TODO - deprecate
      * @return {@code true} on success, {@code false} on failure
      */
-    private boolean addHostRoute(NetworkStateTracker nt, int hostAddress) {
+    private boolean addHostRoute(NetworkStateTracker nt, InetAddress hostAddress) {
         if (nt.getNetworkInfo().getType() == ConnectivityManager.TYPE_WIFI) {
             return false;
         }
 
-        String interfaceName = nt.getInterfaceName();
+        NetworkProperties p = nt.getNetworkProperties();
+        if (p == null) return false;
+        String interfaceName = p.getInterfaceName();
 
         if (DBG) {
-            Slog.d(TAG, "Requested host route to " + Integer.toHexString(hostAddress) +
-                     "(" + interfaceName + ")");
+            Slog.d(TAG, "Requested host route to " + hostAddress + "(" + interfaceName + ")");
         }
-        if (interfaceName != null && hostAddress != -1) {
+        if (interfaceName != null) {
             return NetworkUtils.addHostRoute(interfaceName, hostAddress) == 0;
         } else {
+            if (DBG) Slog.e(TAG, "addHostRoute failed due to null interface name");
             return false;
         }
     }
@@ -1251,21 +1263,20 @@
     }
 
     private void addPrivateDnsRoutes(NetworkStateTracker nt) {
-        String interfaceName = nt.getInterfaceName();
         boolean privateDnsRouteSet = nt.isPrivateDnsRouteSet();
+        NetworkProperties p = nt.getNetworkProperties();
+        if (p == null) return;
+        String interfaceName = p.getInterfaceName();
 
         if (DBG) {
             Slog.d(TAG, "addPrivateDnsRoutes for " + nt +
                     "(" + interfaceName + ") - mPrivateDnsRouteSet = " + privateDnsRouteSet);
         }
-        String[] dnsList = getNameServerList(nt.getDnsPropNames());
         if (interfaceName != null && !privateDnsRouteSet) {
-            for (String addrString : dnsList) {
-                int addr = NetworkUtils.lookupHost(addrString);
-                if (addr != -1 && addr != 0) {
-                    if (DBG) Slog.d(TAG, "  adding "+addrString+" ("+addr+")");
-                    NetworkUtils.addHostRoute(interfaceName, addr);
-                }
+            Collection<InetAddress> dnsList = p.getDnses();
+            for (InetAddress dns : dnsList) {
+                if (DBG) Slog.d(TAG, "  adding " + dns);
+                NetworkUtils.addHostRoute(interfaceName, dns);
             }
             nt.privateDnsRouteSet(true);
         }
@@ -1274,7 +1285,9 @@
     private void removePrivateDnsRoutes(NetworkStateTracker nt) {
         // TODO - we should do this explicitly but the NetUtils api doesnt
         // support this yet - must remove all.  No worse than before
-        String interfaceName = nt.getInterfaceName();
+        NetworkProperties p = nt.getNetworkProperties();
+        if (p == null) return;
+        String interfaceName = p.getInterfaceName();
         boolean privateDnsRouteSet = nt.isPrivateDnsRouteSet();
         if (interfaceName != null && privateDnsRouteSet) {
             if (DBG) {
@@ -1286,61 +1299,42 @@
         }
     }
 
-    /**
-     * Return the IP addresses of the DNS servers available for this
-     * network interface.
-     * @param propertyNames the names of the system properties whose values
-     * give the IP addresses. Properties with no values are skipped.
-     * @return an array of {@code String}s containing the IP addresses
-     * of the DNS servers, in dot-notation. This may have fewer
-     * non-null entries than the list of names passed in, since
-     * some of the passed-in names may have empty values.
-     */
-    String[] getNameServerList(String[] propertyNames) {
-        String[] dnsAddresses = new String[propertyNames.length];
-        int i, j;
-
-        for (i = 0, j = 0; i < propertyNames.length; i++) {
-            String value = SystemProperties.get(propertyNames[i]);
-            // The GSM layer sometimes sets a bogus DNS server address of
-            // 0.0.0.0
-            if (!TextUtils.isEmpty(value) && !TextUtils.equals(value, "0.0.0.0")) {
-                dnsAddresses[j++] = value;
-            }
-        }
-        return dnsAddresses;
-    }
 
     private void addDefaultRoute(NetworkStateTracker nt) {
-        String interfaceName = nt.getInterfaceName();
-        int defaultGatewayAddr = nt.getDefaultGatewayAddr();
+        NetworkProperties p = nt.getNetworkProperties();
+        if (p == null) return;
+        String interfaceName = p.getInterfaceName();
+        InetAddress defaultGatewayAddr = p.getGateway();
         boolean defaultRouteSet = nt.isDefaultRouteSet();
-        NetworkInfo networkInfo = nt.getNetworkInfo();
 
-        if ((interfaceName != null) && (defaultGatewayAddr != 0) &&
-                defaultRouteSet == false) {
-            if (DBG) {
+        if ((interfaceName != null) && (defaultGatewayAddr != null ) &&
+                (defaultRouteSet == false)) {
+            boolean error = (NetworkUtils.setDefaultRoute(interfaceName, defaultGatewayAddr) < 0);
+
+            if (DBG && !error) {
+                NetworkInfo networkInfo = nt.getNetworkInfo();
                 Slog.d(TAG, "addDefaultRoute for " + networkInfo.getTypeName() +
                         " (" + interfaceName + "), GatewayAddr=" + defaultGatewayAddr);
             }
-            NetworkUtils.setDefaultRoute(interfaceName, defaultGatewayAddr);
-            nt.defaultRouteSet(true);
+            nt.defaultRouteSet(!error);
         }
     }
 
 
     public void removeDefaultRoute(NetworkStateTracker nt) {
-        String interfaceName = nt.getInterfaceName();
+        NetworkProperties p = nt.getNetworkProperties();
+        if (p == null) return;
+        String interfaceName = p.getInterfaceName();
         boolean defaultRouteSet = nt.isDefaultRouteSet();
-        NetworkInfo networkInfo = nt.getNetworkInfo();
 
         if (interfaceName != null && defaultRouteSet == true) {
-            if (DBG) {
+            boolean error = (NetworkUtils.removeDefaultRoute(interfaceName) < 0);
+            if (DBG && !error) {
+                NetworkInfo networkInfo = nt.getNetworkInfo();
                 Slog.d(TAG, "removeDefaultRoute for " + networkInfo.getTypeName() + " (" +
                         interfaceName + ")");
             }
-            NetworkUtils.removeDefaultRoute(interfaceName);
-            nt.defaultRouteSet(false);
+            nt.defaultRouteSet(error);
         }
     }
 
@@ -1430,12 +1424,14 @@
             NetworkStateTracker nt = mNetTrackers[i];
             if (nt.getNetworkInfo().isConnected() &&
                     !nt.isTeardownRequested()) {
+                NetworkProperties p = nt.getNetworkProperties();
+                if (p == null) continue;
                 List pids = mNetRequestersPids[i];
                 for (int j=0; j<pids.size(); j++) {
                     Integer pid = (Integer)pids.get(j);
                     if (pid.intValue() == myPid) {
-                        String[] dnsList = getNameServerList(nt.getDnsPropNames());
-                        writePidDns(dnsList, myPid);
+                        Collection<InetAddress> dnses = p.getDnses();
+                        writePidDns(dnses, myPid);
                         if (doBump) {
                             bumpDns();
                         }
@@ -1457,12 +1453,10 @@
         }
     }
 
-    private void writePidDns(String[] dnsList, int pid) {
+    private void writePidDns(Collection <InetAddress> dnses, int pid) {
         int j = 1;
-        for (String dns : dnsList) {
-            if (dns != null && !TextUtils.equals(dns, "0.0.0.0")) {
-                SystemProperties.set("net.dns" + j++ + "." + pid, dns);
-            }
+        for (InetAddress dns : dnses) {
+            SystemProperties.set("net.dns" + j++ + "." + pid, dns.getHostAddress());
         }
     }
 
@@ -1488,17 +1482,17 @@
             NetworkStateTracker nt = mNetTrackers[netType];
             if (nt != null && nt.getNetworkInfo().isConnected() &&
                     !nt.isTeardownRequested()) {
-                String[] dnsList = getNameServerList(nt.getDnsPropNames());
+                NetworkProperties p = nt.getNetworkProperties();
+                if (p == null) continue;
+                Collection<InetAddress> dnses = p.getDnses();
                 if (mNetAttributes[netType].isDefault()) {
                     int j = 1;
-                    for (String dns : dnsList) {
-                        if (dns != null && !TextUtils.equals(dns, "0.0.0.0")) {
-                            if (DBG) {
-                                Slog.d(TAG, "adding dns " + dns + " for " +
-                                        nt.getNetworkInfo().getTypeName());
-                            }
-                            SystemProperties.set("net.dns" + j++, dns);
+                    for (InetAddress dns : dnses) {
+                        if (DBG) {
+                            Slog.d(TAG, "adding dns " + dns + " for " +
+                                    nt.getNetworkInfo().getTypeName());
                         }
+                        SystemProperties.set("net.dns" + j++, dns.getHostAddress());
                     }
                     for (int k=j ; k<mNumDnsEntries; k++) {
                         if (DBG) Slog.d(TAG, "erasing net.dns" + k);
@@ -1510,7 +1504,7 @@
                     List pids = mNetRequestersPids[netType];
                     for (int y=0; y< pids.size(); y++) {
                         Integer pid = (Integer)pids.get(y);
-                        writePidDns(dnsList, pid.intValue());
+                        writePidDns(dnses, pid.intValue());
                     }
                 }
             }
diff --git a/services/java/com/android/server/InputDevice.java b/services/java/com/android/server/InputDevice.java
deleted file mode 100644
index 414b69f..0000000
--- a/services/java/com/android/server/InputDevice.java
+++ /dev/null
@@ -1,1025 +0,0 @@
-/*
- * Copyright (C) 2007 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server;
-
-import android.util.Slog;
-import android.view.Display;
-import android.view.MotionEvent;
-import android.view.Surface;
-import android.view.WindowManagerPolicy;
-
-import java.io.PrintWriter;
-
-public class InputDevice {
-    static final boolean DEBUG_POINTERS = false;
-    static final boolean DEBUG_HACKS = false;
-    
-    /** Amount that trackball needs to move in order to generate a key event. */
-    static final int TRACKBALL_MOVEMENT_THRESHOLD = 6;
-
-    /** Maximum number of pointers we will track and report. */
-    static final int MAX_POINTERS = 10;
-    
-    /**
-     * Slop distance for jumpy pointer detection.
-     * The vertical range of the screen divided by this is our epsilon value.
-     */
-    private static final int JUMPY_EPSILON_DIVISOR = 212;
-    
-    /** Number of jumpy points to drop for touchscreens that need it. */
-    private static final int JUMPY_TRANSITION_DROPS = 3;
-    private static final int JUMPY_DROP_LIMIT = 3;
-    
-    final int id;
-    final int classes;
-    final String name;
-    final AbsoluteInfo absX;
-    final AbsoluteInfo absY;
-    final AbsoluteInfo absPressure;
-    final AbsoluteInfo absSize;
-    
-    long mKeyDownTime = 0;
-    int mMetaKeysState = 0;
-    
-    // For use by KeyInputQueue for keeping track of the current touch
-    // data in the old non-multi-touch protocol.
-    final int[] curTouchVals = new int[MotionEvent.NUM_SAMPLE_DATA * 2];
-    
-    final MotionState mAbs = new MotionState(0, 0);
-    final MotionState mRel = new MotionState(TRACKBALL_MOVEMENT_THRESHOLD,
-            TRACKBALL_MOVEMENT_THRESHOLD);
-    
-    static class MotionState {
-        int xPrecision;
-        int yPrecision;
-        float xMoveScale;
-        float yMoveScale;
-        MotionEvent currentMove = null;
-        boolean changed = false;
-        boolean everChanged = false;
-        long mDownTime = 0;
-        
-        // The currently assigned pointer IDs, corresponding to the last data.
-        int[] mPointerIds = new int[MAX_POINTERS];
-        
-        // This is the last generated pointer data, ordered to match
-        // mPointerIds.
-        boolean mSkipLastPointers;
-        int mLastNumPointers = 0;
-        final int[] mLastData = new int[MotionEvent.NUM_SAMPLE_DATA * MAX_POINTERS];
-        
-        // This is the next set of pointer data being generated.  It is not
-        // in any known order, and will be propagated in to mLastData
-        // as part of mapping it to the appropriate pointer IDs.
-        // Note that we have one extra sample of data here, to help clients
-        // avoid doing bounds checking.
-        int mNextNumPointers = 0;
-        final int[] mNextData = new int[(MotionEvent.NUM_SAMPLE_DATA * MAX_POINTERS)
-                                        + MotionEvent.NUM_SAMPLE_DATA];
-        
-        // Used to determine whether we dropped bad data, to avoid doing
-        // it repeatedly.
-        final boolean[] mDroppedBadPoint = new boolean[MAX_POINTERS];
-
-        // Used to count the number of jumpy points dropped.
-        private int mJumpyPointsDropped = 0;
-        
-        // Used to perform averaging of reported coordinates, to smooth
-        // the data and filter out transients during a release.
-        static final int HISTORY_SIZE = 5;
-        int[] mHistoryDataStart = new int[MAX_POINTERS];
-        int[] mHistoryDataEnd = new int[MAX_POINTERS];
-        final int[] mHistoryData = new int[(MotionEvent.NUM_SAMPLE_DATA * MAX_POINTERS)
-                                        * HISTORY_SIZE];
-        final int[] mAveragedData = new int[MotionEvent.NUM_SAMPLE_DATA * MAX_POINTERS];
-        
-        // Temporary data structures for doing the pointer ID mapping.
-        final int[] mLast2Next = new int[MAX_POINTERS];
-        final int[] mNext2Last = new int[MAX_POINTERS];
-        final long[] mNext2LastDistance = new long[MAX_POINTERS];
-        
-        // Temporary data structure for generating the final motion data.
-        final float[] mReportData = new float[MotionEvent.NUM_SAMPLE_DATA * MAX_POINTERS];
-        
-        // This is not used here, but can be used by callers for state tracking.
-        int mAddingPointerOffset = 0;
-        final boolean[] mDown = new boolean[MAX_POINTERS];
-        
-        void dumpIntArray(PrintWriter pw, int[] array) {
-            pw.print("[");
-            for (int i=0; i<array.length; i++) {
-                if (i > 0) pw.print(", ");
-                pw.print(array[i]);
-            }
-            pw.print("]");
-        }
-        
-        void dumpBooleanArray(PrintWriter pw, boolean[] array) {
-            pw.print("[");
-            for (int i=0; i<array.length; i++) {
-                if (i > 0) pw.print(", ");
-                pw.print(array[i] ? "true" : "false");
-            }
-            pw.print("]");
-        }
-        
-        void dump(PrintWriter pw, String prefix) {
-            pw.print(prefix); pw.print("xPrecision="); pw.print(xPrecision);
-                    pw.print(" yPrecision="); pw.println(yPrecision);
-            pw.print(prefix); pw.print("xMoveScale="); pw.print(xMoveScale);
-                    pw.print(" yMoveScale="); pw.println(yMoveScale);
-            if (currentMove != null) {
-                pw.print(prefix); pw.print("currentMove="); pw.println(currentMove);
-            }
-            if (changed || mDownTime != 0) {
-                pw.print(prefix); pw.print("changed="); pw.print(changed);
-                        pw.print(" mDownTime="); pw.println(mDownTime);
-            }
-            pw.print(prefix); pw.print("mPointerIds="); dumpIntArray(pw, mPointerIds);
-                    pw.println("");
-            if (mSkipLastPointers || mLastNumPointers != 0) {
-                pw.print(prefix); pw.print("mSkipLastPointers="); pw.print(mSkipLastPointers);
-                        pw.print(" mLastNumPointers="); pw.println(mLastNumPointers);
-                pw.print(prefix); pw.print("mLastData="); dumpIntArray(pw, mLastData);
-                        pw.println("");
-            }
-            if (mNextNumPointers != 0) {
-                pw.print(prefix); pw.print("mNextNumPointers="); pw.println(mNextNumPointers);
-                pw.print(prefix); pw.print("mNextData="); dumpIntArray(pw, mNextData);
-                        pw.println("");
-            }
-            pw.print(prefix); pw.print("mDroppedBadPoint=");
-                    dumpBooleanArray(pw, mDroppedBadPoint); pw.println("");
-            pw.print(prefix); pw.print("mAddingPointerOffset="); pw.println(mAddingPointerOffset);
-            pw.print(prefix); pw.print("mDown=");
-                    dumpBooleanArray(pw, mDown); pw.println("");
-        }
-        
-        MotionState(int mx, int my) {
-            xPrecision = mx;
-            yPrecision = my;
-            xMoveScale = mx != 0 ? (1.0f/mx) : 1.0f;
-            yMoveScale = my != 0 ? (1.0f/my) : 1.0f;
-            for (int i=0; i<MAX_POINTERS; i++) {
-                mPointerIds[i] = i;
-            }
-        }
-        
-        /**
-         * Special hack for devices that have bad screen data: if one of the
-         * points has moved more than a screen height from the last position,
-         * then drop it.
-         */
-        void dropBadPoint(InputDevice dev) {
-            // We should always have absY, but let's be paranoid.
-            if (dev.absY == null) {
-                return;
-            }
-            // Don't do anything if a finger is going down or up.  We run
-            // here before assigning pointer IDs, so there isn't a good
-            // way to do per-finger matching.
-            if (mNextNumPointers != mLastNumPointers) {
-                return;
-            }
-            
-            // We consider a single movement across more than a 7/16 of
-            // the long size of the screen to be bad.  This was a magic value
-            // determined by looking at the maximum distance it is feasible
-            // to actually move in one sample.
-            final int maxDy = ((dev.absY.maxValue-dev.absY.minValue)*7)/16;
-            
-            // Look through all new points and see if any are farther than
-            // acceptable from all previous points.
-            for (int i=mNextNumPointers-1; i>=0; i--) {
-                final int ioff = i * MotionEvent.NUM_SAMPLE_DATA;
-                //final int x = mNextData[ioff + MotionEvent.SAMPLE_X];
-                final int y = mNextData[ioff + MotionEvent.SAMPLE_Y];
-                if (DEBUG_HACKS) Slog.v("InputDevice", "Looking at next point #" + i + ": y=" + y);
-                boolean dropped = false;
-                if (!mDroppedBadPoint[i] && mLastNumPointers > 0) {
-                    dropped = true;
-                    int closestDy = -1;
-                    int closestY = -1;
-                    // We will drop this new point if it is sufficiently
-                    // far away from -all- last points.
-                    for (int j=mLastNumPointers-1; j>=0; j--) {
-                        final int joff = j * MotionEvent.NUM_SAMPLE_DATA;
-                        //int dx = x - mLastData[joff + MotionEvent.SAMPLE_X];
-                        int dy = y - mLastData[joff + MotionEvent.SAMPLE_Y];
-                        //if (dx < 0) dx = -dx;
-                        if (dy < 0) dy = -dy;
-                        if (DEBUG_HACKS) Slog.v("InputDevice", "Comparing with last point #" + j
-                                + ": y=" + mLastData[joff] + " dy=" + dy);
-                        if (dy < maxDy) {
-                            dropped = false;
-                            break;
-                        } else if (closestDy < 0 || dy < closestDy) {
-                            closestDy = dy;
-                            closestY = mLastData[joff + MotionEvent.SAMPLE_Y];
-                        }
-                    }
-                    if (dropped) {
-                        dropped = true;
-                        Slog.i("InputDevice", "Dropping bad point #" + i
-                                + ": newY=" + y + " closestDy=" + closestDy
-                                + " maxDy=" + maxDy);
-                        mNextData[ioff + MotionEvent.SAMPLE_Y] = closestY;
-                        break;
-                    }
-                }
-                mDroppedBadPoint[i] = dropped;
-            }
-        }
-        
-        void dropJumpyPoint(InputDevice dev) {
-            // We should always have absY, but let's be paranoid.
-            if (dev.absY == null) {
-                return;
-            }
-            final int jumpyEpsilon = dev.absY.range / JUMPY_EPSILON_DIVISOR;
-            
-            final int nextNumPointers = mNextNumPointers;
-            final int lastNumPointers = mLastNumPointers;
-            final int[] nextData = mNextData;
-            final int[] lastData = mLastData;
-            
-            if (nextNumPointers != mLastNumPointers) {
-                if (DEBUG_HACKS) {
-                    Slog.d("InputDevice", "Different pointer count " + lastNumPointers + 
-                            " -> " + nextNumPointers);
-                    for (int i = 0; i < nextNumPointers; i++) {
-                        int ioff = i * MotionEvent.NUM_SAMPLE_DATA;
-                        Slog.d("InputDevice", "Pointer " + i + " (" + 
-                                mNextData[ioff + MotionEvent.SAMPLE_X] + ", " +
-                                mNextData[ioff + MotionEvent.SAMPLE_Y] + ")");
-                    }
-                }
-                
-                // Just drop the first few events going from 1 to 2 pointers.
-                // They're bad often enough that they're not worth considering.
-                if (lastNumPointers == 1 && nextNumPointers == 2
-                        && mJumpyPointsDropped < JUMPY_TRANSITION_DROPS) {
-                    mNextNumPointers = 1;
-                    mJumpyPointsDropped++;
-                } else if (lastNumPointers == 2 && nextNumPointers == 1
-                        && mJumpyPointsDropped < JUMPY_TRANSITION_DROPS) {
-                    // The event when we go from 2 -> 1 tends to be messed up too
-                    System.arraycopy(lastData, 0, nextData, 0, 
-                            lastNumPointers * MotionEvent.NUM_SAMPLE_DATA);
-                    mNextNumPointers = lastNumPointers;
-                    mJumpyPointsDropped++;
-                    
-                    if (DEBUG_HACKS) {
-                        for (int i = 0; i < mNextNumPointers; i++) {
-                            int ioff = i * MotionEvent.NUM_SAMPLE_DATA;
-                            Slog.d("InputDevice", "Pointer " + i + " replaced (" + 
-                                    mNextData[ioff + MotionEvent.SAMPLE_X] + ", " +
-                                    mNextData[ioff + MotionEvent.SAMPLE_Y] + ")");
-                        }
-                    }
-                } else {
-                    mJumpyPointsDropped = 0;
-                    
-                    if (DEBUG_HACKS) {
-                        Slog.d("InputDevice", "Transition - drop limit reset");
-                    }
-                }
-                return;
-            }
-            
-            // A 'jumpy' point is one where the coordinate value for one axis
-            // has jumped to the other pointer's location. No need to do anything
-            // else if we only have one pointer.
-            if (nextNumPointers < 2) {
-                return;
-            }
-            
-            int badPointerIndex = -1;
-            int badPointerReplaceXWith = 0;
-            int badPointerReplaceYWith = 0;
-            int badPointerDistance = Integer.MIN_VALUE;
-            for (int i = nextNumPointers - 1; i >= 0; i--) {
-                boolean dropx = false;
-                boolean dropy = false;
-                
-                // Limit how many times a jumpy point can get dropped.
-                if (mJumpyPointsDropped < JUMPY_DROP_LIMIT) {
-                    final int ioff = i * MotionEvent.NUM_SAMPLE_DATA;
-                    final int x = nextData[ioff + MotionEvent.SAMPLE_X];
-                    final int y = nextData[ioff + MotionEvent.SAMPLE_Y];
-                    
-                    if (DEBUG_HACKS) {
-                        Slog.d("InputDevice", "Point " + i + " (" + x + ", " + y + ")");
-                    }
-
-                    // Check if a touch point is too close to another's coordinates
-                    for (int j = 0; j < nextNumPointers && !dropx && !dropy; j++) {
-                        if (j == i) {
-                            continue;
-                        }
-
-                        final int joff = j * MotionEvent.NUM_SAMPLE_DATA;
-                        final int xOther = nextData[joff + MotionEvent.SAMPLE_X];
-                        final int yOther = nextData[joff + MotionEvent.SAMPLE_Y];
-
-                        dropx = Math.abs(x - xOther) <= jumpyEpsilon;
-                        dropy = Math.abs(y - yOther) <= jumpyEpsilon;
-                    }
-                    
-                    if (dropx) {
-                        int xreplace = lastData[MotionEvent.SAMPLE_X];
-                        int yreplace = lastData[MotionEvent.SAMPLE_Y];
-                        int distance = Math.abs(yreplace - y);
-                        for (int j = 1; j < lastNumPointers; j++) {
-                            final int joff = j * MotionEvent.NUM_SAMPLE_DATA;
-                            int lasty = lastData[joff + MotionEvent.SAMPLE_Y];   
-                            int currDist = Math.abs(lasty - y);
-                            if (currDist < distance) {
-                                xreplace = lastData[joff + MotionEvent.SAMPLE_X];
-                                yreplace = lasty;
-                                distance = currDist;
-                            }
-                        }
-                        
-                        int badXDelta = Math.abs(xreplace - x);
-                        if (badXDelta > badPointerDistance) {
-                            badPointerDistance = badXDelta;
-                            badPointerIndex = i;
-                            badPointerReplaceXWith = xreplace;
-                            badPointerReplaceYWith = yreplace;
-                        }
-                    } else if (dropy) {
-                        int xreplace = lastData[MotionEvent.SAMPLE_X];
-                        int yreplace = lastData[MotionEvent.SAMPLE_Y];
-                        int distance = Math.abs(xreplace - x);
-                        for (int j = 1; j < lastNumPointers; j++) {
-                            final int joff = j * MotionEvent.NUM_SAMPLE_DATA;
-                            int lastx = lastData[joff + MotionEvent.SAMPLE_X];   
-                            int currDist = Math.abs(lastx - x);
-                            if (currDist < distance) {
-                                xreplace = lastx;
-                                yreplace = lastData[joff + MotionEvent.SAMPLE_Y];
-                                distance = currDist;
-                            }
-                        }
-                        
-                        int badYDelta = Math.abs(yreplace - y);
-                        if (badYDelta > badPointerDistance) {
-                            badPointerDistance = badYDelta;
-                            badPointerIndex = i;
-                            badPointerReplaceXWith = xreplace;
-                            badPointerReplaceYWith = yreplace;
-                        }
-                    }
-                }
-            }
-            if (badPointerIndex >= 0) {
-                if (DEBUG_HACKS) {
-                    Slog.d("InputDevice", "Replacing bad pointer " + badPointerIndex +
-                            " with (" + badPointerReplaceXWith + ", " + badPointerReplaceYWith +
-                            ")");
-                }
-
-                final int offset = badPointerIndex * MotionEvent.NUM_SAMPLE_DATA;
-                nextData[offset + MotionEvent.SAMPLE_X] = badPointerReplaceXWith;
-                nextData[offset + MotionEvent.SAMPLE_Y] = badPointerReplaceYWith;
-                mJumpyPointsDropped++;
-            } else {
-                mJumpyPointsDropped = 0;
-            }
-        }
-        
-        /**
-         * Special hack for devices that have bad screen data: aggregate and
-         * compute averages of the coordinate data, to reduce the amount of
-         * jitter seen by applications.
-         */
-        int[] generateAveragedData(int upOrDownPointer, int lastNumPointers,
-                int nextNumPointers) {
-            final int numPointers = mLastNumPointers;
-            final int[] rawData = mLastData;
-            if (DEBUG_HACKS) Slog.v("InputDevice", "lastNumPointers=" + lastNumPointers
-                    + " nextNumPointers=" + nextNumPointers
-                    + " numPointers=" + numPointers);
-            for (int i=0; i<numPointers; i++) {
-                final int ioff = i * MotionEvent.NUM_SAMPLE_DATA;
-                // We keep the average data in offsets based on the pointer
-                // ID, so we don't need to move it around as fingers are
-                // pressed and released.
-                final int p = mPointerIds[i];
-                final int poff = p * MotionEvent.NUM_SAMPLE_DATA * HISTORY_SIZE;
-                if (i == upOrDownPointer && lastNumPointers != nextNumPointers) {
-                    if (lastNumPointers < nextNumPointers) {
-                        // This pointer is going down.  Clear its history
-                        // and start fresh.
-                        if (DEBUG_HACKS) Slog.v("InputDevice", "Pointer down @ index "
-                                + upOrDownPointer + " id " + mPointerIds[i]);
-                        mHistoryDataStart[i] = 0;
-                        mHistoryDataEnd[i] = 0;
-                        System.arraycopy(rawData, ioff, mHistoryData, poff,
-                                MotionEvent.NUM_SAMPLE_DATA);
-                        System.arraycopy(rawData, ioff, mAveragedData, ioff,
-                                MotionEvent.NUM_SAMPLE_DATA);
-                        continue;
-                    } else {
-                        // The pointer is going up.  Just fall through to
-                        // recompute the last averaged point (and don't add
-                        // it as a new point to include in the average).
-                        if (DEBUG_HACKS) Slog.v("InputDevice", "Pointer up @ index "
-                                + upOrDownPointer + " id " + mPointerIds[i]);
-                    }
-                } else {
-                    int end = mHistoryDataEnd[i];
-                    int eoff = poff + (end*MotionEvent.NUM_SAMPLE_DATA);
-                    int oldX = mHistoryData[eoff + MotionEvent.SAMPLE_X];
-                    int oldY = mHistoryData[eoff + MotionEvent.SAMPLE_Y];
-                    int newX = rawData[ioff + MotionEvent.SAMPLE_X];
-                    int newY = rawData[ioff + MotionEvent.SAMPLE_Y];
-                    int dx = newX-oldX;
-                    int dy = newY-oldY;
-                    int delta = dx*dx + dy*dy;
-                    if (DEBUG_HACKS) Slog.v("InputDevice", "Delta from last: " + delta);
-                    if (delta >= (75*75)) {
-                        // Magic number, if moving farther than this, turn
-                        // off filtering to avoid lag in response.
-                        mHistoryDataStart[i] = 0;
-                        mHistoryDataEnd[i] = 0;
-                        System.arraycopy(rawData, ioff, mHistoryData, poff,
-                                MotionEvent.NUM_SAMPLE_DATA);
-                        System.arraycopy(rawData, ioff, mAveragedData, ioff,
-                                MotionEvent.NUM_SAMPLE_DATA);
-                        continue;
-                    } else {
-                        end++;
-                        if (end >= HISTORY_SIZE) {
-                            end -= HISTORY_SIZE;
-                        }
-                        mHistoryDataEnd[i] = end;
-                        int noff = poff + (end*MotionEvent.NUM_SAMPLE_DATA);
-                        mHistoryData[noff + MotionEvent.SAMPLE_X] = newX;
-                        mHistoryData[noff + MotionEvent.SAMPLE_Y] = newY;
-                        mHistoryData[noff + MotionEvent.SAMPLE_PRESSURE]
-                                = rawData[ioff + MotionEvent.SAMPLE_PRESSURE];
-                        int start = mHistoryDataStart[i];
-                        if (end == start) {
-                            start++;
-                            if (start >= HISTORY_SIZE) {
-                                start -= HISTORY_SIZE;
-                            }
-                            mHistoryDataStart[i] = start;
-                        }
-                    }
-                }
-                
-                // Now compute the average.
-                int start = mHistoryDataStart[i];
-                int end = mHistoryDataEnd[i];
-                int x=0, y=0;
-                int totalPressure = 0;
-                while (start != end) {
-                    int soff = poff + (start*MotionEvent.NUM_SAMPLE_DATA);
-                    int pressure = mHistoryData[soff + MotionEvent.SAMPLE_PRESSURE];
-                    if (pressure <= 0) pressure = 1;
-                    x += mHistoryData[soff + MotionEvent.SAMPLE_X] * pressure;
-                    y += mHistoryData[soff + MotionEvent.SAMPLE_Y] * pressure;
-                    totalPressure += pressure;
-                    start++;
-                    if (start >= HISTORY_SIZE) start = 0;
-                }
-                int eoff = poff + (end*MotionEvent.NUM_SAMPLE_DATA);
-                int pressure = mHistoryData[eoff + MotionEvent.SAMPLE_PRESSURE];
-                if (pressure <= 0) pressure = 1;
-                x += mHistoryData[eoff + MotionEvent.SAMPLE_X] * pressure;
-                y += mHistoryData[eoff + MotionEvent.SAMPLE_Y] * pressure;
-                totalPressure += pressure;
-                x /= totalPressure;
-                y /= totalPressure;
-                if (DEBUG_HACKS) Slog.v("InputDevice", "Averaging " + totalPressure
-                        + " weight: (" + x + "," + y + ")");
-                mAveragedData[ioff + MotionEvent.SAMPLE_X] = x;
-                mAveragedData[ioff + MotionEvent.SAMPLE_Y] = y;
-                mAveragedData[ioff + MotionEvent.SAMPLE_PRESSURE] =
-                        rawData[ioff + MotionEvent.SAMPLE_PRESSURE];
-                mAveragedData[ioff + MotionEvent.SAMPLE_SIZE] =
-                        rawData[ioff + MotionEvent.SAMPLE_SIZE];
-            }
-            return mAveragedData;
-        }
-        
-        private boolean assignPointer(int nextIndex, boolean allowOverlap) {
-            final int lastNumPointers = mLastNumPointers;
-            final int[] next2Last = mNext2Last;
-            final long[] next2LastDistance = mNext2LastDistance;
-            final int[] last2Next = mLast2Next;
-            final int[] lastData = mLastData;
-            final int[] nextData = mNextData;
-            final int id = nextIndex * MotionEvent.NUM_SAMPLE_DATA;
-            
-            if (DEBUG_POINTERS) Slog.v("InputDevice", "assignPointer: nextIndex="
-                    + nextIndex + " dataOff=" + id);
-            final int x1 = nextData[id + MotionEvent.SAMPLE_X];
-            final int y1 = nextData[id + MotionEvent.SAMPLE_Y];
-            
-            long bestDistance = -1;
-            int bestIndex = -1;
-            for (int j=0; j<lastNumPointers; j++) {
-                // If we are not allowing multiple new points to be assigned
-                // to the same old pointer, then skip this one if it is already
-                // detected as a conflict (-2).
-                if (!allowOverlap && last2Next[j] < -1) {
-                    continue;
-                }
-                final int jd = j * MotionEvent.NUM_SAMPLE_DATA;
-                final int xd = lastData[jd + MotionEvent.SAMPLE_X] - x1;
-                final int yd = lastData[jd + MotionEvent.SAMPLE_Y] - y1;
-                final long distance = xd*(long)xd + yd*(long)yd;
-                if (bestDistance == -1 || distance < bestDistance) {
-                    bestDistance = distance;
-                    bestIndex = j;
-                }
-            }
-            
-            if (DEBUG_POINTERS) Slog.v("InputDevice", "New index " + nextIndex
-                    + " best old index=" + bestIndex + " (distance="
-                    + bestDistance + ")");
-            next2Last[nextIndex] = bestIndex;
-            next2LastDistance[nextIndex] = bestDistance;
-            
-            if (bestIndex < 0) {
-                return true;
-            }
-            
-            if (last2Next[bestIndex] == -1) {
-                last2Next[bestIndex] = nextIndex;
-                return false;
-            }
-            
-            if (DEBUG_POINTERS) Slog.v("InputDevice", "Old index " + bestIndex
-                    + " has multiple best new pointers!");
-            
-            last2Next[bestIndex] = -2;
-            return true;
-        }
-        
-        private int updatePointerIdentifiers() {
-            final int[] lastData = mLastData;
-            final int[] nextData = mNextData;
-            final int nextNumPointers = mNextNumPointers;
-            final int lastNumPointers = mLastNumPointers;
-            
-            if (nextNumPointers == 1 && lastNumPointers == 1) {
-                System.arraycopy(nextData, 0, lastData, 0,
-                        MotionEvent.NUM_SAMPLE_DATA);
-                return -1;
-            }
-            
-            // Clear our old state.
-            final int[] last2Next = mLast2Next;
-            for (int i=0; i<lastNumPointers; i++) {
-                last2Next[i] = -1;
-            }
-            
-            if (DEBUG_POINTERS) Slog.v("InputDevice",
-                    "Update pointers: lastNumPointers=" + lastNumPointers
-                    + " nextNumPointers=" + nextNumPointers);
-            
-            // Figure out the closes new points to the previous points.
-            final int[] next2Last = mNext2Last;
-            final long[] next2LastDistance = mNext2LastDistance;
-            boolean conflicts = false;
-            for (int i=0; i<nextNumPointers; i++) {
-                conflicts |= assignPointer(i, true);
-            }
-            
-            // Resolve ambiguities in pointer mappings, when two or more
-            // new pointer locations find their best previous location is
-            // the same.
-            if (conflicts) {
-                if (DEBUG_POINTERS) Slog.v("InputDevice", "Resolving conflicts");
-                
-                for (int i=0; i<lastNumPointers; i++) {
-                    if (last2Next[i] != -2) {
-                        continue;
-                    }
-                    
-                    // Note that this algorithm is far from perfect.  Ideally
-                    // we should do something like the one described at
-                    // http://portal.acm.org/citation.cfm?id=997856
-                    
-                    if (DEBUG_POINTERS) Slog.v("InputDevice",
-                            "Resolving last index #" + i);
-                    
-                    int numFound;
-                    do {
-                        numFound = 0;
-                        long worstDistance = 0;
-                        int worstJ = -1;
-                        for (int j=0; j<nextNumPointers; j++) {
-                            if (next2Last[j] != i) {
-                                continue;
-                            }
-                            numFound++;
-                            if (worstDistance < next2LastDistance[j]) {
-                                worstDistance = next2LastDistance[j];
-                                worstJ = j;
-                            }
-                        }
-                        
-                        if (worstJ >= 0) {
-                            if (DEBUG_POINTERS) Slog.v("InputDevice",
-                                    "Worst new pointer: " + worstJ
-                                    + " (distance=" + worstDistance + ")");
-                            if (assignPointer(worstJ, false)) {
-                                // In this case there is no last pointer
-                                // remaining for this new one!
-                                next2Last[worstJ] = -1;
-                            }
-                        }
-                    } while (numFound > 2);
-                }
-            }
-            
-            int retIndex = -1;
-            
-            if (lastNumPointers < nextNumPointers) {
-                // We have one or more new pointers that are down.  Create a
-                // new pointer identifier for one of them.
-                if (DEBUG_POINTERS) Slog.v("InputDevice", "Adding new pointer");
-                int nextId = 0;
-                int i=0;
-                while (i < lastNumPointers) {
-                    if (mPointerIds[i] > nextId) {
-                        // Found a hole, insert the pointer here.
-                        if (DEBUG_POINTERS) Slog.v("InputDevice",
-                                "Inserting new pointer at hole " + i);
-                        System.arraycopy(mPointerIds, i, mPointerIds,
-                                i+1, lastNumPointers-i);
-                        System.arraycopy(lastData, i*MotionEvent.NUM_SAMPLE_DATA,
-                                lastData, (i+1)*MotionEvent.NUM_SAMPLE_DATA,
-                                (lastNumPointers-i)*MotionEvent.NUM_SAMPLE_DATA);
-                        System.arraycopy(next2Last, i, next2Last,
-                                i+1, lastNumPointers-i);
-                        break;
-                    }
-                    i++;
-                    nextId++;
-                }
-                
-                if (DEBUG_POINTERS) Slog.v("InputDevice",
-                        "New pointer id " + nextId + " at index " + i);
-                
-                mLastNumPointers++;
-                retIndex = i;
-                mPointerIds[i] = nextId;
-                
-                // And assign this identifier to the first new pointer.
-                for (int j=0; j<nextNumPointers; j++) {
-                    if (next2Last[j] < 0) {
-                        if (DEBUG_POINTERS) Slog.v("InputDevice",
-                                "Assigning new id to new pointer index " + j);
-                        next2Last[j] = i;
-                        break;
-                    }
-                }
-            }
-            
-            // Propagate all of the current data into the appropriate
-            // location in the old data to match the pointer ID that was
-            // assigned to it.
-            for (int i=0; i<nextNumPointers; i++) {
-                int lastIndex = next2Last[i];
-                if (lastIndex >= 0) {
-                    if (DEBUG_POINTERS) Slog.v("InputDevice",
-                            "Copying next pointer index " + i
-                            + " to last index " + lastIndex);
-                    System.arraycopy(nextData, i*MotionEvent.NUM_SAMPLE_DATA,
-                            lastData, lastIndex*MotionEvent.NUM_SAMPLE_DATA,
-                            MotionEvent.NUM_SAMPLE_DATA);
-                }
-            }
-            
-            if (lastNumPointers > nextNumPointers) {
-                // One or more pointers has gone up.  Find the first one,
-                // and adjust accordingly.
-                if (DEBUG_POINTERS) Slog.v("InputDevice", "Removing old pointer");
-                for (int i=0; i<lastNumPointers; i++) {
-                    if (last2Next[i] == -1) {
-                        if (DEBUG_POINTERS) Slog.v("InputDevice",
-                                "Removing old pointer at index " + i);
-                        retIndex = i;
-                        break;
-                    }
-                }
-            }
-            
-            return retIndex;
-        }
-        
-        void removeOldPointer(int index) {
-            final int lastNumPointers = mLastNumPointers;
-            if (index >= 0 && index < lastNumPointers) {
-                System.arraycopy(mPointerIds, index+1, mPointerIds,
-                        index, lastNumPointers-index-1);
-                System.arraycopy(mLastData, (index+1)*MotionEvent.NUM_SAMPLE_DATA,
-                        mLastData, (index)*MotionEvent.NUM_SAMPLE_DATA,
-                        (lastNumPointers-index-1)*MotionEvent.NUM_SAMPLE_DATA);
-                mLastNumPointers--;
-            }
-        }
-        
-        MotionEvent generateAbsMotion(InputDevice device, long curTime,
-                long curTimeNano, Display display, int orientation,
-                int metaState) {
-            
-            if (mSkipLastPointers) {
-                mSkipLastPointers = false;
-                mLastNumPointers = 0;
-            }
-            
-            if (mNextNumPointers <= 0 && mLastNumPointers <= 0) {
-                return null;
-            }
-            
-            final int lastNumPointers = mLastNumPointers;
-            final int nextNumPointers = mNextNumPointers;
-            if (mNextNumPointers > MAX_POINTERS) {
-                Slog.w("InputDevice", "Number of pointers " + mNextNumPointers
-                        + " exceeded maximum of " + MAX_POINTERS);
-                mNextNumPointers = MAX_POINTERS;
-            }
-            
-            int upOrDownPointer = updatePointerIdentifiers();
-            
-            final float[] reportData = mReportData;
-            final int[] rawData;
-            if (KeyInputQueue.BAD_TOUCH_HACK) {
-                rawData = generateAveragedData(upOrDownPointer, lastNumPointers,
-                        nextNumPointers);
-            } else {
-                rawData = mLastData;
-            }
-            
-            final int numPointers = mLastNumPointers;
-            
-            if (DEBUG_POINTERS) Slog.v("InputDevice", "Processing "
-                    + numPointers + " pointers (going from " + lastNumPointers
-                    + " to " + nextNumPointers + ")");
-            
-            for (int i=0; i<numPointers; i++) {
-                final int pos = i * MotionEvent.NUM_SAMPLE_DATA;
-                reportData[pos + MotionEvent.SAMPLE_X] = rawData[pos + MotionEvent.SAMPLE_X];
-                reportData[pos + MotionEvent.SAMPLE_Y] = rawData[pos + MotionEvent.SAMPLE_Y];
-                reportData[pos + MotionEvent.SAMPLE_PRESSURE] = rawData[pos + MotionEvent.SAMPLE_PRESSURE];
-                reportData[pos + MotionEvent.SAMPLE_SIZE] = rawData[pos + MotionEvent.SAMPLE_SIZE];
-            }
-            
-            int action;
-            int edgeFlags = 0;
-            if (nextNumPointers != lastNumPointers) {
-                if (nextNumPointers > lastNumPointers) {
-                    if (lastNumPointers == 0) {
-                        action = MotionEvent.ACTION_DOWN;
-                        mDownTime = curTime;
-                    } else {
-                        action = MotionEvent.ACTION_POINTER_DOWN
-                                | (upOrDownPointer << MotionEvent.ACTION_POINTER_INDEX_SHIFT);
-                    }
-                } else {
-                    if (numPointers == 1) {
-                        action = MotionEvent.ACTION_UP;
-                    } else {
-                        action = MotionEvent.ACTION_POINTER_UP
-                                | (upOrDownPointer << MotionEvent.ACTION_POINTER_INDEX_SHIFT);
-                    }
-                }
-                currentMove = null;
-            } else {
-                action = MotionEvent.ACTION_MOVE;
-            }
-            
-            final int dispW = display.getWidth()-1;
-            final int dispH = display.getHeight()-1;
-            int w = dispW;
-            int h = dispH;
-            if (orientation == Surface.ROTATION_90
-                    || orientation == Surface.ROTATION_270) {
-                int tmp = w;
-                w = h;
-                h = tmp;
-            }
-            
-            final AbsoluteInfo absX = device.absX;
-            final AbsoluteInfo absY = device.absY;
-            final AbsoluteInfo absPressure = device.absPressure;
-            final AbsoluteInfo absSize = device.absSize;
-            for (int i=0; i<numPointers; i++) {
-                final int j = i * MotionEvent.NUM_SAMPLE_DATA;
-            
-                if (absX != null) {
-                    reportData[j + MotionEvent.SAMPLE_X] =
-                            ((reportData[j + MotionEvent.SAMPLE_X]-absX.minValue)
-                                / absX.range) * w;
-                }
-                if (absY != null) {
-                    reportData[j + MotionEvent.SAMPLE_Y] =
-                            ((reportData[j + MotionEvent.SAMPLE_Y]-absY.minValue)
-                                / absY.range) * h;
-                }
-                if (absPressure != null) {
-                    reportData[j + MotionEvent.SAMPLE_PRESSURE] = 
-                            ((reportData[j + MotionEvent.SAMPLE_PRESSURE]-absPressure.minValue)
-                                / (float)absPressure.range);
-                }
-                if (absSize != null) {
-                    reportData[j + MotionEvent.SAMPLE_SIZE] = 
-                            ((reportData[j + MotionEvent.SAMPLE_SIZE]-absSize.minValue)
-                                / (float)absSize.range);
-                }
-                
-                switch (orientation) {
-                    case Surface.ROTATION_90: {
-                        final float temp = reportData[j + MotionEvent.SAMPLE_X];
-                        reportData[j + MotionEvent.SAMPLE_X] = reportData[j + MotionEvent.SAMPLE_Y];
-                        reportData[j + MotionEvent.SAMPLE_Y] = w-temp;
-                        break;
-                    }
-                    case Surface.ROTATION_180: {
-                        reportData[j + MotionEvent.SAMPLE_X] = w-reportData[j + MotionEvent.SAMPLE_X];
-                        reportData[j + MotionEvent.SAMPLE_Y] = h-reportData[j + MotionEvent.SAMPLE_Y];
-                        break;
-                    }
-                    case Surface.ROTATION_270: {
-                        final float temp = reportData[j + MotionEvent.SAMPLE_X];
-                        reportData[j + MotionEvent.SAMPLE_X] = h-reportData[j + MotionEvent.SAMPLE_Y];
-                        reportData[j + MotionEvent.SAMPLE_Y] = temp;
-                        break;
-                    }
-                }
-            }
-            
-            // We only consider the first pointer when computing the edge
-            // flags, since they are global to the event.
-            if (action == MotionEvent.ACTION_DOWN) {
-                if (reportData[MotionEvent.SAMPLE_X] <= 0) {
-                    edgeFlags |= MotionEvent.EDGE_LEFT;
-                } else if (reportData[MotionEvent.SAMPLE_X] >= dispW) {
-                    edgeFlags |= MotionEvent.EDGE_RIGHT;
-                }
-                if (reportData[MotionEvent.SAMPLE_Y] <= 0) {
-                    edgeFlags |= MotionEvent.EDGE_TOP;
-                } else if (reportData[MotionEvent.SAMPLE_Y] >= dispH) {
-                    edgeFlags |= MotionEvent.EDGE_BOTTOM;
-                }
-            }
-            
-            if (currentMove != null) {
-                if (false) Slog.i("InputDevice", "Adding batch x="
-                        + reportData[MotionEvent.SAMPLE_X]
-                        + " y=" + reportData[MotionEvent.SAMPLE_Y]
-                        + " to " + currentMove);
-                currentMove.addBatch(curTime, reportData, metaState);
-                if (WindowManagerPolicy.WATCH_POINTER) {
-                    Slog.i("KeyInputQueue", "Updating: " + currentMove);
-                }
-                return null;
-            }
-            
-            MotionEvent me = MotionEvent.obtainNano(mDownTime, curTime,
-                    curTimeNano, action, numPointers, mPointerIds, reportData,
-                    metaState, xPrecision, yPrecision, device.id, edgeFlags);
-            if (action == MotionEvent.ACTION_MOVE) {
-                currentMove = me;
-            }
-            
-            if (nextNumPointers < lastNumPointers) {
-                removeOldPointer(upOrDownPointer);
-            }
-            
-            return me;
-        }
-        
-        boolean hasMore() {
-            return mLastNumPointers != mNextNumPointers;
-        }
-        
-        void finish() {
-            mNextNumPointers = mAddingPointerOffset = 0;
-            mNextData[MotionEvent.SAMPLE_PRESSURE] = 0;
-        }
-        
-        MotionEvent generateRelMotion(InputDevice device, long curTime,
-                long curTimeNano, int orientation, int metaState) {
-            
-            final float[] scaled = mReportData;
-            
-            // For now we only support 1 pointer with relative motions.
-            scaled[MotionEvent.SAMPLE_X] = mNextData[MotionEvent.SAMPLE_X];
-            scaled[MotionEvent.SAMPLE_Y] = mNextData[MotionEvent.SAMPLE_Y];
-            scaled[MotionEvent.SAMPLE_PRESSURE] = 1.0f;
-            scaled[MotionEvent.SAMPLE_SIZE] = 0;
-            int edgeFlags = 0;
-            
-            int action;
-            if (mNextNumPointers != mLastNumPointers) {
-                mNextData[MotionEvent.SAMPLE_X] =
-                        mNextData[MotionEvent.SAMPLE_Y] = 0;
-                if (mNextNumPointers > 0 && mLastNumPointers == 0) {
-                    action = MotionEvent.ACTION_DOWN;
-                    mDownTime = curTime;
-                } else if (mNextNumPointers == 0) {
-                    action = MotionEvent.ACTION_UP;
-                } else {
-                    action = MotionEvent.ACTION_MOVE;
-                }
-                mLastNumPointers = mNextNumPointers;
-                currentMove = null;
-            } else {
-                action = MotionEvent.ACTION_MOVE;
-            }
-            
-            scaled[MotionEvent.SAMPLE_X] *= xMoveScale;
-            scaled[MotionEvent.SAMPLE_Y] *= yMoveScale;
-            switch (orientation) {
-                case Surface.ROTATION_90: {
-                    final float temp = scaled[MotionEvent.SAMPLE_X];
-                    scaled[MotionEvent.SAMPLE_X] = scaled[MotionEvent.SAMPLE_Y];
-                    scaled[MotionEvent.SAMPLE_Y] = -temp;
-                    break;
-                }
-                case Surface.ROTATION_180: {
-                    scaled[MotionEvent.SAMPLE_X] = -scaled[MotionEvent.SAMPLE_X];
-                    scaled[MotionEvent.SAMPLE_Y] = -scaled[MotionEvent.SAMPLE_Y];
-                    break;
-                }
-                case Surface.ROTATION_270: {
-                    final float temp = scaled[MotionEvent.SAMPLE_X];
-                    scaled[MotionEvent.SAMPLE_X] = -scaled[MotionEvent.SAMPLE_Y];
-                    scaled[MotionEvent.SAMPLE_Y] = temp;
-                    break;
-                }
-            }
-            
-            if (currentMove != null) {
-                if (false) Slog.i("InputDevice", "Adding batch x="
-                        + scaled[MotionEvent.SAMPLE_X]
-                        + " y=" + scaled[MotionEvent.SAMPLE_Y]
-                        + " to " + currentMove);
-                currentMove.addBatch(curTime, scaled, metaState);
-                if (WindowManagerPolicy.WATCH_POINTER) {
-                    Slog.i("KeyInputQueue", "Updating: " + currentMove);
-                }
-                return null;
-            }
-            
-            MotionEvent me = MotionEvent.obtainNano(mDownTime, curTime,
-                    curTimeNano, action, 1, mPointerIds, scaled, metaState,
-                    xPrecision, yPrecision, device.id, edgeFlags);
-            if (action == MotionEvent.ACTION_MOVE) {
-                currentMove = me;
-            }
-            return me;
-        }
-    }
-    
-    static class AbsoluteInfo {
-        int minValue;
-        int maxValue;
-        int range;
-        int flat;
-        int fuzz;
-        
-        final void dump(PrintWriter pw) {
-            pw.print("minValue="); pw.print(minValue);
-            pw.print(" maxValue="); pw.print(maxValue);
-            pw.print(" range="); pw.print(range);
-            pw.print(" flat="); pw.print(flat);
-            pw.print(" fuzz="); pw.print(fuzz);
-        }
-    };
-    
-    InputDevice(int _id, int _classes, String _name,
-            AbsoluteInfo _absX, AbsoluteInfo _absY,
-            AbsoluteInfo _absPressure, AbsoluteInfo _absSize) {
-        id = _id;
-        classes = _classes;
-        name = _name;
-        absX = _absX;
-        absY = _absY;
-        absPressure = _absPressure;
-        absSize = _absSize;
-    }
-};
diff --git a/services/java/com/android/server/InputManager.java b/services/java/com/android/server/InputManager.java
index 2ba2914..cdae27c 100644
--- a/services/java/com/android/server/InputManager.java
+++ b/services/java/com/android/server/InputManager.java
@@ -56,7 +56,6 @@
     private final Callbacks mCallbacks;
     private final Context mContext;
     private final WindowManagerService mWindowManagerService;
-    private final WindowManagerPolicy mWindowManagerPolicy;
     private final PowerManager mPowerManager;
     private final PowerManagerService mPowerManagerService;
     
@@ -103,12 +102,10 @@
     
     public InputManager(Context context,
             WindowManagerService windowManagerService,
-            WindowManagerPolicy windowManagerPolicy,
             PowerManager powerManager,
             PowerManagerService powerManagerService) {
         this.mContext = context;
         this.mWindowManagerService = windowManagerService;
-        this.mWindowManagerPolicy = windowManagerPolicy;
         this.mPowerManager = powerManager;
         this.mPowerManagerService = powerManagerService;
         
@@ -325,23 +322,8 @@
         private static final String EXCLUDED_DEVICES_PATH = "etc/excluded-input-devices.xml";
         
         @SuppressWarnings("unused")
-        public boolean isScreenOn() {
-            return mPowerManagerService.isScreenOn();
-        }
-        
-        @SuppressWarnings("unused")
-        public boolean isScreenBright() {
-            return mPowerManagerService.isScreenBright();
-        }
-        
-        @SuppressWarnings("unused")
-        public void virtualKeyFeedback(long whenNanos, int deviceId, int action, int flags,
-                int keyCode, int scanCode, int metaState, long downTimeNanos) {
-            KeyEvent keyEvent = new KeyEvent(downTimeNanos / 1000000,
-                    whenNanos / 1000000, action, keyCode, 0, metaState, scanCode, deviceId,
-                    flags);
-            
-            mWindowManagerService.virtualKeyFeedback(keyEvent);
+        public void virtualKeyDownFeedback() {
+            mWindowManagerService.mInputMonitor.virtualKeyDownFeedback();
         }
         
         @SuppressWarnings("unused")
@@ -356,7 +338,7 @@
         
         @SuppressWarnings("unused")
         public void notifyLidSwitchChanged(long whenNanos, boolean lidOpen) {
-            mWindowManagerPolicy.notifyLidSwitchChanged(whenNanos, lidOpen);
+            mWindowManagerService.mInputMonitor.notifyLidSwitchChanged(whenNanos, lidOpen);
         }
         
         @SuppressWarnings("unused")
@@ -380,17 +362,17 @@
         }
         
         @SuppressWarnings("unused")
-        public int interceptKeyBeforeQueueing(int deviceId, int type, int scanCode,
-                int keyCode, int policyFlags, int value, long whenNanos, boolean isScreenOn) {
-            return mWindowManagerService.mInputMonitor.interceptKeyBeforeQueueing(deviceId, type,
-                    scanCode, keyCode, policyFlags, value, whenNanos, isScreenOn);
+        public int interceptKeyBeforeQueueing(long whenNanos, int keyCode, boolean down,
+                int policyFlags, boolean isScreenOn) {
+            return mWindowManagerService.mInputMonitor.interceptKeyBeforeQueueing(
+                    whenNanos, keyCode, down, policyFlags, isScreenOn);
         }
         
         @SuppressWarnings("unused")
-        public boolean interceptKeyBeforeDispatching(InputChannel focus, int keyCode,
-                int metaState, boolean down, int repeatCount, int policyFlags) {
+        public boolean interceptKeyBeforeDispatching(InputChannel focus, int action,
+                int flags, int keyCode, int metaState, int repeatCount, int policyFlags) {
             return mWindowManagerService.mInputMonitor.interceptKeyBeforeDispatching(focus,
-                    keyCode, metaState, down, repeatCount, policyFlags);
+                    action, flags, keyCode, metaState, repeatCount, policyFlags);
         }
         
         @SuppressWarnings("unused")
@@ -401,18 +383,6 @@
         }
         
         @SuppressWarnings("unused")
-        public void goToSleep(long whenNanos) {
-            long when = whenNanos / 1000000;
-            mPowerManager.goToSleep(when);
-        }
-        
-        @SuppressWarnings("unused")
-        public void pokeUserActivity(long eventTimeNanos, int eventType) {
-            long eventTime = eventTimeNanos / 1000000;
-            mPowerManagerService.userActivity(eventTime, false, eventType, false);
-        }
-        
-        @SuppressWarnings("unused")
         public void notifyAppSwitchComing() {
             mWindowManagerService.mInputMonitor.notifyAppSwitchComing();
         }
diff --git a/services/java/com/android/server/InputMethodManagerService.java b/services/java/com/android/server/InputMethodManagerService.java
index f6e3441..36b3a5e 100644
--- a/services/java/com/android/server/InputMethodManagerService.java
+++ b/services/java/com/android/server/InputMethodManagerService.java
@@ -980,7 +980,7 @@
     void setInputMethodLocked(String id) {
         InputMethodInfo info = mMethodMap.get(id);
         if (info == null) {
-            throw new IllegalArgumentException("Unknown id: " + mCurMethodId);
+            throw new IllegalArgumentException("Unknown id: " + id);
         }
 
         if (id.equals(mCurMethodId)) {
diff --git a/services/java/com/android/server/KeyInputQueue.java b/services/java/com/android/server/KeyInputQueue.java
deleted file mode 100644
index f62c7ee..0000000
--- a/services/java/com/android/server/KeyInputQueue.java
+++ /dev/null
@@ -1,1388 +0,0 @@
-/*
- * Copyright (C) 2007 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server;
-
-import android.content.Context;
-import android.content.res.Configuration;
-import android.content.res.Resources;
-import android.os.Environment;
-import android.os.LatencyTimer;
-import android.os.PowerManager;
-import android.os.SystemClock;
-import android.os.SystemProperties;
-import android.util.Slog;
-import android.util.SparseArray;
-import android.util.Xml;
-import android.view.Display;
-import android.view.KeyEvent;
-import android.view.MotionEvent;
-import android.view.RawInputEvent;
-import android.view.Surface;
-import android.view.WindowManagerPolicy;
-
-import com.android.internal.util.XmlUtils;
-
-import org.xmlpull.v1.XmlPullParser;
-
-import java.io.BufferedReader;
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.FileNotFoundException;
-import java.io.FileReader;
-import java.io.IOException;
-import java.io.InputStreamReader;
-import java.io.PrintWriter;
-import java.util.ArrayList;
-
-public abstract class KeyInputQueue {
-    static final String TAG = "KeyInputQueue";
-
-    static final boolean DEBUG = false;
-    static final boolean DEBUG_VIRTUAL_KEYS = false;
-    static final boolean DEBUG_POINTERS = false;
-    
-    /**
-     * Turn on some hacks we have to improve the touch interaction with a
-     * certain device whose screen currently is not all that good.
-     */
-    static boolean BAD_TOUCH_HACK = false;
-    
-    /**
-     * Turn on some hacks to improve touch interaction with another device
-     * where touch coordinate data can get corrupted.
-     */
-    static boolean JUMPY_TOUCH_HACK = false;
-    
-    private static final String EXCLUDED_DEVICES_PATH = "etc/excluded-input-devices.xml";
-
-    final SparseArray<InputDevice> mDevices = new SparseArray<InputDevice>();
-    final SparseArray<InputDevice> mIgnoredDevices = new SparseArray<InputDevice>();
-    final ArrayList<VirtualKey> mVirtualKeys = new ArrayList<VirtualKey>();
-    final HapticFeedbackCallback mHapticFeedbackCallback;
-    
-    int mGlobalMetaState = 0;
-    boolean mHaveGlobalMetaState = false;
-    
-    final QueuedEvent mFirst;
-    final QueuedEvent mLast;
-    QueuedEvent mCache;
-    int mCacheCount;
-
-    Display mDisplay = null;
-    int mDisplayWidth;
-    int mDisplayHeight;
-    
-    int mOrientation = Surface.ROTATION_0;
-    int[] mKeyRotationMap = null;
-    
-    VirtualKey mPressedVirtualKey = null;
-    
-    PowerManager.WakeLock mWakeLock;
-
-    static final int[] KEY_90_MAP = new int[] {
-        KeyEvent.KEYCODE_DPAD_DOWN, KeyEvent.KEYCODE_DPAD_RIGHT,
-        KeyEvent.KEYCODE_DPAD_RIGHT, KeyEvent.KEYCODE_DPAD_UP,
-        KeyEvent.KEYCODE_DPAD_UP, KeyEvent.KEYCODE_DPAD_LEFT,
-        KeyEvent.KEYCODE_DPAD_LEFT, KeyEvent.KEYCODE_DPAD_DOWN,
-    };
-    
-    static final int[] KEY_180_MAP = new int[] {
-        KeyEvent.KEYCODE_DPAD_DOWN, KeyEvent.KEYCODE_DPAD_UP,
-        KeyEvent.KEYCODE_DPAD_RIGHT, KeyEvent.KEYCODE_DPAD_LEFT,
-        KeyEvent.KEYCODE_DPAD_UP, KeyEvent.KEYCODE_DPAD_DOWN,
-        KeyEvent.KEYCODE_DPAD_LEFT, KeyEvent.KEYCODE_DPAD_RIGHT,
-    };
-    
-    static final int[] KEY_270_MAP = new int[] {
-        KeyEvent.KEYCODE_DPAD_DOWN, KeyEvent.KEYCODE_DPAD_LEFT,
-        KeyEvent.KEYCODE_DPAD_LEFT, KeyEvent.KEYCODE_DPAD_UP,
-        KeyEvent.KEYCODE_DPAD_UP, KeyEvent.KEYCODE_DPAD_RIGHT,
-        KeyEvent.KEYCODE_DPAD_RIGHT, KeyEvent.KEYCODE_DPAD_DOWN,
-    };
-    
-    public static final int FILTER_REMOVE = 0;
-    public static final int FILTER_KEEP = 1;
-    public static final int FILTER_ABORT = -1;
-
-    private static final boolean MEASURE_LATENCY = false;
-    private LatencyTimer lt;
-
-    public interface FilterCallback {
-        int filterEvent(QueuedEvent ev);
-    }
-    
-    public interface HapticFeedbackCallback {
-        void virtualKeyFeedback(KeyEvent event);
-    }
-    
-    static class QueuedEvent {
-        InputDevice inputDevice;
-        long whenNano;
-        int flags; // From the raw event
-        int classType; // One of the class constants in InputEvent
-        Object event;
-        boolean inQueue;
-
-        void copyFrom(QueuedEvent that) {
-            this.inputDevice = that.inputDevice;
-            this.whenNano = that.whenNano;
-            this.flags = that.flags;
-            this.classType = that.classType;
-            this.event = that.event;
-        }
-
-        @Override
-        public String toString() {
-            return "QueuedEvent{"
-                + Integer.toHexString(System.identityHashCode(this))
-                + " " + event + "}";
-        }
-        
-        // not copied
-        QueuedEvent prev;
-        QueuedEvent next;
-    }
-
-    /**
-     * A key that exists as a part of the touch-screen, outside of the normal
-     * display area of the screen.
-     */
-    static class VirtualKey {
-        int scancode;
-        int centerx;
-        int centery;
-        int width;
-        int height;
-        
-        int hitLeft;
-        int hitTop;
-        int hitRight;
-        int hitBottom;
-        
-        InputDevice lastDevice;
-        int lastKeycode;
-        
-        boolean checkHit(int x, int y) {
-            return (x >= hitLeft && x <= hitRight
-                    && y >= hitTop && y <= hitBottom);
-        }
-        
-        void computeHitRect(InputDevice dev, int dw, int dh) {
-            if (dev == lastDevice) {
-                return;
-            }
-            
-            if (DEBUG_VIRTUAL_KEYS) Slog.v(TAG, "computeHitRect for " + scancode
-                    + ": dev=" + dev + " absX=" + dev.absX + " absY=" + dev.absY);
-            
-            lastDevice = dev;
-            
-            int minx = dev.absX.minValue;
-            int maxx = dev.absX.maxValue;
-            
-            int halfw = width/2;
-            int left = centerx - halfw;
-            int right = centerx + halfw;
-            hitLeft = minx + ((left*maxx-minx)/dw);
-            hitRight = minx + ((right*maxx-minx)/dw);
-            
-            int miny = dev.absY.minValue;
-            int maxy = dev.absY.maxValue;
-            
-            int halfh = height/2;
-            int top = centery - halfh;
-            int bottom = centery + halfh;
-            hitTop = miny + ((top*maxy-miny)/dh);
-            hitBottom = miny + ((bottom*maxy-miny)/dh);
-        }
-    }
-
-    private void readVirtualKeys(String deviceName) {
-        try {
-            FileInputStream fis = new FileInputStream(
-                    "/sys/board_properties/virtualkeys." + deviceName);
-            InputStreamReader isr = new InputStreamReader(fis);
-            BufferedReader br = new BufferedReader(isr, 2048);
-            String str = br.readLine();
-            if (str != null) {
-                String[] it = str.split(":");
-                if (DEBUG_VIRTUAL_KEYS) Slog.v(TAG, "***** VIRTUAL KEYS: " + it);
-                final int N = it.length-6;
-                for (int i=0; i<=N; i+=6) {
-                    if (!"0x01".equals(it[i])) {
-                        Slog.w(TAG, "Unknown virtual key type at elem #" + i
-                                + ": " + it[i]);
-                        continue;
-                    }
-                    try {
-                        VirtualKey sb = new VirtualKey();
-                        sb.scancode = Integer.parseInt(it[i+1]);
-                        sb.centerx = Integer.parseInt(it[i+2]);
-                        sb.centery = Integer.parseInt(it[i+3]);
-                        sb.width = Integer.parseInt(it[i+4]);
-                        sb.height = Integer.parseInt(it[i+5]);
-                        if (DEBUG_VIRTUAL_KEYS) Slog.v(TAG, "Virtual key "
-                                + sb.scancode + ": center=" + sb.centerx + ","
-                                + sb.centery + " size=" + sb.width + "x"
-                                + sb.height);
-                        mVirtualKeys.add(sb);
-                    } catch (NumberFormatException e) {
-                        Slog.w(TAG, "Bad number at region " + i + " in: "
-                                + str, e);
-                    }
-                }
-            }
-            br.close();
-        } catch (FileNotFoundException e) {
-            Slog.i(TAG, "No virtual keys found");
-        } catch (IOException e) {
-            Slog.w(TAG, "Error reading virtual keys", e);
-        }
-    }
-
-    private void readExcludedDevices() {
-        // Read partner-provided list of excluded input devices
-        XmlPullParser parser = null;
-        // Environment.getRootDirectory() is a fancy way of saying ANDROID_ROOT or "/system".
-        File confFile = new File(Environment.getRootDirectory(), EXCLUDED_DEVICES_PATH);
-        FileReader confreader = null;
-        try {
-            confreader = new FileReader(confFile);
-            parser = Xml.newPullParser();
-            parser.setInput(confreader);
-            XmlUtils.beginDocument(parser, "devices");
-
-            while (true) {
-                XmlUtils.nextElement(parser);
-                if (!"device".equals(parser.getName())) {
-                    break;
-                }
-                String name = parser.getAttributeValue(null, "name");
-                if (name != null) {
-                    if (DEBUG) Slog.v(TAG, "addExcludedDevice " + name);
-                    addExcludedDevice(name);
-                }
-            }
-        } catch (FileNotFoundException e) {
-            // It's ok if the file does not exist.
-        } catch (Exception e) {
-            Slog.e(TAG, "Exception while parsing '" + confFile.getAbsolutePath() + "'", e);
-        } finally {
-            try { if (confreader != null) confreader.close(); } catch (IOException e) { }
-        }
-    }
-
-    KeyInputQueue(Context context, HapticFeedbackCallback  hapticFeedbackCallback) {
-        if (MEASURE_LATENCY) {
-            lt = new LatencyTimer(100, 1000);
-        }
-
-        Resources r = context.getResources();
-        BAD_TOUCH_HACK = r.getBoolean(com.android.internal.R.bool.config_filterTouchEvents);
-        
-        JUMPY_TOUCH_HACK = r.getBoolean(com.android.internal.R.bool.config_filterJumpyTouchEvents);
-        
-        mHapticFeedbackCallback = hapticFeedbackCallback;
-        
-        if (! WindowManagerService.ENABLE_NATIVE_INPUT_DISPATCH) {
-            readExcludedDevices();
-        }
-        
-        PowerManager pm = (PowerManager)context.getSystemService(
-                                                        Context.POWER_SERVICE);
-        mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,
-                                                        "KeyInputQueue");
-        mWakeLock.setReferenceCounted(false);
-
-        mFirst = new QueuedEvent();
-        mLast = new QueuedEvent();
-        mFirst.next = mLast;
-        mLast.prev = mFirst;
-
-        if (! WindowManagerService.ENABLE_NATIVE_INPUT_DISPATCH) {
-            mThread.start();
-        }
-    }
-
-    public void setDisplay(Display display) {
-        mDisplay = display;
-        
-        // We assume at this point that the display dimensions reflect the
-        // natural, unrotated display.  We will perform hit tests for soft
-        // buttons based on that display.
-        mDisplayWidth = display.getWidth();
-        mDisplayHeight = display.getHeight();
-    }
-    
-    public void getInputConfiguration(Configuration config) {
-        synchronized (mFirst) {
-            config.touchscreen = Configuration.TOUCHSCREEN_NOTOUCH;
-            config.keyboard = Configuration.KEYBOARD_NOKEYS;
-            config.navigation = Configuration.NAVIGATION_NONAV;
-            
-            final int N = mDevices.size();
-            for (int i=0; i<N; i++) {
-                InputDevice d = mDevices.valueAt(i);
-                if (d != null) {
-                    if ((d.classes&RawInputEvent.CLASS_TOUCHSCREEN) != 0) {
-                        config.touchscreen
-                                = Configuration.TOUCHSCREEN_FINGER;
-                        //Slog.i("foo", "***** HAVE TOUCHSCREEN!");
-                    }
-                    if ((d.classes&RawInputEvent.CLASS_ALPHAKEY) != 0) {
-                        config.keyboard
-                                = Configuration.KEYBOARD_QWERTY;
-                        //Slog.i("foo", "***** HAVE QWERTY!");
-                    }
-                    if ((d.classes&RawInputEvent.CLASS_TRACKBALL) != 0) {
-                        config.navigation
-                                = Configuration.NAVIGATION_TRACKBALL;
-                        //Slog.i("foo", "***** HAVE TRACKBALL!");
-                    } else if ((d.classes&RawInputEvent.CLASS_DPAD) != 0) {
-                        config.navigation
-                                = Configuration.NAVIGATION_DPAD;
-                        //Slog.i("foo", "***** HAVE DPAD!");
-                    }
-                }
-            }
-        }
-    }
-    
-    public int getScancodeState(int code) {
-        synchronized (mFirst) {
-            VirtualKey vk = mPressedVirtualKey;
-            if (vk != null) {
-                if (vk.scancode == code) {
-                    return 2;
-                }
-            }
-            return nativeGetScancodeState(code);
-        }
-    }
-    
-    public int getScancodeState(int deviceId, int code) {
-        synchronized (mFirst) {
-            VirtualKey vk = mPressedVirtualKey;
-            if (vk != null) {
-                if (vk.scancode == code) {
-                    return 2;
-                }
-            }
-            return nativeGetScancodeState(deviceId, code);
-        }
-    }
-    
-    public int getTrackballScancodeState(int code) {
-        synchronized (mFirst) {
-            final int N = mDevices.size();
-            for (int i=0; i<N; i++) {
-                InputDevice dev = mDevices.valueAt(i);
-                if ((dev.classes&RawInputEvent.CLASS_TRACKBALL) != 0) {
-                    int res = nativeGetScancodeState(dev.id, code);
-                    if (res > 0) {
-                        return res;
-                    }
-                }
-            }
-        }
-        
-        return 0;
-    }
-    
-    public int getDPadScancodeState(int code) {
-        synchronized (mFirst) {
-            final int N = mDevices.size();
-            for (int i=0; i<N; i++) {
-                InputDevice dev = mDevices.valueAt(i);
-                if ((dev.classes&RawInputEvent.CLASS_DPAD) != 0) {
-                    int res = nativeGetScancodeState(dev.id, code);
-                    if (res > 0) {
-                        return res;
-                    }
-                }
-            }
-        }
-        
-        return 0;
-    }
-    
-    public int getKeycodeState(int code) {
-        synchronized (mFirst) {
-            VirtualKey vk = mPressedVirtualKey;
-            if (vk != null) {
-                if (vk.lastKeycode == code) {
-                    return 2;
-                }
-            }
-            return nativeGetKeycodeState(code);
-        }
-    }
-    
-    public int getKeycodeState(int deviceId, int code) {
-        synchronized (mFirst) {
-            VirtualKey vk = mPressedVirtualKey;
-            if (vk != null) {
-                if (vk.lastKeycode == code) {
-                    return 2;
-                }
-            }
-            return nativeGetKeycodeState(deviceId, code);
-        }
-    }
-    
-    public int getTrackballKeycodeState(int code) {
-        synchronized (mFirst) {
-            final int N = mDevices.size();
-            for (int i=0; i<N; i++) {
-                InputDevice dev = mDevices.valueAt(i);
-                if ((dev.classes&RawInputEvent.CLASS_TRACKBALL) != 0) {
-                    int res = nativeGetKeycodeState(dev.id, code);
-                    if (res > 0) {
-                        return res;
-                    }
-                }
-            }
-        }
-        
-        return 0;
-    }
-    
-    public int getDPadKeycodeState(int code) {
-        synchronized (mFirst) {
-            final int N = mDevices.size();
-            for (int i=0; i<N; i++) {
-                InputDevice dev = mDevices.valueAt(i);
-                if ((dev.classes&RawInputEvent.CLASS_DPAD) != 0) {
-                    int res = nativeGetKeycodeState(dev.id, code);
-                    if (res > 0) {
-                        return res;
-                    }
-                }
-            }
-        }
-        
-        return 0;
-    }
-    
-    public static native String getDeviceName(int deviceId);
-    public static native int getDeviceClasses(int deviceId);
-    public static native void addExcludedDevice(String deviceName);
-    public static native boolean getAbsoluteInfo(int deviceId, int axis,
-            InputDevice.AbsoluteInfo outInfo);
-    public static native int getSwitchState(int sw);
-    public static native int getSwitchState(int deviceId, int sw);
-    public static native int nativeGetScancodeState(int code);
-    public static native int nativeGetScancodeState(int deviceId, int code);
-    public static native int nativeGetKeycodeState(int code);
-    public static native int nativeGetKeycodeState(int deviceId, int code);
-    public static native int scancodeToKeycode(int deviceId, int scancode);
-    public static native boolean hasKeys(int[] keycodes, boolean[] keyExists);
-    
-    public static KeyEvent newKeyEvent(InputDevice device, long downTime,
-            long eventTime, boolean down, int keycode, int repeatCount,
-            int scancode, int flags) {
-        return new KeyEvent(
-                downTime, eventTime,
-                down ? KeyEvent.ACTION_DOWN : KeyEvent.ACTION_UP,
-                keycode, repeatCount,
-                device != null ? device.mMetaKeysState : 0,
-                device != null ? device.id : -1, scancode,
-                flags | KeyEvent.FLAG_FROM_SYSTEM);
-    }
-    
-    Thread mThread = new Thread("InputDeviceReader") {
-        public void run() {
-            if (DEBUG) Slog.v(TAG, "InputDeviceReader.run()");
-            android.os.Process.setThreadPriority(
-                    android.os.Process.THREAD_PRIORITY_URGENT_DISPLAY);
-            
-            RawInputEvent ev = new RawInputEvent();
-            while (true) {
-                try {
-                    InputDevice di;
-
-                    // block, doesn't release the monitor
-                    readEvent(ev);
-
-                    boolean send = false;
-                    boolean configChanged = false;
-                    
-                    if (false) {
-                        Slog.i(TAG, "Input event: dev=0x"
-                                + Integer.toHexString(ev.deviceId)
-                                + " type=0x" + Integer.toHexString(ev.type)
-                                + " scancode=" + ev.scancode
-                                + " keycode=" + ev.keycode
-                                + " value=" + ev.value);
-                    }
-                    
-                    if (ev.type == RawInputEvent.EV_DEVICE_ADDED) {
-                        synchronized (mFirst) {
-                            di = newInputDevice(ev.deviceId);
-                            if (di.classes != 0) {
-                                // If this device is some kind of input class,
-                                // we care about it.
-                                mDevices.put(ev.deviceId, di);
-                                if ((di.classes & RawInputEvent.CLASS_TOUCHSCREEN) != 0) {
-                                    readVirtualKeys(di.name);
-                                }
-                                // The configuration may have changed because
-                                // of this device.
-                                configChanged = true;
-                            } else {
-                                // We won't do anything with this device.
-                                mIgnoredDevices.put(ev.deviceId, di);
-                                Slog.i(TAG, "Ignoring non-input device: id=0x"
-                                        + Integer.toHexString(di.id)
-                                        + ", name=" + di.name);
-                            }
-                        }
-                    } else if (ev.type == RawInputEvent.EV_DEVICE_REMOVED) {
-                        synchronized (mFirst) {
-                            if (false) {
-                                Slog.i(TAG, "Device removed: id=0x"
-                                        + Integer.toHexString(ev.deviceId));
-                            }
-                            di = mDevices.get(ev.deviceId);
-                            if (di != null) {
-                                mDevices.delete(ev.deviceId);
-                                // The configuration may have changed because
-                                // of this device.
-                                configChanged = true;
-                            } else if ((di=mIgnoredDevices.get(ev.deviceId)) != null) {
-                                mIgnoredDevices.remove(ev.deviceId);
-                            } else {
-                                Slog.w(TAG, "Removing bad device id: "
-                                        + Integer.toHexString(ev.deviceId));
-                                continue;
-                            }
-                        }
-                    } else {
-                        di = getInputDevice(ev.deviceId);
-                        if (di == null) {
-                            // This may be some junk from an ignored device.
-                            continue;
-                        }
-                        
-                        // first crack at it
-                        send = preprocessEvent(di, ev);
-
-                        if (ev.type == RawInputEvent.EV_KEY) {
-                            di.mMetaKeysState = makeMetaState(ev.keycode,
-                                    ev.value != 0, di.mMetaKeysState);
-                            mHaveGlobalMetaState = false;
-                        }
-                    }
-
-                    if (configChanged) {
-                        synchronized (mFirst) {
-                            addLocked(di, System.nanoTime(), 0,
-                                    RawInputEvent.CLASS_CONFIGURATION_CHANGED,
-                                    null);
-                        }
-                    }
-                    
-                    if (!send) {
-                        continue;
-                    }
-                    
-                    synchronized (mFirst) {
-                        // NOTE: The event timebase absolutely must be the same
-                        // timebase as SystemClock.uptimeMillis().
-                        //curTime = gotOne ? ev.when : SystemClock.uptimeMillis();
-                        final long curTime = SystemClock.uptimeMillis();
-                        final long curTimeNano = System.nanoTime();
-                        //Slog.i(TAG, "curTime=" + curTime + ", systemClock=" + SystemClock.uptimeMillis());
-                        
-                        final int classes = di.classes;
-                        final int type = ev.type;
-                        final int scancode = ev.scancode;
-                        send = false;
-                        
-                        // Is it a key event?
-                        if (type == RawInputEvent.EV_KEY &&
-                                (classes&RawInputEvent.CLASS_KEYBOARD) != 0 &&
-                                (scancode < RawInputEvent.BTN_FIRST ||
-                                        scancode > RawInputEvent.BTN_LAST)) {
-                            boolean down;
-                            if (ev.value != 0) {
-                                down = true;
-                                di.mKeyDownTime = curTime;
-                            } else {
-                                down = false;
-                            }
-                            int keycode = rotateKeyCodeLocked(ev.keycode);
-                            addLocked(di, curTimeNano, ev.flags,
-                                    RawInputEvent.CLASS_KEYBOARD,
-                                    newKeyEvent(di, di.mKeyDownTime, curTime, down,
-                                            keycode, 0, scancode,
-                                            ((ev.flags & WindowManagerPolicy.FLAG_WOKE_HERE) != 0)
-                                             ? KeyEvent.FLAG_WOKE_HERE : 0));
-                            
-                        } else if (ev.type == RawInputEvent.EV_KEY) {
-                            // Single touch protocol: touch going down or up.
-                            if (ev.scancode == RawInputEvent.BTN_TOUCH &&
-                                    (classes&(RawInputEvent.CLASS_TOUCHSCREEN
-                                            |RawInputEvent.CLASS_TOUCHSCREEN_MT))
-                                            == RawInputEvent.CLASS_TOUCHSCREEN) {
-                                di.mAbs.changed = true;
-                                di.mAbs.mDown[0] = ev.value != 0;
-                            
-                            // Trackball (mouse) protocol: press down or up.
-                            } else if (ev.scancode == RawInputEvent.BTN_MOUSE &&
-                                    (classes&RawInputEvent.CLASS_TRACKBALL) != 0) {
-                                di.mRel.changed = true;
-                                di.mRel.mNextNumPointers = ev.value != 0 ? 1 : 0;
-                                send = true;
-                            }
-    
-                        // Process position events from multitouch protocol.
-                        } else if (ev.type == RawInputEvent.EV_ABS &&
-                                (classes&RawInputEvent.CLASS_TOUCHSCREEN_MT) != 0) {
-                            if (ev.scancode == RawInputEvent.ABS_MT_TOUCH_MAJOR) {
-                                di.mAbs.changed = true;
-                                di.mAbs.mNextData[di.mAbs.mAddingPointerOffset
-                                        + MotionEvent.SAMPLE_PRESSURE] = ev.value;
-                            } else if (ev.scancode == RawInputEvent.ABS_MT_POSITION_X) {
-                                di.mAbs.changed = true;
-                                di.mAbs.mNextData[di.mAbs.mAddingPointerOffset
-                                    + MotionEvent.SAMPLE_X] = ev.value;
-                                if (DEBUG_POINTERS) Slog.v(TAG, "MT @"
-                                        + di.mAbs.mAddingPointerOffset
-                                        + " X:" + ev.value);
-                            } else if (ev.scancode == RawInputEvent.ABS_MT_POSITION_Y) {
-                                di.mAbs.changed = true;
-                                di.mAbs.mNextData[di.mAbs.mAddingPointerOffset
-                                    + MotionEvent.SAMPLE_Y] = ev.value;
-                                if (DEBUG_POINTERS) Slog.v(TAG, "MT @"
-                                        + di.mAbs.mAddingPointerOffset
-                                        + " Y:" + ev.value);
-                            } else if (ev.scancode == RawInputEvent.ABS_MT_WIDTH_MAJOR) {
-                                di.mAbs.changed = true;
-                                di.mAbs.mNextData[di.mAbs.mAddingPointerOffset
-                                    + MotionEvent.SAMPLE_SIZE] = ev.value;
-                            }
-                        
-                        // Process position events from single touch protocol.
-                        } else if (ev.type == RawInputEvent.EV_ABS &&
-                                (classes&RawInputEvent.CLASS_TOUCHSCREEN) != 0) {
-                            if (ev.scancode == RawInputEvent.ABS_X) {
-                                di.mAbs.changed = true;
-                                di.curTouchVals[MotionEvent.SAMPLE_X] = ev.value;
-                            } else if (ev.scancode == RawInputEvent.ABS_Y) {
-                                di.mAbs.changed = true;
-                                di.curTouchVals[MotionEvent.SAMPLE_Y] = ev.value;
-                            } else if (ev.scancode == RawInputEvent.ABS_PRESSURE) {
-                                di.mAbs.changed = true;
-                                di.curTouchVals[MotionEvent.SAMPLE_PRESSURE] = ev.value;
-                                di.curTouchVals[MotionEvent.NUM_SAMPLE_DATA
-                                                 + MotionEvent.SAMPLE_PRESSURE] = ev.value;
-                            } else if (ev.scancode == RawInputEvent.ABS_TOOL_WIDTH) {
-                                di.mAbs.changed = true;
-                                di.curTouchVals[MotionEvent.SAMPLE_SIZE] = ev.value;
-                                di.curTouchVals[MotionEvent.NUM_SAMPLE_DATA
-                                                 + MotionEvent.SAMPLE_SIZE] = ev.value;
-                            }
-    
-                        // Process movement events from trackball (mouse) protocol.
-                        } else if (ev.type == RawInputEvent.EV_REL &&
-                                (classes&RawInputEvent.CLASS_TRACKBALL) != 0) {
-                            // Add this relative movement into our totals.
-                            if (ev.scancode == RawInputEvent.REL_X) {
-                                di.mRel.changed = true;
-                                di.mRel.mNextData[MotionEvent.SAMPLE_X] += ev.value;
-                            } else if (ev.scancode == RawInputEvent.REL_Y) {
-                                di.mRel.changed = true;
-                                di.mRel.mNextData[MotionEvent.SAMPLE_Y] += ev.value;
-                            }
-                        }
-                        
-                        // Handle multitouch protocol sync: tells us that the
-                        // driver has returned all data for -one- of the pointers
-                        // that is currently down.
-                        if (ev.type == RawInputEvent.EV_SYN
-                                && ev.scancode == RawInputEvent.SYN_MT_REPORT
-                                && di.mAbs != null) {
-                            di.mAbs.changed = true;
-                            if (di.mAbs.mNextData[MotionEvent.SAMPLE_PRESSURE] > 0) {
-                                // If the value is <= 0, the pointer is not
-                                // down, so keep it in the count.
-                                
-                                if (di.mAbs.mNextData[di.mAbs.mAddingPointerOffset
-                                                      + MotionEvent.SAMPLE_PRESSURE] != 0) {
-                                    final int num = di.mAbs.mNextNumPointers+1;
-                                    di.mAbs.mNextNumPointers = num;
-                                    if (DEBUG_POINTERS) Slog.v(TAG,
-                                            "MT_REPORT: now have " + num + " pointers");
-                                    final int newOffset = (num <= InputDevice.MAX_POINTERS)
-                                            ? (num * MotionEvent.NUM_SAMPLE_DATA)
-                                            : (InputDevice.MAX_POINTERS *
-                                                    MotionEvent.NUM_SAMPLE_DATA);
-                                    di.mAbs.mAddingPointerOffset = newOffset;
-                                    di.mAbs.mNextData[newOffset
-                                            + MotionEvent.SAMPLE_PRESSURE] = 0;
-                                } else {
-                                    if (DEBUG_POINTERS) Slog.v(TAG, "MT_REPORT: no pointer");
-                                }
-                            }
-                        
-                        // Handle general event sync: all data for the current
-                        // event update has been delivered.
-                        } else if (send || (ev.type == RawInputEvent.EV_SYN
-                                && ev.scancode == RawInputEvent.SYN_REPORT)) {
-                            if (mDisplay != null) {
-                                if (!mHaveGlobalMetaState) {
-                                    computeGlobalMetaStateLocked();
-                                }
-                                
-                                MotionEvent me;
-                                
-                                InputDevice.MotionState ms = di.mAbs;
-                                if (ms.changed) {
-                                    ms.everChanged = true;
-                                    ms.changed = false;
-                                    
-                                    if ((classes&(RawInputEvent.CLASS_TOUCHSCREEN
-                                            |RawInputEvent.CLASS_TOUCHSCREEN_MT))
-                                            == RawInputEvent.CLASS_TOUCHSCREEN) {
-                                        ms.mNextNumPointers = 0;
-                                        if (ms.mDown[0]) {
-                                            System.arraycopy(di.curTouchVals, 0,
-                                                    ms.mNextData, 0,
-                                                    MotionEvent.NUM_SAMPLE_DATA);
-                                            ms.mNextNumPointers++;
-                                        }
-                                    }
-                                    
-                                    if (BAD_TOUCH_HACK) {
-                                        ms.dropBadPoint(di);
-                                    }
-                                    if (JUMPY_TOUCH_HACK) {
-                                        ms.dropJumpyPoint(di);
-                                    }
-                                    
-                                    boolean doMotion = !monitorVirtualKey(di,
-                                            ev, curTime, curTimeNano);
-                                    
-                                    if (doMotion && ms.mNextNumPointers > 0
-                                            && (ms.mLastNumPointers == 0
-                                                    || ms.mSkipLastPointers)) {
-                                        doMotion = !generateVirtualKeyDown(di,
-                                                ev, curTime, curTimeNano);
-                                    }
-                                    
-                                    if (doMotion) {
-                                        // XXX Need to be able to generate
-                                        // multiple events here, for example
-                                        // if two fingers change up/down state
-                                        // at the same time.
-                                        do {
-                                            me = ms.generateAbsMotion(di, curTime,
-                                                    curTimeNano, mDisplay,
-                                                    mOrientation, mGlobalMetaState);
-                                            if (DEBUG_POINTERS) Slog.v(TAG, "Absolute: x="
-                                                    + di.mAbs.mNextData[MotionEvent.SAMPLE_X]
-                                                    + " y="
-                                                    + di.mAbs.mNextData[MotionEvent.SAMPLE_Y]
-                                                    + " ev=" + me);
-                                            if (me != null) {
-                                                if (WindowManagerPolicy.WATCH_POINTER) {
-                                                    Slog.i(TAG, "Enqueueing: " + me);
-                                                }
-                                                addLocked(di, curTimeNano, ev.flags,
-                                                        RawInputEvent.CLASS_TOUCHSCREEN, me);
-                                            }
-                                        } while (ms.hasMore());
-                                    } else {
-                                        // We are consuming movement in the
-                                        // virtual key area...  but still
-                                        // propagate this to the previous
-                                        // data for comparisons.
-                                        int num = ms.mNextNumPointers;
-                                        if (num > InputDevice.MAX_POINTERS) {
-                                            num = InputDevice.MAX_POINTERS;
-                                        }
-                                        System.arraycopy(ms.mNextData, 0,
-                                                ms.mLastData, 0,
-                                                num * MotionEvent.NUM_SAMPLE_DATA);
-                                        ms.mLastNumPointers = num;
-                                        ms.mSkipLastPointers = true;
-                                    }
-                                    
-                                    ms.finish();
-                                }
-                                
-                                ms = di.mRel;
-                                if (ms.changed) {
-                                    ms.everChanged = true;
-                                    ms.changed = false;
-                                    
-                                    me = ms.generateRelMotion(di, curTime,
-                                            curTimeNano,
-                                            mOrientation, mGlobalMetaState);
-                                    if (false) Slog.v(TAG, "Relative: x="
-                                            + di.mRel.mNextData[MotionEvent.SAMPLE_X]
-                                            + " y="
-                                            + di.mRel.mNextData[MotionEvent.SAMPLE_Y]
-                                            + " ev=" + me);
-                                    if (me != null) {
-                                        addLocked(di, curTimeNano, ev.flags,
-                                                RawInputEvent.CLASS_TRACKBALL, me);
-                                    }
-                                }
-                            }
-                        }
-                    }
-                
-                } catch (RuntimeException exc) {
-                    Slog.e(TAG, "InputReaderThread uncaught exception", exc);
-                }
-            }
-        }
-    };
-
-    private boolean isInsideDisplay(InputDevice dev) {
-        final InputDevice.AbsoluteInfo absx = dev.absX;
-        final InputDevice.AbsoluteInfo absy = dev.absY;
-        final InputDevice.MotionState absm = dev.mAbs;
-        if (absx == null || absy == null || absm == null) {
-            return true;
-        }
-        
-        if (absm.mNextData[MotionEvent.SAMPLE_X] >= absx.minValue
-                && absm.mNextData[MotionEvent.SAMPLE_X] <= absx.maxValue
-                && absm.mNextData[MotionEvent.SAMPLE_Y] >= absy.minValue
-                && absm.mNextData[MotionEvent.SAMPLE_Y] <= absy.maxValue) {
-            if (DEBUG_VIRTUAL_KEYS) Slog.v(TAG, "Input ("
-                    + absm.mNextData[MotionEvent.SAMPLE_X]
-                    + "," + absm.mNextData[MotionEvent.SAMPLE_Y]
-                    + ") inside of display");
-            return true;
-        }
-        
-        return false;
-    }
-    
-    private VirtualKey findVirtualKey(InputDevice dev) {
-        final int N = mVirtualKeys.size();
-        if (N <= 0) {
-            return null;
-        }
-        
-        final InputDevice.MotionState absm = dev.mAbs;
-        for (int i=0; i<N; i++) {
-            VirtualKey sb = mVirtualKeys.get(i);
-            sb.computeHitRect(dev, mDisplayWidth, mDisplayHeight);
-            if (DEBUG_VIRTUAL_KEYS) Slog.v(TAG, "Hit test ("
-                    + absm.mNextData[MotionEvent.SAMPLE_X] + ","
-                    + absm.mNextData[MotionEvent.SAMPLE_Y] + ") in code "
-                    + sb.scancode + " - (" + sb.hitLeft
-                    + "," + sb.hitTop + ")-(" + sb.hitRight + ","
-                    + sb.hitBottom + ")");
-            if (sb.checkHit(absm.mNextData[MotionEvent.SAMPLE_X],
-                    absm.mNextData[MotionEvent.SAMPLE_Y])) {
-                if (DEBUG_VIRTUAL_KEYS) Slog.v(TAG, "Hit!");
-                return sb;
-            }
-        }
-        
-        return null;
-    }
-    
-    private boolean generateVirtualKeyDown(InputDevice di, RawInputEvent ev,
-            long curTime, long curTimeNano) {
-        if (isInsideDisplay(di)) {
-            // Didn't consume event.
-            return false;
-        }
-        
-        
-        VirtualKey vk = findVirtualKey(di);
-        if (vk != null) {
-            final InputDevice.MotionState ms = di.mAbs;
-            mPressedVirtualKey = vk;
-            vk.lastKeycode = scancodeToKeycode(di.id, vk.scancode);
-            ms.mLastNumPointers = ms.mNextNumPointers;
-            di.mKeyDownTime = curTime;
-            if (DEBUG_VIRTUAL_KEYS) Slog.v(TAG,
-                    "Generate key down for: " + vk.scancode
-                    + " (keycode=" + vk.lastKeycode + ")");
-            KeyEvent event = newKeyEvent(di, di.mKeyDownTime, curTime, true,
-                    vk.lastKeycode, 0, vk.scancode,
-                    KeyEvent.FLAG_VIRTUAL_HARD_KEY);
-            mHapticFeedbackCallback.virtualKeyFeedback(event);
-            addLocked(di, curTimeNano, ev.flags, RawInputEvent.CLASS_KEYBOARD,
-                    event);
-        }
-        
-        // We always consume the event, even if we didn't
-        // generate a key event.  There are two reasons for
-        // this: to avoid spurious touches when holding
-        // the edges of the device near the touchscreen,
-        // and to avoid reporting events if there are virtual
-        // keys on the touchscreen outside of the display
-        // area.
-        // Note that for all of this we are only looking at the
-        // first pointer, since what we are handling here is the
-        // first pointer going down, and this is the coordinate
-        // that will be used to dispatch the event.
-        if (false) {
-            final InputDevice.AbsoluteInfo absx = di.absX;
-            final InputDevice.AbsoluteInfo absy = di.absY;
-            final InputDevice.MotionState absm = di.mAbs;
-            Slog.v(TAG, "Rejecting ("
-                + absm.mNextData[MotionEvent.SAMPLE_X] + ","
-                + absm.mNextData[MotionEvent.SAMPLE_Y] + "): outside of ("
-                + absx.minValue + "," + absy.minValue
-                + ")-(" + absx.maxValue + ","
-                + absx.maxValue + ")");
-        }
-        return true;
-    }
-    
-    private boolean monitorVirtualKey(InputDevice di, RawInputEvent ev,
-            long curTime, long curTimeNano) {
-        VirtualKey vk = mPressedVirtualKey;
-        if (vk == null) {
-            return false;
-        }
-        
-        final InputDevice.MotionState ms = di.mAbs;
-        if (ms.mNextNumPointers <= 0) {
-            mPressedVirtualKey = null;
-            ms.mLastNumPointers = 0;
-            if (DEBUG_VIRTUAL_KEYS) Slog.v(TAG, "Generate key up for: " + vk.scancode);
-            KeyEvent event = newKeyEvent(di, di.mKeyDownTime, curTime, false,
-                    vk.lastKeycode, 0, vk.scancode,
-                    KeyEvent.FLAG_VIRTUAL_HARD_KEY);
-            mHapticFeedbackCallback.virtualKeyFeedback(event);
-            addLocked(di, curTimeNano, ev.flags, RawInputEvent.CLASS_KEYBOARD,
-                    event);
-            return true;
-            
-        } else if (isInsideDisplay(di)) {
-            // Whoops the pointer has moved into
-            // the display area!  Cancel the
-            // virtual key and start a pointer
-            // motion.
-            mPressedVirtualKey = null;
-            if (DEBUG_VIRTUAL_KEYS) Slog.v(TAG, "Cancel key up for: " + vk.scancode);
-            KeyEvent event = newKeyEvent(di, di.mKeyDownTime, curTime, false,
-                    vk.lastKeycode, 0, vk.scancode,
-                    KeyEvent.FLAG_CANCELED | KeyEvent.FLAG_VIRTUAL_HARD_KEY);
-            mHapticFeedbackCallback.virtualKeyFeedback(event);
-            addLocked(di, curTimeNano, ev.flags, RawInputEvent.CLASS_KEYBOARD,
-                    event);
-            ms.mLastNumPointers = 0;
-            return false;
-        }
-        
-        return true;
-    }
-    
-    /**
-     * Returns a new meta state for the given keys and old state.
-     */
-    private static final int makeMetaState(int keycode, boolean down, int old) {
-        int mask;
-        switch (keycode) {
-        case KeyEvent.KEYCODE_ALT_LEFT:
-            mask = KeyEvent.META_ALT_LEFT_ON;
-            break;
-        case KeyEvent.KEYCODE_ALT_RIGHT:
-            mask = KeyEvent.META_ALT_RIGHT_ON;
-            break;
-        case KeyEvent.KEYCODE_SHIFT_LEFT:
-            mask = KeyEvent.META_SHIFT_LEFT_ON;
-            break;
-        case KeyEvent.KEYCODE_SHIFT_RIGHT:
-            mask = KeyEvent.META_SHIFT_RIGHT_ON;
-            break;
-        case KeyEvent.KEYCODE_SYM:
-            mask = KeyEvent.META_SYM_ON;
-            break;
-        default:
-            return old;
-        }
-        int result = ~(KeyEvent.META_ALT_ON | KeyEvent.META_SHIFT_ON)
-                    & (down ? (old | mask) : (old & ~mask));
-        if (0 != (result & (KeyEvent.META_ALT_LEFT_ON | KeyEvent.META_ALT_RIGHT_ON))) {
-            result |= KeyEvent.META_ALT_ON;
-        }
-        if (0 != (result & (KeyEvent.META_SHIFT_LEFT_ON | KeyEvent.META_SHIFT_RIGHT_ON))) {
-            result |= KeyEvent.META_SHIFT_ON;
-        }
-        return result;
-    }
-
-    private void computeGlobalMetaStateLocked() {
-        int i = mDevices.size();
-        mGlobalMetaState = 0;
-        while ((--i) >= 0) {
-            mGlobalMetaState |= mDevices.valueAt(i).mMetaKeysState;
-        }
-        mHaveGlobalMetaState = true;
-    }
-    
-    /*
-     * Return true if you want the event to get passed on to the 
-     * rest of the system, and false if you've handled it and want
-     * it dropped.
-     */
-    abstract boolean preprocessEvent(InputDevice device, RawInputEvent event);
-
-    InputDevice getInputDevice(int deviceId) {
-        synchronized (mFirst) {
-            return getInputDeviceLocked(deviceId);
-        }
-    }
-    
-    private InputDevice getInputDeviceLocked(int deviceId) {
-        return mDevices.get(deviceId);
-    }
-
-    public void setOrientation(int orientation) {
-        synchronized(mFirst) {
-            mOrientation = orientation;
-            switch (orientation) {
-                case Surface.ROTATION_90:
-                    mKeyRotationMap = KEY_90_MAP;
-                    break;
-                case Surface.ROTATION_180:
-                    mKeyRotationMap = KEY_180_MAP;
-                    break;
-                case Surface.ROTATION_270:
-                    mKeyRotationMap = KEY_270_MAP;
-                    break;
-                default:
-                    mKeyRotationMap = null;
-                    break;
-            }
-        }
-    }
-    
-    public int rotateKeyCode(int keyCode) {
-        synchronized(mFirst) {
-            return rotateKeyCodeLocked(keyCode);
-        }
-    }
-    
-    private int rotateKeyCodeLocked(int keyCode) {
-        int[] map = mKeyRotationMap;
-        if (map != null) {
-            final int N = map.length;
-            for (int i=0; i<N; i+=2) {
-                if (map[i] == keyCode) {
-                    return map[i+1];
-                }
-            }
-        }
-        return keyCode;
-    }
-    
-    boolean hasEvents() {
-        synchronized (mFirst) {
-            return mFirst.next != mLast;
-        }
-    }
-    
-    /*
-     * returns true if we returned an event, and false if we timed out
-     */
-    QueuedEvent getEvent(long timeoutMS) {
-        long begin = SystemClock.uptimeMillis();
-        final long end = begin+timeoutMS;
-        long now = begin;
-        synchronized (mFirst) {
-            while (mFirst.next == mLast && end > now) {
-                try {
-                    mWakeLock.release();
-                    mFirst.wait(end-now);
-                }
-                catch (InterruptedException e) {
-                }
-                now = SystemClock.uptimeMillis();
-                if (begin > now) {
-                    begin = now;
-                }
-            }
-            if (mFirst.next == mLast) {
-                return null;
-            }
-            QueuedEvent p = mFirst.next;
-            mFirst.next = p.next;
-            mFirst.next.prev = mFirst;
-            p.inQueue = false;
-            return p;
-        }
-    }
-
-    /**
-     * Return true if the queue has an up event pending that corresponds
-     * to the same key as the given key event.
-     */
-    boolean hasKeyUpEvent(KeyEvent origEvent) {
-        synchronized (mFirst) {
-            final int keyCode = origEvent.getKeyCode();
-            QueuedEvent cur = mLast.prev;
-            while (cur.prev != null) {
-                if (cur.classType == RawInputEvent.CLASS_KEYBOARD) {
-                    KeyEvent ke = (KeyEvent)cur.event;
-                    if (ke.getAction() == KeyEvent.ACTION_UP
-                            && ke.getKeyCode() == keyCode) {
-                        return true;
-                    }
-                }
-                cur = cur.prev;
-            }
-        }
-        
-        return false;
-    }
-    
-    void recycleEvent(QueuedEvent ev) {
-        synchronized (mFirst) {
-            //Slog.i(TAG, "Recycle event: " + ev);
-            if (ev.event == ev.inputDevice.mAbs.currentMove) {
-                ev.inputDevice.mAbs.currentMove = null;
-            }
-            if (ev.event == ev.inputDevice.mRel.currentMove) {
-                if (false) Slog.i(TAG, "Detach rel " + ev.event);
-                ev.inputDevice.mRel.currentMove = null;
-                ev.inputDevice.mRel.mNextData[MotionEvent.SAMPLE_X] = 0;
-                ev.inputDevice.mRel.mNextData[MotionEvent.SAMPLE_Y] = 0;
-            }
-            recycleLocked(ev);
-        }
-    }
-    
-    void filterQueue(FilterCallback cb) {
-        synchronized (mFirst) {
-            QueuedEvent cur = mLast.prev;
-            while (cur.prev != null) {
-                switch (cb.filterEvent(cur)) {
-                    case FILTER_REMOVE:
-                        cur.prev.next = cur.next;
-                        cur.next.prev = cur.prev;
-                        break;
-                    case FILTER_ABORT:
-                        return;
-                }
-                cur = cur.prev;
-            }
-        }
-    }
-    
-    private QueuedEvent obtainLocked(InputDevice device, long whenNano,
-            int flags, int classType, Object event) {
-        QueuedEvent ev;
-        if (mCacheCount == 0) {
-            ev = new QueuedEvent();
-        } else {
-            ev = mCache;
-            ev.inQueue = false;
-            mCache = ev.next;
-            mCacheCount--;
-        }
-        ev.inputDevice = device;
-        ev.whenNano = whenNano;
-        ev.flags = flags;
-        ev.classType = classType;
-        ev.event = event;
-        return ev;
-    }
-
-    private void recycleLocked(QueuedEvent ev) {
-        if (ev.inQueue) {
-            throw new RuntimeException("Event already in queue!");
-        }
-        if (mCacheCount < 10) {
-            mCacheCount++;
-            ev.next = mCache;
-            mCache = ev;
-            ev.inQueue = true;
-        }
-    }
-
-    private void addLocked(InputDevice device, long whenNano, int flags,
-            int classType, Object event) {
-        boolean poke = mFirst.next == mLast;
-
-        QueuedEvent ev = obtainLocked(device, whenNano, flags, classType, event);
-        QueuedEvent p = mLast.prev;
-        while (p != mFirst && ev.whenNano < p.whenNano) {
-            p = p.prev;
-        }
-
-        ev.next = p.next;
-        ev.prev = p;
-        p.next = ev;
-        ev.next.prev = ev;
-        ev.inQueue = true;
-
-        if (poke) {
-            long time;
-            if (MEASURE_LATENCY) {
-                time = System.nanoTime();
-            }
-            mFirst.notify();
-            mWakeLock.acquire();
-            if (MEASURE_LATENCY) {
-                lt.sample("1 addLocked-queued event ", System.nanoTime() - time);
-            }
-        }
-    }
-
-    private InputDevice newInputDevice(int deviceId) {
-        int classes = getDeviceClasses(deviceId);
-        String name = getDeviceName(deviceId);
-        InputDevice.AbsoluteInfo absX = null;
-        InputDevice.AbsoluteInfo absY = null;
-        InputDevice.AbsoluteInfo absPressure = null;
-        InputDevice.AbsoluteInfo absSize = null;
-        if (classes != 0) {
-            Slog.i(TAG, "Device added: id=0x" + Integer.toHexString(deviceId)
-                    + ", name=" + name
-                    + ", classes=" + Integer.toHexString(classes));
-            if ((classes&RawInputEvent.CLASS_TOUCHSCREEN_MT) != 0) {
-                absX = loadAbsoluteInfo(deviceId,
-                        RawInputEvent.ABS_MT_POSITION_X, "X");
-                absY = loadAbsoluteInfo(deviceId,
-                        RawInputEvent.ABS_MT_POSITION_Y, "Y");
-                absPressure = loadAbsoluteInfo(deviceId,
-                        RawInputEvent.ABS_MT_TOUCH_MAJOR, "Pressure");
-                absSize = loadAbsoluteInfo(deviceId,
-                        RawInputEvent.ABS_MT_WIDTH_MAJOR, "Size");
-            } else if ((classes&RawInputEvent.CLASS_TOUCHSCREEN) != 0) {
-                absX = loadAbsoluteInfo(deviceId,
-                        RawInputEvent.ABS_X, "X");
-                absY = loadAbsoluteInfo(deviceId,
-                        RawInputEvent.ABS_Y, "Y");
-                absPressure = loadAbsoluteInfo(deviceId,
-                        RawInputEvent.ABS_PRESSURE, "Pressure");
-                absSize = loadAbsoluteInfo(deviceId,
-                        RawInputEvent.ABS_TOOL_WIDTH, "Size");
-            }
-        }
-        
-        return new InputDevice(deviceId, classes, name, absX, absY, absPressure, absSize);
-    }
-    
-    private InputDevice.AbsoluteInfo loadAbsoluteInfo(int id, int channel,
-            String name) {
-        InputDevice.AbsoluteInfo info = new InputDevice.AbsoluteInfo();
-        if (getAbsoluteInfo(id, channel, info)
-                && info.minValue != info.maxValue) {
-            Slog.i(TAG, "  " + name + ": min=" + info.minValue
-                    + " max=" + info.maxValue
-                    + " flat=" + info.flat
-                    + " fuzz=" + info.fuzz);
-            info.range = info.maxValue-info.minValue;
-            return info;
-        }
-        Slog.i(TAG, "  " + name + ": unknown values");
-        return null;
-    }
-    private static native boolean readEvent(RawInputEvent outEvent);
-    
-    void dump(PrintWriter pw, String prefix) {
-        synchronized (mFirst) {
-            for (int i=0; i<mDevices.size(); i++) {
-                InputDevice dev = mDevices.valueAt(i);
-                pw.print(prefix); pw.print("Device #");
-                        pw.print(mDevices.keyAt(i)); pw.print(" ");
-                        pw.print(dev.name); pw.print(" (classes=0x");
-                        pw.print(Integer.toHexString(dev.classes));
-                        pw.println("):");
-                pw.print(prefix); pw.print("  mKeyDownTime=");
-                        pw.print(dev.mKeyDownTime); pw.print(" mMetaKeysState=");
-                        pw.println(dev.mMetaKeysState);
-                if (dev.absX != null) {
-                    pw.print(prefix); pw.print("  absX: "); dev.absX.dump(pw);
-                            pw.println("");
-                }
-                if (dev.absY != null) {
-                    pw.print(prefix); pw.print("  absY: "); dev.absY.dump(pw);
-                            pw.println("");
-                }
-                if (dev.absPressure != null) {
-                    pw.print(prefix); pw.print("  absPressure: ");
-                            dev.absPressure.dump(pw); pw.println("");
-                }
-                if (dev.absSize != null) {
-                    pw.print(prefix); pw.print("  absSize: ");
-                            dev.absSize.dump(pw); pw.println("");
-                }
-                if (dev.mAbs.everChanged) {
-                    pw.print(prefix); pw.println("  mAbs:");
-                    dev.mAbs.dump(pw, prefix + "    ");
-                }
-                if (dev.mRel.everChanged) {
-                    pw.print(prefix); pw.println("  mRel:");
-                    dev.mRel.dump(pw, prefix + "    ");
-                }
-            }
-            pw.println(" ");
-            for (int i=0; i<mIgnoredDevices.size(); i++) {
-                InputDevice dev = mIgnoredDevices.valueAt(i);
-                pw.print(prefix); pw.print("Ignored Device #");
-                        pw.print(mIgnoredDevices.keyAt(i)); pw.print(" ");
-                        pw.print(dev.name); pw.print(" (classes=0x");
-                        pw.print(Integer.toHexString(dev.classes));
-                        pw.println(")");
-            }
-            pw.println(" ");
-            for (int i=0; i<mVirtualKeys.size(); i++) {
-                VirtualKey vk = mVirtualKeys.get(i);
-                pw.print(prefix); pw.print("Virtual Key #");
-                        pw.print(i); pw.println(":");
-                pw.print(prefix); pw.print("  scancode="); pw.println(vk.scancode);
-                pw.print(prefix); pw.print("  centerx="); pw.print(vk.centerx);
-                        pw.print(" centery="); pw.print(vk.centery);
-                        pw.print(" width="); pw.print(vk.width);
-                        pw.print(" height="); pw.println(vk.height);
-                pw.print(prefix); pw.print("  hitLeft="); pw.print(vk.hitLeft);
-                        pw.print(" hitTop="); pw.print(vk.hitTop);
-                        pw.print(" hitRight="); pw.print(vk.hitRight);
-                        pw.print(" hitBottom="); pw.println(vk.hitBottom);
-                if (vk.lastDevice != null) {
-                    pw.print(prefix); pw.print("  lastDevice=#");
-                            pw.println(vk.lastDevice.id);
-                }
-                if (vk.lastKeycode != 0) {
-                    pw.print(prefix); pw.print("  lastKeycode=");
-                            pw.println(vk.lastKeycode);
-                }
-            }
-            pw.println(" ");
-            pw.print(prefix); pw.print("  Default keyboard: ");
-                    pw.println(SystemProperties.get("hw.keyboards.0.devname"));
-            pw.print(prefix); pw.print("  mGlobalMetaState=");
-                    pw.print(mGlobalMetaState); pw.print(" mHaveGlobalMetaState=");
-                    pw.println(mHaveGlobalMetaState);
-            pw.print(prefix); pw.print("  mDisplayWidth=");
-                    pw.print(mDisplayWidth); pw.print(" mDisplayHeight=");
-                    pw.println(mDisplayHeight);
-            pw.print(prefix); pw.print("  mOrientation=");
-                    pw.println(mOrientation);
-            if (mPressedVirtualKey != null) {
-                pw.print(prefix); pw.print("  mPressedVirtualKey.scancode=");
-                        pw.println(mPressedVirtualKey.scancode);
-            }
-        }
-    }
-}
diff --git a/services/java/com/android/server/PackageManagerService.java b/services/java/com/android/server/PackageManagerService.java
index 1fd053f..af2145e 100644
--- a/services/java/com/android/server/PackageManagerService.java
+++ b/services/java/com/android/server/PackageManagerService.java
@@ -4583,6 +4583,8 @@
         }
     };
 
+    private static final boolean DEBUG_OBB = false;
+
     private static final void sendPackageBroadcast(String action, String pkg,
             Bundle extras, IIntentReceiver finishedReceiver) {
         IActivityManager am = ActivityManagerNative.getDefault();
@@ -4757,6 +4759,29 @@
         mHandler.sendMessage(msg);
     }
 
+    public void setPackageObbPath(String packageName, String path) {
+        if (DEBUG_OBB)
+            Log.v(TAG, "Setting .obb path for " + packageName + " to: " + path);
+        PackageSetting pkgSetting;
+        final int uid = Binder.getCallingUid();
+        final int permission = mContext.checkCallingPermission(
+                android.Manifest.permission.INSTALL_PACKAGES);
+        final boolean allowedByPermission = (permission == PackageManager.PERMISSION_GRANTED);
+        synchronized (mPackages) {
+            pkgSetting = mSettings.mPackages.get(packageName);
+            if (pkgSetting == null) {
+                throw new IllegalArgumentException("Unknown package: " + packageName);
+            }
+            if (!allowedByPermission && (uid != pkgSetting.userId)) {
+                throw new SecurityException("Permission denial: attempt to set .obb file from pid="
+                        + Binder.getCallingPid() + ", uid=" + uid + ", package uid="
+                        + pkgSetting.userId);
+            }
+            pkgSetting.obbPathString = path;
+            mSettings.writeLP();
+        }
+    }
+
     private void processPendingInstall(final InstallArgs args, final int currentStatus) {
         // Queue up an async operation since the package installation may take a little while.
         mHandler.post(new Runnable() {
@@ -7118,6 +7143,7 @@
                     pw.print("    pkg="); pw.println(ps.pkg);
                     pw.print("    codePath="); pw.println(ps.codePathString);
                     pw.print("    resourcePath="); pw.println(ps.resourcePathString);
+                    pw.print("    obbPath="); pw.println(ps.obbPathString);
                     if (ps.pkg != null) {
                         pw.print("    dataDir="); pw.println(ps.pkg.applicationInfo.dataDir);
                         pw.print("    targetSdk="); pw.println(ps.pkg.applicationInfo.targetSdkVersion);
@@ -7684,6 +7710,7 @@
         String codePathString;
         File resourcePath;
         String resourcePathString;
+        String obbPathString;
         private long timeStamp;
         private String timeStampString = "0";
         int versionCode;
@@ -8684,6 +8711,9 @@
             if (pkg.installerPackageName != null) {
                 serializer.attribute(null, "installer", pkg.installerPackageName);
             }
+            if (pkg.obbPathString != null) {
+                serializer.attribute(null, "obbPath", pkg.obbPathString);
+            }
             pkg.signatures.writeXml(serializer, "sigs", mPastSignatures);
             if ((pkg.pkgFlags&ApplicationInfo.FLAG_SYSTEM) == 0) {
                 serializer.startTag(null, "perms");
@@ -9060,6 +9090,7 @@
             String sharedIdStr = null;
             String codePathStr = null;
             String resourcePathStr = null;
+            String obbPathStr = null;
             String systemStr = null;
             String installerPackageName = null;
             String uidError = null;
@@ -9077,6 +9108,7 @@
                 sharedIdStr = parser.getAttributeValue(null, "sharedUserId");
                 codePathStr = parser.getAttributeValue(null, "codePath");
                 resourcePathStr = parser.getAttributeValue(null, "resourcePath");
+                obbPathStr = parser.getAttributeValue(null, "obbPath");
                 version = parser.getAttributeValue(null, "version");
                 if (version != null) {
                     try {
@@ -9174,6 +9206,7 @@
             if (packageSetting != null) {
                 packageSetting.uidError = "true".equals(uidError);
                 packageSetting.installerPackageName = installerPackageName;
+                packageSetting.obbPathString = obbPathStr;
                 final String enabledStr = parser.getAttributeValue(null, "enabled");
                 if (enabledStr != null) {
                     if (enabledStr.equalsIgnoreCase("true")) {
diff --git a/services/java/com/android/server/PowerManagerService.java b/services/java/com/android/server/PowerManagerService.java
index 493a348..e9d5efc 100644
--- a/services/java/com/android/server/PowerManagerService.java
+++ b/services/java/com/android/server/PowerManagerService.java
@@ -247,6 +247,9 @@
     private static final boolean mSpew = false;
     private static final boolean mDebugProximitySensor = (true || mSpew);
     private static final boolean mDebugLightSensor = (false || mSpew);
+    
+    private native void nativeInit();
+    private native void nativeSetPowerState(boolean screenOn, boolean screenBright);
 
     /*
     static PrintStream mLog;
@@ -481,6 +484,11 @@
                 }
             }
         }
+        
+        nativeInit();
+        synchronized (mLocks) {
+            updateNativePowerStateLocked();
+        }
     }
 
     void initInThread() {
@@ -1557,8 +1565,16 @@
                     }
                 }
             }
+            
+            updateNativePowerStateLocked();
         }
     }
+    
+    private void updateNativePowerStateLocked() {
+        nativeSetPowerState(
+                (mPowerState & SCREEN_ON_BIT) != 0,
+                (mPowerState & SCREEN_BRIGHT) == SCREEN_BRIGHT);
+    }
 
     private int screenOffFinishedAnimatingLocked(int reason) {
         // I don't think we need to check the current state here because all of these
diff --git a/services/java/com/android/server/TelephonyRegistry.java b/services/java/com/android/server/TelephonyRegistry.java
index b1ca7852..73234df 100644
--- a/services/java/com/android/server/TelephonyRegistry.java
+++ b/services/java/com/android/server/TelephonyRegistry.java
@@ -19,6 +19,7 @@
 import android.content.Context;
 import android.content.Intent;
 import android.content.pm.PackageManager;
+import android.net.NetworkProperties;
 import android.os.Binder;
 import android.os.Bundle;
 import android.os.IBinder;
@@ -34,6 +35,7 @@
 import java.util.ArrayList;
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
+import java.net.NetworkInterface;
 
 import com.android.internal.app.IBatteryStats;
 import com.android.internal.telephony.ITelephonyRegistry;
@@ -90,7 +92,7 @@
 
     private ArrayList<String> mConnectedApns;
 
-    private String mDataConnectionInterfaceName = "";
+    private NetworkProperties mDataConnectionProperties;
 
     private Bundle mCellLocation = new Bundle();
 
@@ -353,7 +355,8 @@
     }
 
     public void notifyDataConnection(int state, boolean isDataConnectivityPossible,
-            String reason, String apn, String apnType, String interfaceName, int networkType) {
+            String reason, String apn, String apnType, NetworkProperties networkProperties,
+            int networkType) {
         if (!checkNotifyPermission("notifyDataConnection()" )) {
             return;
         }
@@ -373,14 +376,14 @@
                     mDataConnectionState = state;
                     modified = true;
                 } else {
-                    // we're still connected, so send that out if we send anything.
-                    state = mDataConnectionState;
+                    // leave mDataConnectionState as is and
+                    // send out the new status for the APN in question.
                 }
             }
             mDataConnectionPossible = isDataConnectivityPossible;
             mDataConnectionReason = reason;
             mDataConnectionApn = apn;
-            mDataConnectionInterfaceName = interfaceName;
+            mDataConnectionProperties = networkProperties;
             if (mDataConnectionNetworkType != networkType) {
                 mDataConnectionNetworkType = networkType;
                 modified = true;
@@ -400,7 +403,7 @@
             }
         }
         broadcastDataConnectionStateChanged(state, isDataConnectivityPossible, reason, apn,
-                apnType, interfaceName);
+                apnType, networkProperties);
     }
 
     public void notifyDataConnectionFailed(String reason, String apnType) {
@@ -441,7 +444,7 @@
     /**
      * Copy the service state object so they can't mess it up in the local calls
      */
-    public void sendServiceState(Record r, ServiceState state) {
+    private void sendServiceState(Record r, ServiceState state) {
         try {
             r.callback.onServiceStateChanged(new ServiceState(state));
         } catch (RemoteException ex) {
@@ -487,7 +490,7 @@
             pw.println("  mDataConnectionPossible=" + mDataConnectionPossible);
             pw.println("  mDataConnectionReason=" + mDataConnectionReason);
             pw.println("  mDataConnectionApn=" + mDataConnectionApn);
-            pw.println("  mDataConnectionInterfaceName=" + mDataConnectionInterfaceName);
+            pw.println("  mDataConnectionProperties=" + mDataConnectionProperties);
             pw.println("  mCellLocation=" + mCellLocation);
             pw.println("registrations: count=" + recordCount);
             for (Record r : mRecords) {
@@ -561,7 +564,7 @@
 
     private void broadcastDataConnectionStateChanged(int state,
             boolean isDataConnectivityPossible,
-            String reason, String apn, String apnType, String interfaceName) {
+            String reason, String apn, String apnType, NetworkProperties networkProperties) {
         // Note: not reporting to the battery stats service here, because the
         // status bar takes care of that after taking into account all of the
         // required info.
@@ -574,9 +577,15 @@
         if (reason != null) {
             intent.putExtra(Phone.STATE_CHANGE_REASON_KEY, reason);
         }
+        if (networkProperties != null) {
+            intent.putExtra(Phone.DATA_NETWORK_PROPERTIES_KEY, networkProperties);
+            NetworkInterface iface = networkProperties.getInterface();
+            if (iface != null) {
+                intent.putExtra(Phone.DATA_IFACE_NAME_KEY, iface.getName());
+            }
+        }
         intent.putExtra(Phone.DATA_APN_KEY, apn);
         intent.putExtra(Phone.DATA_APN_TYPE_KEY, apnType);
-        intent.putExtra(Phone.DATA_IFACE_NAME_KEY, interfaceName);
         mContext.sendStickyBroadcast(intent);
     }
 
diff --git a/services/java/com/android/server/ViewServer.java b/services/java/com/android/server/ViewServer.java
index ae00438..b369f71 100644
--- a/services/java/com/android/server/ViewServer.java
+++ b/services/java/com/android/server/ViewServer.java
@@ -21,6 +21,8 @@
 import java.net.ServerSocket;
 import java.net.Socket;
 import java.net.InetAddress;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
 import java.io.IOException;
 import java.io.BufferedReader;
 import java.io.InputStreamReader;
@@ -41,11 +43,13 @@
      */
     public static final int VIEW_SERVER_DEFAULT_PORT = 4939;
 
+    private static final int VIEW_SERVER_MAX_CONNECTIONS = 10;
+
     // Debug facility
     private static final String LOG_TAG = "ViewServer";
 
-    private static final String VALUE_PROTOCOL_VERSION = "2";
-    private static final String VALUE_SERVER_VERSION = "3";
+    private static final String VALUE_PROTOCOL_VERSION = "3";
+    private static final String VALUE_SERVER_VERSION = "4";
 
     // Protocol commands
     // Returns the protocol version
@@ -54,6 +58,8 @@
     private static final String COMMAND_SERVER_VERSION = "SERVER";
     // Lists all of the available windows in the system
     private static final String COMMAND_WINDOW_MANAGER_LIST = "LIST";
+    // Keeps a connection open and notifies when the list of windows changes
+    private static final String COMMAND_WINDOW_MANAGER_AUTOLIST = "AUTOLIST";
 
     private ServerSocket mServer;
     private Thread mThread;
@@ -61,6 +67,8 @@
     private final WindowManagerService mWindowManager;
     private final int mPort;
 
+    private ExecutorService mThreadPool;
+
     /**
      * Creates a new ViewServer associated with the specified window manager.
      * The server uses the default port {@link #VIEW_SERVER_DEFAULT_PORT}. The server
@@ -103,8 +111,9 @@
             return false;
         }
 
-        mServer = new ServerSocket(mPort, 1, InetAddress.getLocalHost());
+        mServer = new ServerSocket(mPort, VIEW_SERVER_MAX_CONNECTIONS, InetAddress.getLocalHost());
         mThread = new Thread(this, "Remote View Server [port=" + mPort + "]");
+        mThreadPool = Executors.newFixedThreadPool(VIEW_SERVER_MAX_CONNECTIONS);
         mThread.start();
 
         return true;
@@ -122,7 +131,16 @@
      */
     boolean stop() {
         if (mThread != null) {
+
             mThread.interrupt();
+            if (mThreadPool != null) {
+                try {
+                    mThreadPool.shutdownNow();
+                } catch (SecurityException e) {
+                    Slog.w(LOG_TAG, "Could not stop all view server threads");
+                }
+            }
+            mThreadPool = null;
             mThread = null;
             try {
                 mServer.close();
@@ -152,62 +170,21 @@
      * Main server loop.
      */
     public void run() {
-        final ServerSocket server = mServer;
-
         while (Thread.currentThread() == mThread) {
-            Socket client = null;
             // Any uncaught exception will crash the system process
             try {
-                client = server.accept();
-
-                BufferedReader in = null;
-                try {
-                    in = new BufferedReader(new InputStreamReader(client.getInputStream()), 1024);
-
-                    final String request = in.readLine();
-
-                    String command;
-                    String parameters;
-
-                    int index = request.indexOf(' ');
-                    if (index == -1) {
-                        command = request;
-                        parameters = "";
-                    } else {
-                        command = request.substring(0, index);
-                        parameters = request.substring(index + 1);
-                    }
-
-                    boolean result;
-                    if (COMMAND_PROTOCOL_VERSION.equalsIgnoreCase(command)) {
-                        result = writeValue(client, VALUE_PROTOCOL_VERSION);
-                    } else if (COMMAND_SERVER_VERSION.equalsIgnoreCase(command)) {
-                        result = writeValue(client, VALUE_SERVER_VERSION);
-                    } else if (COMMAND_WINDOW_MANAGER_LIST.equalsIgnoreCase(command)) {
-                        result = mWindowManager.viewServerListWindows(client);
-                    } else {
-                        result = mWindowManager.viewServerWindowCommand(client,
-                                command, parameters);
-                    }
-
-                    if (!result) {
-                        Slog.w(LOG_TAG, "An error occured with the command: " + command);
-                    }
-                } finally {
-                    if (in != null) {
-                        in.close();
-                    }
-                }
-            } catch (Exception e) {
-                Slog.w(LOG_TAG, "Connection error: ", e);
-            } finally {
-                if (client != null) {
+                Socket client = mServer.accept();
+                if(mThreadPool != null) {
+                    mThreadPool.submit(new ViewServerWorker(client));
+                } else {
                     try {
                         client.close();
                     } catch (IOException e) {
                         e.printStackTrace();
                     }
                 }
+            } catch (Exception e) {
+                Slog.w(LOG_TAG, "Connection error: ", e);
             }
         }
     }
@@ -235,4 +212,131 @@
         }
         return result;
     }
+
+    class ViewServerWorker implements Runnable, WindowManagerService.WindowChangeListener {
+        private Socket mClient;
+        private boolean mNeedWindowListUpdate;
+        private boolean mNeedFocusedWindowUpdate;
+        public ViewServerWorker(Socket client) {
+            mClient = client;
+            mNeedWindowListUpdate = false;
+            mNeedFocusedWindowUpdate = false;
+        }
+
+        public void run() {
+
+            BufferedReader in = null;
+            try {
+                in = new BufferedReader(new InputStreamReader(mClient.getInputStream()), 1024);
+
+                final String request = in.readLine();
+
+                String command;
+                String parameters;
+
+                int index = request.indexOf(' ');
+                if (index == -1) {
+                    command = request;
+                    parameters = "";
+                } else {
+                    command = request.substring(0, index);
+                    parameters = request.substring(index + 1);
+                }
+
+                boolean result;
+                if (COMMAND_PROTOCOL_VERSION.equalsIgnoreCase(command)) {
+                    result = writeValue(mClient, VALUE_PROTOCOL_VERSION);
+                } else if (COMMAND_SERVER_VERSION.equalsIgnoreCase(command)) {
+                    result = writeValue(mClient, VALUE_SERVER_VERSION);
+                } else if (COMMAND_WINDOW_MANAGER_LIST.equalsIgnoreCase(command)) {
+                    result = mWindowManager.viewServerListWindows(mClient);
+                } else if(COMMAND_WINDOW_MANAGER_AUTOLIST.equalsIgnoreCase(command)) {
+                    result = windowManagerAutolistLoop();
+                } else {
+                    result = mWindowManager.viewServerWindowCommand(mClient,
+                            command, parameters);
+                }
+
+                if (!result) {
+                    Slog.w(LOG_TAG, "An error occured with the command: " + command);
+                }
+            } catch(IOException e) {
+                Slog.w(LOG_TAG, "Connection error: ", e);
+            } finally {
+                if (in != null) {
+                    try {
+                        in.close();
+
+                    } catch (IOException e) {
+                        e.printStackTrace();
+                    }
+                }
+                if (mClient != null) {
+                    try {
+                        mClient.close();
+                    } catch (IOException e) {
+                        e.printStackTrace();
+                    }
+                }
+            }
+        }
+
+        public void windowsChanged() {
+            synchronized(this) {
+                mNeedWindowListUpdate = true;
+                notifyAll();
+            }
+        }
+
+        public void focusChanged() {
+            synchronized(this) {
+                mNeedFocusedWindowUpdate = true;
+                notifyAll();
+            }
+        }
+
+        private boolean windowManagerAutolistLoop() {
+            mWindowManager.addWindowChangeListener(this);
+            BufferedWriter out = null;
+            try {
+                out = new BufferedWriter(new OutputStreamWriter(mClient.getOutputStream()));
+                while (!Thread.interrupted()) {
+                    boolean needWindowListUpdate = false;
+                    boolean needFocusedWindowUpdate = false;
+                    synchronized (this) {
+                        while (!mNeedWindowListUpdate && !mNeedFocusedWindowUpdate) {
+                            wait();
+                        }
+                        if (mNeedWindowListUpdate) {
+                            mNeedWindowListUpdate = false;
+                            needWindowListUpdate = true;
+                        }
+                        if (mNeedFocusedWindowUpdate) {
+                            mNeedFocusedWindowUpdate = false;
+                            needFocusedWindowUpdate = true;
+                        }
+                    }
+                    if(needWindowListUpdate) {
+                        out.write("LIST UPDATE\n");
+                        out.flush();
+                    }
+                    if(needFocusedWindowUpdate) {
+                        out.write("FOCUS UPDATE\n");
+                        out.flush();
+                    }
+                }
+            } catch (Exception e) {
+                Slog.w(LOG_TAG, "Connection error: ", e);
+            } finally {
+                if (out != null) {
+                    try {
+                        out.close();
+                    } catch (IOException e) {
+                    }
+                }
+                mWindowManager.removeWindowChangeListener(this);
+            }
+            return true;
+        }
+    }
 }
diff --git a/services/java/com/android/server/WindowManagerService.java b/services/java/com/android/server/WindowManagerService.java
index 580eea4..3475b2fc 100644
--- a/services/java/com/android/server/WindowManagerService.java
+++ b/services/java/com/android/server/WindowManagerService.java
@@ -48,7 +48,6 @@
 import com.android.internal.view.IInputMethodClient;
 import com.android.internal.view.IInputMethodManager;
 import com.android.internal.view.WindowManagerPolicyThread;
-import com.android.server.KeyInputQueue.QueuedEvent;
 import com.android.server.am.BatteryStatsService;
 
 import android.Manifest;
@@ -95,6 +94,7 @@
 import android.util.SparseIntArray;
 import android.view.Display;
 import android.view.Gravity;
+import android.view.HapticFeedbackConstants;
 import android.view.IApplicationToken;
 import android.view.IOnKeyguardExitResult;
 import android.view.IRotationWatcher;
@@ -105,7 +105,6 @@
 import android.view.InputQueue;
 import android.view.KeyEvent;
 import android.view.MotionEvent;
-import android.view.RawInputEvent;
 import android.view.Surface;
 import android.view.SurfaceSession;
 import android.view.View;
@@ -137,7 +136,7 @@
 
 /** {@hide} */
 public class WindowManagerService extends IWindowManager.Stub
-        implements Watchdog.Monitor, KeyInputQueue.HapticFeedbackCallback {
+        implements Watchdog.Monitor {
     static final String TAG = "WindowManager";
     static final boolean DEBUG = false;
     static final boolean DEBUG_FOCUS = false;
@@ -158,17 +157,12 @@
     static final boolean SHOW_TRANSACTIONS = false;
     static final boolean HIDE_STACK_CRAWLS = true;
     static final boolean MEASURE_LATENCY = false;
-    static final boolean ENABLE_NATIVE_INPUT_DISPATCH =
-        WindowManagerPolicy.ENABLE_NATIVE_INPUT_DISPATCH;
     static private LatencyTimer lt;
 
     static final boolean PROFILE_ORIENTATION = false;
     static final boolean BLUR = true;
     static final boolean localLOGV = DEBUG;
 
-    /** How long to wait for subsequent key repeats, in milliseconds */
-    static final int KEY_REPEAT_DELAY = 50;
-
     /** How much to multiply the policy's type layer, to reserve room
      * for multiple windows of the same type and Z-ordering adjustment
      * with TYPE_LAYER_OFFSET. */
@@ -209,34 +203,11 @@
     // Default input dispatching timeout in nanoseconds.
     private static final long DEFAULT_INPUT_DISPATCHING_TIMEOUT_NANOS = 5000 * 1000000L;
 
-    static final int INJECT_FAILED = 0;
-    static final int INJECT_SUCCEEDED = 1;
-    static final int INJECT_NO_PERMISSION = -1;
-
     static final int UPDATE_FOCUS_NORMAL = 0;
     static final int UPDATE_FOCUS_WILL_ASSIGN_LAYERS = 1;
     static final int UPDATE_FOCUS_PLACING_SURFACES = 2;
     static final int UPDATE_FOCUS_WILL_PLACE_SURFACES = 3;
 
-    /** The minimum time between dispatching touch events. */
-    int mMinWaitTimeBetweenTouchEvents = 1000 / 35;
-
-    // Last touch event time
-    long mLastTouchEventTime = 0;
-
-    // Last touch event type
-    int mLastTouchEventType = OTHER_EVENT;
-
-    // Time to wait before calling useractivity again. This saves CPU usage
-    // when we get a flood of touch events.
-    static final int MIN_TIME_BETWEEN_USERACTIVITIES = 1000;
-
-    // Last time we call user activity
-    long mLastUserActivityCallTime = 0;
-
-    // Last time we updated battery stats
-    long mLastBatteryStatsCallTime = 0;
-
     private static final String SYSTEM_SECURE = "ro.secure";
     private static final String SYSTEM_DEBUGGABLE = "ro.debuggable";
 
@@ -485,7 +456,6 @@
     float mLastWallpaperY = -1;
     float mLastWallpaperXStep = -1;
     float mLastWallpaperYStep = -1;
-    boolean mSendingPointersToWallpaper = false;
     // This is set when we are waiting for a wallpaper to tell us it is done
     // changing its scroll position.
     WindowState mWaitingOnWallpaper;
@@ -503,10 +473,7 @@
     float mWindowAnimationScale = 1.0f;
     float mTransitionAnimationScale = 1.0f;
 
-    final KeyWaiter mKeyWaiter = new KeyWaiter();
-    final KeyQ mQueue;
     final InputManager mInputManager;
-    final InputDispatcherThread mInputThread;
 
     // Who is holding the screen on.
     Session mHoldingScreenOn;
@@ -521,8 +488,14 @@
     boolean mInTouchMode = false;
 
     private ViewServer mViewServer;
+    private ArrayList<WindowChangeListener> mWindowChangeListeners =
+        new ArrayList<WindowChangeListener>();
+    private boolean mWindowsChanged = false;
 
-    final Rect mTempRect = new Rect();
+    public interface WindowChangeListener {
+        public void windowsChanged();
+        public void focusChanged();
+    }
 
     final Configuration mTempConfiguration = new Configuration();
     int mScreenLayout = Configuration.SCREENLAYOUT_SIZE_UNDEFINED;
@@ -651,28 +624,11 @@
         filter.addAction(DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED);
         mContext.registerReceiver(mBroadcastReceiver, filter);
 
-        int max_events_per_sec = 35;
-        try {
-            max_events_per_sec = Integer.parseInt(SystemProperties
-                    .get("windowsmgr.max_events_per_sec"));
-            if (max_events_per_sec < 1) {
-                max_events_per_sec = 35;
-            }
-        } catch (NumberFormatException e) {
-        }
-        mMinWaitTimeBetweenTouchEvents = 1000 / max_events_per_sec;
-
         mHoldingScreenWakeLock = pmc.newWakeLock(PowerManager.SCREEN_BRIGHT_WAKE_LOCK,
                 "KEEP_SCREEN_ON_FLAG");
         mHoldingScreenWakeLock.setReferenceCounted(false);
 
-        if (ENABLE_NATIVE_INPUT_DISPATCH) {
-            mInputManager = new InputManager(context, this, mPolicy, pmc, mPowerManager);
-        } else {
-            mInputManager = null;
-        }
-        mQueue = new KeyQ();
-        mInputThread = new InputDispatcherThread();
+        mInputManager = new InputManager(context, this, pmc, mPowerManager);
 
         PolicyThread thr = new PolicyThread(mPolicy, this, context, pm);
         thr.start();
@@ -686,11 +642,7 @@
             }
         }
 
-        if (ENABLE_NATIVE_INPUT_DISPATCH) {
-            mInputManager.start();
-        } else {
-            mInputThread.start();
-        }
+        mInputManager.start();
 
         // Add ourself to the Watchdog monitors.
         Watchdog.getInstance().addMonitor(this);
@@ -717,6 +669,7 @@
             TAG, "Adding window " + window + " at "
             + (i+1) + " of " + mWindows.size() + " (after " + pos + ")");
         mWindows.add(i+1, window);
+        mWindowsChanged = true;
     }
 
     private void placeWindowBefore(Object pos, WindowState window) {
@@ -725,6 +678,7 @@
             TAG, "Adding window " + window + " at "
             + i + " of " + mWindows.size() + " (before " + pos + ")");
         mWindows.add(i, window);
+        mWindowsChanged = true;
     }
 
     //This method finds out the index of a window that has the same app token as
@@ -782,6 +736,7 @@
                                         TAG, "Adding window " + win + " at "
                                         + (newIdx+1) + " of " + N);
                                 localmWindows.add(newIdx+1, win);
+                                mWindowsChanged = true;
                             }
                         }
                     }
@@ -864,6 +819,7 @@
                                     TAG, "Adding window " + win + " at "
                                     + i + " of " + N);
                             localmWindows.add(i, win);
+                            mWindowsChanged = true;
                         }
                     }
                 }
@@ -881,6 +837,7 @@
                         TAG, "Adding window " + win + " at "
                         + i + " of " + N);
                 localmWindows.add(i, win);
+                mWindowsChanged = true;
             }
             if (addToToken) {
                 token.windows.add(tokenWindowsPos, win);
@@ -1089,6 +1046,7 @@
             if (DEBUG_WINDOW_MOVEMENT) Slog.v(
                     TAG, "Adding input method window " + win + " at " + pos);
             mWindows.add(pos, win);
+            mWindowsChanged = true;
             moveInputMethodDialogsLocked(pos+1);
             return;
         }
@@ -1130,6 +1088,7 @@
             if (wpos < interestingPos) interestingPos--;
             if (DEBUG_WINDOW_MOVEMENT) Slog.v(TAG, "Temp removing at " + wpos + ": " + win);
             mWindows.remove(wpos);
+            mWindowsChanged = true;
             int NC = win.mChildWindows.size();
             while (NC > 0) {
                 NC--;
@@ -1156,6 +1115,7 @@
             if (DEBUG_WINDOW_MOVEMENT) Slog.v(TAG, "ReAdd removing from " + wpos
                     + ": " + win);
             mWindows.remove(wpos);
+            mWindowsChanged = true;
             reAddWindowLocked(wpos, win);
         }
     }
@@ -1616,6 +1576,7 @@
                     if (DEBUG_WINDOW_MOVEMENT) Slog.v(TAG, "Wallpaper removing at "
                             + oldIndex + ": " + wallpaper);
                     localmWindows.remove(oldIndex);
+                    mWindowsChanged = true;
                     if (oldIndex < foundI) {
                         foundI--;
                     }
@@ -1627,6 +1588,7 @@
                         + " from " + oldIndex + " to " + foundI);
 
                 localmWindows.add(foundI, wallpaper);
+                mWindowsChanged = true;
                 changed |= ADJUST_WALLPAPER_LAYERS_CHANGED;
             }
         }
@@ -1816,70 +1778,6 @@
             }
         }
     }
-
-    void sendPointerToWallpaperLocked(WindowState srcWin,
-            MotionEvent pointer, long eventTime) {
-        int curTokenIndex = mWallpaperTokens.size();
-        while (curTokenIndex > 0) {
-            curTokenIndex--;
-            WindowToken token = mWallpaperTokens.get(curTokenIndex);
-            int curWallpaperIndex = token.windows.size();
-            while (curWallpaperIndex > 0) {
-                curWallpaperIndex--;
-                WindowState wallpaper = token.windows.get(curWallpaperIndex);
-                if ((wallpaper.mAttrs.flags &
-                        WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE) != 0) {
-                    continue;
-                }
-                try {
-                    MotionEvent ev = MotionEvent.obtainNoHistory(pointer);
-                    if (srcWin != null) {
-                        ev.offsetLocation(srcWin.mFrame.left-wallpaper.mFrame.left,
-                                srcWin.mFrame.top-wallpaper.mFrame.top);
-                    } else {
-                        ev.offsetLocation(-wallpaper.mFrame.left, -wallpaper.mFrame.top);
-                    }
-                    switch (pointer.getAction()) {
-                        case MotionEvent.ACTION_DOWN:
-                            mSendingPointersToWallpaper = true;
-                            break;
-                        case MotionEvent.ACTION_UP:
-                            mSendingPointersToWallpaper = false;
-                            break;
-                    }
-                    wallpaper.mClient.dispatchPointer(ev, eventTime, false);
-                } catch (RemoteException e) {
-                    Slog.w(TAG, "Failure sending pointer to wallpaper", e);
-                }
-            }
-        }
-    }
-
-    void dispatchPointerElsewhereLocked(WindowState srcWin, WindowState relWin,
-            MotionEvent pointer, long eventTime, boolean skipped) {
-        if (relWin != null) {
-            mPolicy.dispatchedPointerEventLw(pointer, relWin.mFrame.left, relWin.mFrame.top);
-        } else {
-            mPolicy.dispatchedPointerEventLw(pointer, 0, 0);
-        }
-        
-        // If we sent an initial down to the wallpaper, then continue
-        // sending events until the final up.
-        if (mSendingPointersToWallpaper) {
-            if (skipped) {
-                Slog.i(TAG, "Sending skipped pointer to wallpaper!");
-            }
-            sendPointerToWallpaperLocked(relWin, pointer, eventTime);
-            
-        // If we are on top of the wallpaper, then the wallpaper also
-        // gets to see this movement.
-        } else if (srcWin != null
-                && pointer.getAction() == MotionEvent.ACTION_DOWN
-                && mWallpaperTarget == srcWin
-                && srcWin.mAttrs.type != WindowManager.LayoutParams.TYPE_KEYGUARD) {
-            sendPointerToWallpaperLocked(relWin, pointer, eventTime);
-        }
-    }
     
     public int addWindow(Session session, IWindow client,
             WindowManager.LayoutParams attrs, int viewVisibility,
@@ -1902,12 +1800,7 @@
                 mDisplay = wm.getDefaultDisplay();
                 mInitialDisplayWidth = mDisplay.getWidth();
                 mInitialDisplayHeight = mDisplay.getHeight();
-                if (ENABLE_NATIVE_INPUT_DISPATCH) {
-                    mInputManager.setDisplaySize(0,
-                            mInitialDisplayWidth, mInitialDisplayHeight);
-                } else {
-                    mQueue.setDisplay(mDisplay);
-                }
+                mInputManager.setDisplaySize(0, mInitialDisplayWidth, mInitialDisplayHeight);
                 reportNewConfig = true;
             }
 
@@ -2001,15 +1894,13 @@
                 return res;
             }
             
-            if (ENABLE_NATIVE_INPUT_DISPATCH) {
-                if (outInputChannel != null) {
-                    String name = win.makeInputChannelName();
-                    InputChannel[] inputChannels = InputChannel.openInputChannelPair(name);
-                    win.mInputChannel = inputChannels[0];
-                    inputChannels[1].transferToBinderOutParameter(outInputChannel);
-                    
-                    mInputManager.registerInputChannel(win.mInputChannel);
-                }
+            if (outInputChannel != null) {
+                String name = win.makeInputChannelName();
+                InputChannel[] inputChannels = InputChannel.openInputChannelPair(name);
+                win.mInputChannel = inputChannels[0];
+                inputChannels[1].transferToBinderOutParameter(outInputChannel);
+                
+                mInputManager.registerInputChannel(win.mInputChannel);
             }
 
             // From now on, no exceptions or errors allowed!
@@ -2185,14 +2076,7 @@
     }
 
     private void removeWindowInnerLocked(Session session, WindowState win) {
-        if (ENABLE_NATIVE_INPUT_DISPATCH) {
-            mInputMonitor.windowIsBeingRemovedLw(win);
-        } else {
-            mKeyWaiter.finishedKey(session, win.mClient, true,
-                    KeyWaiter.RETURN_NOTHING);
-            mKeyWaiter.releasePendingPointerLocked(win.mSession);
-            mKeyWaiter.releasePendingTrackballLocked(win.mSession);
-        }
+        mInputMonitor.windowIsBeingRemovedLw(win);
 
         win.mRemoved = true;
 
@@ -2211,6 +2095,7 @@
 
         mWindowMap.remove(win.mClient.asBinder());
         mWindows.remove(win);
+        mWindowsChanged = true;
         if (DEBUG_WINDOW_MOVEMENT) Slog.v(TAG, "Final remove of window: " + win);
 
         if (mInputMethodWindow == win) {
@@ -2560,12 +2445,7 @@
                               applyAnimationLocked(win, transit, false)) {
                             focusMayChange = true;
                             win.mExiting = true;
-                            if (ENABLE_NATIVE_INPUT_DISPATCH) {
-                                mInputMonitor.windowIsBecomingInvisibleLw(win);
-                            } else {
-                                mKeyWaiter.finishedKey(session, client, true,
-                                        KeyWaiter.RETURN_NOTHING);
-                            }
+                            mInputMonitor.windowIsBecomingInvisibleLw(win);
                         } else if (win.isAnimating()) {
                             // Currently in a hide animation... turn this into
                             // an exit.
@@ -3026,12 +2906,7 @@
                         if (win.isVisibleNow()) {
                             applyAnimationLocked(win,
                                     WindowManagerPolicy.TRANSIT_EXIT, false);
-                            if (ENABLE_NATIVE_INPUT_DISPATCH) {
-                                mInputMonitor.windowIsBeingRemovedLw(win);
-                            } else {
-                                mKeyWaiter.finishedKey(win.mSession, win.mClient, true,
-                                        KeyWaiter.RETURN_NOTHING);
-                            }
+                            mInputMonitor.windowIsBeingRemovedLw(win);
                             changed = true;
                         }
                     }
@@ -3348,12 +3223,8 @@
                 if (DEBUG_FOCUS) Slog.v(TAG, "Clearing focused app, was " + mFocusedApp);
                 changed = mFocusedApp != null;
                 mFocusedApp = null;
-                if (ENABLE_NATIVE_INPUT_DISPATCH) {
-                    if (changed) {
-                        mInputMonitor.setFocusedAppLw(null);
-                    }
-                } else {
-                    mKeyWaiter.tickle();
+                if (changed) {
+                    mInputMonitor.setFocusedAppLw(null);
                 }
             } else {
                 AppWindowToken newFocus = findAppWindowToken(token);
@@ -3364,12 +3235,8 @@
                 changed = mFocusedApp != newFocus;
                 mFocusedApp = newFocus;
                 if (DEBUG_FOCUS) Slog.v(TAG, "Set focused app to: " + mFocusedApp);
-                if (ENABLE_NATIVE_INPUT_DISPATCH) {
-                    if (changed) {
-                        mInputMonitor.setFocusedAppLw(newFocus);
-                    }
-                } else {
-                    mKeyWaiter.tickle();
+                if (changed) {
+                    mInputMonitor.setFocusedAppLw(newFocus);
                 }
             }
 
@@ -3511,6 +3378,7 @@
                         if (DEBUG_WINDOW_MOVEMENT) Slog.v(TAG,
                                 "Removing starting window: " + startingWindow);
                         mWindows.remove(startingWindow);
+                        mWindowsChanged = true;
                         ttoken.windows.remove(startingWindow);
                         ttoken.allAppWindows.remove(startingWindow);
                         addWindowToListInOrderLocked(startingWindow, true);
@@ -3681,12 +3549,7 @@
                         applyAnimationLocked(win,
                                 WindowManagerPolicy.TRANSIT_EXIT, false);
                     }
-                    if (ENABLE_NATIVE_INPUT_DISPATCH) {
-                        mInputMonitor.windowIsBecomingInvisibleLw(win);
-                    } else {
-                        mKeyWaiter.finishedKey(win.mSession, win.mClient, true,
-                                KeyWaiter.RETURN_NOTHING);
-                    }
+                    mInputMonitor.windowIsBecomingInvisibleLw(win);
                     changed = true;
                 }
             }
@@ -3971,11 +3834,7 @@
                     if (DEBUG_FOCUS) Slog.v(TAG, "Removing focused app token:" + wtoken);
                     mFocusedApp = null;
                     updateFocusedWindowLocked(UPDATE_FOCUS_NORMAL);
-                    if (ENABLE_NATIVE_INPUT_DISPATCH) {
-                        mInputMonitor.setFocusedAppLw(null);
-                    } else {
-                        mKeyWaiter.tickle();
-                    }
+                    mInputMonitor.setFocusedAppLw(null);
                 }
             } else {
                 Slog.w(TAG, "Attempted to remove non-existing app token: " + token);
@@ -4001,6 +3860,7 @@
             WindowState win = token.windows.get(i);
             if (DEBUG_WINDOW_MOVEMENT) Slog.v(TAG, "Tmp removing app window " + win);
             mWindows.remove(win);
+            mWindowsChanged = true;
             int j = win.mChildWindows.size();
             while (j > 0) {
                 j--;
@@ -4105,6 +3965,7 @@
             mWindows.add(index, win);
             index++;
         }
+        mWindowsChanged = true;
         return index;
     }
 
@@ -4440,11 +4301,7 @@
                 "getSwitchState()")) {
             throw new SecurityException("Requires READ_INPUT_STATE permission");
         }
-        if (ENABLE_NATIVE_INPUT_DISPATCH) {
-            return mInputManager.getSwitchState(sw);
-        } else {
-            return KeyInputQueue.getSwitchState(sw);
-        }
+        return mInputManager.getSwitchState(sw);
     }
 
     public int getSwitchStateForDevice(int devid, int sw) {
@@ -4452,11 +4309,7 @@
                 "getSwitchStateForDevice()")) {
             throw new SecurityException("Requires READ_INPUT_STATE permission");
         }
-        if (ENABLE_NATIVE_INPUT_DISPATCH) {
-            return mInputManager.getSwitchState(devid, sw);
-        } else {
-            return KeyInputQueue.getSwitchState(devid, sw);
-        }
+        return mInputManager.getSwitchState(devid, sw);
     }
 
     public int getScancodeState(int sw) {
@@ -4464,11 +4317,7 @@
                 "getScancodeState()")) {
             throw new SecurityException("Requires READ_INPUT_STATE permission");
         }
-        if (ENABLE_NATIVE_INPUT_DISPATCH) {
-            return mInputManager.getScancodeState(sw);
-        } else {
-            return mQueue.getScancodeState(sw);
-        }
+        return mInputManager.getScancodeState(sw);
     }
 
     public int getScancodeStateForDevice(int devid, int sw) {
@@ -4476,11 +4325,7 @@
                 "getScancodeStateForDevice()")) {
             throw new SecurityException("Requires READ_INPUT_STATE permission");
         }
-        if (ENABLE_NATIVE_INPUT_DISPATCH) {
-            return mInputManager.getScancodeState(devid, sw);
-        } else {
-            return mQueue.getScancodeState(devid, sw);
-        }
+        return mInputManager.getScancodeState(devid, sw);
     }
 
     public int getTrackballScancodeState(int sw) {
@@ -4488,11 +4333,7 @@
                 "getTrackballScancodeState()")) {
             throw new SecurityException("Requires READ_INPUT_STATE permission");
         }
-        if (ENABLE_NATIVE_INPUT_DISPATCH) {
-            return mInputManager.getTrackballScancodeState(sw);
-        } else {
-            return mQueue.getTrackballScancodeState(sw);
-        }
+        return mInputManager.getTrackballScancodeState(sw);
     }
 
     public int getDPadScancodeState(int sw) {
@@ -4500,11 +4341,7 @@
                 "getDPadScancodeState()")) {
             throw new SecurityException("Requires READ_INPUT_STATE permission");
         }
-        if (ENABLE_NATIVE_INPUT_DISPATCH) {
-            return mInputManager.getDPadScancodeState(sw);
-        } else {
-            return mQueue.getDPadScancodeState(sw);
-        }
+        return mInputManager.getDPadScancodeState(sw);
     }
 
     public int getKeycodeState(int sw) {
@@ -4512,11 +4349,7 @@
                 "getKeycodeState()")) {
             throw new SecurityException("Requires READ_INPUT_STATE permission");
         }
-        if (ENABLE_NATIVE_INPUT_DISPATCH) {
-            return mInputManager.getKeycodeState(sw);
-        } else {
-            return mQueue.getKeycodeState(sw);
-        }
+        return mInputManager.getKeycodeState(sw);
     }
 
     public int getKeycodeStateForDevice(int devid, int sw) {
@@ -4524,11 +4357,7 @@
                 "getKeycodeStateForDevice()")) {
             throw new SecurityException("Requires READ_INPUT_STATE permission");
         }
-        if (ENABLE_NATIVE_INPUT_DISPATCH) {
-            return mInputManager.getKeycodeState(devid, sw);
-        } else {
-            return mQueue.getKeycodeState(devid, sw);
-        }
+        return mInputManager.getKeycodeState(devid, sw);
     }
 
     public int getTrackballKeycodeState(int sw) {
@@ -4536,11 +4365,7 @@
                 "getTrackballKeycodeState()")) {
             throw new SecurityException("Requires READ_INPUT_STATE permission");
         }
-        if (ENABLE_NATIVE_INPUT_DISPATCH) {
-            return mInputManager.getTrackballKeycodeState(sw);
-        } else {
-            return mQueue.getTrackballKeycodeState(sw);
-        }
+        return mInputManager.getTrackballKeycodeState(sw);
     }
 
     public int getDPadKeycodeState(int sw) {
@@ -4548,19 +4373,11 @@
                 "getDPadKeycodeState()")) {
             throw new SecurityException("Requires READ_INPUT_STATE permission");
         }
-        if (ENABLE_NATIVE_INPUT_DISPATCH) {
-            return mInputManager.getDPadKeycodeState(sw);
-        } else {
-            return mQueue.getDPadKeycodeState(sw);
-        }
+        return mInputManager.getDPadKeycodeState(sw);
     }
 
     public boolean hasKeys(int[] keycodes, boolean[] keyExists) {
-        if (ENABLE_NATIVE_INPUT_DISPATCH) {
-            return mInputManager.hasKeys(keycodes, keyExists);
-        } else {
-            return KeyInputQueue.hasKeys(keycodes, keyExists);
-        }
+        return mInputManager.hasKeys(keycodes, keyExists);
     }
 
     public void enableScreenAfterBoot() {
@@ -4704,11 +4521,7 @@
             mLayoutNeeded = true;
             startFreezingDisplayLocked();
             Slog.i(TAG, "Setting rotation to " + rotation + ", animFlags=" + animFlags);
-            if (ENABLE_NATIVE_INPUT_DISPATCH) {
-                mInputManager.setDisplayOrientation(0, rotation);
-            } else {
-                mQueue.setOrientation(rotation);
-            }
+            mInputManager.setDisplayOrientation(0, rotation);
             if (mDisplayEnabled) {
                 Surface.setOrientation(0, rotation, animFlags);
             }
@@ -4990,6 +4803,48 @@
         return success;
     }
 
+    public void addWindowChangeListener(WindowChangeListener listener) {
+        synchronized(mWindowMap) {
+            mWindowChangeListeners.add(listener);
+        }
+    }
+
+    public void removeWindowChangeListener(WindowChangeListener listener) {
+        synchronized(mWindowMap) {
+            mWindowChangeListeners.remove(listener);
+        }
+    }
+
+    private void notifyWindowsChanged() {
+        WindowChangeListener[] windowChangeListeners;
+        synchronized(mWindowMap) {
+            if(mWindowChangeListeners.isEmpty()) {
+                return;
+            }
+            windowChangeListeners = new WindowChangeListener[mWindowChangeListeners.size()];
+            windowChangeListeners = mWindowChangeListeners.toArray(windowChangeListeners);
+        }
+        int N = windowChangeListeners.length;
+        for(int i = 0; i < N; i++) {
+            windowChangeListeners[i].windowsChanged();
+        }
+    }
+
+    private void notifyFocusChanged() {
+        WindowChangeListener[] windowChangeListeners;
+        synchronized(mWindowMap) {
+            if(mWindowChangeListeners.isEmpty()) {
+                return;
+            }
+            windowChangeListeners = new WindowChangeListener[mWindowChangeListeners.size()];
+            windowChangeListeners = mWindowChangeListeners.toArray(windowChangeListeners);
+        }
+        int N = windowChangeListeners.length;
+        for(int i = 0; i < N; i++) {
+            windowChangeListeners[i].focusChanged();
+        }
+    }
+
     private WindowState findWindow(int hashCode) {
         if (hashCode == -1) {
             return getFocusedWindow();
@@ -5039,11 +4894,8 @@
         if (mDisplay == null) {
             return false;
         }
-        if (ENABLE_NATIVE_INPUT_DISPATCH) {
-            mInputManager.getInputConfiguration(config);
-        } else {
-            mQueue.getInputConfiguration(config);
-        }
+        
+        mInputManager.getInputConfiguration(config);
 
         // Use the effective "visual" dimensions based on current rotation
         final boolean rotated = (mRotation == Surface.ROTATION_90
@@ -5324,6 +5176,13 @@
             mTempInputWindows.clear();
         }
         
+        /* Provides feedback for a virtual key down. */
+        public void virtualKeyDownFeedback() {
+            synchronized (mWindowMap) {
+                mPolicy.performHapticFeedbackLw(null, HapticFeedbackConstants.VIRTUAL_KEY, false);
+            }
+        }
+        
         /* Notifies that an app switch key (BACK / HOME) has just been pressed.
          * This essentially starts a .5 second timeout for the application to process
          * subsequent input events while waiting for the app switch to occur.  If it takes longer
@@ -5332,30 +5191,28 @@
         public void notifyAppSwitchComing() {
             // TODO Not implemented yet.  Should go in the native side.
         }
-
+        
+        /* Notifies that the lid switch changed state. */
+        public void notifyLidSwitchChanged(long whenNanos, boolean lidOpen) {
+            mPolicy.notifyLidSwitchChanged(whenNanos, lidOpen);
+        }
+        
         /* 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(int deviceId, int type, int scanCode,
-                int keyCode, int policyFlags, int value, long whenNanos, boolean isScreenOn) {
-            RawInputEvent event = new RawInputEvent();
-            event.deviceId = deviceId;
-            event.type = type;
-            event.scancode = scanCode;
-            event.keycode = keyCode;
-            event.flags = policyFlags;
-            event.value = value;
-            event.when = whenNanos / 1000000;
-            
-            return mPolicy.interceptKeyTq(event, isScreenOn);
+        public int interceptKeyBeforeQueueing(long whenNanos, int keyCode, boolean down,
+                int policyFlags, boolean isScreenOn) {
+            return mPolicy.interceptKeyBeforeQueueing(whenNanos,
+                    keyCode, down, policyFlags, isScreenOn);
         }
         
         /* Provides an opportunity for the window manager policy to process a key before
          * ordinary dispatch. */
-        public boolean interceptKeyBeforeDispatching(InputChannel focus, int keyCode,
-                int metaState, boolean down, int repeatCount, int policyFlags) {
+        public boolean interceptKeyBeforeDispatching(InputChannel focus,
+                int action, int flags, int keyCode, int metaState, int repeatCount,
+                int policyFlags) {
             WindowState windowState = getWindowStateForInputChannel(focus);
-            return mPolicy.interceptKeyTi(windowState, keyCode, metaState, down, repeatCount,
-                    policyFlags);
+            return mPolicy.interceptKeyBeforeDispatching(windowState, action, flags,
+                    keyCode, metaState, repeatCount, policyFlags);
         }
         
         /* Called when the current input focus changes.
@@ -5494,455 +5351,6 @@
         }
     }
 
-    private final void wakeupIfNeeded(WindowState targetWin, int eventType) {
-        long curTime = SystemClock.uptimeMillis();
-
-        if (eventType == TOUCH_EVENT || eventType == LONG_TOUCH_EVENT || eventType == CHEEK_EVENT) {
-            if (mLastTouchEventType == eventType &&
-                    (curTime - mLastUserActivityCallTime) < MIN_TIME_BETWEEN_USERACTIVITIES) {
-                return;
-            }
-            mLastUserActivityCallTime = curTime;
-            mLastTouchEventType = eventType;
-        }
-
-        if (targetWin == null
-                || targetWin.mAttrs.type != WindowManager.LayoutParams.TYPE_KEYGUARD) {
-            mPowerManager.userActivity(curTime, false, eventType, false);
-        }
-    }
-
-    // tells if it's a cheek event or not -- this function is stateful
-    private static final int EVENT_NONE = 0;
-    private static final int EVENT_UNKNOWN = 0;
-    private static final int EVENT_CHEEK = 0;
-    private static final int EVENT_IGNORE_DURATION = 300; // ms
-    private static final float CHEEK_THRESHOLD = 0.6f;
-    private int mEventState = EVENT_NONE;
-    private float mEventSize;
-
-    private int eventType(MotionEvent ev) {
-        float size = ev.getSize();
-        switch (ev.getAction()) {
-        case MotionEvent.ACTION_DOWN:
-            mEventSize = size;
-            return (mEventSize > CHEEK_THRESHOLD) ? CHEEK_EVENT : TOUCH_EVENT;
-        case MotionEvent.ACTION_UP:
-            if (size > mEventSize) mEventSize = size;
-            return (mEventSize > CHEEK_THRESHOLD) ? CHEEK_EVENT : TOUCH_UP_EVENT;
-        case MotionEvent.ACTION_MOVE:
-            final int N = ev.getHistorySize();
-            if (size > mEventSize) mEventSize = size;
-            if (mEventSize > CHEEK_THRESHOLD) return CHEEK_EVENT;
-            for (int i=0; i<N; i++) {
-                size = ev.getHistoricalSize(i);
-                if (size > mEventSize) mEventSize = size;
-                if (mEventSize > CHEEK_THRESHOLD) return CHEEK_EVENT;
-            }
-            if (ev.getEventTime() < ev.getDownTime() + EVENT_IGNORE_DURATION) {
-                return TOUCH_EVENT;
-            } else {
-                return LONG_TOUCH_EVENT;
-            }
-        default:
-            // not good
-            return OTHER_EVENT;
-        }
-    }
-    
-    private boolean mFatTouch; // remove me together with dispatchPointer
-
-    /**
-     * @return Returns true if event was dispatched, false if it was dropped for any reason
-     */
-    private int dispatchPointer(QueuedEvent qev, MotionEvent ev, int pid, int uid) {
-        if (DEBUG_INPUT || WindowManagerPolicy.WATCH_POINTER) Slog.v(TAG,
-                "dispatchPointer " + ev);
-
-        if (MEASURE_LATENCY) {
-            lt.sample("3 Wait for last dispatch ", System.nanoTime() - qev.whenNano);
-        }
-
-        Object targetObj = mKeyWaiter.waitForNextEventTarget(null, qev,
-                ev, true, false, pid, uid);
-
-        if (MEASURE_LATENCY) {
-            lt.sample("3 Last dispatch finished ", System.nanoTime() - qev.whenNano);
-        }
-
-        int action = ev.getAction();
-
-        if (action == MotionEvent.ACTION_UP) {
-            // let go of our target
-            mKeyWaiter.mMotionTarget = null;
-            mPowerManager.logPointerUpEvent();
-        } else if (action == MotionEvent.ACTION_DOWN) {
-            mPowerManager.logPointerDownEvent();
-        }
-
-        if (targetObj == null) {
-            // In this case we are either dropping the event, or have received
-            // a move or up without a down.  It is common to receive move
-            // events in such a way, since this means the user is moving the
-            // pointer without actually pressing down.  All other cases should
-            // be atypical, so let's log them.
-            if (action != MotionEvent.ACTION_MOVE) {
-                Slog.w(TAG, "No window to dispatch pointer action " + ev.getAction());
-            }
-            synchronized (mWindowMap) {
-                dispatchPointerElsewhereLocked(null, null, ev, ev.getEventTime(), true);
-            }
-            if (qev != null) {
-                mQueue.recycleEvent(qev);
-            }
-            ev.recycle();
-            return INJECT_FAILED;
-        }
-        if (targetObj == mKeyWaiter.CONSUMED_EVENT_TOKEN) {
-            synchronized (mWindowMap) {
-                dispatchPointerElsewhereLocked(null, null, ev, ev.getEventTime(), true);
-            }
-            if (qev != null) {
-                mQueue.recycleEvent(qev);
-            }
-            ev.recycle();
-            return INJECT_SUCCEEDED;
-        }
-
-        WindowState target = (WindowState)targetObj;
-
-        final long eventTime = ev.getEventTime();
-        final long eventTimeNano = ev.getEventTimeNano();
-
-        //Slog.i(TAG, "Sending " + ev + " to " + target);
-
-        if (uid != 0 && uid != target.mSession.mUid) {
-            if (mContext.checkPermission(
-                    android.Manifest.permission.INJECT_EVENTS, pid, uid)
-                    != PackageManager.PERMISSION_GRANTED) {
-                Slog.w(TAG, "Permission denied: injecting pointer event from pid "
-                        + pid + " uid " + uid + " to window " + target
-                        + " owned by uid " + target.mSession.mUid);
-                if (qev != null) {
-                    mQueue.recycleEvent(qev);
-                }
-                ev.recycle();
-                return INJECT_NO_PERMISSION;
-            }
-        }
-
-        if (MEASURE_LATENCY) {
-            lt.sample("4 in dispatchPointer     ", System.nanoTime() - eventTimeNano);
-        }
-
-        if ((target.mAttrs.flags &
-                        WindowManager.LayoutParams.FLAG_IGNORE_CHEEK_PRESSES) != 0) {
-            //target wants to ignore fat touch events
-            boolean cheekPress = mPolicy.isCheekPressedAgainstScreen(ev);
-            //explicit flag to return without processing event further
-            boolean returnFlag = false;
-            if((action == MotionEvent.ACTION_DOWN)) {
-                mFatTouch = false;
-                if(cheekPress) {
-                    mFatTouch = true;
-                    returnFlag = true;
-                }
-            } else {
-                if(action == MotionEvent.ACTION_UP) {
-                    if(mFatTouch) {
-                        //earlier even was invalid doesnt matter if current up is cheekpress or not
-                        mFatTouch = false;
-                        returnFlag = true;
-                    } else if(cheekPress) {
-                        //cancel the earlier event
-                        ev.setAction(MotionEvent.ACTION_CANCEL);
-                        action = MotionEvent.ACTION_CANCEL;
-                    }
-                } else if(action == MotionEvent.ACTION_MOVE) {
-                    if(mFatTouch) {
-                        //two cases here
-                        //an invalid down followed by 0 or moves(valid or invalid)
-                        //a valid down,  invalid move, more moves. want to ignore till up
-                        returnFlag = true;
-                    } else if(cheekPress) {
-                        //valid down followed by invalid moves
-                        //an invalid move have to cancel earlier action
-                        ev.setAction(MotionEvent.ACTION_CANCEL);
-                        action = MotionEvent.ACTION_CANCEL;
-                        if (DEBUG_INPUT) Slog.v(TAG, "Sending cancel for invalid ACTION_MOVE");
-                        //note that the subsequent invalid moves will not get here
-                        mFatTouch = true;
-                    }
-                }
-            } //else if action
-            if(returnFlag) {
-                //recycle que, ev
-                if (qev != null) {
-                    mQueue.recycleEvent(qev);
-                }
-                ev.recycle();
-                return INJECT_FAILED;
-            }
-        } //end if target
-
-        // Enable this for testing the "right" value
-        if (false && action == MotionEvent.ACTION_DOWN) {
-            int max_events_per_sec = 35;
-            try {
-                max_events_per_sec = Integer.parseInt(SystemProperties
-                        .get("windowsmgr.max_events_per_sec"));
-                if (max_events_per_sec < 1) {
-                    max_events_per_sec = 35;
-                }
-            } catch (NumberFormatException e) {
-            }
-            mMinWaitTimeBetweenTouchEvents = 1000 / max_events_per_sec;
-        }
-
-        /*
-         * Throttle events to minimize CPU usage when there's a flood of events
-         * e.g. constant contact with the screen
-         */
-        if (action == MotionEvent.ACTION_MOVE) {
-            long nextEventTime = mLastTouchEventTime + mMinWaitTimeBetweenTouchEvents;
-            long now = SystemClock.uptimeMillis();
-            if (now < nextEventTime) {
-                try {
-                    Thread.sleep(nextEventTime - now);
-                } catch (InterruptedException e) {
-                }
-                mLastTouchEventTime = nextEventTime;
-            } else {
-                mLastTouchEventTime = now;
-            }
-        }
-
-        if (MEASURE_LATENCY) {
-            lt.sample("5 in dispatchPointer     ", System.nanoTime() - eventTimeNano);
-        }
-
-        synchronized(mWindowMap) {
-            if (!target.isVisibleLw()) {
-                // During this motion dispatch, the target window has become
-                // invisible.
-                dispatchPointerElsewhereLocked(null, null, ev, ev.getEventTime(), false);
-                if (qev != null) {
-                    mQueue.recycleEvent(qev);
-                }
-                ev.recycle();
-                return INJECT_SUCCEEDED;
-            }
-
-            if (qev != null && action == MotionEvent.ACTION_MOVE) {
-                mKeyWaiter.bindTargetWindowLocked(target,
-                        KeyWaiter.RETURN_PENDING_POINTER, qev);
-                ev = null;
-            } else {
-                if (action == MotionEvent.ACTION_DOWN) {
-                    WindowState out = mKeyWaiter.mOutsideTouchTargets;
-                    if (out != null) {
-                        MotionEvent oev = MotionEvent.obtain(ev);
-                        try {
-                            oev.setAction(MotionEvent.ACTION_OUTSIDE);
-                            do {
-                                final Rect frame = out.mFrame;
-                                oev.offsetLocation(-(float)frame.left, -(float)frame.top);
-                                try {
-                                    out.mClient.dispatchPointer(oev, eventTime, false);
-                                } catch (android.os.RemoteException e) {
-                                    Slog.i(TAG,
-                                            "WINDOW DIED during outside motion dispatch: " + out);
-                                }
-                                oev.offsetLocation((float)frame.left, (float)frame.top);
-                                out = out.mNextOutsideTouch;
-                            } while (out != null);
-                            mKeyWaiter.mOutsideTouchTargets = null;
-                        } finally {
-                            oev.recycle();
-                        }
-                    }
-                }
-
-                dispatchPointerElsewhereLocked(target, null, ev, ev.getEventTime(), false);
-
-                final Rect frame = target.mFrame;
-                ev.offsetLocation(-(float)frame.left, -(float)frame.top);
-                mKeyWaiter.bindTargetWindowLocked(target);
-            }
-        }
-
-        // finally offset the event to the target's coordinate system and
-        // dispatch the event.
-        try {
-            if (DEBUG_INPUT || DEBUG_FOCUS || WindowManagerPolicy.WATCH_POINTER) {
-                Slog.v(TAG, "Delivering pointer " + qev + " to " + target);
-            }
-
-            if (MEASURE_LATENCY) {
-                lt.sample("6 before svr->client ipc ", System.nanoTime() - eventTimeNano);
-            }
-
-            target.mClient.dispatchPointer(ev, eventTime, true);
-
-            if (MEASURE_LATENCY) {
-                lt.sample("7 after  svr->client ipc ", System.nanoTime() - eventTimeNano);
-            }
-            return INJECT_SUCCEEDED;
-        } catch (android.os.RemoteException e) {
-            Slog.i(TAG, "WINDOW DIED during motion dispatch: " + target);
-            mKeyWaiter.mMotionTarget = null;
-            try {
-                removeWindow(target.mSession, target.mClient);
-            } catch (java.util.NoSuchElementException ex) {
-                // This will happen if the window has already been
-                // removed.
-            }
-        }
-        return INJECT_FAILED;
-    }
-
-    /**
-     * @return Returns true if event was dispatched, false if it was dropped for any reason
-     */
-    private int dispatchTrackball(QueuedEvent qev, MotionEvent ev, int pid, int uid) {
-        if (DEBUG_INPUT) Slog.v(
-                TAG, "dispatchTrackball [" + ev.getAction() +"] <" + ev.getX() + ", " + ev.getY() + ">");
-
-        Object focusObj = mKeyWaiter.waitForNextEventTarget(null, qev,
-                ev, false, false, pid, uid);
-        if (focusObj == null) {
-            Slog.w(TAG, "No focus window, dropping trackball: " + ev);
-            if (qev != null) {
-                mQueue.recycleEvent(qev);
-            }
-            ev.recycle();
-            return INJECT_FAILED;
-        }
-        if (focusObj == mKeyWaiter.CONSUMED_EVENT_TOKEN) {
-            if (qev != null) {
-                mQueue.recycleEvent(qev);
-            }
-            ev.recycle();
-            return INJECT_SUCCEEDED;
-        }
-
-        WindowState focus = (WindowState)focusObj;
-
-        if (uid != 0 && uid != focus.mSession.mUid) {
-            if (mContext.checkPermission(
-                    android.Manifest.permission.INJECT_EVENTS, pid, uid)
-                    != PackageManager.PERMISSION_GRANTED) {
-                Slog.w(TAG, "Permission denied: injecting key event from pid "
-                        + pid + " uid " + uid + " to window " + focus
-                        + " owned by uid " + focus.mSession.mUid);
-                if (qev != null) {
-                    mQueue.recycleEvent(qev);
-                }
-                ev.recycle();
-                return INJECT_NO_PERMISSION;
-            }
-        }
-
-        final long eventTime = ev.getEventTime();
-
-        synchronized(mWindowMap) {
-            if (qev != null && ev.getAction() == MotionEvent.ACTION_MOVE) {
-                mKeyWaiter.bindTargetWindowLocked(focus,
-                        KeyWaiter.RETURN_PENDING_TRACKBALL, qev);
-                // We don't deliver movement events to the client, we hold
-                // them and wait for them to call back.
-                ev = null;
-            } else {
-                mKeyWaiter.bindTargetWindowLocked(focus);
-            }
-        }
-
-        try {
-            focus.mClient.dispatchTrackball(ev, eventTime, true);
-            return INJECT_SUCCEEDED;
-        } catch (android.os.RemoteException e) {
-            Slog.i(TAG, "WINDOW DIED during key dispatch: " + focus);
-            try {
-                removeWindow(focus.mSession, focus.mClient);
-            } catch (java.util.NoSuchElementException ex) {
-                // This will happen if the window has already been
-                // removed.
-            }
-        }
-
-        return INJECT_FAILED;
-    }
-
-    /**
-     * @return Returns true if event was dispatched, false if it was dropped for any reason
-     */
-    private int dispatchKey(KeyEvent event, int pid, int uid) {
-        if (DEBUG_INPUT) Slog.v(TAG, "Dispatch key: " + event);
-
-        Object focusObj = mKeyWaiter.waitForNextEventTarget(event, null,
-                null, false, false, pid, uid);
-        if (focusObj == null) {
-            Slog.w(TAG, "No focus window, dropping: " + event);
-            return INJECT_FAILED;
-        }
-        if (focusObj == mKeyWaiter.CONSUMED_EVENT_TOKEN) {
-            return INJECT_SUCCEEDED;
-        }
-
-        // Okay we have finished waiting for the last event to be processed.
-        // First off, if this is a repeat event, check to see if there is
-        // a corresponding up event in the queue.  If there is, we will
-        // just drop the repeat, because it makes no sense to repeat after
-        // the user has released a key.  (This is especially important for
-        // long presses.)
-        if (event.getRepeatCount() > 0 && mQueue.hasKeyUpEvent(event)) {
-            return INJECT_SUCCEEDED;
-        }
-
-        WindowState focus = (WindowState)focusObj;
-
-        if (DEBUG_INPUT) Slog.v(
-            TAG, "Dispatching to " + focus + ": " + event);
-
-        if (uid != 0 && uid != focus.mSession.mUid) {
-            if (mContext.checkPermission(
-                    android.Manifest.permission.INJECT_EVENTS, pid, uid)
-                    != PackageManager.PERMISSION_GRANTED) {
-                Slog.w(TAG, "Permission denied: injecting key event from pid "
-                        + pid + " uid " + uid + " to window " + focus
-                        + " owned by uid " + focus.mSession.mUid);
-                return INJECT_NO_PERMISSION;
-            }
-        }
-
-        synchronized(mWindowMap) {
-            mKeyWaiter.bindTargetWindowLocked(focus);
-        }
-
-        // NOSHIP extra state logging
-        mKeyWaiter.recordDispatchState(event, focus);
-        // END NOSHIP
-
-        try {
-            if (DEBUG_INPUT || DEBUG_FOCUS) {
-                Slog.v(TAG, "Delivering key " + event.getKeyCode()
-                        + " to " + focus);
-            }
-            focus.mClient.dispatchKey(event);
-            return INJECT_SUCCEEDED;
-        } catch (android.os.RemoteException e) {
-            Slog.i(TAG, "WINDOW DIED during key dispatch: " + focus);
-            try {
-                removeWindow(focus.mSession, focus.mClient);
-            } catch (java.util.NoSuchElementException ex) {
-                // This will happen if the window has already been
-                // removed.
-            }
-        }
-
-        return INJECT_FAILED;
-    }
-
     public void pauseKeyDispatching(IBinder _token) {
         if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
                 "pauseKeyDispatching()")) {
@@ -5952,11 +5360,7 @@
         synchronized (mWindowMap) {
             WindowToken token = mTokenMap.get(_token);
             if (token != null) {
-                if (ENABLE_NATIVE_INPUT_DISPATCH) {
-                    mInputMonitor.pauseDispatchingLw(token);
-                } else {
-                    mKeyWaiter.pauseDispatchingLocked(token);
-                }
+                mInputMonitor.pauseDispatchingLw(token);
             }
         }
     }
@@ -5970,11 +5374,7 @@
         synchronized (mWindowMap) {
             WindowToken token = mTokenMap.get(_token);
             if (token != null) {
-                if (ENABLE_NATIVE_INPUT_DISPATCH) {
-                    mInputMonitor.resumeDispatchingLw(token);
-                } else {
-                    mKeyWaiter.resumeDispatchingLocked(token);
-                }
+                mInputMonitor.resumeDispatchingLw(token);
             }
         }
     }
@@ -5986,11 +5386,7 @@
         }
 
         synchronized (mWindowMap) {
-            if (ENABLE_NATIVE_INPUT_DISPATCH) {
-                mInputMonitor.setEventDispatchingLw(enabled);
-            } else {
-                mKeyWaiter.setEventDispatchingLocked(enabled);
-            }
+            mInputMonitor.setEventDispatchingLw(enabled);
         }
     }
 
@@ -6023,16 +5419,8 @@
         final int uid = Binder.getCallingUid();
         final long ident = Binder.clearCallingIdentity();
         
-        final int result;
-        if (ENABLE_NATIVE_INPUT_DISPATCH) {
-            result = mInputManager.injectKeyEvent(newEvent, InputQueue.INPUT_EVENT_NATURE_KEY,
-                    pid, uid, sync, INJECTION_TIMEOUT_MILLIS);
-        } else {
-            result = dispatchKey(newEvent, pid, uid);
-            if (sync) {
-                mKeyWaiter.waitForNextEventTarget(null, null, null, false, true, pid, uid);
-            }
-        }
+        final int result = mInputManager.injectKeyEvent(newEvent,
+                InputQueue.INPUT_EVENT_NATURE_KEY, pid, uid, sync, INJECTION_TIMEOUT_MILLIS);
         
         Binder.restoreCallingIdentity(ident);
         return reportInjectionResult(result);
@@ -6052,16 +5440,8 @@
         final int uid = Binder.getCallingUid();
         final long ident = Binder.clearCallingIdentity();
         
-        final int result;
-        if (ENABLE_NATIVE_INPUT_DISPATCH) {
-            result = mInputManager.injectMotionEvent(ev, InputQueue.INPUT_EVENT_NATURE_TOUCH,
-                    pid, uid, sync, INJECTION_TIMEOUT_MILLIS);
-        } else {
-            result = dispatchPointer(null, ev, pid, uid);
-            if (sync) {
-                mKeyWaiter.waitForNextEventTarget(null, null, null, false, true, pid, uid);
-            }
-        }
+        final int result = mInputManager.injectMotionEvent(ev,
+                InputQueue.INPUT_EVENT_NATURE_TOUCH, pid, uid, sync, INJECTION_TIMEOUT_MILLIS);
         
         Binder.restoreCallingIdentity(ident);
         return reportInjectionResult(result);
@@ -6081,48 +5461,29 @@
         final int uid = Binder.getCallingUid();
         final long ident = Binder.clearCallingIdentity();
         
-        final int result;
-        if (ENABLE_NATIVE_INPUT_DISPATCH) {
-            result = mInputManager.injectMotionEvent(ev, InputQueue.INPUT_EVENT_NATURE_TRACKBALL,
-                    pid, uid, sync, INJECTION_TIMEOUT_MILLIS);
-        } else {
-            result = dispatchTrackball(null, ev, pid, uid);
-            if (sync) {
-                mKeyWaiter.waitForNextEventTarget(null, null, null, false, true, pid, uid);
-            }
-        }
+        final int result = mInputManager.injectMotionEvent(ev,
+                InputQueue.INPUT_EVENT_NATURE_TRACKBALL, pid, uid, sync, INJECTION_TIMEOUT_MILLIS);
         
         Binder.restoreCallingIdentity(ident);
         return reportInjectionResult(result);
     }
     
     private boolean reportInjectionResult(int result) {
-        if (ENABLE_NATIVE_INPUT_DISPATCH) {
-            switch (result) {
-                case InputManager.INPUT_EVENT_INJECTION_PERMISSION_DENIED:
-                    Slog.w(TAG, "Input event injection permission denied.");
-                    throw new SecurityException(
-                            "Injecting to another application requires INJECT_EVENTS permission");
-                case InputManager.INPUT_EVENT_INJECTION_SUCCEEDED:
-                    Slog.v(TAG, "Input event injection succeeded.");
-                    return true;
-                case InputManager.INPUT_EVENT_INJECTION_TIMED_OUT:
-                    Slog.w(TAG, "Input event injection timed out.");
-                    return false;
-                case InputManager.INPUT_EVENT_INJECTION_FAILED:
-                default:
-                    Slog.w(TAG, "Input event injection failed.");
-                    return false;
-            }
-        } else {
-            switch (result) {
-                case INJECT_NO_PERMISSION:
-                    throw new SecurityException(
-                            "Injecting to another application requires INJECT_EVENTS permission");
-                case INJECT_SUCCEEDED:
-                    return true;
-            }
-            return false;
+        switch (result) {
+            case InputManager.INPUT_EVENT_INJECTION_PERMISSION_DENIED:
+                Slog.w(TAG, "Input event injection permission denied.");
+                throw new SecurityException(
+                        "Injecting to another application requires INJECT_EVENTS permission");
+            case InputManager.INPUT_EVENT_INJECTION_SUCCEEDED:
+                Slog.v(TAG, "Input event injection succeeded.");
+                return true;
+            case InputManager.INPUT_EVENT_INJECTION_TIMED_OUT:
+                Slog.w(TAG, "Input event injection timed out.");
+                return false;
+            case InputManager.INPUT_EVENT_INJECTION_FAILED:
+            default:
+                Slog.w(TAG, "Input event injection failed.");
+                return false;
         }
     }
 
@@ -6136,867 +5497,6 @@
         return mCurrentFocus;
     }
 
-    /**
-     * This class holds the state for dispatching key events.  This state
-     * is protected by the KeyWaiter instance, NOT by the window lock.  You
-     * can be holding the main window lock while acquire the KeyWaiter lock,
-     * but not the other way around.
-     */
-    final class KeyWaiter {
-        // NOSHIP debugging
-        public class DispatchState {
-            private KeyEvent event;
-            private WindowState focus;
-            private long time;
-            private WindowState lastWin;
-            private IBinder lastBinder;
-            private boolean finished;
-            private boolean gotFirstWindow;
-            private boolean eventDispatching;
-            private long timeToSwitch;
-            private boolean wasFrozen;
-            private boolean focusPaused;
-            private WindowState curFocus;
-
-            DispatchState(KeyEvent theEvent, WindowState theFocus) {
-                focus = theFocus;
-                event = theEvent;
-                time = System.currentTimeMillis();
-                // snapshot KeyWaiter state
-                lastWin = mLastWin;
-                lastBinder = mLastBinder;
-                finished = mFinished;
-                gotFirstWindow = mGotFirstWindow;
-                eventDispatching = mEventDispatching;
-                timeToSwitch = mTimeToSwitch;
-                wasFrozen = mWasFrozen;
-                curFocus = mCurrentFocus;
-                // cache the paused state at ctor time as well
-                if (theFocus == null || theFocus.mToken == null) {
-                    focusPaused = false;
-                } else {
-                    focusPaused = theFocus.mToken.paused;
-                }
-            }
-
-            public String toString() {
-                return "{{" + event + " to " + focus + " @ " + time
-                        + " lw=" + lastWin + " lb=" + lastBinder
-                        + " fin=" + finished + " gfw=" + gotFirstWindow
-                        + " ed=" + eventDispatching + " tts=" + timeToSwitch
-                        + " wf=" + wasFrozen + " fp=" + focusPaused
-                        + " mcf=" + curFocus + "}}";
-            }
-        };
-        private DispatchState mDispatchState = null;
-        public void recordDispatchState(KeyEvent theEvent, WindowState theFocus) {
-            mDispatchState = new DispatchState(theEvent, theFocus);
-        }
-        // END NOSHIP
-
-        public static final int RETURN_NOTHING = 0;
-        public static final int RETURN_PENDING_POINTER = 1;
-        public static final int RETURN_PENDING_TRACKBALL = 2;
-
-        final Object SKIP_TARGET_TOKEN = new Object();
-        final Object CONSUMED_EVENT_TOKEN = new Object();
-
-        private WindowState mLastWin = null;
-        private IBinder mLastBinder = null;
-        private boolean mFinished = true;
-        private boolean mGotFirstWindow = false;
-        private boolean mEventDispatching = true;
-        private long mTimeToSwitch = 0;
-        /* package */ boolean mWasFrozen = false;
-
-        // Target of Motion events
-        WindowState mMotionTarget;
-
-        // Windows above the target who would like to receive an "outside"
-        // touch event for any down events outside of them.
-        WindowState mOutsideTouchTargets;
-
-        /**
-         * Wait for the last event dispatch to complete, then find the next
-         * target that should receive the given event and wait for that one
-         * to be ready to receive it.
-         */
-        Object waitForNextEventTarget(KeyEvent nextKey, QueuedEvent qev,
-                MotionEvent nextMotion, boolean isPointerEvent,
-                boolean failIfTimeout, int callingPid, int callingUid) {
-            long startTime = SystemClock.uptimeMillis();
-            long keyDispatchingTimeout = 5 * 1000;
-            long waitedFor = 0;
-
-            while (true) {
-                // Figure out which window we care about.  It is either the
-                // last window we are waiting to have process the event or,
-                // if none, then the next window we think the event should go
-                // to.  Note: we retrieve mLastWin outside of the lock, so
-                // it may change before we lock.  Thus we must check it again.
-                WindowState targetWin = mLastWin;
-                boolean targetIsNew = targetWin == null;
-                if (DEBUG_INPUT) Slog.v(
-                        TAG, "waitForLastKey: mFinished=" + mFinished +
-                        ", mLastWin=" + mLastWin);
-                if (targetIsNew) {
-                    Object target = findTargetWindow(nextKey, qev, nextMotion,
-                            isPointerEvent, callingPid, callingUid);
-                    if (target == SKIP_TARGET_TOKEN) {
-                        // The user has pressed a special key, and we are
-                        // dropping all pending events before it.
-                        if (DEBUG_INPUT) Slog.v(TAG, "Skipping: " + nextKey
-                                + " " + nextMotion);
-                        return null;
-                    }
-                    if (target == CONSUMED_EVENT_TOKEN) {
-                        if (DEBUG_INPUT) Slog.v(TAG, "Consumed: " + nextKey
-                                + " " + nextMotion);
-                        return target;
-                    }
-                    targetWin = (WindowState)target;
-                }
-
-                AppWindowToken targetApp = null;
-
-                // Now: is it okay to send the next event to this window?
-                synchronized (this) {
-                    // First: did we come here based on the last window not
-                    // being null, but it changed by the time we got here?
-                    // If so, try again.
-                    if (!targetIsNew && mLastWin == null) {
-                        continue;
-                    }
-
-                    // We never dispatch events if not finished with the
-                    // last one, or the display is frozen.
-                    if (mFinished && !mDisplayFrozen) {
-                        // If event dispatching is disabled, then we
-                        // just consume the events.
-                        if (!mEventDispatching) {
-                            if (DEBUG_INPUT) Slog.v(TAG,
-                                    "Skipping event; dispatching disabled: "
-                                    + nextKey + " " + nextMotion);
-                            return null;
-                        }
-                        if (targetWin != null) {
-                            // If this is a new target, and that target is not
-                            // paused or unresponsive, then all looks good to
-                            // handle the event.
-                            if (targetIsNew && !targetWin.mToken.paused) {
-                                return targetWin;
-                            }
-
-                        // If we didn't find a target window, and there is no
-                        // focused app window, then just eat the events.
-                        } else if (mFocusedApp == null) {
-                            if (DEBUG_INPUT) Slog.v(TAG,
-                                    "Skipping event; no focused app: "
-                                    + nextKey + " " + nextMotion);
-                            return null;
-                        }
-                    }
-
-                    if (DEBUG_INPUT) Slog.v(
-                            TAG, "Waiting for last key in " + mLastBinder
-                            + " target=" + targetWin
-                            + " mFinished=" + mFinished
-                            + " mDisplayFrozen=" + mDisplayFrozen
-                            + " targetIsNew=" + targetIsNew
-                            + " paused="
-                            + (targetWin != null ? targetWin.mToken.paused : false)
-                            + " mFocusedApp=" + mFocusedApp
-                            + " mCurrentFocus=" + mCurrentFocus);
-
-                    targetApp = targetWin != null
-                            ? targetWin.mAppToken : mFocusedApp;
-
-                    long curTimeout = keyDispatchingTimeout;
-                    if (mTimeToSwitch != 0) {
-                        long now = SystemClock.uptimeMillis();
-                        if (mTimeToSwitch <= now) {
-                            // If an app switch key has been pressed, and we have
-                            // waited too long for the current app to finish
-                            // processing keys, then wait no more!
-                            doFinishedKeyLocked(false);
-                            continue;
-                        }
-                        long switchTimeout = mTimeToSwitch - now;
-                        if (curTimeout > switchTimeout) {
-                            curTimeout = switchTimeout;
-                        }
-                    }
-
-                    try {
-                        // after that continue
-                        // processing keys, so we don't get stuck.
-                        if (DEBUG_INPUT) Slog.v(
-                                TAG, "Waiting for key dispatch: " + curTimeout);
-                        wait(curTimeout);
-                        if (DEBUG_INPUT) Slog.v(TAG, "Finished waiting @"
-                                + SystemClock.uptimeMillis() + " startTime="
-                                + startTime + " switchTime=" + mTimeToSwitch
-                                + " target=" + targetWin + " mLW=" + mLastWin
-                                + " mLB=" + mLastBinder + " fin=" + mFinished
-                                + " mCurrentFocus=" + mCurrentFocus);
-                    } catch (InterruptedException e) {
-                    }
-                }
-
-                // If we were frozen during configuration change, restart the
-                // timeout checks from now; otherwise look at whether we timed
-                // out before awakening.
-                if (mWasFrozen) {
-                    waitedFor = 0;
-                    mWasFrozen = false;
-                } else {
-                    waitedFor = SystemClock.uptimeMillis() - startTime;
-                }
-
-                if (waitedFor >= keyDispatchingTimeout && mTimeToSwitch == 0) {
-                    IApplicationToken at = null;
-                    synchronized (this) {
-                        Slog.w(TAG, "Key dispatching timed out sending to " +
-                              (targetWin != null ? targetWin.mAttrs.getTitle()
-                              : "<null>: no window ready for key dispatch"));
-                        // NOSHIP debugging
-                        Slog.w(TAG, "Previous dispatch state: " + mDispatchState);
-                        Slog.w(TAG, "Current dispatch state: " +
-                                new DispatchState(nextKey, targetWin));
-                        // END NOSHIP
-                        //dump();
-                        if (targetWin != null) {
-                            at = targetWin.getAppToken();
-                        } else if (targetApp != null) {
-                            at = targetApp.appToken;
-                        }
-                    }
-
-                    boolean abort = true;
-                    if (at != null) {
-                        try {
-                            long timeout = at.getKeyDispatchingTimeout();
-                            if (timeout > waitedFor) {
-                                // we did not wait the proper amount of time for this application.
-                                // set the timeout to be the real timeout and wait again.
-                                keyDispatchingTimeout = timeout - waitedFor;
-                                continue;
-                            } else {
-                                abort = at.keyDispatchingTimedOut();
-                            }
-                        } catch (RemoteException ex) {
-                        }
-                    }
-
-                    synchronized (this) {
-                        if (abort && (mLastWin == targetWin || targetWin == null)) {
-                            mFinished = true;
-                            if (mLastWin != null) {
-                                if (DEBUG_INPUT) Slog.v(TAG,
-                                        "Window " + mLastWin +
-                                        " timed out on key input");
-                                if (mLastWin.mToken.paused) {
-                                    Slog.w(TAG, "Un-pausing dispatching to this window");
-                                    mLastWin.mToken.paused = false;
-                                }
-                            }
-                            if (mMotionTarget == targetWin) {
-                                mMotionTarget = null;
-                            }
-                            mLastWin = null;
-                            mLastBinder = null;
-                            if (failIfTimeout || targetWin == null) {
-                                return null;
-                            }
-                        } else {
-                            Slog.w(TAG, "Continuing to wait for key to be dispatched");
-                            startTime = SystemClock.uptimeMillis();
-                        }
-                    }
-                }
-            }
-        }
-
-        Object findTargetWindow(KeyEvent nextKey, QueuedEvent qev,
-                MotionEvent nextMotion, boolean isPointerEvent,
-                int callingPid, int callingUid) {
-            mOutsideTouchTargets = null;
-
-            if (nextKey != null) {
-                // Find the target window for a normal key event.
-                final int keycode = nextKey.getKeyCode();
-                final int repeatCount = nextKey.getRepeatCount();
-                final boolean down = nextKey.getAction() != KeyEvent.ACTION_UP;
-                boolean dispatch = mKeyWaiter.checkShouldDispatchKey(keycode);
-
-                if (!dispatch) {
-                    if (callingUid == 0 ||
-                            mContext.checkPermission(
-                                    android.Manifest.permission.INJECT_EVENTS,
-                                    callingPid, callingUid)
-                                    == PackageManager.PERMISSION_GRANTED) {
-                        mPolicy.interceptKeyTi(null, keycode,
-                                nextKey.getMetaState(), down, repeatCount,
-                                nextKey.getFlags());
-                    }
-                    Slog.w(TAG, "Event timeout during app switch: dropping "
-                            + nextKey);
-                    return SKIP_TARGET_TOKEN;
-                }
-
-                // System.out.println("##### [" + SystemClock.uptimeMillis() + "] WindowManagerService.dispatchKey(" + keycode + ", " + down + ", " + repeatCount + ")");
-
-                WindowState focus = null;
-                synchronized(mWindowMap) {
-                    focus = getFocusedWindowLocked();
-                }
-
-                wakeupIfNeeded(focus, LocalPowerManager.BUTTON_EVENT);
-
-                if (callingUid == 0 ||
-                        (focus != null && callingUid == focus.mSession.mUid) ||
-                        mContext.checkPermission(
-                                android.Manifest.permission.INJECT_EVENTS,
-                                callingPid, callingUid)
-                                == PackageManager.PERMISSION_GRANTED) {
-                    if (mPolicy.interceptKeyTi(focus,
-                            keycode, nextKey.getMetaState(), down, repeatCount,
-                            nextKey.getFlags())) {
-                        return CONSUMED_EVENT_TOKEN;
-                    }
-                }
-
-                return focus;
-
-            } else if (!isPointerEvent) {
-                boolean dispatch = mKeyWaiter.checkShouldDispatchKey(-1);
-                if (!dispatch) {
-                    Slog.w(TAG, "Event timeout during app switch: dropping trackball "
-                            + nextMotion);
-                    return SKIP_TARGET_TOKEN;
-                }
-
-                WindowState focus = null;
-                synchronized(mWindowMap) {
-                    focus = getFocusedWindowLocked();
-                }
-
-                wakeupIfNeeded(focus, LocalPowerManager.BUTTON_EVENT);
-                return focus;
-            }
-
-            if (nextMotion == null) {
-                return SKIP_TARGET_TOKEN;
-            }
-
-            boolean dispatch = mKeyWaiter.checkShouldDispatchKey(
-                    KeyEvent.KEYCODE_UNKNOWN);
-            if (!dispatch) {
-                Slog.w(TAG, "Event timeout during app switch: dropping pointer "
-                        + nextMotion);
-                return SKIP_TARGET_TOKEN;
-            }
-
-            // Find the target window for a pointer event.
-            int action = nextMotion.getAction();
-            final float xf = nextMotion.getX();
-            final float yf = nextMotion.getY();
-            final long eventTime = nextMotion.getEventTime();
-
-            final boolean screenWasOff = qev != null
-                    && (qev.flags&WindowManagerPolicy.FLAG_BRIGHT_HERE) != 0;
-
-            WindowState target = null;
-
-            synchronized(mWindowMap) {
-                synchronized (this) {
-                    if (action == MotionEvent.ACTION_DOWN) {
-                        if (mMotionTarget != null) {
-                            // this is weird, we got a pen down, but we thought it was
-                            // already down!
-                            // XXX: We should probably send an ACTION_UP to the current
-                            // target.
-                            Slog.w(TAG, "Pointer down received while already down in: "
-                                    + mMotionTarget);
-                            mMotionTarget = null;
-                        }
-
-                        // ACTION_DOWN is special, because we need to lock next events to
-                        // the window we'll land onto.
-                        final int x = (int)xf;
-                        final int y = (int)yf;
-
-                        final ArrayList windows = mWindows;
-                        final int N = windows.size();
-                        WindowState topErrWindow = null;
-                        final Rect tmpRect = mTempRect;
-                        for (int i=N-1; i>=0; i--) {
-                            WindowState child = (WindowState)windows.get(i);
-                            //Slog.i(TAG, "Checking dispatch to: " + child);
-                            final int flags = child.mAttrs.flags;
-                            if ((flags & WindowManager.LayoutParams.FLAG_SYSTEM_ERROR) != 0) {
-                                if (topErrWindow == null) {
-                                    topErrWindow = child;
-                                }
-                            }
-                            if (!child.isVisibleLw()) {
-                                //Slog.i(TAG, "Not visible!");
-                                continue;
-                            }
-                            if ((flags & WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE) != 0) {
-                                //Slog.i(TAG, "Not touchable!");
-                                if ((flags & WindowManager.LayoutParams
-                                        .FLAG_WATCH_OUTSIDE_TOUCH) != 0) {
-                                    child.mNextOutsideTouch = mOutsideTouchTargets;
-                                    mOutsideTouchTargets = child;
-                                }
-                                continue;
-                            }
-                            tmpRect.set(child.mFrame);
-                            if (child.mTouchableInsets == ViewTreeObserver
-                                        .InternalInsetsInfo.TOUCHABLE_INSETS_CONTENT) {
-                                // The touch is inside of the window if it is
-                                // inside the frame, AND the content part of that
-                                // frame that was given by the application.
-                                tmpRect.left += child.mGivenContentInsets.left;
-                                tmpRect.top += child.mGivenContentInsets.top;
-                                tmpRect.right -= child.mGivenContentInsets.right;
-                                tmpRect.bottom -= child.mGivenContentInsets.bottom;
-                            } else if (child.mTouchableInsets == ViewTreeObserver
-                                        .InternalInsetsInfo.TOUCHABLE_INSETS_VISIBLE) {
-                                // The touch is inside of the window if it is
-                                // inside the frame, AND the visible part of that
-                                // frame that was given by the application.
-                                tmpRect.left += child.mGivenVisibleInsets.left;
-                                tmpRect.top += child.mGivenVisibleInsets.top;
-                                tmpRect.right -= child.mGivenVisibleInsets.right;
-                                tmpRect.bottom -= child.mGivenVisibleInsets.bottom;
-                            }
-                            final int touchFlags = flags &
-                                (WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
-                                |WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL);
-                            if (tmpRect.contains(x, y) || touchFlags == 0) {
-                                //Slog.i(TAG, "Using this target!");
-                                if (!screenWasOff || (flags &
-                                        WindowManager.LayoutParams.FLAG_TOUCHABLE_WHEN_WAKING) != 0) {
-                                    mMotionTarget = child;
-                                } else {
-                                    //Slog.i(TAG, "Waking, skip!");
-                                    mMotionTarget = null;
-                                }
-                                break;
-                            }
-
-                            if ((flags & WindowManager.LayoutParams
-                                    .FLAG_WATCH_OUTSIDE_TOUCH) != 0) {
-                                child.mNextOutsideTouch = mOutsideTouchTargets;
-                                mOutsideTouchTargets = child;
-                                //Slog.i(TAG, "Adding to outside target list: " + child);
-                            }
-                        }
-
-                        // if there's an error window but it's not accepting
-                        // focus (typically because it is not yet visible) just
-                        // wait for it -- any other focused window may in fact
-                        // be in ANR state.
-                        if (topErrWindow != null && mMotionTarget != topErrWindow) {
-                            mMotionTarget = null;
-                        }
-                    }
-
-                    target = mMotionTarget;
-                }
-            }
-
-            wakeupIfNeeded(target, eventType(nextMotion));
-
-            // Pointer events are a little different -- if there isn't a
-            // target found for any event, then just drop it.
-            return target != null ? target : SKIP_TARGET_TOKEN;
-        }
-
-        boolean checkShouldDispatchKey(int keycode) {
-            synchronized (this) {
-                if (mPolicy.isAppSwitchKeyTqTiLwLi(keycode)) {
-                    mTimeToSwitch = 0;
-                    return true;
-                }
-                if (mTimeToSwitch != 0
-                        && mTimeToSwitch < SystemClock.uptimeMillis()) {
-                    return false;
-                }
-                return true;
-            }
-        }
-
-        void bindTargetWindowLocked(WindowState win,
-                int pendingWhat, QueuedEvent pendingMotion) {
-            synchronized (this) {
-                bindTargetWindowLockedLocked(win, pendingWhat, pendingMotion);
-            }
-        }
-
-        void bindTargetWindowLocked(WindowState win) {
-            synchronized (this) {
-                bindTargetWindowLockedLocked(win, RETURN_NOTHING, null);
-            }
-        }
-
-        void bindTargetWindowLockedLocked(WindowState win,
-                int pendingWhat, QueuedEvent pendingMotion) {
-            mLastWin = win;
-            mLastBinder = win.mClient.asBinder();
-            mFinished = false;
-            if (pendingMotion != null) {
-                final Session s = win.mSession;
-                if (pendingWhat == RETURN_PENDING_POINTER) {
-                    releasePendingPointerLocked(s);
-                    s.mPendingPointerMove = pendingMotion;
-                    s.mPendingPointerWindow = win;
-                    if (DEBUG_INPUT) Slog.v(TAG,
-                            "bindTargetToWindow " + s.mPendingPointerMove);
-                } else if (pendingWhat == RETURN_PENDING_TRACKBALL) {
-                    releasePendingTrackballLocked(s);
-                    s.mPendingTrackballMove = pendingMotion;
-                    s.mPendingTrackballWindow = win;
-                }
-            }
-        }
-
-        void releasePendingPointerLocked(Session s) {
-            if (DEBUG_INPUT) Slog.v(TAG,
-                    "releasePendingPointer " + s.mPendingPointerMove);
-            if (s.mPendingPointerMove != null) {
-                mQueue.recycleEvent(s.mPendingPointerMove);
-                s.mPendingPointerMove = null;
-            }
-        }
-
-        void releasePendingTrackballLocked(Session s) {
-            if (s.mPendingTrackballMove != null) {
-                mQueue.recycleEvent(s.mPendingTrackballMove);
-                s.mPendingTrackballMove = null;
-            }
-        }
-
-        MotionEvent finishedKey(Session session, IWindow client, boolean force,
-                int returnWhat) {
-            if (DEBUG_INPUT) Slog.v(
-                TAG, "finishedKey: client=" + client + ", force=" + force);
-
-            if (client == null) {
-                return null;
-            }
-
-            MotionEvent res = null;
-            QueuedEvent qev = null;
-            WindowState win = null;
-
-            synchronized (this) {
-                if (DEBUG_INPUT) Slog.v(
-                    TAG, "finishedKey: client=" + client.asBinder()
-                    + ", force=" + force + ", last=" + mLastBinder
-                    + " (token=" + (mLastWin != null ? mLastWin.mToken : null) + ")");
-
-                if (returnWhat == RETURN_PENDING_POINTER) {
-                    qev = session.mPendingPointerMove;
-                    win = session.mPendingPointerWindow;
-                    session.mPendingPointerMove = null;
-                    session.mPendingPointerWindow = null;
-                } else if (returnWhat == RETURN_PENDING_TRACKBALL) {
-                    qev = session.mPendingTrackballMove;
-                    win = session.mPendingTrackballWindow;
-                    session.mPendingTrackballMove = null;
-                    session.mPendingTrackballWindow = null;
-                }
-
-                if (mLastBinder == client.asBinder()) {
-                    if (DEBUG_INPUT) Slog.v(
-                        TAG, "finishedKey: last paused="
-                        + ((mLastWin != null) ? mLastWin.mToken.paused : "null"));
-                    if (mLastWin != null && (!mLastWin.mToken.paused || force
-                            || !mEventDispatching)) {
-                        doFinishedKeyLocked(true);
-                    } else {
-                        // Make sure to wake up anyone currently waiting to
-                        // dispatch a key, so they can re-evaluate their
-                        // current situation.
-                        mFinished = true;
-                        notifyAll();
-                    }
-                }
-
-                if (qev != null) {
-                    res = (MotionEvent)qev.event;
-                    if (DEBUG_INPUT) Slog.v(TAG,
-                            "Returning pending motion: " + res);
-                    mQueue.recycleEvent(qev);
-                    if (win != null && returnWhat == RETURN_PENDING_POINTER) {
-                        res.offsetLocation(-win.mFrame.left, -win.mFrame.top);
-                    }
-                }
-            }
-
-            if (res != null && returnWhat == RETURN_PENDING_POINTER) {
-                synchronized (mWindowMap) {
-                    dispatchPointerElsewhereLocked(win, win, res, res.getEventTime(), false);
-                }
-            }
-
-            return res;
-        }
-
-        void tickle() {
-            synchronized (this) {
-                notifyAll();
-            }
-        }
-
-        void handleNewWindowLocked(WindowState newWindow) {
-            if (!newWindow.canReceiveKeys()) {
-                return;
-            }
-            synchronized (this) {
-                if (DEBUG_INPUT) Slog.v(
-                    TAG, "New key dispatch window: win="
-                    + newWindow.mClient.asBinder()
-                    + ", last=" + mLastBinder
-                    + " (token=" + (mLastWin != null ? mLastWin.mToken : null)
-                    + "), finished=" + mFinished + ", paused="
-                    + newWindow.mToken.paused);
-
-                // Displaying a window implicitly causes dispatching to
-                // be unpaused.  (This is to protect against bugs if someone
-                // pauses dispatching but forgets to resume.)
-                newWindow.mToken.paused = false;
-
-                mGotFirstWindow = true;
-
-                if ((newWindow.mAttrs.flags & FLAG_SYSTEM_ERROR) != 0) {
-                    if (DEBUG_INPUT) Slog.v(TAG,
-                            "New SYSTEM_ERROR window; resetting state");
-                    mLastWin = null;
-                    mLastBinder = null;
-                    mMotionTarget = null;
-                    mFinished = true;
-                } else if (mLastWin != null) {
-                    // If the new window is above the window we are
-                    // waiting on, then stop waiting and let key dispatching
-                    // start on the new guy.
-                    if (DEBUG_INPUT) Slog.v(
-                        TAG, "Last win layer=" + mLastWin.mLayer
-                        + ", new win layer=" + newWindow.mLayer);
-                    if (newWindow.mLayer >= mLastWin.mLayer) {
-                        // The new window is above the old; finish pending input to the last
-                        // window and start directing it to the new one.
-                        mLastWin.mToken.paused = false;
-                        doFinishedKeyLocked(false);  // does a notifyAll()
-                        return;
-                    }
-                }
-
-                // Now that we've put a new window state in place, make the event waiter
-                // take notice and retarget its attentions.
-                notifyAll();
-            }
-        }
-
-        void pauseDispatchingLocked(WindowToken token) {
-            synchronized (this)
-            {
-                if (DEBUG_INPUT) Slog.v(TAG, "Pausing WindowToken " + token);
-                token.paused = true;
-
-                /*
-                if (mLastWin != null && !mFinished && mLastWin.mBaseLayer <= layer) {
-                    mPaused = true;
-                } else {
-                    if (mLastWin == null) {
-                        Slog.i(TAG, "Key dispatching not paused: no last window.");
-                    } else if (mFinished) {
-                        Slog.i(TAG, "Key dispatching not paused: finished last key.");
-                    } else {
-                        Slog.i(TAG, "Key dispatching not paused: window in higher layer.");
-                    }
-                }
-                */
-            }
-        }
-
-        void resumeDispatchingLocked(WindowToken token) {
-            synchronized (this) {
-                if (token.paused) {
-                    if (DEBUG_INPUT) Slog.v(
-                        TAG, "Resuming WindowToken " + token
-                        + ", last=" + mLastBinder
-                        + " (token=" + (mLastWin != null ? mLastWin.mToken : null)
-                        + "), finished=" + mFinished + ", paused="
-                        + token.paused);
-                    token.paused = false;
-                    if (mLastWin != null && mLastWin.mToken == token && mFinished) {
-                        doFinishedKeyLocked(false);
-                    } else {
-                        notifyAll();
-                    }
-                }
-            }
-        }
-
-        void setEventDispatchingLocked(boolean enabled) {
-            synchronized (this) {
-                mEventDispatching = enabled;
-                notifyAll();
-            }
-        }
-
-        void appSwitchComing() {
-            synchronized (this) {
-                // Don't wait for more than .5 seconds for app to finish
-                // processing the pending events.
-                long now = SystemClock.uptimeMillis() + 500;
-                if (DEBUG_INPUT) Slog.v(TAG, "appSwitchComing: " + now);
-                if (mTimeToSwitch == 0 || now < mTimeToSwitch) {
-                    mTimeToSwitch = now;
-                }
-                notifyAll();
-            }
-        }
-
-        private final void doFinishedKeyLocked(boolean force) {
-            if (mLastWin != null) {
-                releasePendingPointerLocked(mLastWin.mSession);
-                releasePendingTrackballLocked(mLastWin.mSession);
-            }
-
-            if (force || mLastWin == null || !mLastWin.mToken.paused
-                    || !mLastWin.isVisibleLw()) {
-                // If the current window has been paused, we aren't -really-
-                // finished...  so let the waiters still wait.
-                mLastWin = null;
-                mLastBinder = null;
-            }
-            mFinished = true;
-            notifyAll();
-        }
-    }
-
-    private class KeyQ extends KeyInputQueue
-            implements KeyInputQueue.FilterCallback {
-        KeyQ() {
-            super(mContext, WindowManagerService.this);
-        }
-
-        @Override
-        boolean preprocessEvent(InputDevice device, RawInputEvent event) {
-            if (mPolicy.preprocessInputEventTq(event)) {
-                return true;
-            }
-
-            switch (event.type) {
-                case RawInputEvent.EV_KEY: {
-                    // XXX begin hack
-                    if (DEBUG) {
-                        if (event.keycode == KeyEvent.KEYCODE_G) {
-                            if (event.value != 0) {
-                                // G down
-                                mPolicy.screenTurnedOff(WindowManagerPolicy.OFF_BECAUSE_OF_USER);
-                            }
-                            return false;
-                        }
-                        if (event.keycode == KeyEvent.KEYCODE_D) {
-                            if (event.value != 0) {
-                                //dump();
-                            }
-                            return false;
-                        }
-                    }
-                    // XXX end hack
-
-                    boolean screenIsOff = !mPowerManager.isScreenOn();
-                    boolean screenIsDim = !mPowerManager.isScreenBright();
-                    int actions = mPolicy.interceptKeyTq(event, !screenIsOff);
-
-                    if ((actions & WindowManagerPolicy.ACTION_GO_TO_SLEEP) != 0) {
-                        mPowerManager.goToSleep(event.when);
-                    }
-
-                    if (screenIsOff) {
-                        event.flags |= WindowManagerPolicy.FLAG_WOKE_HERE;
-                    }
-                    if (screenIsDim) {
-                        event.flags |= WindowManagerPolicy.FLAG_BRIGHT_HERE;
-                    }
-                    if ((actions & WindowManagerPolicy.ACTION_POKE_USER_ACTIVITY) != 0) {
-                        mPowerManager.userActivity(event.when, false,
-                                LocalPowerManager.BUTTON_EVENT, false);
-                    }
-
-                    if ((actions & WindowManagerPolicy.ACTION_PASS_TO_USER) != 0) {
-                        if (event.value != 0 && mPolicy.isAppSwitchKeyTqTiLwLi(event.keycode)) {
-                            filterQueue(this);
-                            mKeyWaiter.appSwitchComing();
-                        }
-                        return true;
-                    } else {
-                        return false;
-                    }
-                }
-
-                case RawInputEvent.EV_REL: {
-                    boolean screenIsOff = !mPowerManager.isScreenOn();
-                    boolean screenIsDim = !mPowerManager.isScreenBright();
-                    if (screenIsOff) {
-                        if (!mPolicy.isWakeRelMovementTq(event.deviceId,
-                                device.classes, event)) {
-                            //Slog.i(TAG, "dropping because screenIsOff and !isWakeKey");
-                            return false;
-                        }
-                        event.flags |= WindowManagerPolicy.FLAG_WOKE_HERE;
-                    }
-                    if (screenIsDim) {
-                        event.flags |= WindowManagerPolicy.FLAG_BRIGHT_HERE;
-                    }
-                    return true;
-                }
-
-                case RawInputEvent.EV_ABS: {
-                    boolean screenIsOff = !mPowerManager.isScreenOn();
-                    boolean screenIsDim = !mPowerManager.isScreenBright();
-                    if (screenIsOff) {
-                        if (!mPolicy.isWakeAbsMovementTq(event.deviceId,
-                                device.classes, event)) {
-                            //Slog.i(TAG, "dropping because screenIsOff and !isWakeKey");
-                            return false;
-                        }
-                        event.flags |= WindowManagerPolicy.FLAG_WOKE_HERE;
-                    }
-                    if (screenIsDim) {
-                        event.flags |= WindowManagerPolicy.FLAG_BRIGHT_HERE;
-                    }
-                    return true;
-                }
-
-                default:
-                    return true;
-            }
-        }
-
-        public int filterEvent(QueuedEvent ev) {
-            switch (ev.classType) {
-                case RawInputEvent.CLASS_KEYBOARD:
-                    KeyEvent ke = (KeyEvent)ev.event;
-                    if (mPolicy.isMovementKeyTi(ke.getKeyCode())) {
-                        Slog.w(TAG, "Dropping movement key during app switch: "
-                                + ke.getKeyCode() + ", action=" + ke.getAction());
-                        return FILTER_REMOVE;
-                    }
-                    return FILTER_ABORT;
-                default:
-                    return FILTER_KEEP;
-            }
-        }
-    }
-
     public boolean detectSafeMode() {
         mSafeMode = mPolicy.detectSafeMode();
         return mSafeMode;
@@ -7006,219 +5506,6 @@
         mPolicy.systemReady();
     }
 
-    private final class InputDispatcherThread extends Thread {
-        // Time to wait when there is nothing to do: 9999 seconds.
-        static final int LONG_WAIT=9999*1000;
-
-        public InputDispatcherThread() {
-            super("InputDispatcher");
-        }
-
-        @Override
-        public void run() {
-            while (true) {
-                try {
-                    process();
-                } catch (Exception e) {
-                    Slog.e(TAG, "Exception in input dispatcher", e);
-                }
-            }
-        }
-
-        private void process() {
-            android.os.Process.setThreadPriority(
-                    android.os.Process.THREAD_PRIORITY_URGENT_DISPLAY);
-
-            // The last key event we saw
-            KeyEvent lastKey = null;
-
-            // Last keydown time for auto-repeating keys
-            long lastKeyTime = SystemClock.uptimeMillis();
-            long nextKeyTime = lastKeyTime+LONG_WAIT;
-            long downTime = 0;
-
-            // How many successive repeats we generated
-            int keyRepeatCount = 0;
-
-            // Need to report that configuration has changed?
-            boolean configChanged = false;
-
-            while (true) {
-                long curTime = SystemClock.uptimeMillis();
-
-                if (DEBUG_INPUT) Slog.v(
-                    TAG, "Waiting for next key: now=" + curTime
-                    + ", repeat @ " + nextKeyTime);
-
-                // Retrieve next event, waiting only as long as the next
-                // repeat timeout.  If the configuration has changed, then
-                // don't wait at all -- we'll report the change as soon as
-                // we have processed all events.
-                QueuedEvent ev = mQueue.getEvent(
-                    (int)((!configChanged && curTime < nextKeyTime)
-                            ? (nextKeyTime-curTime) : 0));
-
-                if (DEBUG_INPUT && ev != null) Slog.v(
-                        TAG, "Event: type=" + ev.classType + " data=" + ev.event);
-
-                if (MEASURE_LATENCY) {
-                    lt.sample("2 got event              ", System.nanoTime() - ev.whenNano);
-                }
-
-                if (lastKey != null && !mPolicy.allowKeyRepeat()) {
-                    // cancel key repeat at the request of the policy.
-                    lastKey = null;
-                    downTime = 0;
-                    lastKeyTime = curTime;
-                    nextKeyTime = curTime + LONG_WAIT;
-                }
-                try {
-                    if (ev != null) {
-                        curTime = SystemClock.uptimeMillis();
-                        int eventType;
-                        if (ev.classType == RawInputEvent.CLASS_TOUCHSCREEN) {
-                            eventType = eventType((MotionEvent)ev.event);
-                        } else if (ev.classType == RawInputEvent.CLASS_KEYBOARD ||
-                                    ev.classType == RawInputEvent.CLASS_TRACKBALL) {
-                            eventType = LocalPowerManager.BUTTON_EVENT;
-                        } else {
-                            eventType = LocalPowerManager.OTHER_EVENT;
-                        }
-                        try {
-                            if ((curTime - mLastBatteryStatsCallTime)
-                                    >= MIN_TIME_BETWEEN_USERACTIVITIES) {
-                                mLastBatteryStatsCallTime = curTime;
-                                mBatteryStats.noteInputEvent();
-                            }
-                        } catch (RemoteException e) {
-                            // Ignore
-                        }
-
-                        if (ev.classType == RawInputEvent.CLASS_CONFIGURATION_CHANGED) {
-                            // do not wake screen in this case
-                        } else if (eventType != TOUCH_EVENT
-                                && eventType != LONG_TOUCH_EVENT
-                                && eventType != CHEEK_EVENT) {
-                            mPowerManager.userActivity(curTime, false,
-                                    eventType, false);
-                        } else if (mLastTouchEventType != eventType
-                                || (curTime - mLastUserActivityCallTime)
-                                >= MIN_TIME_BETWEEN_USERACTIVITIES) {
-                            mLastUserActivityCallTime = curTime;
-                            mLastTouchEventType = eventType;
-                            mPowerManager.userActivity(curTime, false,
-                                    eventType, false);
-                        }
-
-                        switch (ev.classType) {
-                            case RawInputEvent.CLASS_KEYBOARD:
-                                KeyEvent ke = (KeyEvent)ev.event;
-                                if (ke.isDown()) {
-                                    lastKeyTime = curTime;
-                                    if (lastKey != null &&
-                                            ke.getKeyCode() == lastKey.getKeyCode()) {
-                                        keyRepeatCount++;
-                                        // Arbitrary long timeout to block
-                                        // repeating here since we know that
-                                        // the device driver takes care of it.
-                                        nextKeyTime = lastKeyTime + LONG_WAIT;
-                                        if (DEBUG_INPUT) Slog.v(
-                                                TAG, "Received repeated key down");
-                                    } else {
-                                        downTime = curTime;
-                                        keyRepeatCount = 0;
-                                        nextKeyTime = lastKeyTime
-                                                + ViewConfiguration.getLongPressTimeout();
-                                        if (DEBUG_INPUT) Slog.v(
-                                            TAG, "Received key down: first repeat @ "
-                                            + nextKeyTime);
-                                    }
-                                    lastKey = ke;
-                                } else {
-                                    lastKey = null;
-                                    downTime = 0;
-                                    keyRepeatCount = 0;
-                                    // Arbitrary long timeout.
-                                    lastKeyTime = curTime;
-                                    nextKeyTime = curTime + LONG_WAIT;
-                                    if (DEBUG_INPUT) Slog.v(
-                                        TAG, "Received key up: ignore repeat @ "
-                                        + nextKeyTime);
-                                }
-                                if (keyRepeatCount > 0) {
-                                    dispatchKey(KeyEvent.changeTimeRepeat(ke,
-                                            ke.getEventTime(), keyRepeatCount), 0, 0);
-                                } else {
-                                    dispatchKey(ke, 0, 0);
-                                }
-                                mQueue.recycleEvent(ev);
-                                break;
-                            case RawInputEvent.CLASS_TOUCHSCREEN:
-                                //Slog.i(TAG, "Read next event " + ev);
-                                dispatchPointer(ev, (MotionEvent)ev.event, 0, 0);
-                                break;
-                            case RawInputEvent.CLASS_TRACKBALL:
-                                dispatchTrackball(ev, (MotionEvent)ev.event, 0, 0);
-                                break;
-                            case RawInputEvent.CLASS_CONFIGURATION_CHANGED:
-                                configChanged = true;
-                                break;
-                            default:
-                                mQueue.recycleEvent(ev);
-                            break;
-                        }
-
-                    } else if (configChanged) {
-                        configChanged = false;
-                        sendNewConfiguration();
-
-                    } else if (lastKey != null) {
-                        curTime = SystemClock.uptimeMillis();
-
-                        // Timeout occurred while key was down.  If it is at or
-                        // past the key repeat time, dispatch the repeat.
-                        if (DEBUG_INPUT) Slog.v(
-                            TAG, "Key timeout: repeat=" + nextKeyTime
-                            + ", now=" + curTime);
-                        if (curTime < nextKeyTime) {
-                            continue;
-                        }
-
-                        lastKeyTime = nextKeyTime;
-                        nextKeyTime = nextKeyTime + KEY_REPEAT_DELAY;
-                        keyRepeatCount++;
-                        if (DEBUG_INPUT) Slog.v(
-                            TAG, "Key repeat: count=" + keyRepeatCount
-                            + ", next @ " + nextKeyTime);
-                        KeyEvent newEvent;
-                        if (downTime != 0 && (downTime
-                                + ViewConfiguration.getLongPressTimeout())
-                                <= curTime) {
-                            newEvent = KeyEvent.changeTimeRepeat(lastKey,
-                                    curTime, keyRepeatCount,
-                                    lastKey.getFlags() | KeyEvent.FLAG_LONG_PRESS);
-                            downTime = 0;
-                        } else {
-                            newEvent = KeyEvent.changeTimeRepeat(lastKey,
-                                    curTime, keyRepeatCount);
-                        }
-                        dispatchKey(newEvent, 0, 0);
-
-                    } else {
-                        curTime = SystemClock.uptimeMillis();
-
-                        lastKeyTime = curTime;
-                        nextKeyTime = curTime + LONG_WAIT;
-                    }
-
-                } catch (Exception e) {
-                    Slog.e(TAG,
-                        "Input thread received uncaught exception: " + e, e);
-                }
-            }
-        }
-    }
-
     // -------------------------------------------------------------
     // Client Session State
     // -------------------------------------------------------------
@@ -7234,20 +5521,6 @@
         int mNumWindow = 0;
         boolean mClientDead = false;
 
-        /**
-         * Current pointer move event being dispatched to client window...  must
-         * hold key lock to access.
-         */
-        QueuedEvent mPendingPointerMove;
-        WindowState mPendingPointerWindow;
-
-        /**
-         * Current trackball move event being dispatched to client window...  must
-         * hold key lock to access.
-         */
-        QueuedEvent mPendingTrackballMove;
-        WindowState mPendingTrackballWindow;
-
         public Session(IInputMethodClient client, IInputContext inputContext) {
             mClient = client;
             mInputContext = inputContext;
@@ -7366,36 +5639,6 @@
             finishDrawingWindow(this, window);
         }
 
-        public void finishKey(IWindow window) {
-            if (localLOGV) Slog.v(
-                TAG, "IWindow finishKey called for " + window);
-            if (ENABLE_NATIVE_INPUT_DISPATCH) {
-                throw new IllegalStateException("Should not be called anymore.");
-            }
-            mKeyWaiter.finishedKey(this, window, false,
-                    KeyWaiter.RETURN_NOTHING);
-        }
-
-        public MotionEvent getPendingPointerMove(IWindow window) {
-            if (localLOGV) Slog.v(
-                    TAG, "IWindow getPendingMotionEvent called for " + window);
-            if (ENABLE_NATIVE_INPUT_DISPATCH) {
-                throw new IllegalStateException("Should not be called anymore.");
-            }
-            return mKeyWaiter.finishedKey(this, window, false,
-                    KeyWaiter.RETURN_PENDING_POINTER);
-        }
-
-        public MotionEvent getPendingTrackballMove(IWindow window) {
-            if (localLOGV) Slog.v(
-                    TAG, "IWindow getPendingMotionEvent called for " + window);
-            if (ENABLE_NATIVE_INPUT_DISPATCH) {
-                throw new IllegalStateException("Should not be called anymore.");
-            }
-            return mKeyWaiter.finishedKey(this, window, false,
-                    KeyWaiter.RETURN_PENDING_TRACKBALL);
-        }
-
         public void setInTouchMode(boolean mode) {
             synchronized(mWindowMap) {
                 mInTouchMode = mode;
@@ -7499,16 +5742,6 @@
             pw.print(prefix); pw.print("mNumWindow="); pw.print(mNumWindow);
                     pw.print(" mClientDead="); pw.print(mClientDead);
                     pw.print(" mSurfaceSession="); pw.println(mSurfaceSession);
-            if (mPendingPointerWindow != null || mPendingPointerMove != null) {
-                pw.print(prefix);
-                        pw.print("mPendingPointerWindow="); pw.print(mPendingPointerWindow);
-                        pw.print(" mPendingPointerMove="); pw.println(mPendingPointerMove);
-            }
-            if (mPendingTrackballWindow != null || mPendingTrackballMove != null) {
-                pw.print(prefix);
-                        pw.print("mPendingTrackballWindow="); pw.print(mPendingTrackballWindow);
-                        pw.print(" mPendingTrackballMove="); pw.println(mPendingTrackballMove);
-            }
         }
 
         @Override
@@ -7559,8 +5792,6 @@
         boolean mObscured;
         boolean mTurnOnScreen;
 
-        WindowState mNextOutsideTouch;
-
         int mLayoutSeq = -1;
         
         Configuration mConfiguration = null;
@@ -8077,16 +6308,6 @@
         }
 
         void destroySurfaceLocked() {
-            // Window is no longer on-screen, so can no longer receive
-            // key events...  if we were waiting for it to finish
-            // handling a key event, the wait is over!
-            if (! ENABLE_NATIVE_INPUT_DISPATCH) {
-                mKeyWaiter.finishedKey(mSession, mClient, true,
-                        KeyWaiter.RETURN_NOTHING);
-                mKeyWaiter.releasePendingPointerLocked(mSession);
-                mKeyWaiter.releasePendingTrackballLocked(mSession);
-            }
-
             if (mAppToken != null && this == mAppToken.startingWindow) {
                 mAppToken.startingDisplayed = false;
             }
@@ -8102,9 +6323,7 @@
                     WindowState c = (WindowState)mChildWindows.get(i);
                     c.mAttachedHidden = true;
                     
-                    if (ENABLE_NATIVE_INPUT_DISPATCH) {
-                        mInputMonitor.windowIsBecomingInvisibleLw(c);
-                    }
+                    mInputMonitor.windowIsBecomingInvisibleLw(c);
                 }
 
                 if (mReportDestroySurface) {
@@ -8413,12 +6632,8 @@
                 }
                 mLastHidden = true;
                 
-                if (ENABLE_NATIVE_INPUT_DISPATCH) {
-                    for (int i=0; i<N; i++) {
-                        mInputMonitor.windowIsBecomingInvisibleLw((WindowState)mChildWindows.get(i));
-                    }
-                } else {
-                    mKeyWaiter.releasePendingPointerLocked(mSession);
+                for (int i=0; i<N; i++) {
+                    mInputMonitor.windowIsBecomingInvisibleLw((WindowState)mChildWindows.get(i));
                 }
             }
             mExiting = false;
@@ -8753,13 +6968,11 @@
                 // we are doing this as part of processing a death note.)
             }
             
-            if (ENABLE_NATIVE_INPUT_DISPATCH) {
-                if (mInputChannel != null) {
-                    mInputManager.unregisterInputChannel(mInputChannel);
-                    
-                    mInputChannel.dispose();
-                    mInputChannel = null;
-                }
+            if (mInputChannel != null) {
+                mInputManager.unregisterInputChannel(mInputChannel);
+                
+                mInputChannel.dispose();
+                mInputChannel = null;
             }
         }
 
@@ -9519,6 +7732,7 @@
         public static final int ENABLE_SCREEN = 16;
         public static final int APP_FREEZE_TIMEOUT = 17;
         public static final int SEND_NEW_CONFIGURATION = 18;
+        public static final int REPORT_WINDOWS_CHANGE = 19;
 
         private Session mLastReportedHold;
 
@@ -9570,6 +7784,7 @@
                                 // Ignore if process has died.
                             }
                         }
+                        notifyFocusChanged();
                     }
                 } break;
 
@@ -9850,6 +8065,16 @@
                     break;
                 }
 
+                case REPORT_WINDOWS_CHANGE: {
+                    if (mWindowsChanged) {
+                        synchronized (mWindowMap) {
+                            mWindowsChanged = false;
+                        }
+                        notifyWindowsChanged();
+                    }
+                    break;
+                }
+
             }
         }
     }
@@ -9934,6 +8159,7 @@
             WindowState w = (WindowState)mWindows.get(i);
             if (w.mAppToken != null) {
                 WindowState win = (WindowState)mWindows.remove(i);
+                mWindowsChanged = true;
                 if (DEBUG_WINDOW_MOVEMENT) Slog.v(TAG,
                         "Rebuild removing window: " + win);
                 NW--;
@@ -10069,6 +8295,10 @@
                     requestAnimationLocked(0);
                 }
             }
+            if (mWindowsChanged && !mWindowChangeListeners.isEmpty()) {
+                mH.removeMessages(H.REPORT_WINDOWS_CHANGE);
+                mH.sendMessage(mH.obtainMessage(H.REPORT_WINDOWS_CHANGE));
+            }
         } catch (RuntimeException e) {
             mInLayout = false;
             Slog.e(TAG, "Unhandled exception while layout out windows", e);
@@ -10175,9 +8405,7 @@
         }
         
         // Window frames may have changed.  Tell the input dispatcher about it.
-        if (ENABLE_NATIVE_INPUT_DISPATCH) {
-            mInputMonitor.updateInputWindowsLw();
-        }
+        mInputMonitor.updateInputWindowsLw();
 
         return mPolicy.finishLayoutLw();
     }
@@ -10977,11 +9205,7 @@
                                     Slog.w(TAG, "Exception hiding surface in " + w);
                                 }
                             }
-                            if (ENABLE_NATIVE_INPUT_DISPATCH) {
-                                mInputMonitor.windowIsBecomingInvisibleLw(w);
-                            } else {
-                                mKeyWaiter.releasePendingPointerLocked(w.mSession);
-                            }
+                            mInputMonitor.windowIsBecomingInvisibleLw(w);
                         }
                         // If we are waiting for this window to handle an
                         // orientation change, well, it is hidden, so
@@ -11578,13 +9802,7 @@
     }
     
     private void finishUpdateFocusedWindowAfterAssignLayersLocked() {
-        if (ENABLE_NATIVE_INPUT_DISPATCH) {
-            mInputMonitor.setInputFocusLw(mCurrentFocus);
-        } else {
-            if (mCurrentFocus != null) {
-                mKeyWaiter.handleNewWindowLocked(mCurrentFocus);
-            }
-        }
+        mInputMonitor.setInputFocusLw(mCurrentFocus);
     }
 
     private WindowState computeFocusedWindowLocked() {
@@ -11658,17 +9876,6 @@
 
     private void startFreezingDisplayLocked() {
         if (mDisplayFrozen) {
-            // Freezing the display also suspends key event delivery, to
-            // keep events from going astray while the display is reconfigured.
-            // If someone has changed orientation again while the screen is
-            // still frozen, the events will continue to be blocked while the
-            // successive orientation change is processed.  To prevent spurious
-            // ANRs, we reset the event dispatch timeout in this case.
-            if (! ENABLE_NATIVE_INPUT_DISPATCH) {
-                synchronized (mKeyWaiter) {
-                    mKeyWaiter.mWasFrozen = true;
-                }
-            }
             return;
         }
 
@@ -11689,9 +9896,7 @@
 
         mDisplayFrozen = true;
         
-        if (ENABLE_NATIVE_INPUT_DISPATCH) {
-            mInputMonitor.freezeInputDispatchingLw();
-        }
+        mInputMonitor.freezeInputDispatchingLw();
         
         if (mNextAppTransition != WindowManagerPolicy.TRANSIT_UNSET) {
             mNextAppTransition = WindowManagerPolicy.TRANSIT_UNSET;
@@ -11722,16 +9927,7 @@
         }
         Surface.unfreezeDisplay(0);
 
-        // Reset the key delivery timeout on unfreeze, too.  We force a wakeup here
-        // too because regular key delivery processing should resume immediately.
-        if (ENABLE_NATIVE_INPUT_DISPATCH) {
-            mInputMonitor.thawInputDispatchingLw();
-        } else {
-            synchronized (mKeyWaiter) {
-                mKeyWaiter.mWasFrozen = true;
-                mKeyWaiter.notifyAll();
-            }
-        }
+        mInputMonitor.thawInputDispatchingLw();
 
         // While the display is frozen we don't re-compute the orientation
         // to avoid inconsistent states.  However, something interesting
@@ -11763,13 +9959,8 @@
             return;
         }
 
-        if (ENABLE_NATIVE_INPUT_DISPATCH) {
-            pw.println("Input Dispatcher State:");
-            mInputManager.dump(pw);
-        } else {
-            pw.println("Input State:");
-            mQueue.dump(pw, "  ");
-        }
+        pw.println("Input Dispatcher State:");
+        mInputManager.dump(pw);
         pw.println(" ");
         
         synchronized(mWindowMap) {
@@ -11986,16 +10177,6 @@
             }
             pw.print("  DisplayWidth="); pw.print(mDisplay.getWidth());
                     pw.print(" DisplayHeight="); pw.println(mDisplay.getHeight());
-
-            if (! ENABLE_NATIVE_INPUT_DISPATCH) {
-                pw.println("  KeyWaiter state:");
-                pw.print("    mLastWin="); pw.print(mKeyWaiter.mLastWin);
-                        pw.print(" mLastBinder="); pw.println(mKeyWaiter.mLastBinder);
-                pw.print("    mFinished="); pw.print(mKeyWaiter.mFinished);
-                        pw.print(" mGotFirstWindow="); pw.print(mKeyWaiter.mGotFirstWindow);
-                        pw.print(" mEventDispatching="); pw.print(mKeyWaiter.mEventDispatching);
-                        pw.print(" mTimeToSwitch="); pw.println(mKeyWaiter.mTimeToSwitch);
-            }
         }
     }
 
@@ -12003,12 +10184,6 @@
     public void monitor() {
         synchronized (mWindowMap) { }
         synchronized (mKeyguardTokenWatcher) { }
-        synchronized (mKeyWaiter) { }
-        synchronized (mInputMonitor) { }
-    }
-
-    public void virtualKeyFeedback(KeyEvent event) {
-        mPolicy.keyFeedbackFromInput(event);
     }
 
     /**
diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java
index 93122c4..58aab08 100644
--- a/services/java/com/android/server/am/ActivityManagerService.java
+++ b/services/java/com/android/server/am/ActivityManagerService.java
@@ -11562,7 +11562,69 @@
             }
         }
     }
-    
+
+    public boolean dumpHeap(String process, boolean managed,
+            String path, ParcelFileDescriptor fd) throws RemoteException {
+
+        try {
+            synchronized (this) {
+                // note: hijacking SET_ACTIVITY_WATCHER, but should be changed to
+                // its own permission (same as profileControl).
+                if (checkCallingPermission(android.Manifest.permission.SET_ACTIVITY_WATCHER)
+                        != PackageManager.PERMISSION_GRANTED) {
+                    throw new SecurityException("Requires permission "
+                            + android.Manifest.permission.SET_ACTIVITY_WATCHER);
+                }
+
+                if (fd == null) {
+                    throw new IllegalArgumentException("null fd");
+                }
+
+                ProcessRecord proc = null;
+                try {
+                    int pid = Integer.parseInt(process);
+                    synchronized (mPidsSelfLocked) {
+                        proc = mPidsSelfLocked.get(pid);
+                    }
+                } catch (NumberFormatException e) {
+                }
+
+                if (proc == null) {
+                    HashMap<String, SparseArray<ProcessRecord>> all
+                            = mProcessNames.getMap();
+                    SparseArray<ProcessRecord> procs = all.get(process);
+                    if (procs != null && procs.size() > 0) {
+                        proc = procs.valueAt(0);
+                    }
+                }
+
+                if (proc == null || proc.thread == null) {
+                    throw new IllegalArgumentException("Unknown process: " + process);
+                }
+
+                boolean isSecure = "1".equals(SystemProperties.get(SYSTEM_SECURE, "0"));
+                if (isSecure) {
+                    if ((proc.info.flags&ApplicationInfo.FLAG_DEBUGGABLE) == 0) {
+                        throw new SecurityException("Process not debuggable: " + proc);
+                    }
+                }
+
+                proc.thread.dumpHeap(managed, path, fd);
+                fd = null;
+                return true;
+            }
+        } catch (RemoteException e) {
+            throw new IllegalStateException("Process disappeared");
+        } finally {
+            if (fd != null) {
+                try {
+                    fd.close();
+                } catch (IOException e) {
+                }
+            }
+        }
+    }
+
     /** In this method we try to acquire our lock to make sure that we have not deadlocked */
     public void monitor() {
         synchronized (this) { }
diff --git a/services/jni/Android.mk b/services/jni/Android.mk
index 499ca86..0cf36b3 100644
--- a/services/jni/Android.mk
+++ b/services/jni/Android.mk
@@ -4,9 +4,9 @@
 LOCAL_SRC_FILES:= \
     com_android_server_AlarmManagerService.cpp \
     com_android_server_BatteryService.cpp \
-    com_android_server_KeyInputQueue.cpp \
     com_android_server_InputManager.cpp \
     com_android_server_LightsService.cpp \
+    com_android_server_PowerManagerService.cpp \
     com_android_server_SensorService.cpp \
     com_android_server_SystemServer.cpp \
     com_android_server_VibratorService.cpp \
diff --git a/services/jni/com_android_server_InputManager.cpp b/services/jni/com_android_server_InputManager.cpp
index d0f856b..26e105a 100644
--- a/services/jni/com_android_server_InputManager.cpp
+++ b/services/jni/com_android_server_InputManager.cpp
@@ -40,6 +40,7 @@
 #include "../../core/jni/android_view_KeyEvent.h"
 #include "../../core/jni/android_view_MotionEvent.h"
 #include "../../core/jni/android_view_InputChannel.h"
+#include "com_android_server_PowerManagerService.h"
 
 namespace android {
 
@@ -107,16 +108,6 @@
     LAST_SYSTEM_WINDOW      = 2999,
 };
 
-enum {
-    POWER_MANAGER_OTHER_EVENT = 0,
-    POWER_MANAGER_CHEEK_EVENT = 1,
-    POWER_MANAGER_TOUCH_EVENT = 2, // touch events are TOUCH for 300ms, and then either
-                                   // up events or LONG_TOUCH events.
-    POWER_MANAGER_LONG_TOUCH_EVENT = 3,
-    POWER_MANAGER_TOUCH_UP_EVENT = 4,
-    POWER_MANAGER_BUTTON_EVENT = 5, // Button and trackball events.
-};
-
 // Delay between reporting long touch events to the power manager.
 const nsecs_t EVENT_IGNORE_DURATION = 300 * 1000000LL; // 300 ms
 
@@ -133,20 +124,16 @@
 static struct {
     jclass clazz;
 
-    jmethodID isScreenOn;
-    jmethodID isScreenBright;
     jmethodID notifyConfigurationChanged;
     jmethodID notifyLidSwitchChanged;
     jmethodID notifyInputChannelBroken;
     jmethodID notifyInputChannelANR;
     jmethodID notifyInputChannelRecoveredFromANR;
     jmethodID notifyANR;
-    jmethodID virtualKeyFeedback;
+    jmethodID virtualKeyDownFeedback;
     jmethodID interceptKeyBeforeQueueing;
     jmethodID interceptKeyBeforeDispatching;
     jmethodID checkInjectEventsPermission;
-    jmethodID goToSleep;
-    jmethodID pokeUserActivity;
     jmethodID notifyAppSwitchComing;
     jmethodID filterTouchEvents;
     jmethodID filterJumpyTouchEvents;
@@ -228,9 +215,7 @@
 
     virtual bool getDisplayInfo(int32_t displayId,
             int32_t* width, int32_t* height, int32_t* orientation);
-    virtual void virtualKeyFeedback(nsecs_t when, int32_t deviceId,
-            int32_t action, int32_t flags, int32_t keyCode,
-            int32_t scanCode, int32_t metaState, nsecs_t downTime);
+    virtual void virtualKeyDownFeedback();
     virtual int32_t interceptKey(nsecs_t when, int32_t deviceId,
             bool down, int32_t keyCode, int32_t scanCode, uint32_t policyFlags);
     virtual int32_t interceptTrackball(nsecs_t when, bool buttonChanged, bool buttonDown,
@@ -321,7 +306,7 @@
     int32_t mDisplayWidth, mDisplayHeight;
     int32_t mDisplayOrientation;
 
-    // Callbacks.
+    // Power manager interactions.
     bool isScreenOn();
     bool isScreenBright();
 
@@ -369,9 +354,9 @@
 
     void releaseTouchedWindowLd();
 
-    int32_t identifyTrackballEventTargets(MotionEvent* motionEvent, uint32_t policyFlags,
+    int32_t waitForTrackballEventTargets(MotionEvent* motionEvent, uint32_t policyFlags,
             int32_t injectorPid, int32_t injectorUid, Vector<InputTarget>& outTargets);
-    int32_t identifyTouchEventTargets(MotionEvent* motionEvent, uint32_t policyFlags,
+    int32_t waitForTouchEventTargets(MotionEvent* motionEvent, uint32_t policyFlags,
             int32_t injectorPid, int32_t injectorUid, Vector<InputTarget>& outTargets);
 
     bool interceptKeyBeforeDispatching(const InputTarget& target,
@@ -391,6 +376,7 @@
     }
 
     static bool isAppSwitchKey(int32_t keyCode);
+    static bool isPolicyKey(int32_t keyCode, bool isScreenOn);
     static bool checkAndClearExceptionFromCallback(JNIEnv* env, const char* methodName);
 };
 
@@ -419,7 +405,37 @@
 }
 
 bool NativeInputManager::isAppSwitchKey(int32_t keyCode) {
-    return keyCode == KEYCODE_HOME || keyCode == KEYCODE_ENDCALL;
+    return keyCode == AKEYCODE_HOME || keyCode == AKEYCODE_ENDCALL;
+}
+
+bool NativeInputManager::isPolicyKey(int32_t keyCode, bool isScreenOn) {
+    // Special keys that the WindowManagerPolicy might care about.
+    switch (keyCode) {
+    case AKEYCODE_VOLUME_UP:
+    case AKEYCODE_VOLUME_DOWN:
+    case AKEYCODE_ENDCALL:
+    case AKEYCODE_POWER:
+    case AKEYCODE_CALL:
+    case AKEYCODE_HOME:
+    case AKEYCODE_MENU:
+    case AKEYCODE_SEARCH:
+        // media keys
+    case AKEYCODE_HEADSETHOOK:
+    case AKEYCODE_MEDIA_PLAY_PAUSE:
+    case AKEYCODE_MEDIA_STOP:
+    case AKEYCODE_MEDIA_NEXT:
+    case AKEYCODE_MEDIA_PREVIOUS:
+    case AKEYCODE_MEDIA_REWIND:
+    case AKEYCODE_MEDIA_FAST_FORWARD:
+        return true;
+    default:
+        // We need to pass all keys to the policy in the following cases:
+        // - screen is off
+        // - keyguard is visible
+        // - policy is performing key chording
+        //return ! isScreenOn || keyguardVisible || chording;
+        return true; // XXX stubbed out for now
+    }
 }
 
 bool NativeInputManager::checkAndClearExceptionFromCallback(JNIEnv* env, const char* methodName) {
@@ -546,39 +562,22 @@
 }
 
 bool NativeInputManager::isScreenOn() {
-    JNIEnv* env = jniEnv();
-
-    jboolean result = env->CallBooleanMethod(mCallbacksObj, gCallbacksClassInfo.isScreenOn);
-    if (checkAndClearExceptionFromCallback(env, "isScreenOn")) {
-        return true;
-    }
-    return result;
+    return android_server_PowerManagerService_isScreenOn();
 }
 
 bool NativeInputManager::isScreenBright() {
-    JNIEnv* env = jniEnv();
-
-    jboolean result = env->CallBooleanMethod(mCallbacksObj, gCallbacksClassInfo.isScreenBright);
-    if (checkAndClearExceptionFromCallback(env, "isScreenBright")) {
-        return true;
-    }
-    return result;
+    return android_server_PowerManagerService_isScreenBright();
 }
 
-void NativeInputManager::virtualKeyFeedback(nsecs_t when, int32_t deviceId,
-        int32_t action, int32_t flags, int32_t keyCode,
-        int32_t scanCode, int32_t metaState, nsecs_t downTime) {
+void NativeInputManager::virtualKeyDownFeedback() {
 #if DEBUG_INPUT_READER_POLICY
-    LOGD("virtualKeyFeedback - when=%lld, deviceId=%d, action=%d, flags=%d, keyCode=%d, "
-            "scanCode=%d, metaState=%d, downTime=%lld",
-            when, deviceId, action, flags, keyCode, scanCode, metaState, downTime);
+    LOGD("virtualKeyDownFeedback");
 #endif
 
     JNIEnv* env = jniEnv();
 
-    env->CallVoidMethod(mCallbacksObj, gCallbacksClassInfo.virtualKeyFeedback,
-            when, deviceId, action, flags, keyCode, scanCode, metaState, downTime);
-    checkAndClearExceptionFromCallback(env, "virtualKeyFeedback");
+    env->CallVoidMethod(mCallbacksObj, gCallbacksClassInfo.virtualKeyDownFeedback);
+    checkAndClearExceptionFromCallback(env, "virtualKeyDownFeedback");
 }
 
 int32_t NativeInputManager::interceptKey(nsecs_t when,
@@ -593,16 +592,21 @@
     const int32_t WM_ACTION_POKE_USER_ACTIVITY = 2;
     const int32_t WM_ACTION_GO_TO_SLEEP = 4;
 
-    JNIEnv* env = jniEnv();
-
     bool isScreenOn = this->isScreenOn();
     bool isScreenBright = this->isScreenBright();
 
-    jint wmActions = env->CallIntMethod(mCallbacksObj,
-            gCallbacksClassInfo.interceptKeyBeforeQueueing,
-            deviceId, EV_KEY, scanCode, keyCode, policyFlags, down ? 1 : 0, when, isScreenOn);
-    if (checkAndClearExceptionFromCallback(env, "interceptKeyBeforeQueueing")) {
-        wmActions = 0;
+    jint wmActions = 0;
+    if (isPolicyKey(keyCode, isScreenOn)) {
+        JNIEnv* env = jniEnv();
+
+        wmActions = env->CallIntMethod(mCallbacksObj,
+                gCallbacksClassInfo.interceptKeyBeforeQueueing,
+                when, keyCode, down, policyFlags, isScreenOn);
+        if (checkAndClearExceptionFromCallback(env, "interceptKeyBeforeQueueing")) {
+            wmActions = 0;
+        }
+    } else {
+        wmActions = WM_ACTION_PASS_TO_USER;
     }
 
     int32_t actions = InputReaderPolicyInterface::ACTION_NONE;
@@ -617,8 +621,7 @@
     }
 
     if (wmActions & WM_ACTION_GO_TO_SLEEP) {
-        env->CallVoidMethod(mCallbacksObj, gCallbacksClassInfo.goToSleep, when);
-        checkAndClearExceptionFromCallback(env, "goToSleep");
+        android_server_PowerManagerService_goToSleep(when);
     }
 
     if (wmActions & WM_ACTION_POKE_USER_ACTIVITY) {
@@ -629,6 +632,8 @@
         actions |= InputReaderPolicyInterface::ACTION_DISPATCH;
 
         if (down && isAppSwitchKey(keyCode)) {
+            JNIEnv* env = jniEnv();
+
             env->CallVoidMethod(mCallbacksObj, gCallbacksClassInfo.notifyAppSwitchComing);
             checkAndClearExceptionFromCallback(env, "notifyAppSwitchComing");
 
@@ -1531,11 +1536,13 @@
         windowType = focusedWindow->layoutParamsType;
     } // release lock
 
-    const InputTarget& target = outTargets.top();
-    bool consumed = interceptKeyBeforeDispatching(target, keyEvent, policyFlags);
-    if (consumed) {
-        outTargets.clear();
-        return INPUT_EVENT_INJECTION_SUCCEEDED;
+    if (isPolicyKey(keyEvent->getKeyCode(), isScreenOn())) {
+        const InputTarget& target = outTargets.top();
+        bool consumed = interceptKeyBeforeDispatching(target, keyEvent, policyFlags);
+        if (consumed) {
+            outTargets.clear();
+            return INPUT_EVENT_INJECTION_SUCCEEDED;
+        }
     }
 
     pokeUserActivityIfNeeded(windowType, POWER_MANAGER_BUTTON_EVENT);
@@ -1552,11 +1559,11 @@
 
     switch (motionEvent->getNature()) {
     case INPUT_EVENT_NATURE_TRACKBALL:
-        return identifyTrackballEventTargets(motionEvent, policyFlags, injectorPid, injectorUid,
+        return waitForTrackballEventTargets(motionEvent, policyFlags, injectorPid, injectorUid,
                 outTargets);
 
     case INPUT_EVENT_NATURE_TOUCH:
-        return identifyTouchEventTargets(motionEvent, policyFlags, injectorPid, injectorUid,
+        return waitForTouchEventTargets(motionEvent, policyFlags, injectorPid, injectorUid,
                 outTargets);
 
     default:
@@ -1565,11 +1572,11 @@
     }
 }
 
-int32_t NativeInputManager::identifyTrackballEventTargets(MotionEvent* motionEvent,
+int32_t NativeInputManager::waitForTrackballEventTargets(MotionEvent* motionEvent,
         uint32_t policyFlags, int32_t injectorPid, int32_t injectorUid,
         Vector<InputTarget>& outTargets) {
 #if DEBUG_INPUT_DISPATCHER_POLICY
-    LOGD("identifyTrackballEventTargets - policyFlags=%d, injectorPid=%d, injectorUid=%d",
+    LOGD("waitForTrackballEventTargets - policyFlags=%d, injectorPid=%d, injectorUid=%d",
             policyFlags, injectorPid, injectorUid);
 #endif
 
@@ -1591,11 +1598,11 @@
     return INPUT_EVENT_INJECTION_SUCCEEDED;
 }
 
-int32_t NativeInputManager::identifyTouchEventTargets(MotionEvent* motionEvent,
+int32_t NativeInputManager::waitForTouchEventTargets(MotionEvent* motionEvent,
         uint32_t policyFlags, int32_t injectorPid, int32_t injectorUid,
         Vector<InputTarget>& outTargets) {
 #if DEBUG_INPUT_DISPATCHER_POLICY
-    LOGD("identifyTouchEventTargets - policyFlags=%d, injectorPid=%d, injectorUid=%d",
+    LOGD("waitForTouchEventTargets - policyFlags=%d, injectorPid=%d, injectorUid=%d",
             policyFlags, injectorPid, injectorUid);
 #endif
 
@@ -1642,8 +1649,8 @@
     if (inputChannelObj) {
         jboolean consumed = env->CallBooleanMethod(mCallbacksObj,
                 gCallbacksClassInfo.interceptKeyBeforeDispatching,
-                inputChannelObj, keyEvent->getKeyCode(), keyEvent->getMetaState(),
-                keyEvent->getAction() == KEY_EVENT_ACTION_DOWN,
+                inputChannelObj, keyEvent->getAction(), keyEvent->getFlags(),
+                keyEvent->getKeyCode(), keyEvent->getMetaState(),
                 keyEvent->getRepeatCount(), policyFlags);
         bool error = checkAndClearExceptionFromCallback(env, "interceptKeyBeforeDispatching");
 
@@ -1665,10 +1672,7 @@
 }
 
 void NativeInputManager::pokeUserActivity(nsecs_t eventTime, int32_t eventType) {
-    JNIEnv* env = jniEnv();
-    env->CallVoidMethod(mCallbacksObj, gCallbacksClassInfo.pokeUserActivity,
-            eventTime, eventType);
-    checkAndClearExceptionFromCallback(env, "pokeUserActivity");
+    android_server_PowerManagerService_userActivity(eventTime, eventType);
 }
 
 void NativeInputManager::dumpDispatchStateLd() {
@@ -2082,12 +2086,6 @@
 
     FIND_CLASS(gCallbacksClassInfo.clazz, "com/android/server/InputManager$Callbacks");
 
-    GET_METHOD_ID(gCallbacksClassInfo.isScreenOn, gCallbacksClassInfo.clazz,
-            "isScreenOn", "()Z");
-
-    GET_METHOD_ID(gCallbacksClassInfo.isScreenBright, gCallbacksClassInfo.clazz,
-            "isScreenBright", "()Z");
-
     GET_METHOD_ID(gCallbacksClassInfo.notifyConfigurationChanged, gCallbacksClassInfo.clazz,
             "notifyConfigurationChanged", "(JIII)V");
 
@@ -2106,24 +2104,18 @@
     GET_METHOD_ID(gCallbacksClassInfo.notifyANR, gCallbacksClassInfo.clazz,
             "notifyANR", "(Ljava/lang/Object;)J");
 
-    GET_METHOD_ID(gCallbacksClassInfo.virtualKeyFeedback, gCallbacksClassInfo.clazz,
-            "virtualKeyFeedback", "(JIIIIIIJ)V");
+    GET_METHOD_ID(gCallbacksClassInfo.virtualKeyDownFeedback, gCallbacksClassInfo.clazz,
+            "virtualKeyDownFeedback", "()V");
 
     GET_METHOD_ID(gCallbacksClassInfo.interceptKeyBeforeQueueing, gCallbacksClassInfo.clazz,
-            "interceptKeyBeforeQueueing", "(IIIIIIJZ)I");
+            "interceptKeyBeforeQueueing", "(JIZIZ)I");
 
     GET_METHOD_ID(gCallbacksClassInfo.interceptKeyBeforeDispatching, gCallbacksClassInfo.clazz,
-            "interceptKeyBeforeDispatching", "(Landroid/view/InputChannel;IIZII)Z");
+            "interceptKeyBeforeDispatching", "(Landroid/view/InputChannel;IIIIII)Z");
 
     GET_METHOD_ID(gCallbacksClassInfo.checkInjectEventsPermission, gCallbacksClassInfo.clazz,
             "checkInjectEventsPermission", "(II)Z");
 
-    GET_METHOD_ID(gCallbacksClassInfo.goToSleep, gCallbacksClassInfo.clazz,
-            "goToSleep", "(J)V");
-
-    GET_METHOD_ID(gCallbacksClassInfo.pokeUserActivity, gCallbacksClassInfo.clazz,
-            "pokeUserActivity", "(JI)V");
-
     GET_METHOD_ID(gCallbacksClassInfo.notifyAppSwitchComing, gCallbacksClassInfo.clazz,
             "notifyAppSwitchComing", "()V");
 
diff --git a/services/jni/com_android_server_KeyInputQueue.cpp b/services/jni/com_android_server_KeyInputQueue.cpp
deleted file mode 100644
index f9e3585..0000000
--- a/services/jni/com_android_server_KeyInputQueue.cpp
+++ /dev/null
@@ -1,358 +0,0 @@
-/*
- * Copyright (C) 2007 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#define LOG_TAG "Input"
-
-#include "jni.h"
-#include "JNIHelp.h"
-#include <utils/misc.h>
-#include <utils/Log.h>
-
-#include <ui/EventHub.h>
-#include <utils/threads.h>
-
-#include <stdio.h>
-
-namespace android {
-
-// ----------------------------------------------------------------------------
-
-static struct input_offsets_t
-{
-    jfieldID mMinValue;
-    jfieldID mMaxValue;
-    jfieldID mFlat;
-    jfieldID mFuzz;
-    
-    jfieldID mDeviceId;
-    jfieldID mType;
-    jfieldID mScancode;
-    jfieldID mKeycode;
-    jfieldID mFlags;
-    jfieldID mValue;
-    jfieldID mWhen;
-} gInputOffsets;
-
-// ----------------------------------------------------------------------------
-
-static Mutex gLock;
-static sp<EventHub> gHub;
-
-static jboolean
-android_server_KeyInputQueue_readEvent(JNIEnv* env, jobject clazz,
-                                          jobject event)
-{
-    gLock.lock();
-    sp<EventHub> hub = gHub;
-    if (hub == NULL) {
-        hub = new EventHub;
-        gHub = hub;
-    }
-    gLock.unlock();
-
-    int32_t deviceId;
-    int32_t type;
-    int32_t scancode, keycode;
-    uint32_t flags;
-    int32_t value;
-    nsecs_t when;
-    bool res = hub->getEvent(&deviceId, &type, &scancode, &keycode,
-            &flags, &value, &when);
-
-    env->SetIntField(event, gInputOffsets.mDeviceId, (jint)deviceId);
-    env->SetIntField(event, gInputOffsets.mType, (jint)type);
-    env->SetIntField(event, gInputOffsets.mScancode, (jint)scancode);
-    env->SetIntField(event, gInputOffsets.mKeycode, (jint)keycode);
-    env->SetIntField(event, gInputOffsets.mFlags, (jint)flags);
-    env->SetIntField(event, gInputOffsets.mValue, value);
-    env->SetLongField(event, gInputOffsets.mWhen,
-                        (jlong)(nanoseconds_to_milliseconds(when)));
-
-    return res;
-}
-
-static jint
-android_server_KeyInputQueue_getDeviceClasses(JNIEnv* env, jobject clazz,
-                                              jint deviceId)
-{
-    jint classes = 0;
-    gLock.lock();
-    if (gHub != NULL) classes = gHub->getDeviceClasses(deviceId);
-    gLock.unlock();
-    return classes;
-}
-
-static jstring
-android_server_KeyInputQueue_getDeviceName(JNIEnv* env, jobject clazz,
-                                              jint deviceId)
-{
-    String8 name;
-    gLock.lock();
-    if (gHub != NULL) name = gHub->getDeviceName(deviceId);
-    gLock.unlock();
-    
-    if (name.size() > 0) {
-        return env->NewStringUTF(name.string());
-    }
-    return NULL;
-}
-
-static void
-android_server_KeyInputQueue_addExcludedDevice(JNIEnv* env, jobject clazz,
-                                              jstring deviceName)
-{
-    gLock.lock();
-    sp<EventHub> hub = gHub;
-    if (hub == NULL) {
-        hub = new EventHub;
-        gHub = hub;
-    }
-    gLock.unlock();
-
-    const char* nameStr = env->GetStringUTFChars(deviceName, NULL);
-    gHub->addExcludedDevice(nameStr);
-    env->ReleaseStringUTFChars(deviceName, nameStr);
-}
-
-static jboolean
-android_server_KeyInputQueue_getAbsoluteInfo(JNIEnv* env, jobject clazz,
-                                             jint deviceId, jint axis,
-                                             jobject info)
-{
-    int32_t minValue, maxValue, flat, fuzz;
-    int res = -1;
-    gLock.lock();
-    if (gHub != NULL) {
-        res = gHub->getAbsoluteInfo(deviceId, axis,
-                &minValue, &maxValue, &flat, &fuzz);
-    }
-    gLock.unlock();
-    
-    if (res < 0) return JNI_FALSE;
-    
-    env->SetIntField(info, gInputOffsets.mMinValue, (jint)minValue);
-    env->SetIntField(info, gInputOffsets.mMaxValue, (jint)maxValue);
-    env->SetIntField(info, gInputOffsets.mFlat, (jint)flat);
-    env->SetIntField(info, gInputOffsets.mFuzz, (jint)fuzz);
-    return JNI_TRUE;
-}
-
-static jint
-android_server_KeyInputQueue_getSwitchState(JNIEnv* env, jobject clazz,
-                                           jint sw)
-{
-    jint st = -1;
-    gLock.lock();
-    if (gHub != NULL) st = gHub->getSwitchState(-1, -1, sw);
-    gLock.unlock();
-    
-    return st;
-}
-
-static jint
-android_server_KeyInputQueue_getSwitchStateDevice(JNIEnv* env, jobject clazz,
-                                            jint deviceId, jint sw)
-{
-    jint st = -1;
-    gLock.lock();
-    if (gHub != NULL) st = gHub->getSwitchState(deviceId, -1, sw);
-    gLock.unlock();
-    
-    return st;
-}
-
-static jint
-android_server_KeyInputQueue_getScancodeState(JNIEnv* env, jobject clazz,
-                                           jint sw)
-{
-    jint st = -1;
-    gLock.lock();
-    if (gHub != NULL) st = gHub->getScanCodeState(0, -1, sw);
-    gLock.unlock();
-    
-    return st;
-}
-
-static jint
-android_server_KeyInputQueue_getScancodeStateDevice(JNIEnv* env, jobject clazz,
-                                            jint deviceId, jint sw)
-{
-    jint st = -1;
-    gLock.lock();
-    if (gHub != NULL) st = gHub->getScanCodeState(deviceId, -1, sw);
-    gLock.unlock();
-    
-    return st;
-}
-
-static jint
-android_server_KeyInputQueue_getKeycodeState(JNIEnv* env, jobject clazz,
-                                           jint sw)
-{
-    jint st = -1;
-    gLock.lock();
-    if (gHub != NULL) st = gHub->getKeyCodeState(0, -1, sw);
-    gLock.unlock();
-    
-    return st;
-}
-
-static jint
-android_server_KeyInputQueue_getKeycodeStateDevice(JNIEnv* env, jobject clazz,
-                                            jint deviceId, jint sw)
-{
-    jint st = -1;
-    gLock.lock();
-    if (gHub != NULL) st = gHub->getKeyCodeState(deviceId,-1, sw);
-    gLock.unlock();
-    
-    return st;
-}
-
-static jint
-android_server_KeyInputQueue_scancodeToKeycode(JNIEnv* env, jobject clazz,
-                                            jint deviceId, jint scancode)
-{
-    jint res = 0;
-    gLock.lock();
-    if (gHub != NULL) {
-        int32_t keycode;
-        uint32_t flags;
-        gHub->scancodeToKeycode(deviceId, scancode, &keycode, &flags);
-        res = keycode;
-    }
-    gLock.unlock();
-    
-    return res;
-}
-
-static jboolean
-android_server_KeyInputQueue_hasKeys(JNIEnv* env, jobject clazz,
-                                     jintArray keyCodes, jbooleanArray outFlags)
-{
-    jboolean ret = JNI_FALSE;
-
-    int32_t* codes = env->GetIntArrayElements(keyCodes, NULL);
-    uint8_t* flags = env->GetBooleanArrayElements(outFlags, NULL);
-    jsize numCodes = env->GetArrayLength(keyCodes);
-    if (numCodes == env->GetArrayLength(outFlags)) {
-        gLock.lock();
-        if (gHub != NULL) ret = gHub->hasKeys(numCodes, codes, flags);
-        gLock.unlock();
-    }
-
-    env->ReleaseBooleanArrayElements(outFlags, flags, 0);
-    env->ReleaseIntArrayElements(keyCodes, codes, 0);
-    return ret;
-}
-
-// ----------------------------------------------------------------------------
-
-/*
- * JNI registration.
- */
-static JNINativeMethod gInputMethods[] = {
-    /* name, signature, funcPtr */
-    { "readEvent",       "(Landroid/view/RawInputEvent;)Z",
-            (void*) android_server_KeyInputQueue_readEvent },
-    { "getDeviceClasses", "(I)I",
-        (void*) android_server_KeyInputQueue_getDeviceClasses },
-    { "getDeviceName", "(I)Ljava/lang/String;",
-        (void*) android_server_KeyInputQueue_getDeviceName },
-    { "addExcludedDevice", "(Ljava/lang/String;)V",
-        (void*) android_server_KeyInputQueue_addExcludedDevice },
-    { "getAbsoluteInfo", "(IILcom/android/server/InputDevice$AbsoluteInfo;)Z",
-        (void*) android_server_KeyInputQueue_getAbsoluteInfo },
-    { "getSwitchState", "(I)I",
-        (void*) android_server_KeyInputQueue_getSwitchState },
-    { "getSwitchState", "(II)I",
-        (void*) android_server_KeyInputQueue_getSwitchStateDevice },
-    { "nativeGetScancodeState", "(I)I",
-        (void*) android_server_KeyInputQueue_getScancodeState },
-    { "nativeGetScancodeState", "(II)I",
-        (void*) android_server_KeyInputQueue_getScancodeStateDevice },
-    { "nativeGetKeycodeState", "(I)I",
-        (void*) android_server_KeyInputQueue_getKeycodeState },
-    { "nativeGetKeycodeState", "(II)I",
-        (void*) android_server_KeyInputQueue_getKeycodeStateDevice },
-    { "hasKeys", "([I[Z)Z",
-        (void*) android_server_KeyInputQueue_hasKeys },
-    { "scancodeToKeycode", "(II)I",
-        (void*) android_server_KeyInputQueue_scancodeToKeycode },
-};
-
-int register_android_server_KeyInputQueue(JNIEnv* env)
-{
-    jclass input = env->FindClass("com/android/server/KeyInputQueue");
-    LOG_FATAL_IF(input == NULL, "Unable to find class com/android/server/KeyInputQueue");
-    int res = jniRegisterNativeMethods(env, "com/android/server/KeyInputQueue",
-                                        gInputMethods, NELEM(gInputMethods));
-
-    jclass absoluteInfo = env->FindClass("com/android/server/InputDevice$AbsoluteInfo");
-    LOG_FATAL_IF(absoluteInfo == NULL, "Unable to find class com/android/server/InputDevice$AbsoluteInfo");
-    
-    gInputOffsets.mMinValue
-        = env->GetFieldID(absoluteInfo, "minValue", "I");
-    LOG_FATAL_IF(gInputOffsets.mMinValue == NULL, "Unable to find InputDevice.AbsoluteInfo.minValue");
-    
-    gInputOffsets.mMaxValue
-        = env->GetFieldID(absoluteInfo, "maxValue", "I");
-    LOG_FATAL_IF(gInputOffsets.mMaxValue == NULL, "Unable to find InputDevice.AbsoluteInfo.maxValue");
-    
-    gInputOffsets.mFlat
-        = env->GetFieldID(absoluteInfo, "flat", "I");
-    LOG_FATAL_IF(gInputOffsets.mFlat == NULL, "Unable to find InputDevice.AbsoluteInfo.flat");
-    
-    gInputOffsets.mFuzz
-        = env->GetFieldID(absoluteInfo, "fuzz", "I");
-    LOG_FATAL_IF(gInputOffsets.mFuzz == NULL, "Unable to find InputDevice.AbsoluteInfo.fuzz");
-    
-    jclass inputEvent = env->FindClass("android/view/RawInputEvent");
-    LOG_FATAL_IF(inputEvent == NULL, "Unable to find class android/view/RawInputEvent");
-
-    gInputOffsets.mDeviceId
-        = env->GetFieldID(inputEvent, "deviceId", "I");
-    LOG_FATAL_IF(gInputOffsets.mDeviceId == NULL, "Unable to find RawInputEvent.deviceId");
-    
-    gInputOffsets.mType
-        = env->GetFieldID(inputEvent, "type", "I");
-    LOG_FATAL_IF(gInputOffsets.mType == NULL, "Unable to find RawInputEvent.type");
-    
-    gInputOffsets.mScancode
-        = env->GetFieldID(inputEvent, "scancode", "I");
-    LOG_FATAL_IF(gInputOffsets.mScancode == NULL, "Unable to find RawInputEvent.scancode");
-
-    gInputOffsets.mKeycode
-        = env->GetFieldID(inputEvent, "keycode", "I");
-    LOG_FATAL_IF(gInputOffsets.mKeycode == NULL, "Unable to find RawInputEvent.keycode");
-
-    gInputOffsets.mFlags
-        = env->GetFieldID(inputEvent, "flags", "I");
-    LOG_FATAL_IF(gInputOffsets.mFlags == NULL, "Unable to find RawInputEvent.flags");
-
-    gInputOffsets.mValue
-        = env->GetFieldID(inputEvent, "value", "I");
-    LOG_FATAL_IF(gInputOffsets.mValue == NULL, "Unable to find RawInputEvent.value");
-    
-    gInputOffsets.mWhen
-        = env->GetFieldID(inputEvent, "when", "J");
-    LOG_FATAL_IF(gInputOffsets.mWhen == NULL, "Unable to find RawInputEvent.when");
-
-    return res;
-}
-
-}; // namespace android
-
diff --git a/services/jni/com_android_server_PowerManagerService.cpp b/services/jni/com_android_server_PowerManagerService.cpp
new file mode 100644
index 0000000..b80dbc5
--- /dev/null
+++ b/services/jni/com_android_server_PowerManagerService.cpp
@@ -0,0 +1,142 @@
+/*
+ * 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.
+ */
+
+#define LOG_TAG "PowerManagerService-JNI"
+
+//#define LOG_NDEBUG 0
+
+#include "JNIHelp.h"
+#include "jni.h"
+#include <limits.h>
+#include <android_runtime/AndroidRuntime.h>
+#include "com_android_server_PowerManagerService.h"
+
+namespace android {
+
+// ----------------------------------------------------------------------------
+
+static struct {
+    jclass clazz;
+
+    jmethodID goToSleep;
+    jmethodID userActivity;
+} gPowerManagerServiceClassInfo;
+
+// ----------------------------------------------------------------------------
+
+static jobject gPowerManagerServiceObj;
+
+static Mutex gPowerManagerLock;
+static bool gScreenOn;
+static bool gScreenBright;
+
+// ----------------------------------------------------------------------------
+
+static bool checkAndClearExceptionFromCallback(JNIEnv* env, const char* methodName) {
+    if (env->ExceptionCheck()) {
+        LOGE("An exception was thrown by callback '%s'.", methodName);
+        LOGE_EX(env);
+        env->ExceptionClear();
+        return true;
+    }
+    return false;
+}
+
+bool android_server_PowerManagerService_isScreenOn() {
+    AutoMutex _l(gPowerManagerLock);
+    return gScreenOn;
+}
+
+bool android_server_PowerManagerService_isScreenBright() {
+    AutoMutex _l(gPowerManagerLock);
+    return gScreenBright;
+}
+
+void android_server_PowerManagerService_userActivity(nsecs_t eventTime, int32_t eventType) {
+    if (gPowerManagerServiceObj) {
+        JNIEnv* env = AndroidRuntime::getJNIEnv();
+
+        env->CallVoidMethod(gPowerManagerServiceObj, gPowerManagerServiceClassInfo.userActivity,
+                nanoseconds_to_milliseconds(eventTime), false, eventType, false);
+        checkAndClearExceptionFromCallback(env, "userActivity");
+    }
+}
+
+void android_server_PowerManagerService_goToSleep(nsecs_t eventTime) {
+    if (gPowerManagerServiceObj) {
+        JNIEnv* env = AndroidRuntime::getJNIEnv();
+
+        env->CallVoidMethod(gPowerManagerServiceObj, gPowerManagerServiceClassInfo.goToSleep,
+                nanoseconds_to_milliseconds(eventTime));
+        checkAndClearExceptionFromCallback(env, "goToSleep");
+    }
+}
+
+// ----------------------------------------------------------------------------
+
+static void android_server_PowerManagerService_nativeInit(JNIEnv* env, jobject obj) {
+    gPowerManagerServiceObj = env->NewGlobalRef(obj);
+}
+
+static void android_server_PowerManagerService_nativeSetPowerState(JNIEnv* env,
+        jobject serviceObj, jboolean screenOn, jboolean screenBright) {
+    AutoMutex _l(gPowerManagerLock);
+    gScreenOn = screenOn;
+    gScreenBright = screenBright;
+}
+
+// ----------------------------------------------------------------------------
+
+static JNINativeMethod gPowerManagerServiceMethods[] = {
+    /* name, signature, funcPtr */
+    { "nativeInit", "()V",
+            (void*) android_server_PowerManagerService_nativeInit },
+    { "nativeSetPowerState", "(ZZ)V",
+            (void*) android_server_PowerManagerService_nativeSetPowerState },
+};
+
+#define FIND_CLASS(var, className) \
+        var = env->FindClass(className); \
+        LOG_FATAL_IF(! var, "Unable to find class " className); \
+        var = jclass(env->NewGlobalRef(var));
+
+#define GET_METHOD_ID(var, clazz, methodName, methodDescriptor) \
+        var = env->GetMethodID(clazz, methodName, methodDescriptor); \
+        LOG_FATAL_IF(! var, "Unable to find method " methodName);
+
+#define GET_FIELD_ID(var, clazz, fieldName, fieldDescriptor) \
+        var = env->GetFieldID(clazz, fieldName, fieldDescriptor); \
+        LOG_FATAL_IF(! var, "Unable to find field " fieldName);
+
+int register_android_server_PowerManagerService(JNIEnv* env) {
+    int res = jniRegisterNativeMethods(env, "com/android/server/PowerManagerService",
+            gPowerManagerServiceMethods, NELEM(gPowerManagerServiceMethods));
+    LOG_FATAL_IF(res < 0, "Unable to register native methods.");
+
+    // Callbacks
+
+    FIND_CLASS(gPowerManagerServiceClassInfo.clazz, "com/android/server/PowerManagerService");
+
+    GET_METHOD_ID(gPowerManagerServiceClassInfo.goToSleep, gPowerManagerServiceClassInfo.clazz,
+            "goToSleep", "(J)V");
+
+    GET_METHOD_ID(gPowerManagerServiceClassInfo.userActivity, gPowerManagerServiceClassInfo.clazz,
+            "userActivity", "(JZIZ)V");
+
+    return 0;
+}
+
+} /* namespace android */
diff --git a/services/jni/com_android_server_PowerManagerService.h b/services/jni/com_android_server_PowerManagerService.h
new file mode 100644
index 0000000..9b05f38
--- /dev/null
+++ b/services/jni/com_android_server_PowerManagerService.h
@@ -0,0 +1,42 @@
+/*
+ * 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.
+ */
+
+#ifndef _ANDROID_SERVER_POWER_MANAGER_SERVICE_H
+#define _ANDROID_SERVER_POWER_MANAGER_SERVICE_H
+
+#include "JNIHelp.h"
+#include "jni.h"
+
+namespace android {
+
+enum {
+    POWER_MANAGER_OTHER_EVENT = 0,
+    POWER_MANAGER_CHEEK_EVENT = 1,
+    POWER_MANAGER_TOUCH_EVENT = 2, // touch events are TOUCH for 300ms, and then either
+                                   // up events or LONG_TOUCH events.
+    POWER_MANAGER_LONG_TOUCH_EVENT = 3,
+    POWER_MANAGER_TOUCH_UP_EVENT = 4,
+    POWER_MANAGER_BUTTON_EVENT = 5, // Button and trackball events.
+};
+
+extern bool android_server_PowerManagerService_isScreenOn();
+extern bool android_server_PowerManagerService_isScreenBright();
+extern void android_server_PowerManagerService_userActivity(nsecs_t eventTime, int32_t eventType);
+extern void android_server_PowerManagerService_goToSleep(nsecs_t eventTime);
+
+} // namespace android
+
+#endif // _ANDROID_SERVER_POWER_MANAGER_SERVICE_H
diff --git a/services/jni/onload.cpp b/services/jni/onload.cpp
index a1a6838..1a2d8b6 100644
--- a/services/jni/onload.cpp
+++ b/services/jni/onload.cpp
@@ -6,9 +6,9 @@
 namespace android {
 int register_android_server_AlarmManagerService(JNIEnv* env);
 int register_android_server_BatteryService(JNIEnv* env);
-int register_android_server_KeyInputQueue(JNIEnv* env);
 int register_android_server_InputManager(JNIEnv* env);
 int register_android_server_LightsService(JNIEnv* env);
+int register_android_server_PowerManagerService(JNIEnv* env);
 int register_android_server_SensorService(JNIEnv* env);
 int register_android_server_VibratorService(JNIEnv* env);
 int register_android_server_SystemServer(JNIEnv* env);
@@ -28,7 +28,7 @@
     }
     LOG_ASSERT(env, "Could not retrieve the env!");
 
-    register_android_server_KeyInputQueue(env);
+    register_android_server_PowerManagerService(env);
     register_android_server_InputManager(env);
     register_android_server_LightsService(env);
     register_android_server_AlarmManagerService(env);
diff --git a/libs/surfaceflinger/Android.mk b/services/surfaceflinger/Android.mk
similarity index 100%
rename from libs/surfaceflinger/Android.mk
rename to services/surfaceflinger/Android.mk
diff --git a/libs/surfaceflinger/Barrier.h b/services/surfaceflinger/Barrier.h
similarity index 100%
rename from libs/surfaceflinger/Barrier.h
rename to services/surfaceflinger/Barrier.h
diff --git a/libs/surfaceflinger/BlurFilter.cpp b/services/surfaceflinger/BlurFilter.cpp
similarity index 100%
rename from libs/surfaceflinger/BlurFilter.cpp
rename to services/surfaceflinger/BlurFilter.cpp
diff --git a/libs/surfaceflinger/BlurFilter.h b/services/surfaceflinger/BlurFilter.h
similarity index 100%
rename from libs/surfaceflinger/BlurFilter.h
rename to services/surfaceflinger/BlurFilter.h
diff --git a/libs/surfaceflinger/DisplayHardware/DisplayHardware.cpp b/services/surfaceflinger/DisplayHardware/DisplayHardware.cpp
similarity index 100%
rename from libs/surfaceflinger/DisplayHardware/DisplayHardware.cpp
rename to services/surfaceflinger/DisplayHardware/DisplayHardware.cpp
diff --git a/libs/surfaceflinger/DisplayHardware/DisplayHardware.h b/services/surfaceflinger/DisplayHardware/DisplayHardware.h
similarity index 100%
rename from libs/surfaceflinger/DisplayHardware/DisplayHardware.h
rename to services/surfaceflinger/DisplayHardware/DisplayHardware.h
diff --git a/libs/surfaceflinger/DisplayHardware/DisplayHardwareBase.cpp b/services/surfaceflinger/DisplayHardware/DisplayHardwareBase.cpp
similarity index 100%
rename from libs/surfaceflinger/DisplayHardware/DisplayHardwareBase.cpp
rename to services/surfaceflinger/DisplayHardware/DisplayHardwareBase.cpp
diff --git a/libs/surfaceflinger/DisplayHardware/DisplayHardwareBase.h b/services/surfaceflinger/DisplayHardware/DisplayHardwareBase.h
similarity index 100%
rename from libs/surfaceflinger/DisplayHardware/DisplayHardwareBase.h
rename to services/surfaceflinger/DisplayHardware/DisplayHardwareBase.h
diff --git a/libs/surfaceflinger/GLExtensions.cpp b/services/surfaceflinger/GLExtensions.cpp
similarity index 100%
rename from libs/surfaceflinger/GLExtensions.cpp
rename to services/surfaceflinger/GLExtensions.cpp
diff --git a/libs/surfaceflinger/GLExtensions.h b/services/surfaceflinger/GLExtensions.h
similarity index 100%
rename from libs/surfaceflinger/GLExtensions.h
rename to services/surfaceflinger/GLExtensions.h
diff --git a/libs/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
similarity index 100%
rename from libs/surfaceflinger/Layer.cpp
rename to services/surfaceflinger/Layer.cpp
diff --git a/libs/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h
similarity index 100%
rename from libs/surfaceflinger/Layer.h
rename to services/surfaceflinger/Layer.h
diff --git a/libs/surfaceflinger/LayerBase.cpp b/services/surfaceflinger/LayerBase.cpp
similarity index 100%
rename from libs/surfaceflinger/LayerBase.cpp
rename to services/surfaceflinger/LayerBase.cpp
diff --git a/libs/surfaceflinger/LayerBase.h b/services/surfaceflinger/LayerBase.h
similarity index 100%
rename from libs/surfaceflinger/LayerBase.h
rename to services/surfaceflinger/LayerBase.h
diff --git a/libs/surfaceflinger/LayerBlur.cpp b/services/surfaceflinger/LayerBlur.cpp
similarity index 100%
rename from libs/surfaceflinger/LayerBlur.cpp
rename to services/surfaceflinger/LayerBlur.cpp
diff --git a/libs/surfaceflinger/LayerBlur.h b/services/surfaceflinger/LayerBlur.h
similarity index 100%
rename from libs/surfaceflinger/LayerBlur.h
rename to services/surfaceflinger/LayerBlur.h
diff --git a/libs/surfaceflinger/LayerBuffer.cpp b/services/surfaceflinger/LayerBuffer.cpp
similarity index 100%
rename from libs/surfaceflinger/LayerBuffer.cpp
rename to services/surfaceflinger/LayerBuffer.cpp
diff --git a/libs/surfaceflinger/LayerBuffer.h b/services/surfaceflinger/LayerBuffer.h
similarity index 100%
rename from libs/surfaceflinger/LayerBuffer.h
rename to services/surfaceflinger/LayerBuffer.h
diff --git a/libs/surfaceflinger/LayerDim.cpp b/services/surfaceflinger/LayerDim.cpp
similarity index 100%
rename from libs/surfaceflinger/LayerDim.cpp
rename to services/surfaceflinger/LayerDim.cpp
diff --git a/libs/surfaceflinger/LayerDim.h b/services/surfaceflinger/LayerDim.h
similarity index 100%
rename from libs/surfaceflinger/LayerDim.h
rename to services/surfaceflinger/LayerDim.h
diff --git a/libs/surfaceflinger/MODULE_LICENSE_APACHE2 b/services/surfaceflinger/MODULE_LICENSE_APACHE2
similarity index 100%
rename from libs/surfaceflinger/MODULE_LICENSE_APACHE2
rename to services/surfaceflinger/MODULE_LICENSE_APACHE2
diff --git a/libs/surfaceflinger/MessageQueue.cpp b/services/surfaceflinger/MessageQueue.cpp
similarity index 100%
rename from libs/surfaceflinger/MessageQueue.cpp
rename to services/surfaceflinger/MessageQueue.cpp
diff --git a/libs/surfaceflinger/MessageQueue.h b/services/surfaceflinger/MessageQueue.h
similarity index 100%
rename from libs/surfaceflinger/MessageQueue.h
rename to services/surfaceflinger/MessageQueue.h
diff --git a/libs/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
similarity index 98%
rename from libs/surfaceflinger/SurfaceFlinger.cpp
rename to services/surfaceflinger/SurfaceFlinger.cpp
index 68e8f19..3167c4c 100644
--- a/libs/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -63,20 +63,6 @@
 #define DISPLAY_COUNT       1
 
 namespace android {
-
-// ---------------------------------------------------------------------------
-
-void SurfaceFlinger::instantiate() {
-    defaultServiceManager()->addService(
-            String16("SurfaceFlinger"), new SurfaceFlinger());
-}
-
-void SurfaceFlinger::shutdown() {
-    // we should unregister here, but not really because
-    // when (if) the service manager goes away, all the services
-    // it has a reference to will leave too.
-}
-
 // ---------------------------------------------------------------------------
 
 SurfaceFlinger::LayerVector::LayerVector(const SurfaceFlinger::LayerVector& rhs)
diff --git a/libs/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
similarity index 98%
rename from libs/surfaceflinger/SurfaceFlinger.h
rename to services/surfaceflinger/SurfaceFlinger.h
index 0bfc170..8821e5c 100644
--- a/libs/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -29,6 +29,7 @@
 
 #include <binder/IMemory.h>
 #include <binder/Permission.h>
+#include <binder/BinderService.h>
 
 #include <ui/PixelFormat.h>
 #include <surfaceflinger/ISurfaceComposer.h>
@@ -167,11 +168,13 @@
     eTraversalNeeded        = 0x02
 };
 
-class SurfaceFlinger : public BnSurfaceComposer, protected Thread
+class SurfaceFlinger :
+        public BinderService<SurfaceFlinger>,
+        public BnSurfaceComposer,
+        protected Thread
 {
 public:
-    static void instantiate();
-    static void shutdown();
+    static char const* getServiceName() { return "SurfaceFlinger"; }
 
                     SurfaceFlinger();
     virtual         ~SurfaceFlinger();
diff --git a/libs/surfaceflinger/TextureManager.cpp b/services/surfaceflinger/TextureManager.cpp
similarity index 99%
rename from libs/surfaceflinger/TextureManager.cpp
rename to services/surfaceflinger/TextureManager.cpp
index 6526032..3b326df 100644
--- a/libs/surfaceflinger/TextureManager.cpp
+++ b/services/surfaceflinger/TextureManager.cpp
@@ -107,7 +107,6 @@
 {
     switch (format) {
     case HAL_PIXEL_FORMAT_YV12:
-    case HAL_PIXEL_FORMAT_YV16:
         return true;
     }
     return false;
@@ -118,7 +117,6 @@
     switch (format) {
     // supported YUV formats
     case HAL_PIXEL_FORMAT_YV12:
-    case HAL_PIXEL_FORMAT_YV16:
     // Legacy/deprecated YUV formats
     case HAL_PIXEL_FORMAT_YCbCr_422_SP:
     case HAL_PIXEL_FORMAT_YCrCb_420_SP:
diff --git a/libs/surfaceflinger/TextureManager.h b/services/surfaceflinger/TextureManager.h
similarity index 100%
rename from libs/surfaceflinger/TextureManager.h
rename to services/surfaceflinger/TextureManager.h
diff --git a/libs/surfaceflinger/Transform.cpp b/services/surfaceflinger/Transform.cpp
similarity index 100%
rename from libs/surfaceflinger/Transform.cpp
rename to services/surfaceflinger/Transform.cpp
diff --git a/libs/surfaceflinger/Transform.h b/services/surfaceflinger/Transform.h
similarity index 100%
rename from libs/surfaceflinger/Transform.h
rename to services/surfaceflinger/Transform.h
diff --git a/libs/surfaceflinger/clz.cpp b/services/surfaceflinger/clz.cpp
similarity index 100%
rename from libs/surfaceflinger/clz.cpp
rename to services/surfaceflinger/clz.cpp
diff --git a/libs/surfaceflinger/clz.h b/services/surfaceflinger/clz.h
similarity index 100%
rename from libs/surfaceflinger/clz.h
rename to services/surfaceflinger/clz.h
diff --git a/libs/surfaceflinger/tests/Android.mk b/services/surfaceflinger/tests/Android.mk
similarity index 100%
rename from libs/surfaceflinger/tests/Android.mk
rename to services/surfaceflinger/tests/Android.mk
diff --git a/libs/surfaceflinger/tests/overlays/Android.mk b/services/surfaceflinger/tests/overlays/Android.mk
similarity index 100%
rename from libs/surfaceflinger/tests/overlays/Android.mk
rename to services/surfaceflinger/tests/overlays/Android.mk
diff --git a/libs/surfaceflinger/tests/overlays/overlays.cpp b/services/surfaceflinger/tests/overlays/overlays.cpp
similarity index 100%
rename from libs/surfaceflinger/tests/overlays/overlays.cpp
rename to services/surfaceflinger/tests/overlays/overlays.cpp
diff --git a/libs/surfaceflinger/tests/resize/Android.mk b/services/surfaceflinger/tests/resize/Android.mk
similarity index 100%
rename from libs/surfaceflinger/tests/resize/Android.mk
rename to services/surfaceflinger/tests/resize/Android.mk
diff --git a/libs/surfaceflinger/tests/resize/resize.cpp b/services/surfaceflinger/tests/resize/resize.cpp
similarity index 100%
rename from libs/surfaceflinger/tests/resize/resize.cpp
rename to services/surfaceflinger/tests/resize/resize.cpp
diff --git a/telephony/java/com/android/internal/telephony/DataConnectionTracker.java b/telephony/java/com/android/internal/telephony/DataConnectionTracker.java
index e71fe2e..06807c6 100644
--- a/telephony/java/com/android/internal/telephony/DataConnectionTracker.java
+++ b/telephony/java/com/android/internal/telephony/DataConnectionTracker.java
@@ -17,6 +17,7 @@
 package com.android.internal.telephony;
 
 import android.app.PendingIntent;
+import android.net.NetworkProperties;
 import android.os.AsyncResult;
 import android.os.Handler;
 import android.os.Message;
@@ -26,6 +27,10 @@
 import android.text.TextUtils;
 import android.util.Log;
 
+import java.net.InetAddress;
+import java.net.NetworkInterface;
+import java.net.SocketException;
+import java.net.UnknownHostException;
 import java.util.ArrayList;
 
 /**
@@ -191,6 +196,9 @@
     /** indication of our availability (preconditions to trysetupData are met) **/
     protected boolean mAvailability = false;
 
+    /** all our network properties (dns, gateway, ip, etc) */
+    protected NetworkProperties mNetworkProperties;
+
     /**
      * Default constructor
      */
@@ -424,6 +432,15 @@
 
     protected abstract void setState(State s);
 
+    protected NetworkProperties getNetworkProperties(String apnType) {
+        int id = apnTypeToId(apnType);
+        if (isApnIdEnabled(id)) {
+            return mNetworkProperties;
+        } else {
+            return null;
+        }
+    }
+
     // tell all active apns of the current condition
     protected void notifyDataConnection(String reason) {
         for (int id = 0; id < APN_NUM_TYPES; id++) {
@@ -668,5 +685,43 @@
         }
     }
 
+    protected NetworkProperties makeNetworkProperties(DataConnection connection) {
+        NetworkProperties properties = new NetworkProperties();
+        try {
+            properties.setInterface(NetworkInterface.getByName(connection.getInterface()));
+        } catch (SocketException e) {
+            Log.e(LOG_TAG, "SocketException creating NetworkInterface: " + e);
+        } catch (NullPointerException e) {
+            Log.e(LOG_TAG, "NPE trying to makeNetworkProperties: " + e);
+        }
 
+        try {
+            properties.addAddress(InetAddress.getByName(connection.getIpAddress()));
+        } catch (UnknownHostException e) {
+            Log.e(LOG_TAG, "UnknownHostException setting IpAddress: " + e);
+        } catch (SecurityException e) {
+            Log.e(LOG_TAG, "SecurityException setting IpAddress: " + e);
+        }
+
+        try {
+            properties.setGateway(InetAddress.getByName(connection.getGatewayAddress()));
+        } catch (UnknownHostException e) {
+            Log.e(LOG_TAG, "UnknownHostException setting GatewayAddress: " + e);
+        } catch (SecurityException e) {
+            Log.e(LOG_TAG, "SecurityException setting GatewayAddress: " + e);
+        }
+
+        try {
+            String[] dnsStrings = connection.getDnsServers();
+            for (int i = 0; i<dnsStrings.length; i++) {
+                properties.addDns(InetAddress.getByName(dnsStrings[i]));
+            }
+        } catch (UnknownHostException e) {
+            Log.e(LOG_TAG, "UnknownHostException setting DnsAddress: " + e);
+        } catch (SecurityException e) {
+            Log.e(LOG_TAG, "SecurityException setting DnsAddress: " + e);
+        }
+        // TODO - set Proxy info
+        return properties;
+    }
 }
diff --git a/telephony/java/com/android/internal/telephony/DefaultPhoneNotifier.java b/telephony/java/com/android/internal/telephony/DefaultPhoneNotifier.java
index 0646101..382c19f 100644
--- a/telephony/java/com/android/internal/telephony/DefaultPhoneNotifier.java
+++ b/telephony/java/com/android/internal/telephony/DefaultPhoneNotifier.java
@@ -16,6 +16,7 @@
 
 package com.android.internal.telephony;
 
+import android.net.NetworkProperties;
 import android.os.Bundle;
 import android.os.RemoteException;
 import android.os.ServiceManager;
@@ -107,13 +108,17 @@
         // use apnType as the key to which connection we're talking about.
         // pass apnType back up to fetch particular for this one.
         TelephonyManager telephony = TelephonyManager.getDefault();
+        NetworkProperties networkProperties = null;
+        if (state == Phone.DataState.CONNECTED) {
+            networkProperties = sender.getNetworkProperties(apnType);
+        }
         try {
             mRegistry.notifyDataConnection(
                     convertDataState(state),
                     sender.isDataConnectivityPossible(), reason,
                     sender.getActiveApn(),
                     apnType,
-                    sender.getInterfaceName(null),
+                    networkProperties,
                     ((telephony!=null) ? telephony.getNetworkType() :
                     TelephonyManager.NETWORK_TYPE_UNKNOWN));
         } catch (RemoteException ex) {
diff --git a/telephony/java/com/android/internal/telephony/ITelephonyRegistry.aidl b/telephony/java/com/android/internal/telephony/ITelephonyRegistry.aidl
index 79c2b40..f7b70ee 100644
--- a/telephony/java/com/android/internal/telephony/ITelephonyRegistry.aidl
+++ b/telephony/java/com/android/internal/telephony/ITelephonyRegistry.aidl
@@ -17,6 +17,7 @@
 package com.android.internal.telephony;
 
 import android.content.Intent;
+import android.net.NetworkProperties;
 import android.os.Bundle;
 import android.telephony.ServiceState;
 import android.telephony.SignalStrength;
@@ -32,7 +33,8 @@
     void notifyCallForwardingChanged(boolean cfi);
     void notifyDataActivity(int state);
     void notifyDataConnection(int state, boolean isDataConnectivityPossible,
-            String reason, String apn, String apnType, String interfaceName, int networkType);
+            String reason, String apn, String apnType, in NetworkProperties networkProperties,
+            int networkType);
     void notifyDataConnectionFailed(String reason, String apnType);
     void notifyCellLocation(in Bundle cellLocation);
 }
diff --git a/telephony/java/com/android/internal/telephony/IccPhoneBookInterfaceManager.java b/telephony/java/com/android/internal/telephony/IccPhoneBookInterfaceManager.java
index 9f8e57f..48257cc 100644
--- a/telephony/java/com/android/internal/telephony/IccPhoneBookInterfaceManager.java
+++ b/telephony/java/com/android/internal/telephony/IccPhoneBookInterfaceManager.java
@@ -62,8 +62,8 @@
                             logd("GET_RECORD_SIZE Size " + recordSize[0] +
                                     " total " + recordSize[1] +
                                     " #record " + recordSize[2]);
-                            mLock.notifyAll();
                         }
+                        mLock.notifyAll();
                     }
                     break;
                 case EVENT_UPDATE_DONE:
diff --git a/telephony/java/com/android/internal/telephony/MccTable.java b/telephony/java/com/android/internal/telephony/MccTable.java
index b73c2f7..5dd29af 100644
--- a/telephony/java/com/android/internal/telephony/MccTable.java
+++ b/telephony/java/com/android/internal/telephony/MccTable.java
@@ -23,346 +23,13 @@
 import android.net.wifi.WifiManager;
 import android.os.RemoteException;
 import android.os.SystemProperties;
-import android.provider.Settings;
 import android.text.TextUtils;
 import android.util.Log;
 
-import java.util.Arrays;
-
-/**
- * The table below is built from two resources:
- *
- * 1) ITU "Mobile Network Code (MNC) for the international
- *   identification plan for mobile terminals and mobile users"
- *   which is available as an annex to the ITU operational bulletin
- *   available here: http://www.itu.int/itu-t/bulletin/annex.html
- *
- * 2) The ISO 3166 country codes list, available here:
- *    http://www.iso.org/iso/en/prods-services/iso3166ma/02iso-3166-code-lists/index.html
- *
- * This table was verified (28 Aug 2009) against
- * http://en.wikipedia.org/wiki/List_of_mobile_country_codes with the
- * only unresolved discrepancy being that this list has an extra entry
- * (461) for China.
- *
- * TODO: Complete the mappings for timezones and language/locale codes.
- *
- * The actual table data used in the Java code is generated from the
- * below Python code for efficiency.  The information is expected to
- * be static, but if changes are required, the table in the python
- * code can be modified and the trailing code run to re-generate the
- * tables that are to be used by Java.
-
-mcc_table = [
-  (202, 'gr', 2, 'Greece'),
-  (204, 'nl', 2, 'Europe/Amsterdam', 'nl', 13, 'Netherlands (Kingdom of the)'),
-  (206, 'be', 2, 'Belgium'),
-  (208, 'fr', 2, 'Europe/Paris', 'fr', 'France'),
-  (212, 'mc', 2, 'Monaco (Principality of)'),
-  (213, 'ad', 2, 'Andorra (Principality of)'),
-  (214, 'es', 2, 'Europe/Madrid', 'es', 'Spain'),
-  (216, 'hu', 2, 'Hungary (Republic of)'),
-  (218, 'ba', 2, 'Bosnia and Herzegovina'),
-  (219, 'hr', 2, 'Croatia (Republic of)'),
-  (220, 'rs', 2, 'Serbia and Montenegro'),
-  (222, 'it', 2, 'Europe/Rome', 'it', 'Italy'),
-  (225, 'va', 2, 'Europe/Rome', 'it', 'Vatican City State'),
-  (226, 'ro', 2, 'Romania'),
-  (228, 'ch', 2, 'Europe/Zurich', 'de', 'Switzerland (Confederation of)'),
-  (230, 'cz', 2, 'Europe/Prague', 'cs', 13, 'Czech Republic'),
-  (231, 'sk', 2, 'Slovak Republic'),
-  (232, 'at', 2, 'Europe/Vienna', 'de', 13, 'Austria'),
-  (234, 'gb', 2, 'Europe/London', 'en', 13, 'United Kingdom of Great Britain and Northern Ireland'),
-  (235, 'gb', 2, 'Europe/London', 'en', 13, 'United Kingdom of Great Britain and Northern Ireland'),
-  (238, 'dk', 2, 'Denmark'),
-  (240, 'se', 2, 'Sweden'),
-  (242, 'no', 2, 'Norway'),
-  (244, 'fi', 2, 'Finland'),
-  (246, 'lt', 2, 'Lithuania (Republic of)'),
-  (247, 'lv', 2, 'Latvia (Republic of)'),
-  (248, 'ee', 2, 'Estonia (Republic of)'),
-  (250, 'ru', 2, 'Russian Federation'),
-  (255, 'ua', 2, 'Ukraine'),
-  (257, 'by', 2, 'Belarus (Republic of)'),
-  (259, 'md', 2, 'Moldova (Republic of)'),
-  (260, 'pl', 2, 'Europe/Warsaw', 'Poland (Republic of)'),
-  (262, 'de', 2, 'Europe/Berlin', 'de', 13, 'Germany (Federal Republic of)'),
-  (266, 'gi', 2, 'Gibraltar'),
-  (268, 'pt', 2, 'Portugal'),
-  (270, 'lu', 2, 'Luxembourg'),
-  (272, 'ie', 2, 'Europe/Dublin', 'en', 'Ireland'),
-  (274, 'is', 2, 'Iceland'),
-  (276, 'al', 2, 'Albania (Republic of)'),
-  (278, 'mt', 2, 'Malta'),
-  (280, 'cy', 2, 'Cyprus (Republic of)'),
-  (282, 'ge', 2, 'Georgia'),
-  (283, 'am', 2, 'Armenia (Republic of)'),
-  (284, 'bg', 2, 'Bulgaria (Republic of)'),
-  (286, 'tr', 2, 'Turkey'),
-  (288, 'fo', 2, 'Faroe Islands'),
-  (289, 'ge', 2, 'Abkhazia (Georgia)'),
-  (290, 'gl', 2, 'Greenland (Denmark)'),
-  (292, 'sm', 2, 'San Marino (Republic of)'),
-  (293, 'sl', 2, 'Slovenia (Republic of)'),
-  (294, 'mk', 2, 'The Former Yugoslav Republic of Macedonia'),
-  (295, 'li', 2, 'Liechtenstein (Principality of)'),
-  (297, 'me', 2, 'Montenegro (Republic of)'),
-  (302, 'ca', 3, '', '', 11, 'Canada'),
-  (308, 'pm', 2, 'Saint Pierre and Miquelon (Collectivit territoriale de la Rpublique franaise)'),
-  (310, 'us', 3, '', 'en', 11, 'United States of America'),
-  (311, 'us', 3, '', 'en', 11, 'United States of America'),
-  (312, 'us', 3, '', 'en', 11, 'United States of America'),
-  (313, 'us', 3, '', 'en', 11, 'United States of America'),
-  (314, 'us', 3, '', 'en', 11, 'United States of America'),
-  (315, 'us', 3, '', 'en', 11, 'United States of America'),
-  (316, 'us', 3, '', 'en', 11, 'United States of America'),
-  (330, 'pr', 2, 'Puerto Rico'),
-  (332, 'vi', 2, 'United States Virgin Islands'),
-  (334, 'mx', 3, 'Mexico'),
-  (338, 'jm', 3, 'Jamaica'),
-  (340, 'gp', 2, 'Guadeloupe (French Department of)'),
-  (342, 'bb', 3, 'Barbados'),
-  (344, 'ag', 3, 'Antigua and Barbuda'),
-  (346, 'ky', 3, 'Cayman Islands'),
-  (348, 'vg', 3, 'British Virgin Islands'),
-  (350, 'bm', 2, 'Bermuda'),
-  (352, 'gd', 2, 'Grenada'),
-  (354, 'ms', 2, 'Montserrat'),
-  (356, 'kn', 2, 'Saint Kitts and Nevis'),
-  (358, 'lc', 2, 'Saint Lucia'),
-  (360, 'vc', 2, 'Saint Vincent and the Grenadines'),
-  (362, 'nl', 2, 'Netherlands Antilles'),
-  (363, 'aw', 2, 'Aruba'),
-  (364, 'bs', 2, 'Bahamas (Commonwealth of the)'),
-  (365, 'ai', 3, 'Anguilla'),
-  (366, 'dm', 2, 'Dominica (Commonwealth of)'),
-  (368, 'cu', 2, 'Cuba'),
-  (370, 'do', 2, 'Dominican Republic'),
-  (372, 'ht', 2, 'Haiti (Republic of)'),
-  (374, 'tt', 2, 'Trinidad and Tobago'),
-  (376, 'tc', 2, 'Turks and Caicos Islands'),
-  (400, 'az', 2, 'Azerbaijani Republic'),
-  (401, 'kz', 2, 'Kazakhstan (Republic of)'),
-  (402, 'bt', 2, 'Bhutan (Kingdom of)'),
-  (404, 'in', 2, 'India (Republic of)'),
-  (405, 'in', 2, 'India (Republic of)'),
-  (410, 'pk', 2, 'Pakistan (Islamic Republic of)'),
-  (412, 'af', 2, 'Afghanistan'),
-  (413, 'lk', 2, 'Sri Lanka (Democratic Socialist Republic of)'),
-  (414, 'mm', 2, 'Myanmar (Union of)'),
-  (415, 'lb', 2, 'Lebanon'),
-  (416, 'jo', 2, 'Jordan (Hashemite Kingdom of)'),
-  (417, 'sy', 2, 'Syrian Arab Republic'),
-  (418, 'iq', 2, 'Iraq (Republic of)'),
-  (419, 'kw', 2, 'Kuwait (State of)'),
-  (420, 'sa', 2, 'Saudi Arabia (Kingdom of)'),
-  (421, 'ye', 2, 'Yemen (Republic of)'),
-  (422, 'om', 2, 'Oman (Sultanate of)'),
-  (423, 'ps', 2, 'Palestine'),
-  (424, 'ae', 2, 'United Arab Emirates'),
-  (425, 'il', 2, 'Israel (State of)'),
-  (426, 'bh', 2, 'Bahrain (Kingdom of)'),
-  (427, 'qa', 2, 'Qatar (State of)'),
-  (428, 'mn', 2, 'Mongolia'),
-  (429, 'np', 2, 'Nepal'),
-  (430, 'ae', 2, 'United Arab Emirates'),
-  (431, 'ae', 2, 'United Arab Emirates'),
-  (432, 'ir', 2, 'Iran (Islamic Republic of)'),
-  (434, 'uz', 2, 'Uzbekistan (Republic of)'),
-  (436, 'tj', 2, 'Tajikistan (Republic of)'),
-  (437, 'kg', 2, 'Kyrgyz Republic'),
-  (438, 'tm', 2, 'Turkmenistan'),
-  (440, 'jp', 2, 'Asia/Tokyo', 'ja', 14, 'Japan'),
-  (441, 'jp', 2, 'Asia/Tokyo', 'ja', 14, 'Japan'),
-  (450, 'kr', 2, 'Korea (Republic of)'),
-  (452, 'vn', 2, 'Viet Nam (Socialist Republic of)'),
-  (454, 'hk', 2, '"Hong Kong, China"'),
-  (455, 'mo', 2, '"Macao, China"'),
-  (456, 'kh', 2, 'Cambodia (Kingdom of)'),
-  (457, 'la', 2, "Lao People's Democratic Republic"),
-  (460, 'cn', 2, "Asia/Beijing", 'zh', 13, "China (People's Republic of)"),
-  (461, 'cn', 2, "Asia/Beijing", 'zh', 13, "China (People's Republic of)"),
-  (466, 'tw', 2, "Taiwan (Republic of China)"),
-  (467, 'kp', 2, "Democratic People's Republic of Korea"),
-  (470, 'bd', 2, "Bangladesh (People's Republic of)"),
-  (472, 'mv', 2, 'Maldives (Republic of)'),
-  (502, 'my', 2, 'Malaysia'),
-  (505, 'au', 2, 'Australia/Sydney', 'en', 11, 'Australia'),
-  (510, 'id', 2, 'Indonesia (Republic of)'),
-  (514, 'tl', 2, 'Democratic Republic of Timor-Leste'),
-  (515, 'ph', 2, 'Philippines (Republic of the)'),
-  (520, 'th', 2, 'Thailand'),
-  (525, 'sg', 2, 'Asia/Singapore', 'en', 11, 'Singapore (Republic of)'),
-  (528, 'bn', 2, 'Brunei Darussalam'),
-  (530, 'nz', 2, 'Pacific/Auckland', 'en', 'New Zealand'),
-  (534, 'mp', 2, 'Northern Mariana Islands (Commonwealth of the)'),
-  (535, 'gu', 2, 'Guam'),
-  (536, 'nr', 2, 'Nauru (Republic of)'),
-  (537, 'pg', 2, 'Papua New Guinea'),
-  (539, 'to', 2, 'Tonga (Kingdom of)'),
-  (540, 'sb', 2, 'Solomon Islands'),
-  (541, 'vu', 2, 'Vanuatu (Republic of)'),
-  (542, 'fj', 2, 'Fiji (Republic of)'),
-  (543, 'wf', 2, "Wallis and Futuna (Territoire franais d'outre-mer)"),
-  (544, 'as', 2, 'American Samoa'),
-  (545, 'ki', 2, 'Kiribati (Republic of)'),
-  (546, 'nc', 2, "New Caledonia (Territoire franais d'outre-mer)"),
-  (547, 'pf', 2, "French Polynesia (Territoire franais d'outre-mer)"),
-  (548, 'ck', 2, 'Cook Islands'),
-  (549, 'ws', 2, 'Samoa (Independent State of)'),
-  (550, 'fm', 2, 'Micronesia (Federated States of)'),
-  (551, 'mh', 2, 'Marshall Islands (Republic of the)'),
-  (552, 'pw', 2, 'Palau (Republic of)'),
-  (602, 'eg', 2, 'Egypt (Arab Republic of)'),
-  (603, 'dz', 2, "Algeria (People's Democratic Republic of)"),
-  (604, 'ma', 2, 'Morocco (Kingdom of)'),
-  (605, 'tn', 2, 'Tunisia'),
-  (606, 'ly', 2, "Libya (Socialist People's Libyan Arab Jamahiriya)"),
-  (607, 'gm', 2, 'Gambia (Republic of the)'),
-  (608, 'sn', 2, 'Senegal (Republic of)'),
-  (609, 'mr', 2, 'Mauritania (Islamic Republic of)'),
-  (610, 'ml', 2, 'Mali (Republic of)'),
-  (611, 'gn', 2, 'Guinea (Republic of)'),
-  (612, 'ci', 2, "Cte d'Ivoire (Republic of)"),
-  (613, 'bf', 2, 'Burkina Faso'),
-  (614, 'ne', 2, 'Niger (Republic of the)'),
-  (615, 'tg', 2, 'Togolese Republic'),
-  (616, 'bj', 2, 'Benin (Republic of)'),
-  (617, 'mu', 2, 'Mauritius (Republic of)'),
-  (618, 'lr', 2, 'Liberia (Republic of)'),
-  (619, 'sl', 2, 'Sierra Leone'),
-  (620, 'gh', 2, 'Ghana'),
-  (621, 'ng', 2, 'Nigeria (Federal Republic of)'),
-  (622, 'td', 2, 'Chad (Republic of)'),
-  (623, 'cf', 2, 'Central African Republic'),
-  (624, 'cm', 2, 'Cameroon (Republic of)'),
-  (625, 'cv', 2, 'Cape Verde (Republic of)'),
-  (626, 'st', 2, 'Sao Tome and Principe (Democratic Republic of)'),
-  (627, 'gq', 2, 'Equatorial Guinea (Republic of)'),
-  (628, 'ga', 2, 'Gabonese Republic'),
-  (629, 'cg', 2, 'Congo (Republic of the)'),
-  (630, 'cg', 2, 'Democratic Republic of the Congo'),
-  (631, 'ao', 2, 'Angola (Republic of)'),
-  (632, 'gw', 2, 'Guinea-Bissau (Republic of)'),
-  (633, 'sc', 2, 'Seychelles (Republic of)'),
-  (634, 'sd', 2, 'Sudan (Republic of the)'),
-  (635, 'rw', 2, 'Rwanda (Republic of)'),
-  (636, 'et', 2, 'Ethiopia (Federal Democratic Republic of)'),
-  (637, 'so', 2, 'Somali Democratic Republic'),
-  (638, 'dj', 2, 'Djibouti (Republic of)'),
-  (639, 'ke', 2, 'Kenya (Republic of)'),
-  (640, 'tz', 2, 'Tanzania (United Republic of)'),
-  (641, 'ug', 2, 'Uganda (Republic of)'),
-  (642, 'bi', 2, 'Burundi (Republic of)'),
-  (643, 'mz', 2, 'Mozambique (Republic of)'),
-  (645, 'zm', 2, 'Zambia (Republic of)'),
-  (646, 'mg', 2, 'Madagascar (Republic of)'),
-  (647, 're', 2, 'Reunion (French Department of)'),
-  (648, 'zw', 2, 'Zimbabwe (Republic of)'),
-  (649, 'na', 2, 'Namibia (Republic of)'),
-  (650, 'mw', 2, 'Malawi'),
-  (651, 'ls', 2, 'Lesotho (Kingdom of)'),
-  (652, 'bw', 2, 'Botswana (Republic of)'),
-  (653, 'sz', 2, 'Swaziland (Kingdom of)'),
-  (654, 'km', 2, 'Comoros (Union of the)'),
-  (655, 'za', 2, 'Africa/Johannesburg', 'en', 'South Africa (Republic of)'),
-  (657, 'er', 2, 'Eritrea'),
-  (702, 'bz', 2, 'Belize'),
-  (704, 'gt', 2, 'Guatemala (Republic of)'),
-  (706, 'sv', 2, 'El Salvador (Republic of)'),
-  (708, 'hn', 3, 'Honduras (Republic of)'),
-  (710, 'ni', 2, 'Nicaragua'),
-  (712, 'cr', 2, 'Costa Rica'),
-  (714, 'pa', 2, 'Panama (Republic of)'),
-  (716, 'pe', 2, 'Peru'),
-  (722, 'ar', 3, 'Argentine Republic'),
-  (724, 'br', 2, 'Brazil (Federative Republic of)'),
-  (730, 'cl', 2, 'Chile'),
-  (732, 'co', 3, 'Colombia (Republic of)'),
-  (734, 've', 2, 'Venezuela (Bolivarian Republic of)'),
-  (736, 'bo', 2, 'Bolivia (Republic of)'),
-  (738, 'gy', 2, 'Guyana'),
-  (740, 'ec', 2, 'Ecuador'),
-  (742, 'gf', 2, 'French Guiana (French Department of)'),
-  (744, 'py', 2, 'Paraguay (Republic of)'),
-  (746, 'sr', 2, 'Suriname (Republic of)'),
-  (748, 'uy', 2, 'Uruguay (Eastern Republic of)'),
-  (750, 'fk', 2, 'Falkland Islands (Malvinas)')]
-
-get_mcc = lambda elt: elt[0]
-get_iso = lambda elt: elt[1]
-get_sd = lambda elt: elt[2]
-get_tz = lambda elt: len(elt) > 4 and elt[3] or ''
-get_lang = lambda elt: len(elt) > 5 and elt[4] or ''
-get_wifi = lambda elt: len(elt) > 6 and elt[5] or 0
-
-mcc_codes = ['0x%04x' % get_mcc(elt) for elt in mcc_table]
-tz_set = sorted(x for x in set(get_tz(elt) for elt in mcc_table))
-lang_set = sorted(x for x in set(get_lang(elt) for elt in mcc_table))
-
-def mk_ind_code(elt):
-  iso = get_iso(elt)
-  iso_code = ((ord(iso[0]) << 8) | ord(iso[1])) & 0xFFFF # 16 bits
-  wifi = get_wifi(elt) & 0x000F                          #  4 bits
-  sd = get_sd(elt) & 0x0003                              #  2 bits
-  tz_ind = tz_set.index(get_tz(elt)) & 0x001F            #  5 bits
-  lang_ind = lang_set.index(get_lang(elt)) & 0x000F      #  4 bits
-  return (iso_code << 16) | (wifi << 11) | (sd << 9) | (tz_ind << 4) | lang_ind
-
-ind_codes = ['0x%08x' % mk_ind_code(elt) for elt in mcc_table]
-
-def fmt_list(title, l, batch_sz):
-  sl = []
-  for i in range(len(l) / batch_sz + (len(l) % batch_sz and 1 or 0)):
-    j = i * batch_sz
-    sl.append((' ' * 8) + ', '.join(l[j:j + batch_sz]))
-  return '    private static final %s = {\n' % title + ',\n'.join(sl) + '\n    };\n'
-
-def do_autogen_comment(extra_desc=[]):
-  print '    /' + '**\n    * AUTO GENERATED (by the Python code above)'
-  for line in extra_desc:
-    print '    * %s' % line
-  print '    *' + '/'
-
-do_autogen_comment()
-print fmt_list('String[] TZ_STRINGS', ['"%s"' % x for x in tz_set], 1)
-do_autogen_comment()
-print fmt_list('String[] LANG_STRINGS', ['"%s"' % x for x in lang_set], 10)
-do_autogen_comment(['This table is a list of MCC codes.  The index in this table',
-                    'of a given MCC code is the index of extra information about',
-                    'that MCC in the IND_CODES table.'])
-print fmt_list('short[] MCC_CODES', mcc_codes, 10)
-do_autogen_comment(['The values in this table are broken down as follows (msb to lsb):',
-                    '    iso country code 16 bits',
-                    '    (unused)          1 bit',
-                    '    wifi channel      4 bits',
-                    '    smalled digit     2 bits',
-                    '    default timezone  5 bits',
-                    '    default language  4 bits'])
-print fmt_list('int[] IND_CODES', ind_codes, 6)
-
-def parse_ind_code(ind):
-  mcc = eval(mcc_codes[ind])
-  code = eval(ind_codes[ind])
-  iso_lsb = int((code >> 16) & 0x00FF)
-  iso_msb = int((code >> 24) & 0x00FF)
-  iso = '%s%s' % (chr(iso_msb), chr(iso_lsb))
-  wifi = int((code >> 11) & 0x000F)
-  sd = int((code >> 9) & 0x0003)
-  tz_ind = (code >> 4) & 0x001F
-  lang_ind = (code >> 0) & 0x000F
-  return (mcc, iso, sd, tz_set[tz_ind], lang_set[lang_ind], wifi)
-
-fmt_str = 'mcc = %s, iso = %s, sd = %s, tz = %s, lang = %s, wifi = %s'
-orig_table = [fmt_str % (get_mcc(elt), get_iso(elt), get_sd(elt),
-                         get_tz(elt), get_lang(elt), get_wifi(elt))
-              for elt in mcc_table]
-derived_table = [fmt_str % parse_ind_code(i) for i in range(len(ind_codes))]
-for i in range(len(orig_table)):
-  if orig_table[i] == derived_table[i]: continue
-  print 'MISMATCH ERROR : ', orig_table[i], " != ", derived_table[i]
-
-*/
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Locale;
+import libcore.icu.TimeZones;
 
 /**
  * Mobile Country Code
@@ -371,200 +38,153 @@
  */
 public final class MccTable
 {
-    /**
-     * AUTO GENERATED (by the Python code above)
-     */
-    private static final String[] TZ_STRINGS = {
-        "",
-        "Africa/Johannesburg",
-        "Asia/Beijing",
-        "Asia/Singapore",
-        "Asia/Tokyo",
-        "Australia/Sydney",
-        "Europe/Amsterdam",
-        "Europe/Berlin",
-        "Europe/Dublin",
-        "Europe/London",
-        "Europe/Madrid",
-        "Europe/Paris",
-        "Europe/Prague",
-        "Europe/Rome",
-        "Europe/Vienna",
-        "Europe/Warsaw",
-        "Europe/Zurich",
-        "Pacific/Auckland"
-    };
-
-    /**
-     * AUTO GENERATED (by the Python code above)
-     */
-    private static final String[] LANG_STRINGS = {
-        "", "cs", "de", "en", "es", "fr", "it", "ja", "nl", "zh"
-    };
-
-    /**
-     * AUTO GENERATED (by the Python code above)
-     * This table is a list of MCC codes.  The index in this table
-     * of a given MCC code is the index of extra information about
-     * that MCC in the IND_CODES table.
-     */
-    private static final short[] MCC_CODES = {
-        0x00ca, 0x00cc, 0x00ce, 0x00d0, 0x00d4, 0x00d5, 0x00d6, 0x00d8, 0x00da, 0x00db,
-        0x00dc, 0x00de, 0x00e1, 0x00e2, 0x00e4, 0x00e6, 0x00e7, 0x00e8, 0x00ea, 0x00eb,
-        0x00ee, 0x00f0, 0x00f2, 0x00f4, 0x00f6, 0x00f7, 0x00f8, 0x00fa, 0x00ff, 0x0101,
-        0x0103, 0x0104, 0x0106, 0x010a, 0x010c, 0x010e, 0x0110, 0x0112, 0x0114, 0x0116,
-        0x0118, 0x011a, 0x011b, 0x011c, 0x011e, 0x0120, 0x0121, 0x0122, 0x0124, 0x0125,
-        0x0126, 0x0127, 0x0129, 0x012e, 0x0134, 0x0136, 0x0137, 0x0138, 0x0139, 0x013a,
-        0x013b, 0x013c, 0x014a, 0x014c, 0x014e, 0x0152, 0x0154, 0x0156, 0x0158, 0x015a,
-        0x015c, 0x015e, 0x0160, 0x0162, 0x0164, 0x0166, 0x0168, 0x016a, 0x016b, 0x016c,
-        0x016d, 0x016e, 0x0170, 0x0172, 0x0174, 0x0176, 0x0178, 0x0190, 0x0191, 0x0192,
-        0x0194, 0x0195, 0x019a, 0x019c, 0x019d, 0x019e, 0x019f, 0x01a0, 0x01a1, 0x01a2,
-        0x01a3, 0x01a4, 0x01a5, 0x01a6, 0x01a7, 0x01a8, 0x01a9, 0x01aa, 0x01ab, 0x01ac,
-        0x01ad, 0x01ae, 0x01af, 0x01b0, 0x01b2, 0x01b4, 0x01b5, 0x01b6, 0x01b8, 0x01b9,
-        0x01c2, 0x01c4, 0x01c6, 0x01c7, 0x01c8, 0x01c9, 0x01cc, 0x01cd, 0x01d2, 0x01d3,
-        0x01d6, 0x01d8, 0x01f6, 0x01f9, 0x01fe, 0x0202, 0x0203, 0x0208, 0x020d, 0x0210,
-        0x0212, 0x0216, 0x0217, 0x0218, 0x0219, 0x021b, 0x021c, 0x021d, 0x021e, 0x021f,
-        0x0220, 0x0221, 0x0222, 0x0223, 0x0224, 0x0225, 0x0226, 0x0227, 0x0228, 0x025a,
-        0x025b, 0x025c, 0x025d, 0x025e, 0x025f, 0x0260, 0x0261, 0x0262, 0x0263, 0x0264,
-        0x0265, 0x0266, 0x0267, 0x0268, 0x0269, 0x026a, 0x026b, 0x026c, 0x026d, 0x026e,
-        0x026f, 0x0270, 0x0271, 0x0272, 0x0273, 0x0274, 0x0275, 0x0276, 0x0277, 0x0278,
-        0x0279, 0x027a, 0x027b, 0x027c, 0x027d, 0x027e, 0x027f, 0x0280, 0x0281, 0x0282,
-        0x0283, 0x0285, 0x0286, 0x0287, 0x0288, 0x0289, 0x028a, 0x028b, 0x028c, 0x028d,
-        0x028e, 0x028f, 0x0291, 0x02be, 0x02c0, 0x02c2, 0x02c4, 0x02c6, 0x02c8, 0x02ca,
-        0x02cc, 0x02d2, 0x02d4, 0x02da, 0x02dc, 0x02de, 0x02e0, 0x02e2, 0x02e4, 0x02e6,
-        0x02e8, 0x02ea, 0x02ec, 0x02ee
-    };
-
-    /**
-     * AUTO GENERATED (by the Python code above)
-     * The values in this table are broken down as follows (msb to lsb):
-     *     iso country code 16 bits
-     *     (unused)          1 bit
-     *     wifi channel      4 bits
-     *     smalled digit     2 bits
-     *     default timezone  5 bits
-     *     default language  4 bits
-     */
-    private static final int[] IND_CODES = {
-        0x67720400, 0x6e6c6c68, 0x62650400, 0x667204b5, 0x6d630400, 0x61640400,
-        0x657304a4, 0x68750400, 0x62610400, 0x68720400, 0x72730400, 0x697404d6,
-        0x766104d6, 0x726f0400, 0x63680502, 0x637a6cc1, 0x736b0400, 0x61746ce2,
-        0x67626c93, 0x67626c93, 0x646b0400, 0x73650400, 0x6e6f0400, 0x66690400,
-        0x6c740400, 0x6c760400, 0x65650400, 0x72750400, 0x75610400, 0x62790400,
-        0x6d640400, 0x706c04f0, 0x64656c72, 0x67690400, 0x70740400, 0x6c750400,
-        0x69650483, 0x69730400, 0x616c0400, 0x6d740400, 0x63790400, 0x67650400,
-        0x616d0400, 0x62670400, 0x74720400, 0x666f0400, 0x67650400, 0x676c0400,
-        0x736d0400, 0x736c0400, 0x6d6b0400, 0x6c690400, 0x6d650400, 0x63615e00,
-        0x706d0400, 0x75735e03, 0x75735e03, 0x75735e03, 0x75735e03, 0x75735e03,
-        0x75735e03, 0x75735e03, 0x70720400, 0x76690400, 0x6d780600, 0x6a6d0600,
-        0x67700400, 0x62620600, 0x61670600, 0x6b790600, 0x76670600, 0x626d0400,
-        0x67640400, 0x6d730400, 0x6b6e0400, 0x6c630400, 0x76630400, 0x6e6c0400,
-        0x61770400, 0x62730400, 0x61690600, 0x646d0400, 0x63750400, 0x646f0400,
-        0x68740400, 0x74740400, 0x74630400, 0x617a0400, 0x6b7a0400, 0x62740400,
-        0x696e0400, 0x696e0400, 0x706b0400, 0x61660400, 0x6c6b0400, 0x6d6d0400,
-        0x6c620400, 0x6a6f0400, 0x73790400, 0x69710400, 0x6b770400, 0x73610400,
-        0x79650400, 0x6f6d0400, 0x70730400, 0x61650400, 0x696c0400, 0x62680400,
-        0x71610400, 0x6d6e0400, 0x6e700400, 0x61650400, 0x61650400, 0x69720400,
-        0x757a0400, 0x746a0400, 0x6b670400, 0x746d0400, 0x6a707447, 0x6a707447,
-        0x6b720400, 0x766e0400, 0x686b0400, 0x6d6f0400, 0x6b680400, 0x6c610400,
-        0x636e6c29, 0x636e6c29, 0x74770400, 0x6b700400, 0x62640400, 0x6d760400,
-        0x6d790400, 0x61755c53, 0x69640400, 0x746c0400, 0x70680400, 0x74680400,
-        0x73675c33, 0x626e0400, 0x6e7a0513, 0x6d700400, 0x67750400, 0x6e720400,
-        0x70670400, 0x746f0400, 0x73620400, 0x76750400, 0x666a0400, 0x77660400,
-        0x61730400, 0x6b690400, 0x6e630400, 0x70660400, 0x636b0400, 0x77730400,
-        0x666d0400, 0x6d680400, 0x70770400, 0x65670400, 0x647a0400, 0x6d610400,
-        0x746e0400, 0x6c790400, 0x676d0400, 0x736e0400, 0x6d720400, 0x6d6c0400,
-        0x676e0400, 0x63690400, 0x62660400, 0x6e650400, 0x74670400, 0x626a0400,
-        0x6d750400, 0x6c720400, 0x736c0400, 0x67680400, 0x6e670400, 0x74640400,
-        0x63660400, 0x636d0400, 0x63760400, 0x73740400, 0x67710400, 0x67610400,
-        0x63670400, 0x63670400, 0x616f0400, 0x67770400, 0x73630400, 0x73640400,
-        0x72770400, 0x65740400, 0x736f0400, 0x646a0400, 0x6b650400, 0x747a0400,
-        0x75670400, 0x62690400, 0x6d7a0400, 0x7a6d0400, 0x6d670400, 0x72650400,
-        0x7a770400, 0x6e610400, 0x6d770400, 0x6c730400, 0x62770400, 0x737a0400,
-        0x6b6d0400, 0x7a610413, 0x65720400, 0x627a0400, 0x67740400, 0x73760400,
-        0x686e0600, 0x6e690400, 0x63720400, 0x70610400, 0x70650400, 0x61720600,
-        0x62720400, 0x636c0400, 0x636f0600, 0x76650400, 0x626f0400, 0x67790400,
-        0x65630400, 0x67660400, 0x70790400, 0x73720400, 0x75790400, 0x666b0400
-    };
-
     static final String LOG_TAG = "MccTable";
 
+    static ArrayList<MccEntry> table;
+
+    static class MccEntry implements Comparable<MccEntry>
+    {
+        int mcc;
+        String iso;
+        int smallestDigitsMnc;
+        String language;
+        int wifiChannels;
+
+        MccEntry(int mnc, String iso, int smallestDigitsMCC) {
+            this(mnc, iso, smallestDigitsMCC, null);
+        }
+
+        MccEntry(int mnc, String iso, int smallestDigitsMCC, String language) {
+            this(mnc, iso, smallestDigitsMCC, language, 0);
+        }
+
+        MccEntry(int mnc, String iso, int smallestDigitsMCC, String language, int wifiChannels) {
+            this.mcc = mnc;
+            this.iso = iso;
+            this.smallestDigitsMnc = smallestDigitsMCC;
+            this.language = language;
+            this.wifiChannels = wifiChannels;
+        }
+
+
+        public int compareTo(MccEntry o)
+        {
+            return mcc - o.mcc;
+        }
+    }
+
+    private static MccEntry
+    entryForMcc(int mcc)
+    {
+        int index;
+
+        MccEntry m;
+
+        m = new MccEntry(mcc, null, 0);
+
+        index = Collections.binarySearch(table, m);
+
+        if (index < 0) {
+            return null;
+        } else {
+            return table.get(index);
+        }
+    }
+
     /**
-     * Given a Mobile Country Code, returns a default time zone ID
-     * if available.  Returns null if unavailable.
+     * Returns a default time zone ID for the given MCC.
+     * @param mcc Mobile Country Code
+     * @return default TimeZone ID, or null if not specified
      */
     public static String defaultTimeZoneForMcc(int mcc) {
-        int index = Arrays.binarySearch(MCC_CODES, (short)mcc);
-        if (index < 0) {
+        MccEntry entry;
+
+        entry = entryForMcc(mcc);
+        if (entry == null || entry.iso == null) {
             return null;
+        } else {
+            Locale locale;
+            if (entry.language == null) {
+                locale = new Locale(entry.iso);
+            } else {
+                locale = new Locale(entry.language, entry.iso);
+            }
+            String[] tz = TimeZones.forLocale(locale);
+            if (tz.length == 0) return null;
+            return tz[0];
         }
-        int indCode = IND_CODES[index];
-        int tzInd = (indCode >>> 4) & 0x001F;
-        String tz = TZ_STRINGS[tzInd];
-        if (tz == "") {
-            return null;
-        }
-        return tz;
     }
 
     /**
-     * Given a Mobile Country Code, returns an ISO two-character
-     * country code if available.  Returns "" if unavailable.
+     * Given a GSM Mobile Country Code, returns
+     * an ISO two-character country code if available.
+     * Returns "" if unavailable.
      */
-    public static String countryCodeForMcc(int mcc) {
-        int index = Arrays.binarySearch(MCC_CODES, (short)mcc);
-        if (index < 0) {
+    public static String
+    countryCodeForMcc(int mcc)
+    {
+        MccEntry entry;
+
+        entry = entryForMcc(mcc);
+
+        if (entry == null) {
             return "";
+        } else {
+            return entry.iso;
         }
-        int indCode = IND_CODES[index];
-        byte[] iso = {(byte)((indCode >>> 24) & 0x00FF), (byte)((indCode >>> 16) & 0x00FF)};
-        return new String(iso);
     }
 
     /**
-     * Given a GSM Mobile Country Code, returns an ISO 2-3 character
-     * language code if available.  Returns null if unavailable.
+     * Given a GSM Mobile Country Code, returns
+     * an ISO 2-3 character language code if available.
+     * Returns null if unavailable.
      */
     public static String defaultLanguageForMcc(int mcc) {
-        int index = Arrays.binarySearch(MCC_CODES, (short)mcc);
-        if (index < 0) {
+        MccEntry entry;
+
+        entry = entryForMcc(mcc);
+
+        if (entry == null) {
             return null;
+        } else {
+            return entry.language;
         }
-        int indCode = IND_CODES[index];
-        int langInd = indCode & 0x000F;
-        String lang = LANG_STRINGS[langInd];
-        if (lang == "") {
-            return null;
-        }
-        return lang;
     }
 
     /**
-     * Given a GSM Mobile Country Code, returns the corresponding
-     * smallest number of digits field.  Returns 2 if unavailable.
+     * Given a GSM Mobile Country Code, returns
+     * the smallest number of digits that M if available.
+     * Returns 2 if unavailable.
      */
-    public static int smallestDigitsMccForMnc(int mcc) {
-        int index = Arrays.binarySearch(MCC_CODES, (short)mcc);
-        if (index < 0) {
+    public static int
+    smallestDigitsMccForMnc(int mcc)
+    {
+        MccEntry entry;
+
+        entry = entryForMcc(mcc);
+
+        if (entry == null) {
             return 2;
+        } else {
+            return entry.smallestDigitsMnc;
         }
-        int indCode = IND_CODES[index];
-        int smDig = (indCode >>> 9) & 0x0003;
-        return smDig;
     }
 
     /**
      * Given a GSM Mobile Country Code, returns the number of wifi
      * channels allowed in that country.  Returns 0 if unavailable.
      */
-    public static int wifiChannelsForMcc(int mcc) {
-        int index = Arrays.binarySearch(MCC_CODES, (short)mcc);
-        if (index < 0) {
+    public static int
+    wifiChannelsForMcc(int mcc) {
+        MccEntry entry;
+
+        entry = entryForMcc(mcc);
+
+        if (entry == null) {
             return 0;
+        } else {
+            return entry.wifiChannels;
         }
-        int indCode = IND_CODES[index];
-        int wifi = (indCode >>> 11) & 0x000F;
-        return wifi;
     }
 
     /**
@@ -656,4 +276,262 @@
             wM.setNumAllowedChannels(wifiChannels, true);
         }
     }
+
+    static {
+        table = new ArrayList<MccEntry>(240);
+
+
+        /*
+         * The table below is built from two resources:
+         *
+         * 1) ITU "Mobile Network Code (MNC) for the international
+         *   identification plan for mobile terminals and mobile users"
+         *   which is available as an annex to the ITU operational bulletin
+         *   available here: http://www.itu.int/itu-t/bulletin/annex.html
+         *
+         * 2) The ISO 3166 country codes list, available here:
+         *    http://www.iso.org/iso/en/prods-services/iso3166ma/02iso-3166-code-lists/index.html
+         *
+         * This table has not been verified.
+         *
+         */
+
+		table.add(new MccEntry(202,"gr",2));	//Greece
+		table.add(new MccEntry(204,"nl",2,"nl",13));	//Netherlands (Kingdom of the)
+		table.add(new MccEntry(206,"be",2));	//Belgium
+		table.add(new MccEntry(208,"fr",2,"fr"));	//France
+		table.add(new MccEntry(212,"mc",2));	//Monaco (Principality of)
+		table.add(new MccEntry(213,"ad",2));	//Andorra (Principality of)
+		table.add(new MccEntry(214,"es",2,"es"));	//Spain
+		table.add(new MccEntry(216,"hu",2));	//Hungary (Republic of)
+		table.add(new MccEntry(218,"ba",2));	//Bosnia and Herzegovina
+		table.add(new MccEntry(219,"hr",2));	//Croatia (Republic of)
+		table.add(new MccEntry(220,"rs",2));	//Serbia and Montenegro
+		table.add(new MccEntry(222,"it",2,"it"));	//Italy
+		table.add(new MccEntry(225,"va",2,"it"));	//Vatican City State
+		table.add(new MccEntry(226,"ro",2));	//Romania
+		table.add(new MccEntry(228,"ch",2,"de"));	//Switzerland (Confederation of)
+		table.add(new MccEntry(230,"cz",2,"cs",13));	//Czech Republic
+		table.add(new MccEntry(231,"sk",2));	//Slovak Republic
+		table.add(new MccEntry(232,"at",2,"de",13));	//Austria
+		table.add(new MccEntry(234,"gb",2,"en",13));	//United Kingdom of Great Britain and Northern Ireland
+		table.add(new MccEntry(235,"gb",2,"en",13));	//United Kingdom of Great Britain and Northern Ireland
+		table.add(new MccEntry(238,"dk",2));	//Denmark
+		table.add(new MccEntry(240,"se",2));	//Sweden
+		table.add(new MccEntry(242,"no",2));	//Norway
+		table.add(new MccEntry(244,"fi",2));	//Finland
+		table.add(new MccEntry(246,"lt",2));	//Lithuania (Republic of)
+		table.add(new MccEntry(247,"lv",2));	//Latvia (Republic of)
+		table.add(new MccEntry(248,"ee",2));	//Estonia (Republic of)
+		table.add(new MccEntry(250,"ru",2));	//Russian Federation
+		table.add(new MccEntry(255,"ua",2));	//Ukraine
+		table.add(new MccEntry(257,"by",2));	//Belarus (Republic of)
+		table.add(new MccEntry(259,"md",2));	//Moldova (Republic of)
+		table.add(new MccEntry(260,"pl",2));	//Poland (Republic of)
+		table.add(new MccEntry(262,"de",2,"de",13));	//Germany (Federal Republic of)
+		table.add(new MccEntry(266,"gi",2));	//Gibraltar
+		table.add(new MccEntry(268,"pt",2));	//Portugal
+		table.add(new MccEntry(270,"lu",2));	//Luxembourg
+		table.add(new MccEntry(272,"ie",2,"en"));	//Ireland
+		table.add(new MccEntry(274,"is",2));	//Iceland
+		table.add(new MccEntry(276,"al",2));	//Albania (Republic of)
+		table.add(new MccEntry(278,"mt",2));	//Malta
+		table.add(new MccEntry(280,"cy",2));	//Cyprus (Republic of)
+		table.add(new MccEntry(282,"ge",2));	//Georgia
+		table.add(new MccEntry(283,"am",2));	//Armenia (Republic of)
+		table.add(new MccEntry(284,"bg",2));	//Bulgaria (Republic of)
+		table.add(new MccEntry(286,"tr",2));	//Turkey
+		table.add(new MccEntry(288,"fo",2));	//Faroe Islands
+                table.add(new MccEntry(289,"ge",2));    //Abkhazia (Georgia)
+		table.add(new MccEntry(290,"gl",2));	//Greenland (Denmark)
+		table.add(new MccEntry(292,"sm",2));	//San Marino (Republic of)
+		table.add(new MccEntry(293,"sl",2));	//Slovenia (Republic of)
+                table.add(new MccEntry(294,"mk",2));   //The Former Yugoslav Republic of Macedonia
+		table.add(new MccEntry(295,"li",2));	//Liechtenstein (Principality of)
+                table.add(new MccEntry(297,"me",2));    //Montenegro (Republic of)
+		table.add(new MccEntry(302,"ca",3,"",11));	//Canada
+		table.add(new MccEntry(308,"pm",2));	//Saint Pierre and Miquelon (Collectivit territoriale de la Rpublique franaise)
+		table.add(new MccEntry(310,"us",3,"en",11));	//United States of America
+		table.add(new MccEntry(311,"us",3,"en",11));	//United States of America
+		table.add(new MccEntry(312,"us",3,"en",11));	//United States of America
+		table.add(new MccEntry(313,"us",3,"en",11));	//United States of America
+		table.add(new MccEntry(314,"us",3,"en",11));	//United States of America
+		table.add(new MccEntry(315,"us",3,"en",11));	//United States of America
+		table.add(new MccEntry(316,"us",3,"en",11));	//United States of America
+		table.add(new MccEntry(330,"pr",2));	//Puerto Rico
+		table.add(new MccEntry(332,"vi",2));	//United States Virgin Islands
+		table.add(new MccEntry(334,"mx",3));	//Mexico
+		table.add(new MccEntry(338,"jm",3));	//Jamaica
+		table.add(new MccEntry(340,"gp",2));	//Guadeloupe (French Department of)
+		table.add(new MccEntry(342,"bb",3));	//Barbados
+		table.add(new MccEntry(344,"ag",3));	//Antigua and Barbuda
+		table.add(new MccEntry(346,"ky",3));	//Cayman Islands
+		table.add(new MccEntry(348,"vg",3));	//British Virgin Islands
+		table.add(new MccEntry(350,"bm",2));	//Bermuda
+		table.add(new MccEntry(352,"gd",2));	//Grenada
+		table.add(new MccEntry(354,"ms",2));	//Montserrat
+		table.add(new MccEntry(356,"kn",2));	//Saint Kitts and Nevis
+		table.add(new MccEntry(358,"lc",2));	//Saint Lucia
+		table.add(new MccEntry(360,"vc",2));	//Saint Vincent and the Grenadines
+		table.add(new MccEntry(362,"nl",2));	//Netherlands Antilles
+		table.add(new MccEntry(363,"aw",2));	//Aruba
+		table.add(new MccEntry(364,"bs",2));	//Bahamas (Commonwealth of the)
+		table.add(new MccEntry(365,"ai",3));	//Anguilla
+		table.add(new MccEntry(366,"dm",2));	//Dominica (Commonwealth of)
+		table.add(new MccEntry(368,"cu",2));	//Cuba
+		table.add(new MccEntry(370,"do",2));	//Dominican Republic
+		table.add(new MccEntry(372,"ht",2));	//Haiti (Republic of)
+		table.add(new MccEntry(374,"tt",2));	//Trinidad and Tobago
+		table.add(new MccEntry(376,"tc",2));	//Turks and Caicos Islands
+		table.add(new MccEntry(400,"az",2));	//Azerbaijani Republic
+		table.add(new MccEntry(401,"kz",2));	//Kazakhstan (Republic of)
+		table.add(new MccEntry(402,"bt",2));	//Bhutan (Kingdom of)
+		table.add(new MccEntry(404,"in",2));	//India (Republic of)
+		table.add(new MccEntry(405,"in",2));	//India (Republic of)
+		table.add(new MccEntry(410,"pk",2));	//Pakistan (Islamic Republic of)
+		table.add(new MccEntry(412,"af",2));	//Afghanistan
+		table.add(new MccEntry(413,"lk",2));	//Sri Lanka (Democratic Socialist Republic of)
+		table.add(new MccEntry(414,"mm",2));	//Myanmar (Union of)
+		table.add(new MccEntry(415,"lb",2));	//Lebanon
+		table.add(new MccEntry(416,"jo",2));	//Jordan (Hashemite Kingdom of)
+		table.add(new MccEntry(417,"sy",2));	//Syrian Arab Republic
+		table.add(new MccEntry(418,"iq",2));	//Iraq (Republic of)
+		table.add(new MccEntry(419,"kw",2));	//Kuwait (State of)
+		table.add(new MccEntry(420,"sa",2));	//Saudi Arabia (Kingdom of)
+		table.add(new MccEntry(421,"ye",2));	//Yemen (Republic of)
+		table.add(new MccEntry(422,"om",2));	//Oman (Sultanate of)
+                table.add(new MccEntry(423,"ps",2));    //Palestine
+		table.add(new MccEntry(424,"ae",2));	//United Arab Emirates
+		table.add(new MccEntry(425,"il",2));	//Israel (State of)
+		table.add(new MccEntry(426,"bh",2));	//Bahrain (Kingdom of)
+		table.add(new MccEntry(427,"qa",2));	//Qatar (State of)
+		table.add(new MccEntry(428,"mn",2));	//Mongolia
+		table.add(new MccEntry(429,"np",2));	//Nepal
+		table.add(new MccEntry(430,"ae",2));	//United Arab Emirates
+		table.add(new MccEntry(431,"ae",2));	//United Arab Emirates
+		table.add(new MccEntry(432,"ir",2));	//Iran (Islamic Republic of)
+		table.add(new MccEntry(434,"uz",2));	//Uzbekistan (Republic of)
+		table.add(new MccEntry(436,"tj",2));	//Tajikistan (Republic of)
+		table.add(new MccEntry(437,"kg",2));	//Kyrgyz Republic
+		table.add(new MccEntry(438,"tm",2));	//Turkmenistan
+		table.add(new MccEntry(440,"jp",2,"ja",14));	//Japan
+		table.add(new MccEntry(441,"jp",2,"ja",14));	//Japan
+		table.add(new MccEntry(450,"kr",2));	//Korea (Republic of)
+		table.add(new MccEntry(452,"vn",2));	//Viet Nam (Socialist Republic of)
+		table.add(new MccEntry(454,"hk",2));	//"Hong Kong, China"
+		table.add(new MccEntry(455,"mo",2));	//"Macao, China"
+		table.add(new MccEntry(456,"kh",2));	//Cambodia (Kingdom of)
+		table.add(new MccEntry(457,"la",2));	//Lao People's Democratic Republic
+		table.add(new MccEntry(460,"cn",2,"zh",13));	//China (People's Republic of)
+		table.add(new MccEntry(461,"cn",2,"zh",13));	//China (People's Republic of)
+		table.add(new MccEntry(466,"tw",2));	//"Taiwan, China"
+		table.add(new MccEntry(467,"kp",2));	//Democratic People's Republic of Korea
+		table.add(new MccEntry(470,"bd",2));	//Bangladesh (People's Republic of)
+		table.add(new MccEntry(472,"mv",2));	//Maldives (Republic of)
+		table.add(new MccEntry(502,"my",2));	//Malaysia
+		table.add(new MccEntry(505,"au",2,"en",11));	//Australia
+		table.add(new MccEntry(510,"id",2));	//Indonesia (Republic of)
+		table.add(new MccEntry(514,"tl",2));	//Democratic Republic of Timor-Leste
+		table.add(new MccEntry(515,"ph",2));	//Philippines (Republic of the)
+		table.add(new MccEntry(520,"th",2));	//Thailand
+		table.add(new MccEntry(525,"sg",2,"en",11));	//Singapore (Republic of)
+		table.add(new MccEntry(528,"bn",2));	//Brunei Darussalam
+		table.add(new MccEntry(530,"nz",2, "en"));	//New Zealand
+		table.add(new MccEntry(534,"mp",2));	//Northern Mariana Islands (Commonwealth of the)
+		table.add(new MccEntry(535,"gu",2));	//Guam
+		table.add(new MccEntry(536,"nr",2));	//Nauru (Republic of)
+		table.add(new MccEntry(537,"pg",2));	//Papua New Guinea
+		table.add(new MccEntry(539,"to",2));	//Tonga (Kingdom of)
+		table.add(new MccEntry(540,"sb",2));	//Solomon Islands
+		table.add(new MccEntry(541,"vu",2));	//Vanuatu (Republic of)
+		table.add(new MccEntry(542,"fj",2));	//Fiji (Republic of)
+		table.add(new MccEntry(543,"wf",2));	//Wallis and Futuna (Territoire franais d'outre-mer)
+		table.add(new MccEntry(544,"as",2));	//American Samoa
+		table.add(new MccEntry(545,"ki",2));	//Kiribati (Republic of)
+		table.add(new MccEntry(546,"nc",2));	//New Caledonia (Territoire franais d'outre-mer)
+		table.add(new MccEntry(547,"pf",2));	//French Polynesia (Territoire franais d'outre-mer)
+		table.add(new MccEntry(548,"ck",2));	//Cook Islands
+		table.add(new MccEntry(549,"ws",2));	//Samoa (Independent State of)
+		table.add(new MccEntry(550,"fm",2));	//Micronesia (Federated States of)
+		table.add(new MccEntry(551,"mh",2));	//Marshall Islands (Republic of the)
+		table.add(new MccEntry(552,"pw",2));	//Palau (Republic of)
+		table.add(new MccEntry(602,"eg",2));	//Egypt (Arab Republic of)
+		table.add(new MccEntry(603,"dz",2));	//Algeria (People's Democratic Republic of)
+		table.add(new MccEntry(604,"ma",2));	//Morocco (Kingdom of)
+		table.add(new MccEntry(605,"tn",2));	//Tunisia
+		table.add(new MccEntry(606,"ly",2));	//Libya (Socialist People's Libyan Arab Jamahiriya)
+		table.add(new MccEntry(607,"gm",2));	//Gambia (Republic of the)
+		table.add(new MccEntry(608,"sn",2));	//Senegal (Republic of)
+		table.add(new MccEntry(609,"mr",2));	//Mauritania (Islamic Republic of)
+		table.add(new MccEntry(610,"ml",2));	//Mali (Republic of)
+		table.add(new MccEntry(611,"gn",2));	//Guinea (Republic of)
+		table.add(new MccEntry(612,"ci",2));	//Cte d'Ivoire (Republic of)
+		table.add(new MccEntry(613,"bf",2));	//Burkina Faso
+		table.add(new MccEntry(614,"ne",2));	//Niger (Republic of the)
+		table.add(new MccEntry(615,"tg",2));	//Togolese Republic
+		table.add(new MccEntry(616,"bj",2));	//Benin (Republic of)
+		table.add(new MccEntry(617,"mu",2));	//Mauritius (Republic of)
+		table.add(new MccEntry(618,"lr",2));	//Liberia (Republic of)
+		table.add(new MccEntry(619,"sl",2));	//Sierra Leone
+		table.add(new MccEntry(620,"gh",2));	//Ghana
+		table.add(new MccEntry(621,"ng",2));	//Nigeria (Federal Republic of)
+		table.add(new MccEntry(622,"td",2));	//Chad (Republic of)
+		table.add(new MccEntry(623,"cf",2));	//Central African Republic
+		table.add(new MccEntry(624,"cm",2));	//Cameroon (Republic of)
+		table.add(new MccEntry(625,"cv",2));	//Cape Verde (Republic of)
+		table.add(new MccEntry(626,"st",2));	//Sao Tome and Principe (Democratic Republic of)
+		table.add(new MccEntry(627,"gq",2));	//Equatorial Guinea (Republic of)
+		table.add(new MccEntry(628,"ga",2));	//Gabonese Republic
+		table.add(new MccEntry(629,"cg",2));	//Congo (Republic of the)
+		table.add(new MccEntry(630,"cg",2));	//Democratic Republic of the Congo
+		table.add(new MccEntry(631,"ao",2));	//Angola (Republic of)
+		table.add(new MccEntry(632,"gw",2));	//Guinea-Bissau (Republic of)
+		table.add(new MccEntry(633,"sc",2));	//Seychelles (Republic of)
+		table.add(new MccEntry(634,"sd",2));	//Sudan (Republic of the)
+		table.add(new MccEntry(635,"rw",2));	//Rwanda (Republic of)
+		table.add(new MccEntry(636,"et",2));	//Ethiopia (Federal Democratic Republic of)
+		table.add(new MccEntry(637,"so",2));	//Somali Democratic Republic
+		table.add(new MccEntry(638,"dj",2));	//Djibouti (Republic of)
+		table.add(new MccEntry(639,"ke",2));	//Kenya (Republic of)
+		table.add(new MccEntry(640,"tz",2));	//Tanzania (United Republic of)
+		table.add(new MccEntry(641,"ug",2));	//Uganda (Republic of)
+		table.add(new MccEntry(642,"bi",2));	//Burundi (Republic of)
+		table.add(new MccEntry(643,"mz",2));	//Mozambique (Republic of)
+		table.add(new MccEntry(645,"zm",2));	//Zambia (Republic of)
+		table.add(new MccEntry(646,"mg",2));	//Madagascar (Republic of)
+		table.add(new MccEntry(647,"re",2));	//Reunion (French Department of)
+		table.add(new MccEntry(648,"zw",2));	//Zimbabwe (Republic of)
+		table.add(new MccEntry(649,"na",2));	//Namibia (Republic of)
+		table.add(new MccEntry(650,"mw",2));	//Malawi
+		table.add(new MccEntry(651,"ls",2));	//Lesotho (Kingdom of)
+		table.add(new MccEntry(652,"bw",2));	//Botswana (Republic of)
+		table.add(new MccEntry(653,"sz",2));	//Swaziland (Kingdom of)
+		table.add(new MccEntry(654,"km",2));	//Comoros (Union of the)
+		table.add(new MccEntry(655,"za",2,"en"));	//South Africa (Republic of)
+		table.add(new MccEntry(657,"er",2));	//Eritrea
+		table.add(new MccEntry(702,"bz",2));	//Belize
+		table.add(new MccEntry(704,"gt",2));	//Guatemala (Republic of)
+		table.add(new MccEntry(706,"sv",2));	//El Salvador (Republic of)
+		table.add(new MccEntry(708,"hn",3));	//Honduras (Republic of)
+		table.add(new MccEntry(710,"ni",2));	//Nicaragua
+		table.add(new MccEntry(712,"cr",2));	//Costa Rica
+		table.add(new MccEntry(714,"pa",2));	//Panama (Republic of)
+		table.add(new MccEntry(716,"pe",2));	//Peru
+		table.add(new MccEntry(722,"ar",3));	//Argentine Republic
+		table.add(new MccEntry(724,"br",2));	//Brazil (Federative Republic of)
+		table.add(new MccEntry(730,"cl",2));	//Chile
+		table.add(new MccEntry(732,"co",3));	//Colombia (Republic of)
+		table.add(new MccEntry(734,"ve",2));	//Venezuela (Bolivarian Republic of)
+		table.add(new MccEntry(736,"bo",2));	//Bolivia (Republic of)
+		table.add(new MccEntry(738,"gy",2));	//Guyana
+		table.add(new MccEntry(740,"ec",2));	//Ecuador
+		table.add(new MccEntry(742,"gf",2));	//French Guiana (French Department of)
+		table.add(new MccEntry(744,"py",2));	//Paraguay (Republic of)
+		table.add(new MccEntry(746,"sr",2));	//Suriname (Republic of)
+		table.add(new MccEntry(748,"uy",2));	//Uruguay (Eastern Republic of)
+		table.add(new MccEntry(750,"fk",2));	//Falkland Islands (Malvinas)
+        //table.add(new MccEntry(901,"",2));	//"International Mobile, shared code"
+
+        Collections.sort(table);
+    }
 }
diff --git a/telephony/java/com/android/internal/telephony/Phone.java b/telephony/java/com/android/internal/telephony/Phone.java
index 7029031..769b2fc8 100644
--- a/telephony/java/com/android/internal/telephony/Phone.java
+++ b/telephony/java/com/android/internal/telephony/Phone.java
@@ -18,6 +18,7 @@
 
 import android.content.Context;
 import android.content.SharedPreferences;
+import android.net.NetworkProperties;
 import android.os.Handler;
 import android.os.Message;
 import android.preference.PreferenceManager;
@@ -101,6 +102,7 @@
     static final String STATE_CHANGE_REASON_KEY = "reason";
     static final String DATA_APN_TYPE_KEY = "apnType";
     static final String DATA_APN_KEY = "apn";
+    static final String DATA_NETWORK_PROPERTIES_KEY = "dataProperties";
 
     static final String DATA_IFACE_NAME_KEY = "iface";
     static final String NETWORK_UNAVAILABLE_KEY = "networkUnvailable";
@@ -319,6 +321,11 @@
     String getActiveApn();
 
     /**
+     * Return the NetworkProperties for the named apn or null if not available
+     */
+    NetworkProperties getNetworkProperties(String apnType);
+
+    /**
      * Get current signal strength. No change notification available on this
      * interface. Use <code>PhoneStateNotifier</code> or an equivalent.
      * An ASU is 0-31 or -1 if unknown (for GSM, dBm = -113 - 2 * asu).
diff --git a/telephony/java/com/android/internal/telephony/PhoneBase.java b/telephony/java/com/android/internal/telephony/PhoneBase.java
index cf80691..e5968a7 100644
--- a/telephony/java/com/android/internal/telephony/PhoneBase.java
+++ b/telephony/java/com/android/internal/telephony/PhoneBase.java
@@ -21,6 +21,7 @@
 import android.content.Context;
 import android.content.res.Configuration;
 import android.content.SharedPreferences;
+import android.net.NetworkProperties;
 import android.net.wifi.WifiManager;
 import android.os.AsyncResult;
 import android.os.Handler;
@@ -955,6 +956,10 @@
         return mDataConnection.getActiveApnTypes();
     }
 
+    public NetworkProperties getNetworkProperties(String apnType) {
+        return mDataConnection.getNetworkProperties(apnType);
+    }
+
     public String getActiveApn() {
         return mDataConnection.getActiveApnString();
     }
diff --git a/telephony/java/com/android/internal/telephony/PhoneProxy.java b/telephony/java/com/android/internal/telephony/PhoneProxy.java
index fb2a938..d84859c 100644
--- a/telephony/java/com/android/internal/telephony/PhoneProxy.java
+++ b/telephony/java/com/android/internal/telephony/PhoneProxy.java
@@ -21,6 +21,7 @@
 import android.content.Context;
 import android.content.Intent;
 import android.content.SharedPreferences;
+import android.net.NetworkProperties;
 import android.os.Handler;
 import android.os.Message;
 import android.os.SystemProperties;
@@ -211,6 +212,10 @@
         return mActivePhone.getActiveApnTypes();
     }
 
+    public NetworkProperties getNetworkProperties(String apnType) {
+        return mActivePhone.getNetworkProperties(apnType);
+    }
+
     public String getActiveApn() {
         return mActivePhone.getActiveApn();
     }
diff --git a/telephony/java/com/android/internal/telephony/cdma/CdmaDataConnectionTracker.java b/telephony/java/com/android/internal/telephony/cdma/CdmaDataConnectionTracker.java
index bd103d4..8a3af3b 100644
--- a/telephony/java/com/android/internal/telephony/cdma/CdmaDataConnectionTracker.java
+++ b/telephony/java/com/android/internal/telephony/cdma/CdmaDataConnectionTracker.java
@@ -53,6 +53,7 @@
 import com.android.internal.telephony.RetryManager;
 import com.android.internal.telephony.ServiceStateTracker;
 
+import java.net.NetworkInterface;
 import java.util.ArrayList;
 
 /**
@@ -736,6 +737,8 @@
         }
 
         if (ar.exception == null) {
+            mNetworkProperties = makeNetworkProperties(mActiveDataConnection);
+
             // everything is setup
             notifyDefaultData(reason);
         } else {
diff --git a/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java b/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java
index 6826fa8..c76da80 100644
--- a/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java
+++ b/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java
@@ -30,6 +30,8 @@
 import android.net.ConnectivityManager;
 import android.net.IConnectivityManager;
 import android.net.NetworkInfo;
+import android.net.NetworkProperties;
+import android.net.ProxyProperties;
 import android.net.TrafficStats;
 import android.net.Uri;
 import android.net.wifi.WifiManager;
@@ -58,6 +60,9 @@
 import com.android.internal.telephony.DataConnection.FailCause;
 
 import java.io.IOException;
+import java.net.InetAddress;
+import java.net.NetworkInterface;
+import java.net.UnknownHostException;
 import java.util.ArrayList;
 
 /**
@@ -1133,6 +1138,25 @@
         }
 
         if (ar.exception == null) {
+            mNetworkProperties = makeNetworkProperties(mActivePdp);
+
+            ApnSetting apn = mActivePdp.getApn();
+            if (apn.proxy != null && apn.proxy.length() != 0) {
+                try {
+                    ProxyProperties proxy = new ProxyProperties();
+                    proxy.setAddress(InetAddress.getByName(apn.proxy));
+                    proxy.setPort(Integer.parseInt(apn.port));
+                    mNetworkProperties.setHttpProxy(proxy);
+                } catch (UnknownHostException e) {
+                    Log.e(LOG_TAG, "UnknownHostException making ProxyProperties: " + e);
+                } catch (SecurityException e) {
+                    Log.e(LOG_TAG, "SecurityException making ProxyProperties: " + e);
+                } catch (NumberFormatException e) {
+                    Log.e(LOG_TAG, "NumberFormatException making ProxyProperties (" + apn.port +
+                            "): " + e);
+                }
+            }
+
             // everything is setup
             if (isApnTypeActive(Phone.APN_TYPE_DEFAULT)) {
                 SystemProperties.set("gsm.defaultpdpcontext.active", "true");
diff --git a/telephony/java/com/android/internal/telephony/gsm/SmsMessage.java b/telephony/java/com/android/internal/telephony/gsm/SmsMessage.java
index 487372e..278e1ba 100644
--- a/telephony/java/com/android/internal/telephony/gsm/SmsMessage.java
+++ b/telephony/java/com/android/internal/telephony/gsm/SmsMessage.java
@@ -932,6 +932,8 @@
         // TP-Message-Type-Indicator
         // 9.2.3
         case 0:
+        case 3: //GSM 03.40 9.2.3.1: MTI == 3 is Reserved.
+                //This should be processed in the same way as MTI == 0 (Deliver)
             parseSmsDeliver(p, firstByte);
             break;
         case 2:
diff --git a/telephony/tests/telephonytests/src/com/android/internal/telephony/MccTableTest.java b/telephony/tests/telephonytests/src/com/android/internal/telephony/MccTableTest.java
index 2d6977c..7eb3df8 100644
--- a/telephony/tests/telephonytests/src/com/android/internal/telephony/MccTableTest.java
+++ b/telephony/tests/telephonytests/src/com/android/internal/telephony/MccTableTest.java
@@ -28,7 +28,7 @@
 
     @SmallTest
     public void testTimeZone() throws Exception {
-        assertEquals(MccTable.defaultTimeZoneForMcc(208), "Europe/Paris");
+        assertEquals(MccTable.defaultTimeZoneForMcc(208), "ECT");
         assertEquals(MccTable.defaultTimeZoneForMcc(232), "Europe/Vienna");
         assertEquals(MccTable.defaultTimeZoneForMcc(655), "Africa/Johannesburg");
         assertEquals(MccTable.defaultTimeZoneForMcc(440), "Asia/Tokyo");
diff --git a/telephony/tests/telephonytests/src/com/android/internal/telephony/PhoneNumberUtilsTest.java b/telephony/tests/telephonytests/src/com/android/internal/telephony/PhoneNumberUtilsTest.java
index a74c5c2..de59b81 100644
--- a/telephony/tests/telephonytests/src/com/android/internal/telephony/PhoneNumberUtilsTest.java
+++ b/telephony/tests/telephonytests/src/com/android/internal/telephony/PhoneNumberUtilsTest.java
@@ -496,9 +496,11 @@
         assertFalse(PhoneNumberUtils.isVoiceMailNumber("+18001234567"));
         assertFalse(PhoneNumberUtils.isVoiceMailNumber(""));
         assertFalse(PhoneNumberUtils.isVoiceMailNumber(null));
-        TelephonyManager mTelephonyManager =
+        // This test fails on a device without a sim card
+        /*TelephonyManager mTelephonyManager =
             (TelephonyManager)getContext().getSystemService(Context.TELEPHONY_SERVICE);
         String mVoiceMailNumber = mTelephonyManager.getDefault().getVoiceMailNumber();
         assertTrue(PhoneNumberUtils.isVoiceMailNumber(mVoiceMailNumber));
+        */
     }
 }
diff --git a/test-runner/src/android/test/InstrumentationTestRunner.java b/test-runner/src/android/test/InstrumentationTestRunner.java
index 63d50c7..70d1643 100644
--- a/test-runner/src/android/test/InstrumentationTestRunner.java
+++ b/test-runner/src/android/test/InstrumentationTestRunner.java
@@ -496,9 +496,18 @@
         return null;
     }
 
+    /**
+     * Initialize the current thread as a looper.
+     * <p/>
+     * Exposed for unit testing.
+     */
+    void prepareLooper() {
+        Looper.prepare();
+    }
+
     @Override
     public void onStart() {
-        Looper.prepare();
+        prepareLooper();
 
         if (mJustCount) {
             mResults.putString(Instrumentation.REPORT_KEY_IDENTIFIER, REPORT_VALUE_ID);
@@ -521,6 +530,11 @@
                 long runTime = System.currentTimeMillis() - startTime;
 
                 resultPrinter.print(mTestRunner.getTestResult(), runTime);
+            } catch (Throwable t) {
+                // catch all exceptions so a more verbose error message can be outputted
+                writer.println(String.format("Test run aborted due to unexpected exception: %s",
+                                t.getMessage()));
+                t.printStackTrace(writer);
             } finally {
                 mResults.putString(Instrumentation.REPORT_KEY_STREAMRESULT,
                         String.format("\nTest results for %s=%s",
@@ -762,9 +776,11 @@
                             TimedTest.class).includeDetailedStats();
                 }
             } catch (SecurityException e) {
-                throw new IllegalStateException(e);
+                // ignore - the test with given name cannot be accessed. Will be handled during
+                // test execution
             } catch (NoSuchMethodException e) {
-                throw new IllegalStateException(e);
+                // ignore- the test with given name does not exist. Will be handled during test
+                // execution
             }
 
             if (mIsTimedTest && mIncludeDetailedStats) {
diff --git a/test-runner/src/android/test/mock/MockPackageManager.java b/test-runner/src/android/test/mock/MockPackageManager.java
index 3e77b9b..e96173b 100644
--- a/test-runner/src/android/test/mock/MockPackageManager.java
+++ b/test-runner/src/android/test/mock/MockPackageManager.java
@@ -483,4 +483,9 @@
     public boolean isSafeMode() {
         throw new UnsupportedOperationException();
     }
+
+    @Override
+    public void setPackageObbPath(String packageName, String path) {
+        throw new UnsupportedOperationException();
+    }
 }
diff --git a/test-runner/tests/src/android/test/InstrumentationTestRunnerTest.java b/test-runner/tests/src/android/test/InstrumentationTestRunnerTest.java
index 6db72ad..d98b217 100644
--- a/test-runner/tests/src/android/test/InstrumentationTestRunnerTest.java
+++ b/test-runner/tests/src/android/test/InstrumentationTestRunnerTest.java
@@ -16,6 +16,7 @@
 
 package android.test;
 
+import android.app.Instrumentation;
 import android.content.Context;
 import android.os.Bundle;
 import android.test.mock.MockContext;
@@ -89,6 +90,42 @@
         
     }
 
+    /**
+     * Test that runtime exceptions during runTest are handled gracefully
+     */
+    public void testUnhandledException() throws Exception {
+        StubAndroidTestRunner stubAndroidTestRunner = new StubAndroidTestRunner() {
+            @Override
+            public void runTest() {
+                throw new RuntimeException();
+            }
+        };
+        StubInstrumentationTestRunner instrumentationTestRunner = new StubInstrumentationTestRunner(
+                new StubContext("com.google.foo.tests"),
+                new StubContext(mTargetContextPackageName), stubAndroidTestRunner);
+        instrumentationTestRunner.onCreate(new Bundle());
+        instrumentationTestRunner.onStart();
+        assertTrue("Instrumentation did not finish", instrumentationTestRunner.isFinished());
+        // ensure a meaningful error message placed in results
+        String resultsData = instrumentationTestRunner.mResults.getString(
+                Instrumentation.REPORT_KEY_STREAMRESULT);
+        assertTrue("Instrumentation results is missing RuntimeException",
+                resultsData.contains("RuntimeException"));
+    }
+
+    /**
+     * Test that specifying a method which does not exist is handled gracefully
+     */
+    public void testBadMethodArgument() throws Exception {
+        String testClassName = PlaceHolderTest.class.getName();
+        String invalidMethodName = "testNoExist";
+        String classAndMethod = testClassName + "#" + invalidMethodName;
+        mInstrumentationTestRunner.onCreate(createBundle(
+                InstrumentationTestRunner.ARGUMENT_TEST_CLASS, classAndMethod));
+        assertTestRunnerCalledWithExpectedParameters(testClassName,
+                invalidMethodName);
+    }
+
     public void testDelayParameter() throws Exception {
         int delayMsec = 1000;
         Bundle args = new Bundle();
@@ -170,6 +207,7 @@
         private TestSuite mTestSuite;
         private TestSuite mDefaultTestSuite;
         private String mPackageNameForDefaultTests;
+        private Bundle mResults;
 
         public StubInstrumentationTestRunner(Context context, Context targetContext,
                 AndroidTestRunner androidTestRunner) {
@@ -200,6 +238,7 @@
 
         public void finish(int resultCode, Bundle results) {
             mFinished = true;
+            mResults = results;
         }
 
         public boolean isStarted() {
@@ -221,6 +260,11 @@
         public String getPackageNameForDefaultTests() {
             return mPackageNameForDefaultTests;
         }
+
+        @Override
+        void prepareLooper() {
+            // ignore
+        }
     }
 
     private static class StubContext extends MockContext {
diff --git a/tests/DumpRenderTree/src/com/android/dumprendertree/FsUtils.java b/tests/DumpRenderTree/src/com/android/dumprendertree/FsUtils.java
index 0883387..4475e92 100644
--- a/tests/DumpRenderTree/src/com/android/dumprendertree/FsUtils.java
+++ b/tests/DumpRenderTree/src/com/android/dumprendertree/FsUtils.java
@@ -77,7 +77,9 @@
                 continue;
             }
 
-            if ((s.toLowerCase().endsWith(".html") || s.toLowerCase().endsWith(".xml"))
+            if ((s.toLowerCase().endsWith(".html")
+                    || s.toLowerCase().endsWith(".xml")
+                    || s.toLowerCase().endsWith(".xhtml"))
                     && !s.endsWith("TEMPLATE.html")) {
                 Log.v(LOGTAG, "Recording " + s);
                 bos.write(s.getBytes());
diff --git a/tests/DumpRenderTree/src/com/android/dumprendertree/LayoutTestsAutoTest.java b/tests/DumpRenderTree/src/com/android/dumprendertree/LayoutTestsAutoTest.java
index fabbf89..3618c7b 100644
--- a/tests/DumpRenderTree/src/com/android/dumprendertree/LayoutTestsAutoTest.java
+++ b/tests/DumpRenderTree/src/com/android/dumprendertree/LayoutTestsAutoTest.java
@@ -222,14 +222,22 @@
         // The generic result is at <path>/<name>-expected.txt
         // First try the Android-specific result at
         // platform/android-<js-engine>/<path>/<name>-expected.txt
+        // then
+        // platform/android/<path>/<name>-expected.txt
         int pos = test.lastIndexOf('.');
         if (pos == -1)
             return null;
         String genericExpectedResult = test.substring(0, pos) + "-expected.txt";
         String androidExpectedResultsDir = "platform/android-" + mJsEngine + "/";
-        String androidExpectedResult =
-            genericExpectedResult.replaceFirst(LAYOUT_TESTS_ROOT, LAYOUT_TESTS_ROOT + androidExpectedResultsDir);
+        String androidExpectedResult = genericExpectedResult.replaceFirst(LAYOUT_TESTS_ROOT,
+                LAYOUT_TESTS_ROOT + androidExpectedResultsDir);
         File f = new File(androidExpectedResult);
+        if (f.exists())
+            return androidExpectedResult;
+        androidExpectedResultsDir = "platform/android/";
+        androidExpectedResult = genericExpectedResult.replaceFirst(LAYOUT_TESTS_ROOT,
+                LAYOUT_TESTS_ROOT + androidExpectedResultsDir);
+        f = new File(androidExpectedResult);
         return f.exists() ? androidExpectedResult : genericExpectedResult;
     }
 
@@ -328,6 +336,7 @@
         intent.putExtra(TestShellActivity.TIMEOUT_IN_MILLIS, timeout);
         intent.putExtra(TestShellActivity.TOTAL_TEST_COUNT, mTestCount);
         intent.putExtra(TestShellActivity.CURRENT_TEST_NUMBER, testNumber);
+        intent.putExtra(TestShellActivity.STOP_ON_REF_ERROR, true);
         activity.startActivity(intent);
 
         // Wait until done.
diff --git a/tests/DumpRenderTree/src/com/android/dumprendertree/TestShellActivity.java b/tests/DumpRenderTree/src/com/android/dumprendertree/TestShellActivity.java
index 0a04712..bf66fae 100644
--- a/tests/DumpRenderTree/src/com/android/dumprendertree/TestShellActivity.java
+++ b/tests/DumpRenderTree/src/com/android/dumprendertree/TestShellActivity.java
@@ -179,6 +179,7 @@
         mTimeoutInMillis = intent.getIntExtra(TIMEOUT_IN_MILLIS, 0);
         mGetDrawtime = intent.getBooleanExtra(GET_DRAW_TIME, false);
         mSaveImagePath = intent.getStringExtra(SAVE_IMAGE);
+        mStopOnRefError = intent.getBooleanExtra(STOP_ON_REF_ERROR, false);
         setTitle("Test " + mCurrentTestNumber + " of " + mTotalTestCount);
         float ratio = (float)mCurrentTestNumber / mTotalTestCount;
         int progress = (int)(ratio * Window.PROGRESS_END);
@@ -699,8 +700,8 @@
             // waiting for "notifyDone" signal to finish, then there's no point in waiting
             // anymore because the JS execution is already terminated at this point and a
             // "notifyDone" will never come out so it's just wasting time till timeout kicks in
-            if (msg.contains("Uncaught ReferenceError:") || msg.contains("Uncaught TypeError:")
-                    && mWaitUntilDone) {
+            if ((msg.contains("Uncaught ReferenceError:") || msg.contains("Uncaught TypeError:"))
+                    && mWaitUntilDone && mStopOnRefError) {
                 Log.w(LOGTAG, "Terminating test case on uncaught ReferenceError or TypeError.");
                 mHandler.postDelayed(new Runnable() {
                     public void run() {
@@ -857,6 +858,7 @@
     private boolean mGetDrawtime;
     private int mTotalTestCount;
     private int mCurrentTestNumber;
+    private boolean mStopOnRefError;
 
     // States
     private boolean mTimedOut;
@@ -897,6 +899,7 @@
     static final String SAVE_IMAGE = "SaveImage";
     static final String TOTAL_TEST_COUNT = "TestCount";
     static final String CURRENT_TEST_NUMBER = "TestNumber";
+    static final String STOP_ON_REF_ERROR = "StopOnReferenceError";
 
     static final int DRAW_RUNS = 5;
     static final String DRAW_TIME_LOG = "/sdcard/android/page_draw_time.txt";
diff --git a/tests/DumpRenderTree2/Android.mk b/tests/DumpRenderTree2/Android.mk
index f3d2e9c..2aa6799 100644
--- a/tests/DumpRenderTree2/Android.mk
+++ b/tests/DumpRenderTree2/Android.mk
@@ -5,6 +5,6 @@
 
 LOCAL_SRC_FILES := $(call all-subdir-java-files)
 
-LOCAL_MODULE := DumpRenderTree2
+LOCAL_PACKAGE_NAME := DumpRenderTree2
 
-include $(BUILD_JAVA_LIBRARY)
+include $(BUILD_PACKAGE)
\ No newline at end of file
diff --git a/tests/DumpRenderTree2/AndroidManifest.xml b/tests/DumpRenderTree2/AndroidManifest.xml
new file mode 100644
index 0000000..baa365c
--- /dev/null
+++ b/tests/DumpRenderTree2/AndroidManifest.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+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.
+-->
+<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.android.dumprendertree2">
+    <application>
+        <activity android:name=".ui.DirListActivity"
+                  android:label="Dump Render Tree 2"
+                  android:configChanges="orientation">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.LAUNCHER" />
+            </intent-filter>
+        </activity>
+    </application>
+</manifest>
\ No newline at end of file
diff --git a/tests/DumpRenderTree2/res/drawable/folder.png b/tests/DumpRenderTree2/res/drawable/folder.png
new file mode 100644
index 0000000..5b3fcec
--- /dev/null
+++ b/tests/DumpRenderTree2/res/drawable/folder.png
Binary files differ
diff --git a/tests/DumpRenderTree2/res/drawable/runtest.png b/tests/DumpRenderTree2/res/drawable/runtest.png
new file mode 100644
index 0000000..910c654
--- /dev/null
+++ b/tests/DumpRenderTree2/res/drawable/runtest.png
Binary files differ
diff --git a/tests/DumpRenderTree2/res/layout/dirlist_row.xml b/tests/DumpRenderTree2/res/layout/dirlist_row.xml
new file mode 100644
index 0000000..e5578a6
--- /dev/null
+++ b/tests/DumpRenderTree2/res/layout/dirlist_row.xml
@@ -0,0 +1,43 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+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.
+-->
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:orientation="horizontal"
+    android:gravity="center_vertical"
+    android:layout_width="fill_parent"
+    android:layout_height="wrap_content">
+
+    <ImageView
+        android:id="@+id/icon"
+        android:layout_width="80px"
+        android:adjustViewBounds="true"
+        android:paddingLeft="15px"
+        android:paddingRight="15px"
+        android:paddingTop="15px"
+        android:paddingBottom="15px"
+        android:layout_height="wrap_content"
+    />
+
+    <TextView
+        android:id="@+id/label"
+        android:layout_width="fill_parent"
+        android:layout_height="wrap_content"
+        android:minHeight="60px"
+        android:gravity="center_vertical"
+        android:textSize="14sp"
+    />
+
+</LinearLayout>
\ No newline at end of file
diff --git a/tests/DumpRenderTree2/res/values/strings.xml b/tests/DumpRenderTree2/res/values/strings.xml
new file mode 100644
index 0000000..2dcd3ca
--- /dev/null
+++ b/tests/DumpRenderTree2/res/values/strings.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+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.
+-->
+<resources>
+    <string name="dialog_run_abort_dir_title_prefix">Directory:</string>
+    <string name="dialog_run_abort_dir_msg">This will run all the tests in this directory and all
+            the subdirectories. It may take a few hours!</string>
+    <string name="dialog_run_abort_dir_ok_button">Run tests!</string>
+    <string name="dialog_run_abort_dir_abort_button">Abort</string>
+
+    <string name="dialog_progress_title">Loading items.</string>
+    <string name="dialog_progress_msg">Please wait...</string>
+</resources>
\ No newline at end of file
diff --git a/tests/DumpRenderTree2/src/com/android/dumprendertree2/FileFilter.java b/tests/DumpRenderTree2/src/com/android/dumprendertree2/FileFilter.java
index 98801d3..64ef8a4 100644
--- a/tests/DumpRenderTree2/src/com/android/dumprendertree2/FileFilter.java
+++ b/tests/DumpRenderTree2/src/com/android/dumprendertree2/FileFilter.java
@@ -227,13 +227,14 @@
     }
 
     /**
-     * Checks if the file is a test or something else.
+     * Checks if the file is a test.
+     * Currently we run .html and .xhtml tests.
      *
      * @param testName
      * @return
      *      if the file is a test
      */
     public static boolean isTestFile(String testName) {
-        return testName.endsWith(".html");
+        return testName.endsWith(".html") || testName.endsWith(".xhtml");
     }
-}
\ No newline at end of file
+}
diff --git a/tests/DumpRenderTree2/src/com/android/dumprendertree2/ui/DirListActivity.java b/tests/DumpRenderTree2/src/com/android/dumprendertree2/ui/DirListActivity.java
new file mode 100644
index 0000000..d8509c1
--- /dev/null
+++ b/tests/DumpRenderTree2/src/com/android/dumprendertree2/ui/DirListActivity.java
@@ -0,0 +1,389 @@
+/*
+ * 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 com.android.dumprendertree2.ui;
+
+import com.android.dumprendertree2.FileFilter;
+import com.android.dumprendertree2.R;
+
+import android.app.Activity;
+import android.app.AlertDialog;
+import android.app.Dialog;
+import android.app.ListActivity;
+import android.app.ProgressDialog;
+import android.content.DialogInterface;
+import android.content.res.Configuration;
+import android.os.Bundle;
+import android.os.Environment;
+import android.os.Handler;
+import android.os.Message;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.AdapterView;
+import android.widget.ArrayAdapter;
+import android.widget.ImageView;
+import android.widget.ListView;
+import android.widget.TextView;
+
+import java.io.File;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * An Activity that allows navigating through tests folders and choosing folders or tests to run.
+ */
+public class DirListActivity extends ListActivity {
+
+    private static final String LOG_TAG = "DirListActivity";
+    private static final String ROOT_DIR_PATH =
+            Environment.getExternalStorageDirectory() +
+            File.separator + "android" +
+            File.separator + "LayoutTests";
+
+    /** TODO: This is just a guess - think of a better way to achieve it */
+    private static final int MEAN_TITLE_CHAR_SIZE = 13;
+
+    private static final int PROGRESS_DIALOG_DELAY_MS = 200;
+
+    /** Code for the dialog, used in showDialog and onCreateDialog */
+    private static final int DIALOG_RUN_ABORT_DIR = 0;
+
+    /** Messages codes */
+    private static final int MSG_LOADED_ITEMS = 0;
+    private static final int MSG_SHOW_PROGRESS_DIALOG = 1;
+
+    /** Initialized lazily before first sProgressDialog.show() */
+    private static ProgressDialog sProgressDialog;
+
+    private ListView mListView;
+
+    /** This is a relative path! */
+    private String mCurrentDirPath;
+
+    /**
+     * TODO: This should not be a constant, but rather be configurable from somewhere.
+     */
+    private String mRootDirPath = ROOT_DIR_PATH;
+
+    /**
+     * A thread responsible for loading the contents of the directory from sd card
+     * and sending them via Message to main thread that then loads them into
+     * ListView
+     */
+    private class LoadListItemsThread extends Thread {
+        private Handler mHandler;
+        private String mRelativePath;
+
+        public LoadListItemsThread(String relativePath, Handler handler) {
+            mRelativePath = relativePath;
+            mHandler = handler;
+        }
+
+        @Override
+        public void run() {
+            Message msg = mHandler.obtainMessage(MSG_LOADED_ITEMS);
+            msg.obj = getDirList(mRelativePath);
+            mHandler.sendMessage(msg);
+        }
+    }
+
+    /**
+     * Very simple object to use inside ListView as an item.
+     */
+    private static class ListItem implements Comparable<ListItem> {
+        private String mRelativePath;
+        private String mName;
+        private boolean mIsDirectory;
+
+        public ListItem(String relativePath, boolean isDirectory) {
+            mRelativePath = relativePath;
+            mName = new File(relativePath).getName();
+            mIsDirectory = isDirectory;
+        }
+
+        public boolean isDirectory() {
+            return mIsDirectory;
+        }
+
+        public String getRelativePath() {
+            return mRelativePath;
+        }
+
+        public String getName() {
+            return mName;
+        }
+
+        @Override
+        public int compareTo(ListItem another) {
+            return mRelativePath.compareTo(another.getRelativePath());
+        }
+
+        @Override
+        public boolean equals(Object o) {
+            if (!(o instanceof ListItem)) {
+                return false;
+            }
+
+            return mRelativePath.equals(((ListItem) o).getRelativePath());
+        }
+
+        @Override
+        public int hashCode() {
+            return mRelativePath.hashCode();
+        }
+
+    }
+
+    /**
+     * A custom adapter that sets the proper icon and label in the list view.
+     */
+    private static class DirListAdapter extends ArrayAdapter<ListItem> {
+        private Activity mContext;
+        private ListItem[] mItems;
+
+        public DirListAdapter(Activity context, ListItem[] items) {
+            super(context, R.layout.dirlist_row, items);
+
+            mContext = context;
+            mItems = items;
+        }
+
+        @Override
+        public View getView(int position, View convertView, ViewGroup parent) {
+            LayoutInflater inflater = mContext.getLayoutInflater();
+            View row = inflater.inflate(R.layout.dirlist_row, null);
+
+            TextView label = (TextView) row.findViewById(R.id.label);
+            label.setText(mItems[position].getName());
+
+            ImageView icon = (ImageView) row.findViewById(R.id.icon);
+            if (mItems[position].isDirectory()) {
+                icon.setImageResource(R.drawable.folder);
+            } else {
+                icon.setImageResource(R.drawable.runtest);
+            }
+
+            return row;
+        }
+    }
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+
+        mListView = getListView();
+
+        mListView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
+            @Override
+            public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
+                ListItem item = (ListItem) parent.getItemAtPosition(position);
+
+                if (item.isDirectory()) {
+                    showDir(item.getRelativePath());
+                } else {
+                    /** TODO: run the test */
+                }
+            }
+        });
+
+        mListView.setOnItemLongClickListener(new AdapterView.OnItemLongClickListener() {
+            @Override
+            public boolean onItemLongClick(AdapterView<?> parent, View view, int position, long id) {
+                ListItem item = (ListItem) parent.getItemAtPosition(position);
+
+                if (item.isDirectory()) {
+                    Bundle arguments = new Bundle(1);
+                    arguments.putString("name", item.getName());
+                    arguments.putString("relativePath", item.getRelativePath());
+                    showDialog(DIALOG_RUN_ABORT_DIR, arguments);
+                } else {
+                    /** TODO: Maybe show some info about a test? */
+                }
+
+                return true;
+            }
+        });
+
+        /** All the paths are relative to test root dir where possible */
+        showDir("");
+    }
+
+    @Override
+    /**
+     * Moves to the parent directory if one exists. Does not allow to move above
+     * the test 'root' directory.
+     */
+    public void onBackPressed() {
+        File currentDirParent = new File(mCurrentDirPath).getParentFile();
+        if (currentDirParent != null) {
+            showDir(currentDirParent.getPath());
+        } else {
+            showDir("");
+        }
+    }
+
+    /**
+     * Prevents the activity from recreating on change of orientation. The title needs to
+     * be recalculated.
+     */
+    @Override
+    public void onConfigurationChanged(Configuration newConfig) {
+        super.onConfigurationChanged(newConfig);
+
+        setTitle(shortenTitle(mCurrentDirPath));
+    }
+
+    @Override
+    protected Dialog onCreateDialog(int id, Bundle args) {
+        Dialog dialog = null;
+        AlertDialog.Builder builder = new AlertDialog.Builder(this);
+
+        switch (id) {
+            case DIALOG_RUN_ABORT_DIR:
+                builder.setTitle(getText(R.string.dialog_run_abort_dir_title_prefix) + " " +
+                        args.getString("name"));
+                builder.setMessage(R.string.dialog_run_abort_dir_msg);
+                builder.setCancelable(true);
+
+                builder.setPositiveButton(R.string.dialog_run_abort_dir_ok_button,
+                        new DialogInterface.OnClickListener() {
+                    @Override
+                    public void onClick(DialogInterface dialog, int which) {
+                        /** TODO: Run tests from the dir */
+                        removeDialog(DIALOG_RUN_ABORT_DIR);
+                    }
+                });
+
+                builder.setNegativeButton(R.string.dialog_run_abort_dir_abort_button,
+                        new DialogInterface.OnClickListener() {
+                    @Override
+                    public void onClick(DialogInterface dialog, int which) {
+                        removeDialog(DIALOG_RUN_ABORT_DIR);
+                    }
+                });
+
+                dialog = builder.create();
+                dialog.setOnCancelListener(new DialogInterface.OnCancelListener() {
+                    @Override
+                    public void onCancel(DialogInterface dialog) {
+                        removeDialog(DIALOG_RUN_ABORT_DIR);
+                    }
+                });
+                break;
+        }
+
+        return dialog;
+    }
+
+    /**
+     * Loads the contents of dir into the list view.
+     *
+     * @param dirPath
+     *      directory to load into list view
+     */
+    private void showDir(String dirPath) {
+        mCurrentDirPath = dirPath;
+
+        /** Show progress dialog with a delay */
+        final Handler delayedDialogHandler = new Handler() {
+            @Override
+            public void handleMessage(Message msg) {
+                if (msg.what == MSG_SHOW_PROGRESS_DIALOG) {
+                    if (sProgressDialog == null) {
+                        sProgressDialog = new ProgressDialog(DirListActivity.this);
+                        sProgressDialog.setCancelable(false);
+                        sProgressDialog.setProgressStyle(ProgressDialog.STYLE_SPINNER);
+                        sProgressDialog.setTitle(R.string.dialog_progress_title);
+                        sProgressDialog.setMessage(getText(R.string.dialog_progress_msg));
+                    }
+                    sProgressDialog.show();
+                }
+            }
+        };
+        Message msgShowDialog = delayedDialogHandler.obtainMessage(MSG_SHOW_PROGRESS_DIALOG);
+        delayedDialogHandler.sendMessageDelayed(msgShowDialog, PROGRESS_DIALOG_DELAY_MS);
+
+        /** Delegate loading contents from SD card to a new thread */
+        new LoadListItemsThread(mCurrentDirPath, new Handler() {
+            @Override
+            public void handleMessage(Message msg) {
+                if (msg.what == MSG_LOADED_ITEMS) {
+                    setListAdapter(new DirListAdapter(DirListActivity.this,
+                            (ListItem[])msg.obj));
+                    delayedDialogHandler.removeMessages(MSG_SHOW_PROGRESS_DIALOG);
+                    setTitle(shortenTitle(mCurrentDirPath));
+                    if (sProgressDialog != null) {
+                        sProgressDialog.dismiss();
+                    }
+                }
+            }
+        }).start();
+    }
+
+    /**
+     * TODO: find a neat way to determine number of characters that fit in the title
+     * bar.
+     * */
+    private String shortenTitle(String title) {
+        if (title.equals("")) {
+            return "Tests' root dir:";
+        }
+        int charCount = mListView.getWidth() / MEAN_TITLE_CHAR_SIZE;
+
+        if (title.length() > charCount) {
+            return "..." + title.substring(title.length() - charCount);
+        } else {
+            return title;
+        }
+    }
+
+    /**
+     * Return the array with contents of the given directory.
+     * First it contains the subfolders, then the files. Both sorted
+     * alphabetically.
+     *
+     * The dirPath is relative.
+     */
+    private ListItem[] getDirList(String dirPath) {
+        File dir = new File(mRootDirPath, dirPath);
+
+        List<ListItem> subDirs = new ArrayList<ListItem>();
+        List<ListItem> subFiles = new ArrayList<ListItem>();
+
+        for (File item : dir.listFiles()) {
+            if (item.isDirectory() && FileFilter.isTestDir(item.getName())) {
+                subDirs.add(new ListItem(getRelativePath(item), true));
+            } else if (FileFilter.isTestFile(item.getName())) {
+                subFiles.add(new ListItem(getRelativePath(item), false));
+            }
+        }
+
+        Collections.sort(subDirs);
+        Collections.sort(subFiles);
+
+        /** Concatenate the two lists */
+        subDirs.addAll(subFiles);
+
+        return subDirs.toArray(new ListItem[subDirs.size()]);
+    }
+
+    private String getRelativePath(File file) {
+        File rootDir = new File(mRootDirPath);
+        return file.getAbsolutePath().replaceFirst(rootDir.getPath() + File.separator, "");
+    }
+}
\ No newline at end of file
diff --git a/tests/HwAccelerationTest/AndroidManifest.xml b/tests/HwAccelerationTest/AndroidManifest.xml
index 79eed4e..098359c 100644
--- a/tests/HwAccelerationTest/AndroidManifest.xml
+++ b/tests/HwAccelerationTest/AndroidManifest.xml
@@ -69,6 +69,42 @@
                 <category android:name="android.intent.category.LAUNCHER" />
             </intent-filter>
         </activity>
+        
+        <activity
+                android:name="NinePatchesActivity"
+                android:label="_9patch">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.LAUNCHER" />
+            </intent-filter>
+        </activity>
+        
+        <activity
+                android:name="QuickRejectActivity"
+                android:label="_QuickReject">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.LAUNCHER" />
+            </intent-filter>
+        </activity>
+        
+        <activity
+                android:name="RotationActivity"
+                android:label="_Rotation">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.LAUNCHER" />
+            </intent-filter>
+        </activity>
+
+        <activity
+                android:name="ShadersActivity"
+                android:label="_Shaders">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.LAUNCHER" />
+            </intent-filter>
+        </activity>
                 
     </application>
 </manifest>
diff --git a/tests/HwAccelerationTest/src/com/google/android/test/hwui/BitmapsActivity.java b/tests/HwAccelerationTest/src/com/google/android/test/hwui/BitmapsActivity.java
index dfc8a71..cfa8d3c 100644
--- a/tests/HwAccelerationTest/src/com/google/android/test/hwui/BitmapsActivity.java
+++ b/tests/HwAccelerationTest/src/com/google/android/test/hwui/BitmapsActivity.java
@@ -25,9 +25,11 @@
 import android.graphics.PorterDuff;
 import android.graphics.PorterDuffXfermode;
 import android.os.Bundle;
+import android.view.Gravity;
 import android.view.View;
 import android.view.animation.Animation;
 import android.view.animation.ScaleAnimation;
+import android.widget.FrameLayout;
 
 @SuppressWarnings({"UnusedDeclaration"})
 public class BitmapsActivity extends Activity {
@@ -35,7 +37,9 @@
     protected void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
         final BitmapsView view = new BitmapsView(this);
-        setContentView(view);
+        final FrameLayout layout = new FrameLayout(this);
+        layout.addView(view, new FrameLayout.LayoutParams(480, 800, Gravity.CENTER));
+        setContentView(layout);
         
         ScaleAnimation a = new ScaleAnimation(1.0f, 2.0f, 1.0f, 2.0f,
                 ScaleAnimation.RELATIVE_TO_SELF, 0.5f,
@@ -50,6 +54,7 @@
         private Paint mBitmapPaint;
         private final Bitmap mBitmap1;
         private final Bitmap mBitmap2;
+        private final PorterDuffXfermode mDstIn;
 
         BitmapsView(Context c) {
             super(c);
@@ -58,6 +63,7 @@
             mBitmap2 = BitmapFactory.decodeResource(c.getResources(), R.drawable.sunset2);
 
             mBitmapPaint = new Paint();
+            mDstIn = new PorterDuffXfermode(PorterDuff.Mode.DST_IN);
         }
 
         @Override
@@ -81,10 +87,10 @@
             canvas.translate(0.0f, 25.0f);
             mBitmapPaint.setColor(0xffff0000);
             canvas.drawRect(0.0f, 0.0f, mBitmap2.getWidth(), mBitmap2.getHeight(), mBitmapPaint);
-            mBitmapPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_IN));
+            mBitmapPaint.setXfermode(mDstIn);
             canvas.drawBitmap(mBitmap2, 0.0f, 0.0f, mBitmapPaint);
 
-            mBitmapPaint = new Paint();
+            mBitmapPaint.reset();
         }
     }
 }
diff --git a/tests/HwAccelerationTest/src/com/google/android/test/hwui/NinePatchesActivity.java b/tests/HwAccelerationTest/src/com/google/android/test/hwui/NinePatchesActivity.java
new file mode 100644
index 0000000..3268fbf
--- /dev/null
+++ b/tests/HwAccelerationTest/src/com/google/android/test/hwui/NinePatchesActivity.java
@@ -0,0 +1,41 @@
+/*
+ * 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 com.google.android.test.hwui;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.view.Gravity;
+import android.widget.Button;
+import android.widget.FrameLayout;
+
+@SuppressWarnings({"UnusedDeclaration"})
+public class NinePatchesActivity extends Activity {
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        
+        FrameLayout layout = new FrameLayout(this);
+        Button b = new Button(this);
+        b.setLayoutParams(new FrameLayout.LayoutParams(FrameLayout.LayoutParams.WRAP_CONTENT,
+                FrameLayout.LayoutParams.WRAP_CONTENT, Gravity.CENTER));
+        b.setText("9 patches");
+        layout.addView(b);
+        layout.setBackgroundColor(0xffffffff);
+        
+        setContentView(layout);
+    }
+}
diff --git a/tests/HwAccelerationTest/src/com/google/android/test/hwui/QuickRejectActivity.java b/tests/HwAccelerationTest/src/com/google/android/test/hwui/QuickRejectActivity.java
new file mode 100644
index 0000000..fd7a1e6
--- /dev/null
+++ b/tests/HwAccelerationTest/src/com/google/android/test/hwui/QuickRejectActivity.java
@@ -0,0 +1,62 @@
+/*
+ * 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 com.google.android.test.hwui;
+
+import android.app.Activity;
+import android.content.Context;
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+import android.graphics.Canvas;
+import android.graphics.Paint;
+import android.os.Bundle;
+import android.view.View;
+
+@SuppressWarnings({"UnusedDeclaration"})
+public class QuickRejectActivity extends Activity {
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        final QuickRejectView view = new QuickRejectView(this);
+        setContentView(view);
+    }
+
+    static class QuickRejectView extends View {
+        private Paint mBitmapPaint;
+        private final Bitmap mBitmap1;
+
+        QuickRejectView(Context c) {
+            super(c);
+
+            mBitmap1 = BitmapFactory.decodeResource(c.getResources(), R.drawable.sunset1);
+
+            mBitmapPaint = new Paint();
+            mBitmapPaint.setFilterBitmap(true);
+        }
+
+        @Override
+        protected void onDraw(Canvas canvas) {
+            super.onDraw(canvas);
+
+            canvas.save();
+            canvas.clipRect(0.0f, 0.0f, 40.0f, 40.0f);
+            canvas.drawBitmap(mBitmap1, 0.0f, 0.0f, mBitmapPaint);
+            canvas.drawBitmap(mBitmap1, -mBitmap1.getWidth(), 0.0f, mBitmapPaint);
+            canvas.drawBitmap(mBitmap1, 50.0f, 0.0f, mBitmapPaint);
+            canvas.restore();
+        }
+    }
+}
\ No newline at end of file
diff --git a/tests/HwAccelerationTest/src/com/google/android/test/hwui/RotationActivity.java b/tests/HwAccelerationTest/src/com/google/android/test/hwui/RotationActivity.java
new file mode 100644
index 0000000..e629cb8
--- /dev/null
+++ b/tests/HwAccelerationTest/src/com/google/android/test/hwui/RotationActivity.java
@@ -0,0 +1,63 @@
+/*
+ * 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 com.google.android.test.hwui;
+
+import android.app.Activity;
+import android.content.Context;
+import android.graphics.Canvas;
+import android.graphics.Paint;
+import android.os.Bundle;
+import android.view.View;
+
+@SuppressWarnings({"UnusedDeclaration"})
+public class RotationActivity extends Activity {
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+
+        DrawingView container = new DrawingView(this);
+
+        setContentView(container);
+    }
+    
+    @SuppressWarnings({"UnusedDeclaration"})
+    static int dipToPx(Context c, int dip) {
+        return (int) (c.getResources().getDisplayMetrics().density * dip + 0.5f);
+    }
+
+    static class DrawingView extends View {
+        private final Paint mPaint;
+
+        DrawingView(Context c) {
+            super(c);
+            mPaint = new Paint();
+            mPaint.setAntiAlias(true);
+        }
+
+        @Override
+        protected void onDraw(Canvas canvas) {
+            canvas.save();
+            canvas.translate(dipToPx(getContext(), 400), dipToPx(getContext(), 200));
+            canvas.rotate(45.0f);
+            canvas.drawRGB(255, 255, 255);
+            mPaint.setColor(0xffff0000);
+            canvas.drawRect(-80.0f, -80.0f, 80.0f, 80.0f, mPaint);
+            canvas.drawRect(0.0f, 0.0f, 220.0f, 220.0f, mPaint);            
+            canvas.restore();
+        }
+    }
+}
diff --git a/tests/HwAccelerationTest/src/com/google/android/test/hwui/ShadersActivity.java b/tests/HwAccelerationTest/src/com/google/android/test/hwui/ShadersActivity.java
new file mode 100644
index 0000000..851a06c
--- /dev/null
+++ b/tests/HwAccelerationTest/src/com/google/android/test/hwui/ShadersActivity.java
@@ -0,0 +1,131 @@
+/*
+ * 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 com.google.android.test.hwui;
+
+import android.app.Activity;
+import android.content.Context;
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+import android.graphics.BitmapShader;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.LinearGradient;
+import android.graphics.Matrix;
+import android.graphics.Paint;
+import android.graphics.Shader;
+import android.os.Bundle;
+import android.view.View;
+
+@SuppressWarnings({"UnusedDeclaration"})
+public class ShadersActivity extends Activity {
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+
+        setContentView(new ShadersView(this));
+    }
+
+    static class ShadersView extends View {
+        private BitmapShader mRepeatShader;
+        private BitmapShader mTranslatedShader;
+        private BitmapShader mScaledShader;
+        private int mTexWidth;
+        private int mTexHeight;
+        private Paint mPaint;
+        private float mDrawWidth;
+        private float mDrawHeight;
+        private LinearGradient mHorGradient;
+        private LinearGradient mDiagGradient;
+        private LinearGradient mVertGradient;
+
+        ShadersView(Context c) {
+            super(c);
+
+            Bitmap texture = BitmapFactory.decodeResource(c.getResources(), R.drawable.sunset1);
+            mTexWidth = texture.getWidth();
+            mTexHeight = texture.getHeight();
+            mDrawWidth = mTexWidth * 2.2f;
+            mDrawHeight = mTexHeight * 1.2f;
+
+            mRepeatShader = new BitmapShader(texture, Shader.TileMode.REPEAT,
+                    Shader.TileMode.REPEAT);
+
+            mTranslatedShader = new BitmapShader(texture, Shader.TileMode.REPEAT,
+                    Shader.TileMode.REPEAT);
+            Matrix m1 = new Matrix();
+            m1.setTranslate(mTexWidth / 2.0f, mTexHeight / 2.0f);
+            mTranslatedShader.setLocalMatrix(m1);
+            
+            mScaledShader = new BitmapShader(texture, Shader.TileMode.MIRROR,
+                    Shader.TileMode.MIRROR);
+            Matrix m2 = new Matrix();
+            m2.setScale(0.5f, 0.5f);
+            mScaledShader.setLocalMatrix(m2);
+
+            mHorGradient = new LinearGradient(0.0f, 0.0f, mDrawWidth, 0.0f,
+                    Color.RED, Color.GREEN, Shader.TileMode.REPEAT);
+            
+            mDiagGradient = new LinearGradient(0.0f, 0.0f, mDrawWidth / 1.5f, mDrawHeight,
+                    Color.BLUE, Color.MAGENTA, Shader.TileMode.CLAMP);
+            
+            mVertGradient = new LinearGradient(0.0f, 0.0f, 0.0f, mDrawHeight / 2.0f,
+                    Color.YELLOW, Color.MAGENTA, Shader.TileMode.MIRROR);
+
+            mPaint = new Paint();
+        }
+
+        @Override
+        protected void onDraw(Canvas canvas) {
+            super.onDraw(canvas);
+            canvas.drawRGB(255, 255, 255);
+
+            // Bitmap shaders
+            canvas.save();
+            canvas.translate(40.0f, 40.0f);
+
+            mPaint.setShader(mRepeatShader);
+            canvas.drawRect(0.0f, 0.0f, mDrawWidth, mDrawHeight, mPaint);
+            
+            canvas.translate(0.0f, 40.0f + mDrawHeight);
+            mPaint.setShader(mTranslatedShader);
+            canvas.drawRect(0.0f, 0.0f, mDrawWidth, mDrawHeight, mPaint);
+
+            canvas.translate(0.0f, 40.0f + mDrawHeight);
+            mPaint.setShader(mScaledShader);
+            canvas.drawRect(0.0f, 0.0f, mDrawWidth, mDrawHeight, mPaint);
+
+            canvas.restore();
+
+            // Gradients
+            canvas.save();
+            canvas.translate(40.0f + mDrawWidth + 40.0f, 40.0f);
+
+            mPaint.setShader(mHorGradient);
+            canvas.drawRect(0.0f, 0.0f, mDrawWidth, mDrawHeight, mPaint);
+            
+            canvas.translate(0.0f, 40.0f + mDrawHeight);
+            mPaint.setShader(mDiagGradient);
+            canvas.drawRect(0.0f, 0.0f, mDrawWidth, mDrawHeight, mPaint);
+
+            canvas.translate(0.0f, 40.0f + mDrawHeight);
+            mPaint.setShader(mVertGradient);
+            canvas.drawRect(0.0f, 0.0f, mDrawWidth, mDrawHeight, mPaint);
+            
+            canvas.restore();
+        }
+    }
+}
diff --git a/tools/layoutlib/Android.mk b/tools/layoutlib/Android.mk
index 6d606a9..135a633 100644
--- a/tools/layoutlib/Android.mk
+++ b/tools/layoutlib/Android.mk
@@ -52,13 +52,15 @@
 $(LOCAL_BUILT_MODULE): $(built_core_dep) \
                        $(built_framework_dep) \
                        $(built_layoutlib_create_jar)
-	@echo "host layoutlib_create: $@"
-	@mkdir -p $(dir $@)
-	@rm -f $@
+	$(hide) echo "host layoutlib_create: $@"
+	$(hide) mkdir -p $(dir $@)
+	$(hide) rm -f $@
+	$(hide) ls -l $(built_framework_classes)
 	$(hide) java -jar $(built_layoutlib_create_jar) \
 	             $@ \
 	             $(built_core_classes) \
 	             $(built_framework_classes)
+	$(hide) ls -l $(built_framework_classes)
 
 
 #
diff --git a/wifi/java/android/net/wifi/WifiStateTracker.java b/wifi/java/android/net/wifi/WifiStateTracker.java
index 5b4faf97..5780a04 100644
--- a/wifi/java/android/net/wifi/WifiStateTracker.java
+++ b/wifi/java/android/net/wifi/WifiStateTracker.java
@@ -30,6 +30,7 @@
 import android.net.ConnectivityManager;
 import android.net.NetworkInfo.DetailedState;
 import android.net.NetworkInfo.State;
+import android.net.NetworkProperties;
 import android.os.Message;
 import android.os.Parcelable;
 import android.os.Handler;
@@ -54,6 +55,9 @@
 import android.database.ContentObserver;
 import com.android.internal.app.IBatteryStats;
 
+import java.net.InetAddress;
+import java.net.NetworkInterface;
+import java.net.SocketException;
 import java.net.UnknownHostException;
 import java.util.ArrayList;
 import java.util.List;
@@ -211,6 +215,7 @@
     private boolean mDisconnectExpected;
     private DhcpHandler mDhcpTarget;
     private DhcpInfo mDhcpInfo;
+    private NetworkProperties mNetworkProperties;
     private int mLastSignalLevel = -1;
     private String mLastBssid;
     private String mLastSsid;
@@ -315,7 +320,6 @@
     private String mInterfaceName;
     private static String LS = System.getProperty("line.separator");
 
-    private static String[] sDnsPropNames;
     private Handler mTarget;
     private Context mContext;
     private boolean mPrivateDnsRouteSet = false;
@@ -379,10 +383,7 @@
         mSettingsObserver = new SettingsObserver(new Handler());
 
         mInterfaceName = SystemProperties.get("wifi.interface", "tiwlan0");
-        sDnsPropNames = new String[] {
-            "dhcp." + mInterfaceName + ".dns1",
-            "dhcp." + mInterfaceName + ".dns2"
-        };
+        mNetworkProperties = new NetworkProperties();
         mBatteryStats = IBatteryStats.Stub.asInterface(ServiceManager.getService("batteryinfo"));
 
     }
@@ -477,15 +478,6 @@
     }
 
     /**
-     * Return the IP addresses of the DNS servers available for the WLAN
-     * network interface.
-     * @return a list of DNS addresses, with no holes.
-     */
-    public String[] getDnsPropNames() {
-        return sDnsPropNames;
-    }
-
-    /**
      * Return the name of our WLAN network interface.
      * @return the name of our interface.
      */
@@ -901,6 +893,7 @@
                 }
                 setDetailedState(DetailedState.DISCONNECTED);
                 setSupplicantState(SupplicantState.UNINITIALIZED);
+                mNetworkProperties.clear();
                 mHaveIpAddress = false;
                 mObtainingIpAddress = false;
                 if (died) {
@@ -1008,6 +1001,7 @@
                             reconnectCommand();
                         }
                     } else if (newState == SupplicantState.DISCONNECTED) {
+                        mNetworkProperties.clear();
                         mHaveIpAddress = false;
                         if (isDriverStopped() || mDisconnectExpected) {
                             handleDisconnectedState(DetailedState.DISCONNECTED, true);
@@ -1192,6 +1186,7 @@
                 }
                 mReconnectCount = 0;
                 mHaveIpAddress = true;
+                configureNetworkProperties();
                 mObtainingIpAddress = false;
                 mWifiInfo.setIpAddress(mDhcpInfo.ipAddress);
                 mLastSignalLevel = -1; // force update of signal strength
@@ -1217,6 +1212,7 @@
                     // [31- 1] Reserved for future use
                     // [ 0- 0] Interface configuration succeeded (1) or failed (0)
                     EventLog.writeEvent(EVENTLOG_INTERFACE_CONFIGURATION_STATE_CHANGED, 0);
+                    mNetworkProperties.clear();
                     mHaveIpAddress = false;
                     mWifiInfo.setIpAddress(0);
                     mObtainingIpAddress = false;
@@ -1289,6 +1285,49 @@
         return disabledNetwork;
     }
 
+
+    private void configureNetworkProperties() {
+        try {
+            mNetworkProperties.setInterface(NetworkInterface.getByName(mInterfaceName));
+        } catch (SocketException e) {
+            Log.e(TAG, "SocketException creating NetworkInterface from " + mInterfaceName +
+                    ". e=" + e);
+            return;
+        } catch (NullPointerException e) {
+            Log.e(TAG, "NPE creating NetworkInterface. e=" + e);
+            return;
+        }
+        // TODO - fix this for v6
+        try {
+            mNetworkProperties.addAddress(InetAddress.getByAddress(
+                    NetworkUtils.v4IntToArray(mDhcpInfo.ipAddress)));
+        } catch (UnknownHostException e) {
+            Log.e(TAG, "Exception setting IpAddress using " + mDhcpInfo + ", e=" + e);
+        }
+
+        try {
+            mNetworkProperties.setGateway(InetAddress.getByAddress(NetworkUtils.v4IntToArray(
+                    mDhcpInfo.gateway)));
+        } catch (UnknownHostException e) {
+            Log.e(TAG, "Exception setting Gateway using " + mDhcpInfo + ", e=" + e);
+        }
+
+        try {
+            mNetworkProperties.addDns(InetAddress.getByAddress(
+                    NetworkUtils.v4IntToArray(mDhcpInfo.dns1)));
+        } catch (UnknownHostException e) {
+            Log.e(TAG, "Exception setting Dns1 using " + mDhcpInfo + ", e=" + e);
+        }
+        try {
+            mNetworkProperties.addDns(InetAddress.getByAddress(
+                    NetworkUtils.v4IntToArray(mDhcpInfo.dns2)));
+
+        } catch (UnknownHostException e) {
+            Log.e(TAG, "Exception setting Dns2 using " + mDhcpInfo + ", e=" + e);
+        }
+        // TODO - add proxy info
+    }
+
     private void configureInterface() {
         checkPollTimer();
         mLastSignalLevel = -1;
@@ -1300,11 +1339,9 @@
         } else {
             int event;
             if (NetworkUtils.configureInterface(mInterfaceName, mDhcpInfo)) {
-                mHaveIpAddress = true;
                 event = EVENT_INTERFACE_CONFIGURATION_SUCCEEDED;
                 if (LOCAL_LOGD) Log.v(TAG, "Static IP configuration succeeded");
             } else {
-                mHaveIpAddress = false;
                 event = EVENT_INTERFACE_CONFIGURATION_FAILED;
                 if (LOCAL_LOGD) Log.v(TAG, "Static IP configuration failed");
             }
@@ -1339,6 +1376,7 @@
      */
     public void resetConnections(boolean disableInterface) {
         if (LOCAL_LOGD) Log.d(TAG, "Reset connections and stopping DHCP");
+        mNetworkProperties.clear();
         mHaveIpAddress = false;
         mObtainingIpAddress = false;
         mWifiInfo.setIpAddress(0);
@@ -2282,11 +2320,12 @@
         mNotificationRepeatTime = 0;
         mNumScansSinceNetworkStateChange = 0;
     }
-    
+
     @Override
     public String toString() {
         StringBuffer sb = new StringBuffer();
-        sb.append("interface ").append(mInterfaceName);
+
+        sb.append(mNetworkProperties.toString());
         sb.append(" runState=");
         if (mRunState >= 1 && mRunState <= mRunStateNames.length) {
             sb.append(mRunStateNames[mRunState-1]);
@@ -2366,7 +2405,7 @@
                         setBluetoothCoexistenceMode(
                                 WifiNative.BLUETOOTH_COEXISTENCE_MODE_DISABLED);
                     }
-                    
+
                     powerMode = getPowerMode();
                     if (powerMode < 0) {
                       // Handle the case where supplicant driver does not support
@@ -2588,4 +2627,8 @@
                     Settings.Secure.WIFI_NETWORKS_AVAILABLE_NOTIFICATION_ON, 1) == 1;
         }
     }
+
+    public NetworkProperties getNetworkProperties() {
+        return mNetworkProperties;
+    }
 }