Merge "Never drag scroll views with no children." into honeycomb
diff --git a/Android.mk b/Android.mk
index f581515..5d989d1 100644
--- a/Android.mk
+++ b/Android.mk
@@ -167,6 +167,7 @@
 	core/java/com/android/internal/view/IInputMethodManager.aidl \
 	core/java/com/android/internal/view/IInputMethodSession.aidl \
 	core/java/com/android/internal/widget/IRemoteViewsFactory.aidl \
+	core/java/com/android/internal/widget/IRemoteViewsAdapterConnection.aidl \
 	location/java/android/location/ICountryDetector.aidl \
 	location/java/android/location/ICountryListener.aidl \
 	location/java/android/location/IGeocodeProvider.aidl \
diff --git a/CleanSpec.mk b/CleanSpec.mk
index 1acb620..337b30f 100644
--- a/CleanSpec.mk
+++ b/CleanSpec.mk
@@ -89,6 +89,7 @@
 $(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/framework_intermediates/src/core/java/android/nfc/INdefTag.java)
 $(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/STATIC_LIBRARIES/libstagefright_aacdec_intermediates)
 $(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/STATIC_LIBRARIES/libstagefright_mp3dec_intermediates)
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/build.prop)
 
 # ************************************************
 # NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST
diff --git a/api/11.xml b/api/11.xml
index 5087eca..31cfc85 100644
--- a/api/11.xml
+++ b/api/11.xml
@@ -188,6 +188,17 @@
  visibility="public"
 >
 </field>
+<field name="BIND_REMOTEVIEWS"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;android.permission.BIND_REMOTEVIEWS&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
 <field name="BIND_WALLPAPER"
  type="java.lang.String"
  transient="false"
@@ -2710,6 +2721,17 @@
  visibility="public"
 >
 </field>
+<field name="calendarViewStyle"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="16843613"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
 <field name="candidatesTextStyleSpans"
  type="int"
  transient="false"
@@ -3271,6 +3293,17 @@
  visibility="public"
 >
 </field>
+<field name="datePickerStyle"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="16843612"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
 <field name="dateTextAppearance"
  type="int"
  transient="false"
@@ -8716,17 +8749,6 @@
  visibility="public"
 >
 </field>
-<field name="solidColor"
- type="int"
- transient="false"
- volatile="false"
- value="16843594"
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
 <field name="soundEffectsEnabled"
  type="int"
  transient="false"
@@ -10894,6 +10916,17 @@
  visibility="public"
 >
 </field>
+<field name="windowCloseOnTouchOutside"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="16843611"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
 <field name="windowContentOverlay"
  type="int"
  transient="false"
@@ -15971,7 +16004,7 @@
  type="int"
  transient="false"
  volatile="false"
- value="16974069"
+ value="16974060"
  static="true"
  final="true"
  deprecated="not deprecated"
@@ -16022,6 +16055,17 @@
  visibility="public"
 >
 </field>
+<field name="Widget_DatePicker"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="16974063"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
 <field name="Widget_DropDownItem"
  type="int"
  transient="false"
@@ -16055,17 +16099,6 @@
  visibility="public"
 >
 </field>
-<field name="Widget_EditText_NumberPickerInputText"
- type="int"
- transient="false"
- volatile="false"
- value="16974061"
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
 <field name="Widget_ExpandableListView"
  type="int"
  transient="false"
@@ -16257,7 +16290,7 @@
  type="int"
  transient="false"
  volatile="false"
- value="16974070"
+ value="16974061"
  static="true"
  final="true"
  deprecated="not deprecated"
@@ -16297,6 +16330,17 @@
  visibility="public"
 >
 </field>
+<field name="Widget_Holo_DatePicker"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="16974064"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
 <field name="Widget_Holo_DropDownItem"
  type="int"
  transient="false"
@@ -16330,17 +16374,6 @@
  visibility="public"
 >
 </field>
-<field name="Widget_Holo_EditText_NumberPickerInputText"
- type="int"
- transient="false"
- volatile="false"
- value="16974064"
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
 <field name="Widget_Holo_ExpandableListView"
  type="int"
  transient="false"
@@ -16385,28 +16418,6 @@
  visibility="public"
 >
 </field>
-<field name="Widget_Holo_ImageButton_NumberPickerDownButton"
- type="int"
- transient="false"
- volatile="false"
- value="16974065"
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
-<field name="Widget_Holo_ImageButton_NumberPickerUpButton"
- type="int"
- transient="false"
- volatile="false"
- value="16974063"
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
 <field name="Widget_Holo_Light"
  type="int"
  transient="false"
@@ -16532,7 +16543,7 @@
  type="int"
  transient="false"
  volatile="false"
- value="16974071"
+ value="16974062"
  static="true"
  final="true"
  deprecated="not deprecated"
@@ -16605,17 +16616,6 @@
  visibility="public"
 >
 </field>
-<field name="Widget_Holo_Light_EditText_NumberPickerInputText"
- type="int"
- transient="false"
- volatile="false"
- value="16974067"
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
 <field name="Widget_Holo_Light_ExpandableListView"
  type="int"
  transient="false"
@@ -16660,28 +16660,6 @@
  visibility="public"
 >
 </field>
-<field name="Widget_Holo_Light_ImageButton_NumberPickerDownButton"
- type="int"
- transient="false"
- volatile="false"
- value="16974068"
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
-<field name="Widget_Holo_Light_ImageButton_NumberPickerUpButton"
- type="int"
- transient="false"
- volatile="false"
- value="16974066"
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
 <field name="Widget_Holo_Light_ListPopupWindow"
  type="int"
  transient="false"
@@ -17210,28 +17188,6 @@
  visibility="public"
 >
 </field>
-<field name="Widget_ImageButton_NumberPickerDownButton"
- type="int"
- transient="false"
- volatile="false"
- value="16974062"
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
-<field name="Widget_ImageButton_NumberPickerUpButton"
- type="int"
- transient="false"
- volatile="false"
- value="16974060"
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
 <field name="Widget_ImageWell"
  type="int"
  transient="false"
@@ -24300,6 +24256,19 @@
 <parameter name="uri" type="android.net.Uri">
 </parameter>
 </method>
+<method name="setFinishOnTouchOutside"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="finish" type="boolean">
+</parameter>
+</method>
 <method name="setIntent"
  return="void"
  abstract="false"
@@ -136088,6 +136057,17 @@
  visibility="public"
 >
 </method>
+<method name="getPreserveEGLContextOnPause"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
 <method name="getRenderMode"
  return="int"
  abstract="false"
@@ -136259,6 +136239,19 @@
 <parameter name="glWrapper" type="android.opengl.GLSurfaceView.GLWrapper">
 </parameter>
 </method>
+<method name="setPreserveEGLContextOnPause"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="preserveOnPause" type="boolean">
+</parameter>
+</method>
 <method name="setRenderMode"
  return="void"
  abstract="false"
@@ -146691,6 +146684,16 @@
  visibility="public"
 >
 </constructor>
+<constructor name="StrictMode.VmPolicy.Builder"
+ type="android.os.StrictMode.VmPolicy.Builder"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="base" type="android.os.StrictMode.VmPolicy">
+</parameter>
+</constructor>
 <method name="build"
  return="android.os.StrictMode.VmPolicy"
  abstract="false"
@@ -146768,6 +146771,21 @@
  visibility="public"
 >
 </method>
+<method name="setClassInstanceLimit"
+ return="android.os.StrictMode.VmPolicy.Builder"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="klass" type="java.lang.Class">
+</parameter>
+<parameter name="instanceLimit" type="int">
+</parameter>
+</method>
 </class>
 <class name="SystemClock"
  extends="java.lang.Object"
@@ -160195,17 +160213,6 @@
  visibility="public"
 >
 </field>
-<field name="ACTION_MTP_SESSION_END"
- type="java.lang.String"
- transient="false"
- volatile="false"
- value="&quot;android.provider.action.MTP_SESSION_END&quot;"
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
 <field name="ACTION_VIDEO_CAPTURE"
  type="java.lang.String"
  transient="false"
@@ -166475,6 +166482,74 @@
 <parameter name="d" type="float[]">
 </parameter>
 </method>
+<method name="copy1DRangeFromUnchecked"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="off" type="int">
+</parameter>
+<parameter name="count" type="int">
+</parameter>
+<parameter name="d" type="int[]">
+</parameter>
+</method>
+<method name="copy1DRangeFromUnchecked"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="off" type="int">
+</parameter>
+<parameter name="count" type="int">
+</parameter>
+<parameter name="d" type="short[]">
+</parameter>
+</method>
+<method name="copy1DRangeFromUnchecked"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="off" type="int">
+</parameter>
+<parameter name="count" type="int">
+</parameter>
+<parameter name="d" type="byte[]">
+</parameter>
+</method>
+<method name="copy1DRangeFromUnchecked"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="off" type="int">
+</parameter>
+<parameter name="count" type="int">
+</parameter>
+<parameter name="d" type="float[]">
+</parameter>
+</method>
 <method name="copy2DRangeFrom"
  return="void"
  abstract="false"
@@ -166654,6 +166729,58 @@
 <parameter name="b" type="android.graphics.Bitmap">
 </parameter>
 </method>
+<method name="copyFromUnchecked"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="d" type="int[]">
+</parameter>
+</method>
+<method name="copyFromUnchecked"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="d" type="short[]">
+</parameter>
+</method>
+<method name="copyFromUnchecked"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="d" type="byte[]">
+</parameter>
+</method>
+<method name="copyFromUnchecked"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="d" type="float[]">
+</parameter>
+</method>
 <method name="copyTo"
  return="void"
  abstract="false"
@@ -175623,6 +175750,17 @@
  visibility="public"
 >
 </field>
+<field name="KEY_PARAM_PAN"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;pan&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
 <field name="KEY_PARAM_STREAM"
  type="java.lang.String"
  transient="false"
@@ -175645,6 +175783,17 @@
  visibility="public"
 >
 </field>
+<field name="KEY_PARAM_VOLUME"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;volume&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
 </class>
 <interface name="TextToSpeech.OnInitListener"
  abstract="true"
@@ -219385,6 +219534,14 @@
 <parameter name="view" type="android.view.View">
 </parameter>
 </constructor>
+<constructor name="View.DragShadowBuilder"
+ type="android.view.View.DragShadowBuilder"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</constructor>
 <method name="getView"
  return="android.view.View"
  abstract="false"
@@ -236035,6 +236192,48 @@
 </parameter>
 </method>
 </class>
+<class name="WebStorage.Origin"
+ extends="java.lang.Object"
+ abstract="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<method name="getOrigin"
+ return="java.lang.String"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getQuota"
+ return="long"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getUsage"
+ return="long"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+</class>
 <interface name="WebStorage.QuotaUpdater"
  abstract="true"
  static="true"
@@ -252327,6 +252526,8 @@
  deprecated="not deprecated"
  visibility="public"
 >
+<parameter name="appWidgetId" type="int">
+</parameter>
 <parameter name="viewId" type="int">
 </parameter>
 <parameter name="intent" type="android.content.Intent">
diff --git a/api/current.xml b/api/current.xml
index 76be208..83bfedb 100644
--- a/api/current.xml
+++ b/api/current.xml
@@ -188,6 +188,17 @@
  visibility="public"
 >
 </field>
+<field name="BIND_REMOTEVIEWS"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;android.permission.BIND_REMOTEVIEWS&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
 <field name="BIND_WALLPAPER"
  type="java.lang.String"
  transient="false"
@@ -2710,6 +2721,17 @@
  visibility="public"
 >
 </field>
+<field name="calendarViewStyle"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="16843613"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
 <field name="candidatesTextStyleSpans"
  type="int"
  transient="false"
@@ -3271,6 +3293,17 @@
  visibility="public"
 >
 </field>
+<field name="datePickerStyle"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="16843612"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
 <field name="dateTextAppearance"
  type="int"
  transient="false"
@@ -8716,17 +8749,6 @@
  visibility="public"
 >
 </field>
-<field name="solidColor"
- type="int"
- transient="false"
- volatile="false"
- value="16843594"
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
 <field name="soundEffectsEnabled"
  type="int"
  transient="false"
@@ -15982,7 +16004,7 @@
  type="int"
  transient="false"
  volatile="false"
- value="16974069"
+ value="16974060"
  static="true"
  final="true"
  deprecated="not deprecated"
@@ -16033,6 +16055,17 @@
  visibility="public"
 >
 </field>
+<field name="Widget_DatePicker"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="16974063"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
 <field name="Widget_DropDownItem"
  type="int"
  transient="false"
@@ -16066,17 +16099,6 @@
  visibility="public"
 >
 </field>
-<field name="Widget_EditText_NumberPickerInputText"
- type="int"
- transient="false"
- volatile="false"
- value="16974061"
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
 <field name="Widget_ExpandableListView"
  type="int"
  transient="false"
@@ -16268,7 +16290,7 @@
  type="int"
  transient="false"
  volatile="false"
- value="16974070"
+ value="16974061"
  static="true"
  final="true"
  deprecated="not deprecated"
@@ -16308,6 +16330,17 @@
  visibility="public"
 >
 </field>
+<field name="Widget_Holo_DatePicker"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="16974064"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
 <field name="Widget_Holo_DropDownItem"
  type="int"
  transient="false"
@@ -16341,17 +16374,6 @@
  visibility="public"
 >
 </field>
-<field name="Widget_Holo_EditText_NumberPickerInputText"
- type="int"
- transient="false"
- volatile="false"
- value="16974064"
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
 <field name="Widget_Holo_ExpandableListView"
  type="int"
  transient="false"
@@ -16396,28 +16418,6 @@
  visibility="public"
 >
 </field>
-<field name="Widget_Holo_ImageButton_NumberPickerDownButton"
- type="int"
- transient="false"
- volatile="false"
- value="16974065"
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
-<field name="Widget_Holo_ImageButton_NumberPickerUpButton"
- type="int"
- transient="false"
- volatile="false"
- value="16974063"
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
 <field name="Widget_Holo_Light"
  type="int"
  transient="false"
@@ -16543,7 +16543,7 @@
  type="int"
  transient="false"
  volatile="false"
- value="16974071"
+ value="16974062"
  static="true"
  final="true"
  deprecated="not deprecated"
@@ -16616,17 +16616,6 @@
  visibility="public"
 >
 </field>
-<field name="Widget_Holo_Light_EditText_NumberPickerInputText"
- type="int"
- transient="false"
- volatile="false"
- value="16974067"
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
 <field name="Widget_Holo_Light_ExpandableListView"
  type="int"
  transient="false"
@@ -16671,28 +16660,6 @@
  visibility="public"
 >
 </field>
-<field name="Widget_Holo_Light_ImageButton_NumberPickerDownButton"
- type="int"
- transient="false"
- volatile="false"
- value="16974068"
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
-<field name="Widget_Holo_Light_ImageButton_NumberPickerUpButton"
- type="int"
- transient="false"
- volatile="false"
- value="16974066"
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
 <field name="Widget_Holo_Light_ListPopupWindow"
  type="int"
  transient="false"
@@ -17221,28 +17188,6 @@
  visibility="public"
 >
 </field>
-<field name="Widget_ImageButton_NumberPickerDownButton"
- type="int"
- transient="false"
- volatile="false"
- value="16974062"
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
-<field name="Widget_ImageButton_NumberPickerUpButton"
- type="int"
- transient="false"
- volatile="false"
- value="16974060"
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
 <field name="Widget_ImageWell"
  type="int"
  transient="false"
@@ -136112,6 +136057,17 @@
  visibility="public"
 >
 </method>
+<method name="getPreserveEGLContextOnPause"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
 <method name="getRenderMode"
  return="int"
  abstract="false"
@@ -136283,6 +136239,19 @@
 <parameter name="glWrapper" type="android.opengl.GLSurfaceView.GLWrapper">
 </parameter>
 </method>
+<method name="setPreserveEGLContextOnPause"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="preserveOnPause" type="boolean">
+</parameter>
+</method>
 <method name="setRenderMode"
  return="void"
  abstract="false"
@@ -146736,6 +146705,17 @@
  visibility="public"
 >
 </method>
+<method name="detectActivityLeaks"
+ return="android.os.StrictMode.VmPolicy.Builder"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
 <method name="detectAll"
  return="android.os.StrictMode.VmPolicy.Builder"
  abstract="false"
@@ -160244,17 +160224,6 @@
  visibility="public"
 >
 </field>
-<field name="ACTION_MTP_SESSION_END"
- type="java.lang.String"
- transient="false"
- volatile="false"
- value="&quot;android.provider.action.MTP_SESSION_END&quot;"
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
 <field name="ACTION_VIDEO_CAPTURE"
  type="java.lang.String"
  transient="false"
@@ -166524,6 +166493,74 @@
 <parameter name="d" type="float[]">
 </parameter>
 </method>
+<method name="copy1DRangeFromUnchecked"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="off" type="int">
+</parameter>
+<parameter name="count" type="int">
+</parameter>
+<parameter name="d" type="int[]">
+</parameter>
+</method>
+<method name="copy1DRangeFromUnchecked"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="off" type="int">
+</parameter>
+<parameter name="count" type="int">
+</parameter>
+<parameter name="d" type="short[]">
+</parameter>
+</method>
+<method name="copy1DRangeFromUnchecked"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="off" type="int">
+</parameter>
+<parameter name="count" type="int">
+</parameter>
+<parameter name="d" type="byte[]">
+</parameter>
+</method>
+<method name="copy1DRangeFromUnchecked"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="off" type="int">
+</parameter>
+<parameter name="count" type="int">
+</parameter>
+<parameter name="d" type="float[]">
+</parameter>
+</method>
 <method name="copy2DRangeFrom"
  return="void"
  abstract="false"
@@ -166703,6 +166740,58 @@
 <parameter name="b" type="android.graphics.Bitmap">
 </parameter>
 </method>
+<method name="copyFromUnchecked"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="d" type="int[]">
+</parameter>
+</method>
+<method name="copyFromUnchecked"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="d" type="short[]">
+</parameter>
+</method>
+<method name="copyFromUnchecked"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="d" type="byte[]">
+</parameter>
+</method>
+<method name="copyFromUnchecked"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="d" type="float[]">
+</parameter>
+</method>
 <method name="copyTo"
  return="void"
  abstract="false"
@@ -175672,6 +175761,17 @@
  visibility="public"
 >
 </field>
+<field name="KEY_PARAM_PAN"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;pan&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
 <field name="KEY_PARAM_STREAM"
  type="java.lang.String"
  transient="false"
@@ -175694,6 +175794,17 @@
  visibility="public"
 >
 </field>
+<field name="KEY_PARAM_VOLUME"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;volume&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
 </class>
 <interface name="TextToSpeech.OnInitListener"
  abstract="true"
@@ -219434,6 +219545,14 @@
 <parameter name="view" type="android.view.View">
 </parameter>
 </constructor>
+<constructor name="View.DragShadowBuilder"
+ type="android.view.View.DragShadowBuilder"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</constructor>
 <method name="getView"
  return="android.view.View"
  abstract="false"
@@ -252418,6 +252537,8 @@
  deprecated="not deprecated"
  visibility="public"
 >
+<parameter name="appWidgetId" type="int">
+</parameter>
 <parameter name="viewId" type="int">
 </parameter>
 <parameter name="intent" type="android.content.Intent">
diff --git a/build/phone-hdpi-512-dalvik-heap.mk b/build/phone-hdpi-512-dalvik-heap.mk
index afc45ee..630cf03 100644
--- a/build/phone-hdpi-512-dalvik-heap.mk
+++ b/build/phone-hdpi-512-dalvik-heap.mk
@@ -19,5 +19,5 @@
 
 PRODUCT_PROPERTY_OVERRIDES += \
     dalvik.vm.heapstartsize=5m \
-    dalvik.vm.smallheapsize=32m \
-    dalvik.vm.heapsize=32m
+    dalvik.vm.growthlimit=32m \
+    dalvik.vm.heapsize=128m
diff --git a/build/phone-hdpi-dalvik-heap.mk b/build/phone-hdpi-dalvik-heap.mk
index ee30b92..ab33b96 100644
--- a/build/phone-hdpi-dalvik-heap.mk
+++ b/build/phone-hdpi-dalvik-heap.mk
@@ -18,5 +18,4 @@
 
 PRODUCT_PROPERTY_OVERRIDES += \
     dalvik.vm.heapstartsize=5m \
-    dalvik.vm.smallheapsize=32m \
     dalvik.vm.heapsize=32m
diff --git a/build/tablet-dalvik-heap.mk b/build/tablet-dalvik-heap.mk
index 9cb2f6b..37c3ec5 100644
--- a/build/tablet-dalvik-heap.mk
+++ b/build/tablet-dalvik-heap.mk
@@ -18,5 +18,5 @@
 
 PRODUCT_PROPERTY_OVERRIDES += \
     dalvik.vm.heapstartsize=5m \
-    dalvik.vm.smallheapsize=48m \
-    dalvik.vm.heapsize=48m
+    dalvik.vm.growthlimit=48m \
+    dalvik.vm.heapsize=256m
diff --git a/core/java/android/accounts/AccountManagerService.java b/core/java/android/accounts/AccountManagerService.java
index e6eaf71..2c99f14 100644
--- a/core/java/android/accounts/AccountManagerService.java
+++ b/core/java/android/accounts/AccountManagerService.java
@@ -722,6 +722,9 @@
                 final String[] argsAccountId = {String.valueOf(accountId)};
                 db.update(TABLE_ACCOUNTS, values, ACCOUNTS_ID + "=?", argsAccountId);
                 db.delete(TABLE_AUTHTOKENS, AUTHTOKENS_ACCOUNTS_ID + "=?", argsAccountId);
+                synchronized (mCacheLock) {
+                    mAuthTokenCache.remove(account);
+                }
                 db.setTransactionSuccessful();
             }
         } finally {
@@ -1812,6 +1815,11 @@
                 try {
                     db.execSQL("DELETE from " + TABLE_AUTHTOKENS);
                     db.execSQL("UPDATE " + TABLE_ACCOUNTS + " SET " + ACCOUNTS_PASSWORD + " = ''");
+
+                    synchronized (mCacheLock) {
+                        mAuthTokenCache = new HashMap<Account, HashMap<String, String>>();
+                    }
+
                     db.setTransactionSuccessful();
                 } finally {
                     db.endTransaction();
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index 0a64070..ec6eaaa 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -4433,6 +4433,9 @@
             mStopped = true;
         }
         mResumed = false;
+
+        // Check for Activity leaks, if enabled.
+        StrictMode.conditionallyCheckInstanceCounts();
     }
 
     final void performDestroy() {
diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java
index d5aa961..133a7d0 100644
--- a/core/java/android/app/ActivityManager.java
+++ b/core/java/android/app/ActivityManager.java
@@ -64,8 +64,11 @@
     static public int staticGetMemoryClass() {
         // Really brain dead right now -- just take this from the configured
         // vm heap size, and assume it is in megabytes and thus ends with "m".
-        String vmHeapSize = SystemProperties.get("dalvik.vm.smallheapsize", "16m");
-        return Integer.parseInt(vmHeapSize.substring(0, vmHeapSize.length()-1));
+        String vmHeapSize = SystemProperties.get("dalvik.vm.growthlimit", "");
+        if (vmHeapSize != null && !"".equals(vmHeapSize)) {
+            return Integer.parseInt(vmHeapSize.substring(0, vmHeapSize.length()-1));
+        }
+        return staticGetLargeMemoryClass();
     }
     
     /**
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index db046ef..7cf60f9 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -3463,7 +3463,7 @@
         }
 
         if ((data.appInfo.flags&ApplicationInfo.FLAG_LARGE_HEAP) != 0) {
-            // XXX bump up Dalvik's heap.
+            dalvik.system.VMRuntime.getRuntime().clearGrowthLimit();
         }
 
         // If the app is being launched for full backup or restore, bring it up in
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index 0243b02..de84c56 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -34,6 +34,9 @@
  * A class that represents how a persistent notification is to be presented to
  * the user using the {@link android.app.NotificationManager}.
  *
+ * <p>The {@link Notification.Builder Notification.Builder} has been added to make it
+ * easier to construct Notifications.</p>
+ *
  * <p>For a guide to creating notifications, see the
  * <a href="{@docRoot}guide/topics/ui/notifiers/notifications.html">Creating Status 
  * Bar Notifications</a> document in the Dev Guide.</p>
@@ -119,15 +122,8 @@
 
     /**
      * An intent to launch instead of posting the notification to the status bar.
-     * Only for use with extremely high-priority notifications demanding the user's
-     * <strong>immediate</strong> attention, such as an incoming phone call or
-     * alarm clock that the user has explicitly set to a particular time.
-     * If this facility is used for something else, please give the user an option
-     * to turn it off and use a normal notification, as this can be extremely
-     * disruptive.
-     * 
-     * <p>Use with {@link #FLAG_HIGH_PRIORITY} to ensure that this notification
-     * will reach the user even when other notifications are suppressed.
+     *
+     * @see Notification.Builder#setFullScreenIntent
      */
     public PendingIntent fullScreenIntent;
 
@@ -278,7 +274,7 @@
     /**
      * Bit to be bitwise-ored into the {@link #flags} field that should be
      * set if the notification should be canceled when it is clicked by the
-     * user. 
+     * user.  On tablets, the 
      */
     public static final int FLAG_AUTO_CANCEL        = 0x00000010;
 
@@ -618,6 +614,10 @@
         return sb.toString();
     }
 
+    /**
+     * Builder class for {@link Notification} objects.  Allows easier control over
+     * all the flags, as well as help constructing the typical notification layouts.
+     */
     public static class Builder {
         private Context mContext;
 
@@ -644,6 +644,16 @@
         private int mDefaults;
         private int mFlags;
 
+        /**
+         * Constructor.
+         *
+         * Automatically sets the when field to {@link System#currentTimeMillis()
+         * System.currentTimeMllis()} and the audio stream to the {@link #STREAM_DEFAULT}.
+         *
+         * @param context A {@link Context} that will be used to construct the
+         *      RemoteViews. The Context will not be held past the lifetime of this
+         *      Builder object.
+         */
         public Builder(Context context) {
             mContext = context;
 
@@ -652,96 +662,192 @@
             mAudioStreamType = STREAM_DEFAULT;
         }
 
+        /**
+         * Set the time that the event occurred.  Notifications in the panel are
+         * sorted by this time.
+         */
         public Builder setWhen(long when) {
             mWhen = when;
             return this;
         }
 
+        /**
+         * Set the small icon to use in the notification layouts.  Different classes of devices
+         * may return different sizes.  See the UX guidelines for more information on how to
+         * design these icons.
+         *
+         * @param icon A resource ID in the application's package of the drawble to use.
+         */
         public Builder setSmallIcon(int icon) {
             mSmallIcon = icon;
             return this;
         }
 
+        /**
+         * A variant of {@link #setSmallIcon(int) setSmallIcon(int)} that takes an additional
+         * level parameter for when the icon is a {@link android.graphics.drawable.LevelListDrawable
+         * LevelListDrawable}.
+         *
+         * @param icon A resource ID in the application's package of the drawble to use.
+         * @param level The level to use for the icon.
+         *
+         * @see android.graphics.drawable.LevelListDrawable
+         */
         public Builder setSmallIcon(int icon, int level) {
             mSmallIcon = icon;
             mSmallIconLevel = level;
             return this;
         }
 
+        /**
+         * Set the title (first row) of the notification, in a standard notification.
+         */
         public Builder setContentTitle(CharSequence title) {
             mContentTitle = title;
             return this;
         }
 
+        /**
+         * Set the text (second row) of the notification, in a standard notification.
+         */
         public Builder setContentText(CharSequence text) {
             mContentText = text;
             return this;
         }
 
+        /**
+         * Set the large number at the right-hand side of the notification.  This is
+         * equivalent to setContentInfo, although it might show the number in a different
+         * font size for readability.
+         */
         public Builder setNumber(int number) {
             mNumber = number;
             return this;
         }
 
+        /**
+         * Set the large text at the right-hand side of the notification.
+         */
         public Builder setContentInfo(CharSequence info) {
             mContentInfo = info;
             return this;
         }
 
+        /**
+         * Supply a custom RemoteViews to use instead of the standard one.
+         */
         public Builder setContent(RemoteViews views) {
             mContentView = views;
             return this;
         }
 
+        /**
+         * Supply a {@link PendingIntent} to send when the notification is clicked.
+         * If you do not supply an intent, you can now add PendingIntents to individual
+         * views to be launched when clicked by calling {@link RemoteViews#setOnClickPendingIntent
+         * RemoteViews.setOnClickPendingIntent(int,PendingIntent)}.
+         */
         public Builder setContentIntent(PendingIntent intent) {
             mContentIntent = intent;
             return this;
         }
 
+        /**
+         * Supply a {@link PendingIntent} to send when the notification is cleared by the user
+         * directly from the notification panel.  For example, this intent is sent when the user
+         * clicks the "Clear all" button, or the individual "X" buttons on notifications.  This
+         * intent is not sent when the application calls {@link NotificationManager#cancel
+         * NotificationManager.cancel(int)}.
+         */
         public Builder setDeleteIntent(PendingIntent intent) {
             mDeleteIntent = intent;
             return this;
         }
 
+        /**
+         * An intent to launch instead of posting the notification to the status bar.
+         * Only for use with extremely high-priority notifications demanding the user's
+         * <strong>immediate</strong> attention, such as an incoming phone call or
+         * alarm clock that the user has explicitly set to a particular time.
+         * If this facility is used for something else, please give the user an option
+         * to turn it off and use a normal notification, as this can be extremely
+         * disruptive.
+         *
+         * @param intent The pending intent to launch.
+         * @param highPriority Passing true will cause this notification to be sent
+         *          even if other notifications are suppressed.
+         */
         public Builder setFullScreenIntent(PendingIntent intent, boolean highPriority) {
             mFullScreenIntent = intent;
             setFlag(FLAG_HIGH_PRIORITY, highPriority);
             return this;
         }
 
+        /**
+         * Set the text that is displayed in the status bar when the notification first
+         * arrives.
+         */
         public Builder setTicker(CharSequence tickerText) {
             mTickerText = tickerText;
             return this;
         }
 
+        /**
+         * Set the text that is displayed in the status bar when the notification first
+         * arrives, and also a RemoteViews object that may be displayed instead on some
+         * devices.
+         */
         public Builder setTicker(CharSequence tickerText, RemoteViews views) {
             mTickerText = tickerText;
             mTickerView = views;
             return this;
         }
 
+        /**
+         * Set the large icon that is shown in the ticker and notification.
+         */
         public Builder setLargeIcon(Bitmap icon) {
             mLargeIcon = icon;
             return this;
         }
 
+        /**
+         * Set the sound to play.  It will play on the default stream.
+         */
         public Builder setSound(Uri sound) {
             mSound = sound;
             mAudioStreamType = STREAM_DEFAULT;
             return this;
         }
 
+        /**
+         * Set the sound to play.  It will play on the stream you supply.
+         *
+         * @see #STREAM_DEFAULT
+         * @see AudioManager for the <code>STREAM_</code> constants.
+         */
         public Builder setSound(Uri sound, int streamType) {
             mSound = sound;
             mAudioStreamType = streamType;
             return this;
         }
 
+        /**
+         * Set the vibration pattern to use.
+         *
+         * @see android.os.Vibrator for a discussion of the <code>pattern</code>
+         * parameter.
+         */
         public Builder setVibrate(long[] pattern) {
             mVibrate = pattern;
             return this;
         }
 
+        /**
+         * Set the argb value that you would like the LED on the device to blnk, as well as the
+         * rate.  The rate is specified in terms of the number of milliseconds to be on
+         * and then the number of milliseconds to be off.
+         */
         public Builder setLights(int argb, int onMs, int offMs) {
             mLedArgb = argb;
             mLedOnMs = onMs;
@@ -749,21 +855,51 @@
             return this;
         }
 
+        /**
+         * Set whether this is an ongoing notification.
+         *
+         * <p>Ongoing notifications differ from regular notifications in the following ways:
+         * <ul>
+         *   <li>Ongoing notifications are sorted above the regular notifications in the
+         *   notification panel.</li>
+         *   <li>Ongoing notifications do not have an 'X' close button, and are not affected
+         *   by the "Clear all" button.
+         * </ul>
+         */
         public Builder setOngoing(boolean ongoing) {
             setFlag(FLAG_ONGOING_EVENT, ongoing);
             return this;
         }
 
+        /**
+         * Set this flag if you would only like the sound, vibrate
+         * and ticker to be played if the notification is not already showing.
+         */
         public Builder setOnlyAlertOnce(boolean onlyAlertOnce) {
             setFlag(FLAG_ONLY_ALERT_ONCE, onlyAlertOnce);
             return this;
         }
 
+        /**
+         * Setting this flag will make it so the notification is automatically
+         * canceled when the user clicks it in the panel.  The PendingIntent
+         * set with {@link #setDeleteIntent} will be broadcast when the notification
+         * is canceled.
+         */
         public Builder setAutoCancel(boolean autoCancel) {
             setFlag(FLAG_AUTO_CANCEL, autoCancel);
             return this;
         }
 
+        /**
+         * Set the default notification options that will be used.
+         * <p>
+         * The value should be one or more of the following fields combined with
+         * bitwise-or:
+         * {@link #DEFAULT_SOUND}, {@link #DEFAULT_VIBRATE}, {@link #DEFAULT_LIGHTS}.
+         * <p>
+         * For all default values, use {@link #DEFAULT_ALL}.
+         */
         public Builder setDefaults(int defaults) {
             mDefaults = defaults;
             return this;
@@ -834,6 +970,10 @@
             }
         }
 
+        /**
+         * Combine all of the options that have been set and return a new {@link Notification}
+         * object.
+         */
         public Notification getNotification() {
             Notification n = new Notification();
             n.when = mWhen;
diff --git a/core/java/android/appwidget/AppWidgetManager.java b/core/java/android/appwidget/AppWidgetManager.java
index 2a583c1..019652c 100644
--- a/core/java/android/appwidget/AppWidgetManager.java
+++ b/core/java/android/appwidget/AppWidgetManager.java
@@ -18,6 +18,7 @@
 
 import android.content.ComponentName;
 import android.content.Context;
+import android.content.Intent;
 import android.os.IBinder;
 import android.os.RemoteException;
 import android.os.ServiceManager;
@@ -438,6 +439,47 @@
     }
 
     /**
+     * Binds the RemoteViewsService for a given appWidgetId and intent.
+     *
+     * The appWidgetId specified must already be bound to the calling AppWidgetHost via
+     * {@link android.appwidget.AppWidgetManager#bindAppWidgetId AppWidgetManager.bindAppWidgetId()}.
+     *
+     * @param appWidgetId   The AppWidget instance for which to bind the RemoteViewsService.
+     * @param intent        The intent of the service which will be providing the data to the
+     *                      RemoteViewsAdapter.
+     * @param connection    The callback interface to be notified when a connection is made or lost.
+     * @hide
+     */
+    public void bindRemoteViewsService(int appWidgetId, Intent intent, IBinder connection) {
+        try {
+            sService.bindRemoteViewsService(appWidgetId, intent, connection);
+        }
+        catch (RemoteException e) {
+            throw new RuntimeException("system server dead?", e);
+        }
+    }
+
+    /**
+     * Unbinds the RemoteViewsService for a given appWidgetId and intent.
+     *
+     * The appWidgetId specified muse already be bound to the calling AppWidgetHost via
+     * {@link android.appwidget.AppWidgetManager#bindAppWidgetId AppWidgetManager.bindAppWidgetId()}.
+     *
+     * @param appWidgetId   The AppWidget instance for which to bind the RemoteViewsService.
+     * @param intent        The intent of the service which will be providing the data to the
+     *                      RemoteViewsAdapter.
+     * @hide
+     */
+    public void unbindRemoteViewsService(int appWidgetId, Intent intent) {
+        try {
+            sService.unbindRemoteViewsService(appWidgetId, intent);
+        }
+        catch (RemoteException e) {
+            throw new RuntimeException("system server dead?", e);
+        }
+    }
+
+    /**
      * Get the list of appWidgetIds that have been bound to the given AppWidget
      * provider.
      *
diff --git a/core/java/android/bluetooth/BluetoothInputDevice.java b/core/java/android/bluetooth/BluetoothInputDevice.java
index bc8a836..a70de59 100644
--- a/core/java/android/bluetooth/BluetoothInputDevice.java
+++ b/core/java/android/bluetooth/BluetoothInputDevice.java
@@ -85,6 +85,19 @@
      */
     public static final int PRIORITY_UNDEFINED = -1;
 
+    /**
+     * Return codes for the connect and disconnect Bluez / Dbus calls.
+     */
+    public static final int INPUT_DISCONNECT_FAILED_NOT_CONNECTED = 5000;
+
+    public static final int INPUT_CONNECT_FAILED_ALREADY_CONNECTED = 5001;
+
+    public static final int INPUT_CONNECT_FAILED_ATTEMPT_FAILED = 5002;
+
+    public static final int INPUT_OPERATION_GENERIC_FAILURE = 5003;
+
+    public static final int INPUT_OPERATION_SUCCESS = 5004;
+
     private final IBluetooth mService;
     private final Context mContext;
 
diff --git a/core/java/android/bluetooth/BluetoothPan.java b/core/java/android/bluetooth/BluetoothPan.java
index 7dee25e..1f07349 100644
--- a/core/java/android/bluetooth/BluetoothPan.java
+++ b/core/java/android/bluetooth/BluetoothPan.java
@@ -70,6 +70,19 @@
     public static final int STATE_CONNECTED    = 2;
     public static final int STATE_DISCONNECTING = 3;
 
+    /**
+     * Return codes for the connect and disconnect Bluez / Dbus calls.
+     */
+    public static final int PAN_DISCONNECT_FAILED_NOT_CONNECTED = 1000;
+
+    public static final int PAN_CONNECT_FAILED_ALREADY_CONNECTED = 1001;
+
+    public static final int PAN_CONNECT_FAILED_ATTEMPT_FAILED = 1002;
+
+    public static final int PAN_OPERATION_GENERIC_FAILURE = 1003;
+
+    public static final int PAN_OPERATION_SUCCESS = 1004;
+
     private final IBluetooth mService;
     private final Context mContext;
 
diff --git a/core/java/android/os/Build.java b/core/java/android/os/Build.java
index af7b28b..35f1c58 100644
--- a/core/java/android/os/Build.java
+++ b/core/java/android/os/Build.java
@@ -211,6 +211,12 @@
          *      {@link android.R.style#Theme_Holo}.
          * <li> The activity lifecycle has changed slightly as per
          * {@link android.app.Activity}.
+         * <li> When an application requires a permission to access on of
+         * its components (activity, receiver, service, provider), this
+         * permission is no longer enforced when the application wants to
+         * access its own component.  This means it can require a permission
+         * on a component that it does not itself hold and still access that
+         * component.
          * </ul>
          */
         public static final int HONEYCOMB = CUR_DEVELOPMENT;
diff --git a/core/java/android/os/Environment.java b/core/java/android/os/Environment.java
index 904b2e9..ec5030c 100644
--- a/core/java/android/os/Environment.java
+++ b/core/java/android/os/Environment.java
@@ -416,6 +416,7 @@
      * <p>See {@link #getExternalStorageDirectory()} for more information.
      */
     public static boolean isExternalStorageRemovable() {
+        if (isExternalStorageEmulated()) return false;
         return Resources.getSystem().getBoolean(
                 com.android.internal.R.bool.config_externalStorageRemovable);
     }
diff --git a/core/java/android/os/StrictMode.java b/core/java/android/os/StrictMode.java
index 997ea53..ae92b09 100644
--- a/core/java/android/os/StrictMode.java
+++ b/core/java/android/os/StrictMode.java
@@ -30,6 +30,7 @@
 
 import dalvik.system.BlockGuard;
 import dalvik.system.CloseGuard;
+import dalvik.system.VMDebug;
 
 import java.io.PrintWriter;
 import java.io.StringWriter;
@@ -184,6 +185,15 @@
     /**
      * @hide
      */
+    private static final int DETECT_VM_INSTANCE_LEAKS = 0x1000;  // for VmPolicy
+
+    private static final int ALL_VM_DETECT_BITS =
+            DETECT_VM_CURSOR_LEAKS | DETECT_VM_CLOSABLE_LEAKS |
+            DETECT_VM_ACTIVITY_LEAKS | DETECT_VM_INSTANCE_LEAKS;
+
+    /**
+     * @hide
+     */
     public static final int PENALTY_LOG = 0x10;  // normal android.util.Log
 
     // Used for both process and thread policy:
@@ -573,11 +583,15 @@
                 } else if (mClassInstanceLimit == null) {
                     mClassInstanceLimit = new HashMap<Class, Integer>();
                 }
+                mMask |= DETECT_VM_INSTANCE_LEAKS;
                 mClassInstanceLimit.put(klass, instanceLimit);
                 return this;
             }
 
-            private Builder detectActivityLeaks() {
+            /**
+             * Detect leaks of {@link android.app.Activity} subclasses.
+             */
+            public Builder detectActivityLeaks() {
                 return enable(DETECT_VM_ACTIVITY_LEAKS);
             }
 
@@ -585,8 +599,8 @@
              * Detect everything that's potentially suspect.
              *
              * <p>In the Honeycomb release this includes leaks of
-             * SQLite cursors and other closable objects but will
-             * likely expand in future releases.
+             * SQLite cursors, Activities, and other closable objects
+             * but will likely expand in future releases.
              */
             public Builder detectAll() {
                 return enable(DETECT_VM_ACTIVITY_LEAKS |
@@ -1347,6 +1361,41 @@
     }
 
     /**
+     * @hide
+     */
+    public static void conditionallyCheckInstanceCounts() {
+        VmPolicy policy = getVmPolicy();
+        if (policy.classInstanceLimit.size() == 0) {
+            return;
+        }
+        Runtime.getRuntime().gc();
+        // Note: classInstanceLimit is immutable, so this is lock-free
+        for (Class klass : policy.classInstanceLimit.keySet()) {
+            int limit = policy.classInstanceLimit.get(klass);
+            long instances = VMDebug.countInstancesOfClass(klass, false);
+            if (instances <= limit) {
+                continue;
+            }
+            Throwable tr = new InstanceCountViolation(klass, instances, limit);
+            onVmPolicyViolation(tr.getMessage(), tr);
+        }
+    }
+
+    private static long sLastInstanceCountCheckMillis = 0;
+    private static boolean sIsIdlerRegistered = false;  // guarded by sProcessIdleHandler
+    private static final MessageQueue.IdleHandler sProcessIdleHandler =
+            new MessageQueue.IdleHandler() {
+                public boolean queueIdle() {
+                    long now = SystemClock.uptimeMillis();
+                    if (now - sLastInstanceCountCheckMillis > 30 * 1000) {
+                        sLastInstanceCountCheckMillis = now;
+                        conditionallyCheckInstanceCounts();
+                    }
+                    return true;
+                }
+            };
+
+    /**
      * Sets the policy for what actions in the VM process (on any
      * thread) should be detected, as well as the penalty if such
      * actions occur.
@@ -1357,6 +1406,19 @@
         sVmPolicy = policy;
         sVmPolicyMask = policy.mask;
         setCloseGuardEnabled(vmClosableObjectLeaksEnabled());
+
+        Looper looper = Looper.getMainLooper();
+        if (looper != null) {
+            MessageQueue mq = looper.mQueue;
+            synchronized (sProcessIdleHandler) {
+                if (policy.classInstanceLimit.size() == 0) {
+                    mq.removeIdleHandler(sProcessIdleHandler);
+                } else if (!sIsIdlerRegistered) {
+                    mq.addIdleHandler(sProcessIdleHandler);
+                    sIsIdlerRegistered = true;
+                }
+            }
+        }
     }
 
     /**
@@ -1406,19 +1468,39 @@
         onVmPolicyViolation(message, originStack);
     }
 
+    // Map from VM violation fingerprint to uptime millis.
+    private static final HashMap<Integer, Long> sLastVmViolationTime = new HashMap<Integer, Long>();
+
     /**
      * @hide
      */
     public static void onVmPolicyViolation(String message, Throwable originStack) {
-        if ((sVmPolicyMask & PENALTY_LOG) != 0) {
+        final boolean penaltyDropbox = (sVmPolicyMask & PENALTY_DROPBOX) != 0;
+        final boolean penaltyDeath = (sVmPolicyMask & PENALTY_DEATH) != 0;
+        final boolean penaltyLog = (sVmPolicyMask & PENALTY_LOG) != 0;
+        final ViolationInfo info = new ViolationInfo(originStack, sVmPolicyMask);
+
+        final Integer fingerprint = info.hashCode();
+        final long now = SystemClock.uptimeMillis();
+        long lastViolationTime = 0;
+        long timeSinceLastViolationMillis = Long.MAX_VALUE;
+        synchronized (sLastVmViolationTime) {
+            if (sLastVmViolationTime.containsKey(fingerprint)) {
+                lastViolationTime = sLastVmViolationTime.get(fingerprint);
+                timeSinceLastViolationMillis = now - lastViolationTime;
+            }
+            if (timeSinceLastViolationMillis > MIN_LOG_INTERVAL_MS) {
+                sLastVmViolationTime.put(fingerprint, now);
+            }
+        }
+
+        Log.d(TAG, "Time since last vm violation: " + timeSinceLastViolationMillis);
+
+        if (penaltyLog && timeSinceLastViolationMillis > MIN_LOG_INTERVAL_MS) {
             Log.e(TAG, message, originStack);
         }
 
-        boolean penaltyDropbox = (sVmPolicyMask & PENALTY_DROPBOX) != 0;
-        boolean penaltyDeath = (sVmPolicyMask & PENALTY_DEATH) != 0;
-
-        int violationMaskSubset = PENALTY_DROPBOX | DETECT_VM_CURSOR_LEAKS;
-        ViolationInfo info = new ViolationInfo(originStack, sVmPolicyMask);
+        int violationMaskSubset = PENALTY_DROPBOX | (ALL_VM_DETECT_BITS & sVmPolicyMask);
 
         if (penaltyDropbox && !penaltyDeath) {
             // Common case for userdebug/eng builds.  If no death and
@@ -1428,7 +1510,7 @@
             return;
         }
 
-        if (penaltyDropbox) {
+        if (penaltyDropbox && lastViolationTime == 0) {
             // The violationMask, passed to ActivityManager, is a
             // subset of the original StrictMode policy bitmask, with
             // only the bit violated and penalty bits to be executed
@@ -1786,6 +1868,12 @@
         public String broadcastIntentAction;
 
         /**
+         * If this is a instance count violation, the number of instances in memory,
+         * else -1.
+         */
+        public long numInstances = -1;
+
+        /**
          * Create an uninitialized instance of ViolationInfo
          */
         public ViolationInfo() {
@@ -1806,6 +1894,9 @@
                 broadcastIntentAction = broadcastIntent.getAction();
             }
             ThreadSpanState state = sThisThreadSpanState.get();
+            if (tr instanceof InstanceCountViolation) {
+                this.numInstances = ((InstanceCountViolation) tr).mInstances;
+            }
             synchronized (state) {
                 int spanActiveCount = state.mActiveSize;
                 if (spanActiveCount > MAX_SPAN_TAGS) {
@@ -1867,6 +1958,7 @@
             violationNumThisLoop = in.readInt();
             numAnimationsRunning = in.readInt();
             violationUptimeMillis = in.readLong();
+            numInstances = in.readLong();
             broadcastIntentAction = in.readString();
             tags = in.readStringArray();
         }
@@ -1881,6 +1973,7 @@
             dest.writeInt(violationNumThisLoop);
             dest.writeInt(numAnimationsRunning);
             dest.writeLong(violationUptimeMillis);
+            dest.writeLong(numInstances);
             dest.writeString(broadcastIntentAction);
             dest.writeStringArray(tags);
         }
@@ -1895,6 +1988,9 @@
             if (durationMillis != -1) {
                 pw.println(prefix + "durationMillis: " + durationMillis);
             }
+            if (numInstances != -1) {
+                pw.println(prefix + "numInstances: " + numInstances);
+            }
             if (violationNumThisLoop != 0) {
                 pw.println(prefix + "violationNumThisLoop: " + violationNumThisLoop);
             }
@@ -1914,4 +2010,29 @@
         }
 
     }
+
+    // Dummy throwable, for now, since we don't know when or where the
+    // leaked instances came from.  We might in the future, but for
+    // now we suppress the stack trace because it's useless and/or
+    // misleading.
+    private static class InstanceCountViolation extends Throwable {
+        final Class mClass;
+        final long mInstances;
+        final int mLimit;
+
+        private static final StackTraceElement[] FAKE_STACK = new StackTraceElement[1];
+        static {
+            FAKE_STACK[0] = new StackTraceElement("android.os.StrictMode", "setClassInstanceLimit",
+                                                  "StrictMode.java", 1);
+        }
+
+        public InstanceCountViolation(Class klass, long instances, int limit) {
+            // Note: now including instances here, otherwise signatures would all be different.
+            super(klass.toString() + "; limit=" + limit);
+            setStackTrace(FAKE_STACK);
+            mClass = klass;
+            mInstances = instances;
+            mLimit = limit;
+        }
+    }
 }
diff --git a/core/java/android/provider/MediaStore.java b/core/java/android/provider/MediaStore.java
index 9f0ea32..82fe7de 100644
--- a/core/java/android/provider/MediaStore.java
+++ b/core/java/android/provider/MediaStore.java
@@ -57,6 +57,8 @@
      * Broadcast Action:  A broadcast to indicate the end of an MTP session with the host.
      * This broadcast is only sent if MTP activity has modified the media database during the
      * most recent MTP session.
+     *
+     * @hide
      */
     public static final String ACTION_MTP_SESSION_END = "android.provider.action.MTP_SESSION_END";
 
diff --git a/core/java/android/server/BluetoothEventLoop.java b/core/java/android/server/BluetoothEventLoop.java
index 539a696..cd3bc3e 100644
--- a/core/java/android/server/BluetoothEventLoop.java
+++ b/core/java/android/server/BluetoothEventLoop.java
@@ -748,9 +748,9 @@
         }
     }
 
-    private void onInputDeviceConnectionResult(String path, boolean result) {
+    private void onInputDeviceConnectionResult(String path, int result) {
         // Success case gets handled by Property Change signal
-        if (!result) {
+        if (result != BluetoothInputDevice.INPUT_OPERATION_SUCCESS) {
             String address = mBluetoothService.getAddressFromObjectPath(path);
             if (address == null) return;
 
@@ -758,9 +758,18 @@
             BluetoothDevice device = mAdapter.getRemoteDevice(address);
             int state = mBluetoothService.getInputDeviceState(device);
             if (state == BluetoothInputDevice.STATE_CONNECTING) {
-                connected = false;
+                if (result == BluetoothInputDevice.INPUT_CONNECT_FAILED_ALREADY_CONNECTED) {
+                    connected = true;
+                } else {
+                    connected = false;
+                }
             } else if (state == BluetoothInputDevice.STATE_DISCONNECTING) {
-                connected = true;
+                if (result == BluetoothInputDevice.INPUT_DISCONNECT_FAILED_NOT_CONNECTED) {
+                    connected = false;
+                } else {
+                    // There is no better way to handle this, this shouldn't happen
+                    connected = true;
+                }
             } else {
                 Log.e(TAG, "Error onInputDeviceConnectionResult. State is:" + state);
             }
@@ -768,10 +777,10 @@
         }
     }
 
-    private void onPanDeviceConnectionResult(String path, boolean result) {
+    private void onPanDeviceConnectionResult(String path, int result) {
         log ("onPanDeviceConnectionResult " + path + " " + result);
         // Success case gets handled by Property Change signal
-        if (!result) {
+        if (result != BluetoothPan.PAN_OPERATION_SUCCESS) {
             String address = mBluetoothService.getAddressFromObjectPath(path);
             if (address == null) return;
 
@@ -779,9 +788,18 @@
             BluetoothDevice device = mAdapter.getRemoteDevice(address);
             int state = mBluetoothService.getPanDeviceState(device);
             if (state == BluetoothPan.STATE_CONNECTING) {
-                connected = false;
+                if (result == BluetoothPan.PAN_CONNECT_FAILED_ALREADY_CONNECTED) {
+                    connected = true;
+                } else {
+                    connected = false;
+                }
             } else if (state == BluetoothPan.STATE_DISCONNECTING) {
-                connected = true;
+                if (result == BluetoothPan.PAN_DISCONNECT_FAILED_NOT_CONNECTED) {
+                    connected = false;
+                } else {
+                    // There is no better way to handle this, this shouldn't happen
+                    connected = true;
+                }
             } else {
                 Log.e(TAG, "Error onPanDeviceConnectionResult. State is: "
                         + state + " result: "+ result);
diff --git a/core/java/android/speech/tts/TextToSpeech.java b/core/java/android/speech/tts/TextToSpeech.java
index f010076..c46d2c5 100755
--- a/core/java/android/speech/tts/TextToSpeech.java
+++ b/core/java/android/speech/tts/TextToSpeech.java
@@ -349,19 +349,17 @@
          */
         public static final String KEY_PARAM_UTTERANCE_ID = "utteranceId";
         /**
-         * {@hide}
          * Parameter key to specify the speech volume relative to the current stream type
          * volume used when speaking text. Volume is specified as a float ranging from 0 to 1
-         * where 0 is silence, and 1 is the maximum volume.
+         * where 0 is silence, and 1 is the maximum volume (the default behavior).
          * @see TextToSpeech#speak(String, int, HashMap)
          * @see TextToSpeech#playEarcon(String, int, HashMap)
          */
         public static final String KEY_PARAM_VOLUME = "volume";
         /**
-         * {@hide}
          * Parameter key to specify how the speech is panned from left to right when speaking text.
          * Pan is specified as a float ranging from -1 to +1 where -1 maps to a hard-left pan,
-         * 0 to center, and +1 to hard-right.
+         * 0 to center (the default behavior), and +1 to hard-right.
          * @see TextToSpeech#speak(String, int, HashMap)
          * @see TextToSpeech#playEarcon(String, int, HashMap)
          */
diff --git a/core/java/android/view/DragEvent.java b/core/java/android/view/DragEvent.java
index 6634f00..25b680e6 100644
--- a/core/java/android/view/DragEvent.java
+++ b/core/java/android/view/DragEvent.java
@@ -274,7 +274,7 @@
     public String toString() {
         return "DragEvent{" + Integer.toHexString(System.identityHashCode(this))
         + " action=" + mAction + " @ (" + mX + ", " + mY + ") desc=" + mClipDescription
-        + " data=" + mClipData + " result=" + mDragResult
+        + " data=" + mClipData + " local=" + mLocalState + " result=" + mDragResult
         + "}";
     }
 
diff --git a/core/java/android/view/GLES20Canvas.java b/core/java/android/view/GLES20Canvas.java
index 99b686e..f480554 100644
--- a/core/java/android/view/GLES20Canvas.java
+++ b/core/java/android/view/GLES20Canvas.java
@@ -452,11 +452,14 @@
     @Override
     public int saveLayer(float left, float top, float right, float bottom, Paint paint,
             int saveFlags) {
-        boolean hasColorFilter = paint != null && setupColorFilter(paint);
-        final int nativePaint = paint == null ? 0 : paint.mNativePaint;
-        int count = nSaveLayer(mRenderer, left, top, right, bottom, nativePaint, saveFlags);
-        if (hasColorFilter) nResetModifiers(mRenderer);
-        return count;
+        if (left < right && top < bottom) {
+            boolean hasColorFilter = paint != null && setupColorFilter(paint);
+            final int nativePaint = paint == null ? 0 : paint.mNativePaint;
+            int count = nSaveLayer(mRenderer, left, top, right, bottom, nativePaint, saveFlags);
+            if (hasColorFilter) nResetModifiers(mRenderer);
+            return count;
+        }
+        return save(saveFlags);
     }
 
     private native int nSaveLayer(int renderer, float left, float top, float right, float bottom,
@@ -471,7 +474,10 @@
     @Override
     public int saveLayerAlpha(float left, float top, float right, float bottom, int alpha,
             int saveFlags) {
-        return nSaveLayerAlpha(mRenderer, left, top, right, bottom, alpha, saveFlags);
+        if (left < right && top < bottom) {
+            return nSaveLayerAlpha(mRenderer, left, top, right, bottom, alpha, saveFlags);
+        }
+        return save(saveFlags);
     }
 
     private native int nSaveLayerAlpha(int renderer, float left, float top, float right,
diff --git a/core/java/android/view/HardwareRenderer.java b/core/java/android/view/HardwareRenderer.java
index f9a6c1b..addd1b3 100644
--- a/core/java/android/view/HardwareRenderer.java
+++ b/core/java/android/view/HardwareRenderer.java
@@ -84,6 +84,13 @@
      * @return True if the initialization was successful, false otherwise.
      */
     abstract boolean initialize(SurfaceHolder holder);
+    
+    /**
+     * Updates the hardware renderer for the specified surface.
+     * 
+     * @param holder The holder for the surface to hardware accelerate.
+     */
+    abstract void updateSurface(SurfaceHolder holder);
 
     /**
      * Setup the hardware renderer for drawing. This is called for every
@@ -330,6 +337,13 @@
             }
             return false;
         }
+        
+        @Override
+        void updateSurface(SurfaceHolder holder) {
+            if (isRequested() && isEnabled()) {
+                createEglSurface(holder);
+            }
+        }
 
         abstract GLES20Canvas createCanvas();
 
diff --git a/core/java/android/view/Surface.java b/core/java/android/view/Surface.java
index e203355..0326a8f 100644
--- a/core/java/android/view/Surface.java
+++ b/core/java/android/view/Surface.java
@@ -159,6 +159,8 @@
     private Canvas mCanvas;
     @SuppressWarnings("unused")
     private int mNativeSurface;
+    @SuppressWarnings("unused")
+    private int mSurfaceGenerationId;
     private String mName;
 
     // The display metrics used to provide the pseudo canvas size for applications
@@ -308,6 +310,13 @@
      * returns false.
      */
     public native   boolean isValid();
+
+    /**
+     * @hide
+     */
+    public int getGenerationId() {
+        return mSurfaceGenerationId;
+    }
     
     /** Free all server-side state associated with this surface and
      * release this object's reference. {@hide} */
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 53fc0c0..2447f8c 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -58,7 +58,6 @@
 import android.util.Pools;
 import android.util.SparseArray;
 import android.view.ContextMenu.ContextMenuInfo;
-import android.view.View.MeasureSpec;
 import android.view.accessibility.AccessibilityEvent;
 import android.view.accessibility.AccessibilityEventSource;
 import android.view.accessibility.AccessibilityManager;
@@ -10606,13 +10605,38 @@
         private final WeakReference<View> mView;
 
         /**
-         * Construct a shadow builder object for use with the given view.
-         * @param view
+         * Construct a shadow builder object for use with the given View object.  The
+         * default implementation will construct a drag shadow the same size and
+         * appearance as the supplied View.
+         *
+         * @param view A view within the application's layout whose appearance
+         *        should be replicated as the drag shadow.
          */
         public DragShadowBuilder(View view) {
             mView = new WeakReference<View>(view);
         }
 
+        /**
+         * Construct a shadow builder object with no associated View.  This
+         * constructor variant is only useful when the {@link #onProvideShadowMetrics(Point, Point)}
+         * and {@link #onDrawShadow(Canvas)} methods are also overridden in order
+         * to supply the drag shadow's dimensions and appearance without
+         * reference to any View object.
+         */
+        public DragShadowBuilder() {
+            mView = new WeakReference<View>(null);
+        }
+
+        /**
+         * Returns the View object that had been passed to the
+         * {@link #View.DragShadowBuilder(View)}
+         * constructor.  If that View parameter was {@code null} or if the
+         * {@link #View.DragShadowBuilder()}
+         * constructor was used to instantiate the builder object, this method will return
+         * null.
+         *
+         * @return The View object associate with this builder object.
+         */
         final public View getView() {
             return mView.get();
         }
@@ -10623,8 +10647,10 @@
          * be centered under the touch location while dragging.
          * <p>
          * The default implementation sets the dimensions of the shadow to be the
-         * same as the dimensions of the View itself and centers the shadow under
-         * the touch point.
+         * same as the dimensions of the View object that had been supplied to the
+         * {@link #View.DragShadowBuilder(View)} constructor
+         * when the builder object was instantiated, and centers the shadow under the touch
+         * point.
          *
          * @param shadowSize The application should set the {@code x} member of this
          *        parameter to the desired shadow width, and the {@code y} member to
@@ -10647,6 +10673,11 @@
          * Draw the shadow image for the upcoming drag.  The shadow canvas was
          * created with the dimensions supplied by the
          * {@link #onProvideShadowMetrics(Point, Point)} callback.
+         * <p>
+         * The default implementation replicates the appearance of the View object
+         * that had been supplied to the
+         * {@link #View.DragShadowBuilder(View)}
+         * constructor when the builder object was instantiated.
          *
          * @param canvas
          */
diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java
index d1781cc..115431e 100644
--- a/core/java/android/view/ViewGroup.java
+++ b/core/java/android/view/ViewGroup.java
@@ -935,15 +935,17 @@
         } break;
 
         case DragEvent.ACTION_DRAG_ENDED: {
-            // If a child was notified about an ongoing drag, it's told that it's over
-            for (View child : mDragNotifiedChildren) {
-                child.dispatchDragEvent(event);
-            }
-
             // Release the bookkeeping now that the drag lifecycle has ended
-            mDragNotifiedChildren.clear();
-            mCurrentDrag.recycle();
-            mCurrentDrag = null;
+            if (mDragNotifiedChildren != null) {
+                for (View child : mDragNotifiedChildren) {
+                    // If a child was notified about an ongoing drag, it's told that it's over
+                    child.dispatchDragEvent(event);
+                }
+
+                mDragNotifiedChildren.clear();
+                mCurrentDrag.recycle();
+                mCurrentDrag = null;
+            }
 
             // We consider drag-ended to have been handled if one of our children
             // had offered to handle the drag.
diff --git a/core/java/android/view/ViewRoot.java b/core/java/android/view/ViewRoot.java
index 96f8cdc..1f15628 100644
--- a/core/java/android/view/ViewRoot.java
+++ b/core/java/android/view/ViewRoot.java
@@ -983,6 +983,8 @@
                     Log.i(TAG, "host=w:" + host.getMeasuredWidth() + ", h:" +
                             host.getMeasuredHeight() + ", params=" + params);
                 }
+
+                final int surfaceGenerationId = mSurface.getGenerationId();
                 relayoutResult = relayoutWindow(params, viewVisibility, insetsPending);
 
                 if (params != null) {
@@ -1043,6 +1045,9 @@
                         mScroller.abortAnimation();
                     }
                     disposeResizeBitmap();
+                } else if (surfaceGenerationId != mSurface.getGenerationId() &&
+                        mSurfaceHolder == null && mAttachInfo.mHardwareRenderer != null) {
+                    mAttachInfo.mHardwareRenderer.updateSurface(mHolder);
                 }
             } catch (RemoteException e) {
             }
@@ -2798,6 +2803,7 @@
 
                 // Report the drop result when we're done
                 if (what == DragEvent.ACTION_DROP) {
+                    mDragDescription = null;
                     try {
                         Log.i(TAG, "Reporting drop result: " + result);
                         sWindowSession.reportDropResult(mWindow, result);
diff --git a/core/java/android/view/VolumePanel.java b/core/java/android/view/VolumePanel.java
index e21824e..e447dbb 100644
--- a/core/java/android/view/VolumePanel.java
+++ b/core/java/android/view/VolumePanel.java
@@ -284,10 +284,11 @@
 
         synchronized (this) {
             ToneGenerator toneGen = getOrCreateToneGenerator(streamType);
-            toneGen.startTone(ToneGenerator.TONE_PROP_BEEP);
+            if (toneGen != null) {
+                toneGen.startTone(ToneGenerator.TONE_PROP_BEEP);
+                sendMessageDelayed(obtainMessage(MSG_STOP_SOUNDS), BEEP_DURATION);
+            }
         }
-
-        sendMessageDelayed(obtainMessage(MSG_STOP_SOUNDS), BEEP_DURATION);
     }
 
     protected void onStopSounds() {
@@ -319,10 +320,16 @@
     private ToneGenerator getOrCreateToneGenerator(int streamType) {
         synchronized (this) {
             if (mToneGenerators[streamType] == null) {
-                return mToneGenerators[streamType] = new ToneGenerator(streamType, MAX_VOLUME);
-            } else {
-                return mToneGenerators[streamType];
+                try {
+                    mToneGenerators[streamType] = new ToneGenerator(streamType, MAX_VOLUME);
+                } catch (RuntimeException e) {
+                    if (LOGD) {
+                        Log.d(TAG, "ToneGenerator constructor failed with "
+                                + "RuntimeException: " + e);
+                    }
+                }
             }
+            return mToneGenerators[streamType];
         }
     }
 
diff --git a/core/java/android/view/Window.java b/core/java/android/view/Window.java
index f1883dc..217e731 100644
--- a/core/java/android/view/Window.java
+++ b/core/java/android/view/Window.java
@@ -795,8 +795,11 @@
     }
     
     /** @hide */
-    public boolean hasSetCloseOnTouchOutside() {
-        return mSetCloseOnTouchOutside;
+    public void setCloseOnTouchOutsideIfNotSet(boolean close) {
+        if (!mSetCloseOnTouchOutside) {
+            mCloseOnTouchOutside = close;
+            mSetCloseOnTouchOutside = true;
+        }
     }
     
     /** @hide */
diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java
index c54a3cf..8eb4269 100644
--- a/core/java/android/view/WindowManager.java
+++ b/core/java/android/view/WindowManager.java
@@ -817,7 +817,7 @@
         public static final int SOFT_INPUT_IS_FORWARD_NAVIGATION = 0x100;
 
         /**
-         * Desired operating mode for any soft input area.  May any combination
+         * Desired operating mode for any soft input area.  May be any combination
          * of:
          * 
          * <ul>
diff --git a/core/java/android/webkit/HTML5VideoViewProxy.java b/core/java/android/webkit/HTML5VideoViewProxy.java
index 85bff4f..d8f34e0 100644
--- a/core/java/android/webkit/HTML5VideoViewProxy.java
+++ b/core/java/android/webkit/HTML5VideoViewProxy.java
@@ -495,6 +495,7 @@
                         break;
                     }
                     case ENDED:
+                        mSeekPosition = 0;
                         nativeOnEnded(mNativePointer);
                         break;
                     case PAUSED:
@@ -538,10 +539,15 @@
      * Play a video stream.
      * @param url is the URL of the video stream.
      */
-    public void play(String url) {
+    public void play(String url, int position) {
         if (url == null) {
             return;
         }
+
+        if (position > 0) {
+            seek(position);
+        }
+
         Message message = obtainMessage(PLAY);
         message.obj = url;
         sendMessage(message);
diff --git a/core/java/android/webkit/WebIconDatabase.java b/core/java/android/webkit/WebIconDatabase.java
index bb9ec48..54dfab3 100644
--- a/core/java/android/webkit/WebIconDatabase.java
+++ b/core/java/android/webkit/WebIconDatabase.java
@@ -24,6 +24,7 @@
 import android.provider.Browser;
 import android.util.Log;
 
+import java.io.File;
 import java.util.HashMap;
 import java.util.Vector;
 
@@ -194,13 +195,16 @@
     /**
      * Open a the icon database and store the icons in the given path.
      * @param path The directory path where the icon database will be stored.
-     * @return True if the database was successfully opened or created in
-     *         the given path.
      */
     public void open(String path) {
         if (path != null) {
+            // Make the directories and parents if they don't exist
+            File db = new File(path);
+            if (!db.exists()) {
+                db.mkdirs();
+            }
             mEventHandler.postMessage(
-                    Message.obtain(null, EventHandler.OPEN, path));
+                    Message.obtain(null, EventHandler.OPEN, db.getAbsolutePath()));
         }
     }
 
diff --git a/core/java/android/webkit/WebSettings.java b/core/java/android/webkit/WebSettings.java
index 2f96782b4..518ba69 100644
--- a/core/java/android/webkit/WebSettings.java
+++ b/core/java/android/webkit/WebSettings.java
@@ -1569,6 +1569,7 @@
     public void setCacheMode(int mode) {
         if (mode != mOverrideCacheMode) {
             mOverrideCacheMode = mode;
+            postSync();
         }
     }
 
diff --git a/core/java/android/webkit/WebTextView.java b/core/java/android/webkit/WebTextView.java
index 1313fcc..72b0023 100644
--- a/core/java/android/webkit/WebTextView.java
+++ b/core/java/android/webkit/WebTextView.java
@@ -132,6 +132,10 @@
     private boolean mAutoFillable; // Is this textview part of an autofillable form?
     private int mQueryId;
     private boolean mAutoFillProfileIsSet;
+    // Used to determine whether onFocusChanged was called as a result of
+    // calling remove().
+    private boolean mInsideRemove;
+    private boolean mInPassword;
 
     // Types used with setType.  Keep in sync with CachedInput.h
     private static final int NORMAL_TEXT_FIELD = 0;
@@ -540,6 +544,11 @@
             Rect previouslyFocusedRect) {
         mFromFocusChange = true;
         super.onFocusChanged(focused, direction, previouslyFocusedRect);
+        if (focused) {
+            mWebView.setActive(true);
+        } else if (!mInsideRemove) {
+            mWebView.setActive(false);
+        }
         mFromFocusChange = false;
     }
 
@@ -770,26 +779,17 @@
         if (imm.isActive(this)) {
             imm.hideSoftInputFromWindow(getWindowToken(), 0);
         }
+        mInsideRemove = true;
         mWebView.removeView(this);
         mWebView.requestFocus();
-    }
-
-    /**
-     * Move the caret/selection into view.
-     */
-    /* package */ void bringIntoView() {
-        bringPointIntoView(Selection.getSelectionEnd(getText()));
+        mInsideRemove = false;
     }
 
     @Override
     public boolean bringPointIntoView(int offset) {
-        if (mWebView == null) return false;
-        if (mWebView.nativeFocusCandidateIsPassword()) {
+        if (mInPassword) {
             return getLayout() != null && super.bringPointIntoView(offset);
         }
-        // For non password text input, tell webkit to move the caret/selection
-        // on screen, since webkit draws them.
-        mWebView.revealSelection();
         return true;
     }
 
@@ -904,6 +904,7 @@
      * @param   inPassword  True if the textfield is a password field.
      */
     /* package */ void setInPassword(boolean inPassword) {
+        mInPassword = inPassword;
         if (inPassword) {
             setInputType(EditorInfo.TYPE_CLASS_TEXT | EditorInfo.
                 TYPE_TEXT_VARIATION_WEB_PASSWORD);
diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java
index 78d4cd2..7b3ea74 100644
--- a/core/java/android/webkit/WebView.java
+++ b/core/java/android/webkit/WebView.java
@@ -408,10 +408,13 @@
     PluginFullScreenHolder mFullScreenHolder;
 
     /**
-     * Position of the last touch event.
+     * Position of the last touch event in pixels.
+     * Use integer to prevent loss of dragging delta calculation accuracy;
+     * which was done in float and converted to integer, and resulted in gradual
+     * and compounding touch position and view dragging mismatch.
      */
-    private float mLastTouchX;
-    private float mLastTouchY;
+    private int mLastTouchX;
+    private int mLastTouchY;
 
     /**
      * Time of the last touch event.
@@ -2218,8 +2221,8 @@
         if (type == HitTestResult.UNKNOWN_TYPE
                 || type == HitTestResult.SRC_ANCHOR_TYPE) {
             // Now check to see if it is an image.
-            int contentX = viewToContentX((int) mLastTouchX + mScrollX);
-            int contentY = viewToContentY((int) mLastTouchY + mScrollY);
+            int contentX = viewToContentX(mLastTouchX + mScrollX);
+            int contentY = viewToContentY(mLastTouchY + mScrollY);
             String text = nativeImageURI(contentX, contentY);
             if (text != null) {
                 result.setType(type == HitTestResult.UNKNOWN_TYPE ?
@@ -2256,8 +2259,8 @@
         if (hrefMsg == null) {
             return;
         }
-        int contentX = viewToContentX((int) mLastTouchX + mScrollX);
-        int contentY = viewToContentY((int) mLastTouchY + mScrollY);
+        int contentX = viewToContentX(mLastTouchX + mScrollX);
+        int contentY = viewToContentY(mLastTouchY + mScrollY);
         mWebViewCore.sendMessage(EventHub.REQUEST_CURSOR_HREF,
                 contentX, contentY, hrefMsg);
     }
@@ -2271,8 +2274,8 @@
      */
     public void requestImageRef(Message msg) {
         if (0 == mNativeClass) return; // client isn't initialized
-        int contentX = viewToContentX((int) mLastTouchX + mScrollX);
-        int contentY = viewToContentY((int) mLastTouchY + mScrollY);
+        int contentX = viewToContentX(mLastTouchX + mScrollX);
+        int contentY = viewToContentY(mLastTouchY + mScrollY);
         String ref = nativeImageURI(contentX, contentY);
         Bundle data = msg.getData();
         data.putString("url", ref);
@@ -3856,8 +3859,8 @@
      * @hide pending API council approval
      */
     public boolean selectText() {
-        int x = viewToContentX((int) mLastTouchX + mScrollX);
-        int y = viewToContentY((int) mLastTouchY + mScrollY);
+        int x = viewToContentX(mLastTouchX + mScrollX);
+        int y = viewToContentY(mLastTouchY + mScrollY);
         return selectText(x, y);
     }
 
@@ -4268,7 +4271,7 @@
         Rect vBox = contentToViewRect(bounds);
         mWebTextView.setRect(vBox.left, vBox.top, vBox.width(), vBox.height());
         if (!Rect.intersects(bounds, visibleRect)) {
-            mWebTextView.bringIntoView();
+            revealSelection();
         }
         String text = nativeFocusCandidateText();
         int nodePointer = nativeFocusCandidatePointer();
@@ -4858,8 +4861,8 @@
             mSelectX = contentToViewX(rect.left);
             mSelectY = contentToViewY(rect.top);
         } else if (mLastTouchY > getVisibleTitleHeight()) {
-            mSelectX = mScrollX + (int) mLastTouchX;
-            mSelectY = mScrollY + (int) mLastTouchY;
+            mSelectX = mScrollX + mLastTouchX;
+            mSelectY = mScrollY + mLastTouchY;
         } else {
             mSelectX = mScrollX + getViewWidth() / 2;
             mSelectY = mScrollY + getViewHeightWithTitle() / 2;
@@ -5050,7 +5053,7 @@
     public void onGlobalFocusChanged(View oldFocus, View newFocus) {
     }
 
-    private void setActive(boolean active) {
+    void setActive(boolean active) {
         if (active) {
             if (hasFocus()) {
                 // If our window regained focus, and we have focus, then begin
@@ -5235,7 +5238,7 @@
             if (event.getAction() == KeyEvent.ACTION_DOWN) {
                 mGotKeyDown = true;
             } else {
-                if (!mGotKeyDown) {
+                if (!mGotKeyDown && event.getAction() != KeyEvent.ACTION_MULTIPLE) {
                     /*
                      * We got a key up for which we were not the recipient of
                      * the original key down. Don't give it to the view.
@@ -5357,7 +5360,7 @@
             return true;
         }
 
-        return handleTouchEventCommon(ev, ev.getX(), ev.getY());
+        return handleTouchEventCommon(ev, Math.round(ev.getX()), Math.round(ev.getY()));
     }
 
     /*
@@ -5365,7 +5368,7 @@
      * (x, y) denotes current focus point, which is the touch point for single touch
      * and the middle point for multi-touch.
      */
-    private boolean handleTouchEventCommon(MotionEvent ev, float x, float y) {
+    private boolean handleTouchEventCommon(MotionEvent ev, int x, int y) {
         int action = ev.getAction();
         long eventTime = ev.getEventTime();
 
@@ -5377,12 +5380,10 @@
         x = Math.min(x, getViewWidth() - 1);
         y = Math.min(y, getViewHeightWithTitle() - 1);
 
-        float fDeltaX = mLastTouchX - x;
-        float fDeltaY = mLastTouchY - y;
-        int deltaX = (int) fDeltaX;
-        int deltaY = (int) fDeltaY;
-        int contentX = viewToContentX((int) x + mScrollX);
-        int contentY = viewToContentY((int) y + mScrollY);
+        int deltaX = mLastTouchX - x;
+        int deltaY = mLastTouchY - y;
+        int contentX = viewToContentX(x + mScrollX);
+        int contentY = viewToContentY(y + mScrollY);
 
         switch (action) {
             case MotionEvent.ACTION_DOWN: {
@@ -5607,8 +5608,6 @@
                     mTouchMode = TOUCH_DRAG_MODE;
                     mLastTouchX = x;
                     mLastTouchY = y;
-                    fDeltaX = 0.0f;
-                    fDeltaY = 0.0f;
                     deltaX = 0;
                     deltaY = 0;
 
@@ -5619,9 +5618,7 @@
                 // do pan
                 boolean done = false;
                 boolean keepScrollBarsVisible = false;
-                if (Math.abs(fDeltaX) < 1.0f && Math.abs(fDeltaY) < 1.0f) {
-                    mLastTouchX = x;
-                    mLastTouchY = y;
+                if (deltaX == 0 && deltaY == 0) {
                     keepScrollBarsVisible = done = true;
                 } else {
                     if (mSnapScrollMode == SNAP_X || mSnapScrollMode == SNAP_Y) {
@@ -5670,12 +5667,6 @@
                             mLastTouchY = y;
                         }
                         mHeldMotionless = MOTIONLESS_FALSE;
-                    } else {
-                        // keep the scrollbar on the screen even there is no
-                        // scroll
-                        mLastTouchX = x;
-                        mLastTouchY = y;
-                        keepScrollBarsVisible = true;
                     }
                     mLastTouchTime = eventTime;
                     mUserScroll = true;
@@ -5937,8 +5928,8 @@
             action = MotionEvent.ACTION_DOWN;
         } else if (action == MotionEvent.ACTION_POINTER_UP) {
             // set mLastTouchX/Y to the remaining point
-            mLastTouchX = x;
-            mLastTouchY = y;
+            mLastTouchX = Math.round(x);
+            mLastTouchY = Math.round(y);
         } else if (action == MotionEvent.ACTION_MOVE) {
             // negative x or y indicate it is on the edge, skip it.
             if (x < 0 || y < 0) {
@@ -5946,7 +5937,7 @@
             }
         }
 
-        return handleTouchEventCommon(ev, x, y);
+        return handleTouchEventCommon(ev, Math.round(x), Math.round(y));
     }
 
     private void cancelWebCoreTouchEvent(int x, int y, boolean removeEvents) {
@@ -5967,8 +5958,8 @@
 
     private void startTouch(float x, float y, long eventTime) {
         // Remember where the motion event started
-        mLastTouchX = x;
-        mLastTouchY = y;
+        mLastTouchX = Math.round(x);
+        mLastTouchY = Math.round(y);
         mLastTouchTime = eventTime;
         mVelocityTracker = VelocityTracker.obtain();
         mSnapScrollMode = SNAP_NONE;
@@ -6598,8 +6589,8 @@
             return;
         }
         // mLastTouchX and mLastTouchY are the point in the current viewport
-        int contentX = viewToContentX((int) mLastTouchX + mScrollX);
-        int contentY = viewToContentY((int) mLastTouchY + mScrollY);
+        int contentX = viewToContentX(mLastTouchX + mScrollX);
+        int contentY = viewToContentY(mLastTouchY + mScrollY);
         Rect rect = new Rect(contentX - mNavSlop, contentY - mNavSlop,
                 contentX + mNavSlop, contentY + mNavSlop);
         nativeSelectBestAt(rect);
@@ -6630,8 +6621,8 @@
         if (!inEditingMode()) {
             return;
         }
-        mLastTouchX = x + (float) (mWebTextView.getLeft() - mScrollX);
-        mLastTouchY = y + (float) (mWebTextView.getTop() - mScrollY);
+        mLastTouchX = Math.round(x + mWebTextView.getLeft() - mScrollX);
+        mLastTouchY = Math.round(y + mWebTextView.getTop() - mScrollY);
         mLastTouchTime = eventTime;
         if (!mScroller.isFinished()) {
             abortAnimation();
@@ -6690,8 +6681,8 @@
         mTouchMode = TOUCH_DONE_MODE;
         switchOutDrawHistory();
         // mLastTouchX and mLastTouchY are the point in the current viewport
-        int contentX = viewToContentX((int) mLastTouchX + mScrollX);
-        int contentY = viewToContentY((int) mLastTouchY + mScrollY);
+        int contentX = viewToContentX(mLastTouchX + mScrollX);
+        int contentY = viewToContentY(mLastTouchY + mScrollY);
         if (getSettings().supportTouchOnly()) {
             removeTouchHighlight(false);
             WebViewCore.TouchUpData touchUpData = new WebViewCore.TouchUpData();
@@ -7052,8 +7043,8 @@
                             || (msg.arg1 == MotionEvent.ACTION_MOVE
                             && mPreventDefault == PREVENT_DEFAULT_NO_FROM_TOUCH_DOWN)) {
                         cancelWebCoreTouchEvent(
-                                viewToContentX((int) mLastTouchX + mScrollX),
-                                viewToContentY((int) mLastTouchY + mScrollY),
+                                viewToContentX(mLastTouchX + mScrollX),
+                                viewToContentY(mLastTouchY + mScrollY),
                                 true);
                     }
                     break;
@@ -7104,8 +7095,8 @@
                         ted.mIds = new int[1];
                         ted.mIds[0] = 0;
                         ted.mPoints = new Point[1];
-                        ted.mPoints[0] = new Point(viewToContentX((int) mLastTouchX + mScrollX),
-                                                   viewToContentY((int) mLastTouchY + mScrollY));
+                        ted.mPoints[0] = new Point(viewToContentX(mLastTouchX + mScrollX),
+                                                   viewToContentY(mLastTouchY + mScrollY));
                         // metaState for long press is tricky. Should it be the
                         // state when the press started or when the press was
                         // released? Or some intermediary key state? For
@@ -7274,7 +7265,6 @@
                     // this is sent after finishing resize in WebViewCore. Make
                     // sure the text edit box is still on the  screen.
                     if (inEditingMode() && nativeCursorIsTextInput()) {
-                        mWebTextView.bringIntoView();
                         rebuildWebTextView();
                     }
                     break;
diff --git a/core/java/android/webkit/ZoomManager.java b/core/java/android/webkit/ZoomManager.java
index 88a54ea..9a050c5 100644
--- a/core/java/android/webkit/ZoomManager.java
+++ b/core/java/android/webkit/ZoomManager.java
@@ -148,13 +148,13 @@
      */
     private float mInitialScale;
 
-    private static float MINIMUM_SCALE_INCREMENT = 0.01f;
+    private static float MINIMUM_SCALE_INCREMENT = 0.007f;
 
     /*
      *  The touch points could be changed even the fingers stop moving.
      *  We use the following to filter out the zooming jitters.
      */
-    private static float MINIMUM_SCALE_WITHOUT_JITTER = 0.05f;
+    private static float MINIMUM_SCALE_WITHOUT_JITTER = 0.007f;
 
     /*
      * The following member variables are only to be used for animating zoom. If
diff --git a/core/java/android/widget/AbsListView.java b/core/java/android/widget/AbsListView.java
index d8f5972..a65de13 100644
--- a/core/java/android/widget/AbsListView.java
+++ b/core/java/android/widget/AbsListView.java
@@ -2439,8 +2439,12 @@
             if (adapter != null && mItemCount > 0 &&
                     motionPosition != INVALID_POSITION &&
                     motionPosition < adapter.getCount() && sameWindow()) {
-                performItemClick(getChildAt(motionPosition - mFirstPosition), motionPosition,
-                        adapter.getItemId(motionPosition));
+                final View view = getChildAt(motionPosition - mFirstPosition);
+                // If there is no view, something bad happened (the view scrolled off the
+                // screen, etc.) and we should cancel the click
+                if (view != null) {
+                    performItemClick(view, motionPosition, adapter.getItemId(motionPosition));
+                }
             }
         }
     }
@@ -5315,6 +5319,24 @@
         mRecycler.mRecyclerListener = listener;
     }
 
+    class AdapterDataSetObserver extends AdapterView<ListAdapter>.AdapterDataSetObserver {
+        @Override
+        public void onChanged() {
+            super.onChanged();
+            if (mFastScroller != null) {
+                mFastScroller.onSectionsChanged();
+            }
+        }
+
+        @Override
+        public void onInvalidated() {
+            super.onInvalidated();
+            if (mFastScroller != null) {
+                mFastScroller.onSectionsChanged();
+            }
+        }
+    }
+
     /**
      * A MultiChoiceModeListener receives events for {@link AbsListView#CHOICE_MODE_MULTIPLE_MODAL}.
      * It acts as the {@link ActionMode.Callback} for the selection mode and also receives
diff --git a/core/java/android/widget/ArrayAdapter.java b/core/java/android/widget/ArrayAdapter.java
index b4ece24..593cb59 100644
--- a/core/java/android/widget/ArrayAdapter.java
+++ b/core/java/android/widget/ArrayAdapter.java
@@ -25,9 +25,9 @@
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collection;
-import java.util.List;
-import java.util.Comparator;
 import java.util.Collections;
+import java.util.Comparator;
+import java.util.List;
 
 /**
  * A concrete BaseAdapter that is backed by an array of arbitrary
@@ -86,6 +86,8 @@
 
     private Context mContext;
 
+    // A copy of the original mObjects array, initialized from and then used instead as soon as
+    // the mFilter ArrayFilter is used. mObjects will then only contain the filtered values.
     private ArrayList<T> mOriginalValues;
     private ArrayFilter mFilter;
 
@@ -170,15 +172,14 @@
      * @param object The object to add at the end of the array.
      */
     public void add(T object) {
-        if (mOriginalValues != null) {
-            synchronized (mLock) {
+        synchronized (mLock) {
+            if (mOriginalValues != null) {
                 mOriginalValues.add(object);
-                if (mNotifyOnChange) notifyDataSetChanged();
+            } else {
+                mObjects.add(object);
             }
-        } else {
-            mObjects.add(object);
-            if (mNotifyOnChange) notifyDataSetChanged();
         }
+        if (mNotifyOnChange) notifyDataSetChanged();
     }
 
     /**
@@ -187,15 +188,14 @@
      * @param collection The Collection to add at the end of the array.
      */
     public void addAll(Collection<? extends T> collection) {
-        if (mOriginalValues != null) {
-            synchronized (mLock) {
+        synchronized (mLock) {
+            if (mOriginalValues != null) {
                 mOriginalValues.addAll(collection);
-                if (mNotifyOnChange) notifyDataSetChanged();
+            } else {
+                mObjects.addAll(collection);
             }
-        } else {
-            mObjects.addAll(collection);
-            if (mNotifyOnChange) notifyDataSetChanged();
         }
+        if (mNotifyOnChange) notifyDataSetChanged();
     }
 
     /**
@@ -204,19 +204,18 @@
      * @param items The items to add at the end of the array.
      */
     public void addAll(T ... items) {
-        if (mOriginalValues != null) {
-            synchronized (mLock) {
+        synchronized (mLock) {
+            if (mOriginalValues != null) {
                 for (T item : items) {
                     mOriginalValues.add(item);
                 }
-                if (mNotifyOnChange) notifyDataSetChanged();
+            } else {
+                for (T item : items) {
+                    mObjects.add(item);
+                }
             }
-        } else {
-            for (T item : items) {
-                mObjects.add(item);
-            }
-            if (mNotifyOnChange) notifyDataSetChanged();
         }
+        if (mNotifyOnChange) notifyDataSetChanged();
     }
 
     /**
@@ -226,15 +225,14 @@
      * @param index The index at which the object must be inserted.
      */
     public void insert(T object, int index) {
-        if (mOriginalValues != null) {
-            synchronized (mLock) {
+        synchronized (mLock) {
+            if (mOriginalValues != null) {
                 mOriginalValues.add(index, object);
-                if (mNotifyOnChange) notifyDataSetChanged();
+            } else {
+                mObjects.add(index, object);
             }
-        } else {
-            mObjects.add(index, object);
-            if (mNotifyOnChange) notifyDataSetChanged();
         }
+        if (mNotifyOnChange) notifyDataSetChanged();
     }
 
     /**
@@ -243,12 +241,12 @@
      * @param object The object to remove.
      */
     public void remove(T object) {
-        if (mOriginalValues != null) {
-            synchronized (mLock) {
+        synchronized (mLock) {
+            if (mOriginalValues != null) {
                 mOriginalValues.remove(object);
+            } else {
+                mObjects.remove(object);
             }
-        } else {
-            mObjects.remove(object);
         }
         if (mNotifyOnChange) notifyDataSetChanged();
     }
@@ -257,12 +255,12 @@
      * Remove all elements from the list.
      */
     public void clear() {
-        if (mOriginalValues != null) {
-            synchronized (mLock) {
+        synchronized (mLock) {
+            if (mOriginalValues != null) {
                 mOriginalValues.clear();
+            } else {
+                mObjects.clear();
             }
-        } else {
-            mObjects.clear();
         }
         if (mNotifyOnChange) notifyDataSetChanged();
     }
@@ -274,7 +272,13 @@
      *        in this adapter.
      */
     public void sort(Comparator<? super T> comparator) {
-        Collections.sort(mObjects, comparator);
+        synchronized (mLock) {
+            if (mOriginalValues != null) {
+                Collections.sort(mOriginalValues, comparator);
+            } else {
+                Collections.sort(mObjects, comparator);
+            }
+        }
         if (mNotifyOnChange) notifyDataSetChanged();
     }
 
@@ -482,6 +486,7 @@
                         final String[] words = valueText.split(" ");
                         final int wordCount = words.length;
 
+                        // Start at index 0, in case valueText starts with space(s)
                         for (int k = 0; k < wordCount; k++) {
                             if (words[k].startsWith(prefixString)) {
                                 newValues.add(value);
diff --git a/core/java/android/widget/AutoCompleteTextView.java b/core/java/android/widget/AutoCompleteTextView.java
index 4d8d21f..707b92d5 100644
--- a/core/java/android/widget/AutoCompleteTextView.java
+++ b/core/java/android/widget/AutoCompleteTextView.java
@@ -16,6 +16,8 @@
 
 package android.widget;
 
+import com.android.internal.R;
+
 import android.content.Context;
 import android.content.res.TypedArray;
 import android.database.DataSetObserver;
@@ -36,8 +38,6 @@
 import android.view.inputmethod.EditorInfo;
 import android.view.inputmethod.InputMethodManager;
 
-import com.android.internal.R;
-
 
 /**
  * <p>An editable text view that shows completion suggestions automatically
@@ -113,6 +113,7 @@
 
     private Validator mValidator = null;
 
+    // Set to true when text is set directly and no filtering shall be performed
     private boolean mBlockCompletion;
 
     private PassThroughClickListener mPassThroughClickListener;
@@ -721,6 +722,10 @@
             return;
         }
 
+        updateList();
+    }
+
+    private void updateList() {
         // the drop down is shown only when a minimum number of characters
         // was typed in the text view
         if (enoughToFilter()) {
@@ -840,7 +845,7 @@
 
             mBlockCompletion = true;
             replaceText(convertSelectionToString(selectedItem));
-            mBlockCompletion = false;            
+            mBlockCompletion = false;
 
             if (mItemClickListener != null) {
                 final ListPopupWindow list = mPopup;
@@ -903,10 +908,10 @@
 
     /** {@inheritDoc} */
     public void onFilterComplete(int count) {
-        updateDropDownForFilter(count);
+        updateDropDownForFilter(count, true);
     }
 
-    private void updateDropDownForFilter(int count) {
+    private void updateDropDownForFilter(int count, boolean forceShow) {
         // Not attached to window, don't update drop-down
         if (getWindowVisibility() == View.GONE) return;
 
@@ -919,7 +924,7 @@
 
         final boolean dropDownAlwaysVisible = mPopup.isDropDownAlwaysVisible();
         if ((count > 0 || dropDownAlwaysVisible) && enoughToFilter()) {
-            if (hasFocus() && hasWindowFocus()) {
+            if (hasFocus() && hasWindowFocus() && (forceShow || isPopupShowing())) {
                 showDropDown();
             }
         } else if (!dropDownAlwaysVisible) {
@@ -1182,12 +1187,14 @@
                 // If the popup is not showing already, showing it will cause
                 // the list of data set observers attached to the adapter to
                 // change. We can't do it from here, because we are in the middle
-                // of iterating throught he list of observers.
+                // of iterating through the list of observers.
                 post(new Runnable() {
                     public void run() {
                         final ListAdapter adapter = mAdapter;
                         if (adapter != null) {
-                            updateDropDownForFilter(adapter.getCount());
+                            // This will re-layout, thus resetting mDataChanged, so that the
+                            // listView click listener stays responsive
+                            updateDropDownForFilter(adapter.getCount(), false);
                         }
                     }
                 });
diff --git a/core/java/android/widget/DatePicker.java b/core/java/android/widget/DatePicker.java
index 2c53005..af5de8a 100644
--- a/core/java/android/widget/DatePicker.java
+++ b/core/java/android/widget/DatePicker.java
@@ -129,27 +129,30 @@
     }
 
     public DatePicker(Context context, AttributeSet attrs) {
-        this(context, attrs, 0);
+        this(context, attrs, R.attr.datePickerStyle);
     }
 
     public DatePicker(Context context, AttributeSet attrs, int defStyle) {
         super(context, attrs, defStyle);
 
-        TypedArray attributesArray = context.obtainStyledAttributes(attrs, R.styleable.DatePicker);
+        TypedArray attributesArray = context.obtainStyledAttributes(attrs, R.styleable.DatePicker,
+                defStyle, 0);
         boolean spinnersShown = attributesArray.getBoolean(R.styleable.DatePicker_spinnersShown,
                 DEFAULT_SPINNERS_SHOWN);
         boolean calendarViewShown = attributesArray.getBoolean(
                 R.styleable.DatePicker_calendarViewShown, DEFAULT_CALENDAR_VIEW_SHOWN);
-        int startYear = attributesArray
-                .getInt(R.styleable.DatePicker_startYear, DEFAULT_START_YEAR);
+        int startYear = attributesArray.getInt(R.styleable.DatePicker_startYear,
+                DEFAULT_START_YEAR);
         int endYear = attributesArray.getInt(R.styleable.DatePicker_endYear, DEFAULT_END_YEAR);
         String minDate = attributesArray.getString(R.styleable.DatePicker_minDate);
         String maxDate = attributesArray.getString(R.styleable.DatePicker_maxDate);
+        int layoutResourceId = attributesArray.getResourceId(R.styleable.DatePicker_layout,
+                R.layout.date_picker);
         attributesArray.recycle();
 
         LayoutInflater inflater = (LayoutInflater) context
                 .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
-        inflater.inflate(R.layout.date_picker, this, true);
+        inflater.inflate(layoutResourceId, this, true);
 
         OnValueChangedListener onChangeListener = new OnValueChangedListener() {
             public void onValueChange(NumberPicker picker, int oldVal, int newVal) {
diff --git a/core/java/android/widget/FastScroller.java b/core/java/android/widget/FastScroller.java
index dfa94c7..200c870 100644
--- a/core/java/android/widget/FastScroller.java
+++ b/core/java/android/widget/FastScroller.java
@@ -476,6 +476,10 @@
         }
     }
 
+    public void onSectionsChanged() {
+        mListAdapter = null;
+    }
+
     private void scrollTo(float position) {
         int count = mList.getCount();
         mScrollCompleted = false;
diff --git a/core/java/android/widget/NumberPicker.java b/core/java/android/widget/NumberPicker.java
index 63dbfbf..ba1c0ec 100644
--- a/core/java/android/widget/NumberPicker.java
+++ b/core/java/android/widget/NumberPicker.java
@@ -62,8 +62,6 @@
  * <p>
  * For an example of using this widget, see {@link android.widget.TimePicker}.
  * </p>
- *
- * @attr ref android.R.styleable#NumberPicker_solidColor
  */
 @Widget
 public class NumberPicker extends LinearLayout {
@@ -325,6 +323,11 @@
     private final int mSolidColor;
 
     /**
+     * Flag indicating if this widget supports flinging.
+     */
+    private final boolean mFlingable;
+
+    /**
      * Reusable {@link Rect} instance.
      */
     private final Rect mTempRect = new Rect();
@@ -427,9 +430,8 @@
         // process style attributes
         TypedArray attributesArray = context.obtainStyledAttributes(attrs,
                 R.styleable.NumberPicker, defStyle, 0);
-        int orientation = attributesArray.getInt(R.styleable.NumberPicker_orientation, VERTICAL);
-        setOrientation(orientation);
         mSolidColor = attributesArray.getColor(R.styleable.NumberPicker_solidColor, 0);
+        mFlingable = attributesArray.getBoolean(R.styleable.NumberPicker_flingable, true);
         attributesArray.recycle();
 
         // By default Linearlayout that we extend is not drawn. This is
@@ -563,7 +565,7 @@
 
     @Override
     public boolean onInterceptTouchEvent(MotionEvent event) {
-        if (!isEnabled()) {
+        if (!isEnabled() || !mFlingable) {
             return false;
         }
         switch (event.getActionMasked()) {
diff --git a/core/java/android/widget/RemoteViews.java b/core/java/android/widget/RemoteViews.java
index 8f25311..482ce56 100644
--- a/core/java/android/widget/RemoteViews.java
+++ b/core/java/android/widget/RemoteViews.java
@@ -59,6 +59,12 @@
     private static final String LOG_TAG = "RemoteViews";
     
     /**
+     * The intent extra that contains the appWidgetId.
+     * @hide
+     */
+    static final String EXTRA_REMOTEADAPTER_APPWIDGET_ID = "remoteAdapterAppWidgetId";
+
+    /**
      * The package name of the package containing the layout 
      * resource. (Added to the parcel)
      */
@@ -1271,11 +1277,15 @@
     /**
      * Equivalent to calling {@link android.widget.AbsListView#setRemoteViewsAdapter(Intent)}.
      *
+     * @param appWidgetId The id of the app widget which contains the specified view
      * @param viewId The id of the view whose text should change
      * @param intent The intent of the service which will be
      *            providing data to the RemoteViewsAdapter
      */
-    public void setRemoteAdapter(int viewId, Intent intent) {
+    public void setRemoteAdapter(int appWidgetId, int viewId, Intent intent) {
+        // Embed the AppWidget Id for use in RemoteViewsAdapter when connecting to the intent
+        // RemoteViewsService
+        intent.putExtra(EXTRA_REMOTEADAPTER_APPWIDGET_ID, appWidgetId);
         setIntent(viewId, "setRemoteViewsAdapter", intent);
     }
 
diff --git a/core/java/android/widget/RemoteViewsAdapter.java b/core/java/android/widget/RemoteViewsAdapter.java
index ab69725..f329a3e 100644
--- a/core/java/android/widget/RemoteViewsAdapter.java
+++ b/core/java/android/widget/RemoteViewsAdapter.java
@@ -22,20 +22,21 @@
 import java.util.LinkedList;
 import java.util.Map;
 
-import android.content.ComponentName;
+import android.appwidget.AppWidgetManager;
 import android.content.Context;
 import android.content.Intent;
-import android.content.ServiceConnection;
 import android.os.Handler;
 import android.os.HandlerThread;
 import android.os.IBinder;
 import android.os.Looper;
+import android.os.Message;
 import android.util.Log;
 import android.view.LayoutInflater;
 import android.view.View;
 import android.view.ViewGroup;
 import android.view.View.MeasureSpec;
 
+import com.android.internal.widget.IRemoteViewsAdapterConnection;
 import com.android.internal.widget.IRemoteViewsFactory;
 
 /**
@@ -43,11 +44,22 @@
  * to be later inflated as child views.
  */
 /** @hide */
-public class RemoteViewsAdapter extends BaseAdapter {
+public class RemoteViewsAdapter extends BaseAdapter implements Handler.Callback {
     private static final String TAG = "RemoteViewsAdapter";
 
-    private Context mContext;
-    private Intent mIntent;
+    // The max number of items in the cache
+    private static final int sDefaultCacheSize = 36;
+    // The delay (in millis) to wait until attempting to unbind from a service after a request.
+    // This ensures that we don't stay continually bound to the service and that it can be destroyed
+    // if we need the memory elsewhere in the system.
+    private static final int sUnbindServiceDelay = 5000;
+    // Type defs for controlling different messages across the main and worker message queues
+    private static final int sDefaultMessageType = 0;
+    private static final int sUnbindServiceMessageType = 1;
+
+    private final Context mContext;
+    private final Intent mIntent;
+    private final int mAppWidgetId;
     private LayoutInflater mLayoutInflater;
     private RemoteViewsAdapterServiceConnection mServiceConnection;
     private WeakReference<RemoteAdapterConnectionCallback> mCallback;
@@ -79,7 +91,8 @@
      * garbage collected, and would cause us to leak activities due to the caching mechanism for
      * FrameLayouts in the adapter).
      */
-    private static class RemoteViewsAdapterServiceConnection implements ServiceConnection {
+    private static class RemoteViewsAdapterServiceConnection extends
+            IRemoteViewsAdapterConnection.Stub {
         private boolean mConnected;
         private WeakReference<RemoteViewsAdapter> mAdapter;
         private IRemoteViewsFactory mRemoteViewsFactory;
@@ -88,8 +101,7 @@
             mAdapter = new WeakReference<RemoteViewsAdapter>(adapter);
         }
 
-        public void onServiceConnected(ComponentName name,
-                IBinder service) {
+        public void onServiceConnected(IBinder service) {
             mRemoteViewsFactory = IRemoteViewsFactory.Stub.asInterface(service);
             mConnected = true;
 
@@ -137,7 +149,7 @@
             });
         }
 
-        public void onServiceDisconnected(ComponentName name) {
+        public void onServiceDisconnected() {
             mConnected = false;
             mRemoteViewsFactory = null;
 
@@ -145,8 +157,9 @@
             if (adapter == null) return;
             
             // Clear the main/worker queues
-            adapter.mMainQueue.removeMessages(0);
-            adapter.mWorkerQueue.removeMessages(0);
+            adapter.mMainQueue.removeMessages(sUnbindServiceMessageType);
+            adapter.mMainQueue.removeMessages(sDefaultMessageType);
+            adapter.mWorkerQueue.removeMessages(sDefaultMessageType);
 
             final RemoteAdapterConnectionCallback callback = adapter.mCallback.get();
             if (callback != null) {
@@ -574,20 +587,26 @@
     public RemoteViewsAdapter(Context context, Intent intent, RemoteAdapterConnectionCallback callback) {
         mContext = context;
         mIntent = intent;
+        mAppWidgetId = intent.getIntExtra(RemoteViews.EXTRA_REMOTEADAPTER_APPWIDGET_ID, -1);
         mLayoutInflater = LayoutInflater.from(context);
         if (mIntent == null) {
             throw new IllegalArgumentException("Non-null Intent must be specified.");
         }
         mRequestedViews = new RemoteViewsFrameLayoutRefSet();
 
-        // initialize the worker thread
+        // Strip the previously injected app widget id from service intent
+        if (intent.hasExtra(RemoteViews.EXTRA_REMOTEADAPTER_APPWIDGET_ID)) {
+            intent.removeExtra(RemoteViews.EXTRA_REMOTEADAPTER_APPWIDGET_ID);
+        }
+
+        // Initialize the worker thread
         mWorkerThread = new HandlerThread("RemoteViewsCache-loader");
         mWorkerThread.start();
         mWorkerQueue = new Handler(mWorkerThread.getLooper());
-        mMainQueue = new Handler(Looper.myLooper());
+        mMainQueue = new Handler(Looper.myLooper(), this);
 
-        // initialize the cache and the service connection on startup
-        mCache = new FixedSizeRemoteViewsCache(50);
+        // Initialize the cache and the service connection on startup
+        mCache = new FixedSizeRemoteViewsCache(sDefaultCacheSize);
         mCallback = new WeakReference<RemoteAdapterConnectionCallback>(callback);
         mServiceConnection = new RemoteViewsAdapterServiceConnection(this);
         requestBindService();
@@ -687,6 +706,7 @@
                     @Override
                     public void run() {
                         mRequestedViews.notifyOnRemoteViewsLoaded(position, rv, typeId);
+                        enqueueDeferredUnbindServiceMessage();
                     }
                 });
             }
@@ -879,10 +899,36 @@
         super.notifyDataSetChanged();
     }
 
+    @Override
+    public boolean handleMessage(Message msg) {
+        boolean result = false;
+        switch (msg.what) {
+        case sUnbindServiceMessageType:
+            final AppWidgetManager mgr = AppWidgetManager.getInstance(mContext);
+            if (mServiceConnection.isConnected()) {
+                mgr.unbindRemoteViewsService(mAppWidgetId, mIntent);
+            }
+            result = true;
+            break;
+        default:
+            break;
+        }
+        return result;
+    }
+
+    private void enqueueDeferredUnbindServiceMessage() {
+        /* Temporarily disable delayed service unbinding
+        // Remove any existing deferred-unbind messages
+        mMainQueue.removeMessages(sUnbindServiceMessageType);
+        mMainQueue.sendEmptyMessageDelayed(sUnbindServiceMessageType, sUnbindServiceDelay);
+        */
+    }
+
     private boolean requestBindService() {
-        // try binding the service (which will start it if it's not already running)
+        // Try binding the service (which will start it if it's not already running)
         if (!mServiceConnection.isConnected()) {
-            mContext.bindService(mIntent, mServiceConnection, Context.BIND_AUTO_CREATE);
+            final AppWidgetManager mgr = AppWidgetManager.getInstance(mContext);
+            mgr.bindRemoteViewsService(mAppWidgetId, mIntent, mServiceConnection.asBinder());
         }
 
         return mServiceConnection.isConnected();
diff --git a/core/java/android/widget/SuggestionsAdapter.java b/core/java/android/widget/SuggestionsAdapter.java
index 1ebe622..2cfc016 100644
--- a/core/java/android/widget/SuggestionsAdapter.java
+++ b/core/java/android/widget/SuggestionsAdapter.java
@@ -78,15 +78,15 @@
     // URL color
     private ColorStateList mUrlColor;
 
-    // Cached column indexes, updated when the cursor changes.
-    private int mText1Col;
-    private int mText2Col;
-    private int mText2UrlCol;
-    private int mIconName1Col;
-    private int mIconName2Col;
-    private int mFlagsCol;
+    static final int INVALID_INDEX = -1;
 
-    static final int NONE = -1;
+    // Cached column indexes, updated when the cursor changes.
+    private int mText1Col = INVALID_INDEX;
+    private int mText2Col = INVALID_INDEX;
+    private int mText2UrlCol = INVALID_INDEX;
+    private int mIconName1Col = INVALID_INDEX;
+    private int mIconName2Col = INVALID_INDEX;
+    private int mFlagsCol = INVALID_INDEX;
 
     private final Runnable mStartSpinnerRunnable;
     private final Runnable mStopSpinnerRunnable;
@@ -308,7 +308,7 @@
         ChildViewCache views = (ChildViewCache) view.getTag();
 
         int flags = 0;
-        if (mFlagsCol != -1) {
+        if (mFlagsCol != INVALID_INDEX) {
             flags = cursor.getInt(mFlagsCol);
         }
         if (views.mText1 != null) {
@@ -391,7 +391,7 @@
     }
 
     private Drawable getIcon1(Cursor cursor) {
-        if (mIconName1Col < 0) {
+        if (mIconName1Col == INVALID_INDEX) {
             return null;
         }
         String value = cursor.getString(mIconName1Col);
@@ -403,7 +403,7 @@
     }
 
     private Drawable getIcon2(Cursor cursor) {
-        if (mIconName2Col < 0) {
+        if (mIconName2Col == INVALID_INDEX) {
             return null;
         }
         String value = cursor.getString(mIconName2Col);
@@ -687,7 +687,7 @@
     }
 
     private static String getStringOrNull(Cursor cursor, int col) {
-        if (col == NONE) {
+        if (col == INVALID_INDEX) {
             return null;
         }
         try {
diff --git a/core/java/android/widget/TimePicker.java b/core/java/android/widget/TimePicker.java
index 8f3442e..26fbbbd 100644
--- a/core/java/android/widget/TimePicker.java
+++ b/core/java/android/widget/TimePicker.java
@@ -20,6 +20,7 @@
 
 import android.annotation.Widget;
 import android.content.Context;
+import android.content.res.TypedArray;
 import android.os.Parcel;
 import android.os.Parcelable;
 import android.util.AttributeSet;
@@ -31,50 +32,55 @@
 import java.util.Calendar;
 
 /**
- * A view for selecting the time of day, in either 24 hour or AM/PM mode.
- *
- * The hour, each minute digit, and AM/PM (if applicable) can be conrolled by
- * vertical spinners.
- *
- * The hour can be entered by keyboard input.  Entering in two digit hours
- * can be accomplished by hitting two digits within a timeout of about a
- * second (e.g. '1' then '2' to select 12).
- *
- * The minutes can be entered by entering single digits.
- *
- * Under AM/PM mode, the user can hit 'a', 'A", 'p' or 'P' to pick.
- *
- * For a dialog using this view, see {@link android.app.TimePickerDialog}.
- *
- * <p>See the <a href="{@docRoot}resources/tutorials/views/hello-timepicker.html">Time Picker
- * tutorial</a>.</p>
+ * A view for selecting the time of day, in either 24 hour or AM/PM mode. The
+ * hour, each minute digit, and AM/PM (if applicable) can be conrolled by
+ * vertical spinners. The hour can be entered by keyboard input. Entering in two
+ * digit hours can be accomplished by hitting two digits within a timeout of
+ * about a second (e.g. '1' then '2' to select 12). The minutes can be entered
+ * by entering single digits. Under AM/PM mode, the user can hit 'a', 'A", 'p'
+ * or 'P' to pick. For a dialog using this view, see
+ * {@link android.app.TimePickerDialog}.
+ *<p>
+ * See the <a href="{@docRoot}
+ * resources/tutorials/views/hello-timepicker.html">Time Picker tutorial</a>.
+ * </p>
  */
 @Widget
 public class TimePicker extends FrameLayout {
 
     private static final boolean DEFAULT_ENABLED_STATE = true;
 
+    private static final int HOURS_IN_HALF_DAY = 12;
+
     /**
-     * A no-op callback used in the constructor to avoid null checks
-     * later in the code.
+     * A no-op callback used in the constructor to avoid null checks later in
+     * the code.
      */
     private static final OnTimeChangedListener NO_OP_CHANGE_LISTENER = new OnTimeChangedListener() {
         public void onTimeChanged(TimePicker view, int hourOfDay, int minute) {
         }
     };
-    
+
     // state
-    private int mCurrentHour = 0; // 0-23
-    private int mCurrentMinute = 0; // 0-59
-    private Boolean mIs24HourView = false;
+    private boolean mIs24HourView;
+
     private boolean mIsAm;
 
     // ui components
     private final NumberPicker mHourSpinner;
+
     private final NumberPicker mMinuteSpinner;
+
     private final NumberPicker mAmPmSpinner;
+
     private final TextView mDivider;
 
+    // Note that the legacy implementation of the TimePicker is
+    // using a button for toggling between AM/PM while the new
+    // version uses a NumberPicker spinner. Therefore the code
+    // accommodates these two cases to be backwards compatible.
+    private final Button mAmPmButton;
+
     private final String[] mAmPmStrings;
 
     private boolean mIsEnabled = DEFAULT_ENABLED_STATE;
@@ -98,45 +104,51 @@
     public TimePicker(Context context) {
         this(context, null);
     }
-    
+
     public TimePicker(Context context, AttributeSet attrs) {
-        this(context, attrs, 0);
+        this(context, attrs, R.attr.timePickerStyle);
     }
 
     public TimePicker(Context context, AttributeSet attrs, int defStyle) {
         super(context, attrs, defStyle);
 
-        LayoutInflater inflater =
-                (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
-        inflater.inflate(R.layout.time_picker,
-            this, // we are the parent
-            true);
+        // process style attributes
+        TypedArray attributesArray = context.obtainStyledAttributes(
+                attrs, R.styleable.TimePicker, defStyle, 0);
+        int layoutResourceId = attributesArray.getResourceId(
+                R.styleable.TimePicker_layout, R.layout.time_picker);
+        attributesArray.recycle();
+
+        LayoutInflater inflater = (LayoutInflater) context.getSystemService(
+                Context.LAYOUT_INFLATER_SERVICE);
+        inflater.inflate(layoutResourceId, this, true);
 
         // hour
         mHourSpinner = (NumberPicker) findViewById(R.id.hour);
         mHourSpinner.setOnValueChangedListener(new NumberPicker.OnValueChangedListener() {
             public void onValueChange(NumberPicker spinner, int oldVal, int newVal) {
-                mCurrentHour = newVal;
-                if (!mIs24HourView) {
-                    // adjust from [1-12] to [0-11] internally, with the times
-                    // written "12:xx" being the start of the half-day
-                    if (mCurrentHour == 12) {
-                        mCurrentHour = 0;
-                    }
-                    if (!mIsAm) {
-                        // PM means 12 hours later than nominal
-                        mCurrentHour += 12;
+                if (!is24HourView()) {
+                    int minValue = mHourSpinner.getMinValue();
+                    int maxValue = mHourSpinner.getMaxValue();
+                    // toggle AM/PM if the spinner has wrapped and not in 24
+                    // format
+                    if ((oldVal == maxValue && newVal == minValue)
+                            || (oldVal == minValue && newVal == maxValue)) {
+                        mIsAm = !mIsAm;
+                        updateAmPmControl();
                     }
                 }
                 onTimeChanged();
             }
         });
 
-        // divider
+        // divider (only for the new widget style)
         mDivider = (TextView) findViewById(R.id.divider);
-        mDivider.setText(R.string.time_picker_separator);
+        if (mDivider != null) {
+            mDivider.setText(R.string.time_picker_separator);
+        }
 
-        // digits of minute
+        // minute
         mMinuteSpinner = (NumberPicker) findViewById(R.id.minute);
         mMinuteSpinner.setMinValue(0);
         mMinuteSpinner.setMaxValue(59);
@@ -144,28 +156,25 @@
         mMinuteSpinner.setFormatter(NumberPicker.TWO_DIGIT_FORMATTER);
         mMinuteSpinner.setOnValueChangedListener(new NumberPicker.OnValueChangedListener() {
             public void onValueChange(NumberPicker spinner, int oldVal, int newVal) {
-                mCurrentMinute = newVal;
-                onTimeChanged();
-            }
-        });
-
-        // am/pm
-        mAmPmSpinner = (NumberPicker) findViewById(R.id.amPm);
-        mAmPmSpinner.setOnValueChangedListener(new OnValueChangedListener() {
-            public void onValueChange(NumberPicker picker, int oldVal, int newVal) {
-                picker.requestFocus();
-                if (mIsAm) {
-                    // Currently AM switching to PM
-                    if (mCurrentHour < 12) {
-                        mCurrentHour += 12;
+                int minValue = mMinuteSpinner.getMinValue();
+                int maxValue = mMinuteSpinner.getMaxValue();
+                if (oldVal == maxValue && newVal == minValue) {
+                    int currentHour = mHourSpinner.getValue();
+                    // toggle AM/PM if the spinner is about to wrap
+                    if (!is24HourView() && currentHour == mHourSpinner.getMaxValue()) {
+                        mIsAm = !mIsAm;
+                        updateAmPmControl();
                     }
-                } else {
-                    // Currently PM switching to AM
-                    if (mCurrentHour >= 12) {
-                        mCurrentHour -= 12;
+                    mHourSpinner.setValue(currentHour + 1);
+                } else if (oldVal == minValue && newVal == maxValue) {
+                    int currentHour = mHourSpinner.getValue();
+                    // toggle AM/PM if the spinner is about to wrap
+                    if (!is24HourView() && currentHour == mHourSpinner.getMinValue()) {
+                        mIsAm = !mIsAm;
+                        updateAmPmControl();
                     }
+                    mHourSpinner.setValue(currentHour - 1);
                 }
-                mIsAm = !mIsAm;
                 onTimeChanged();
             }
         });
@@ -173,17 +182,44 @@
         /* Get the localized am/pm strings and use them in the spinner */
         mAmPmStrings = new DateFormatSymbols().getAmPmStrings();
 
-        // now that the hour/minute picker objects have been initialized, set
-        // the hour range properly based on the 12/24 hour display mode.
-        configurePickerRanges();
+        // am/pm
+        View amPmView = findViewById(R.id.amPm);
+        if (amPmView instanceof Button) {
+            mAmPmSpinner = null;
+            mAmPmButton = (Button) amPmView;
+            mAmPmButton.setOnClickListener(new OnClickListener() {
+                public void onClick(View button) {
+                    button.requestFocus();
+                    mIsAm = !mIsAm;
+                    updateAmPmControl();
+                }
+            });
+        } else {
+            mAmPmButton = null;
+            mAmPmSpinner = (NumberPicker) amPmView;
+            mAmPmSpinner.setMinValue(0);
+            mAmPmSpinner.setMaxValue(1);
+            mAmPmSpinner.setDisplayedValues(mAmPmStrings);
+            mAmPmSpinner.setOnValueChangedListener(new OnValueChangedListener() {
+                public void onValueChange(NumberPicker picker, int oldVal, int newVal) {
+                    picker.requestFocus();
+                    mIsAm = !mIsAm;
+                    updateAmPmControl();
+                }
+            });
+        }
+
+        // update controls to initial state
+        updateHourControl();
+        updateAmPmControl();
 
         // initialize to current time
-        Calendar cal = Calendar.getInstance();
+        Calendar calendar = Calendar.getInstance();
         setOnTimeChangedListener(NO_OP_CHANGE_LISTENER);
 
-        // by default we're not in 24 hour mode
-        setCurrentHour(cal.get(Calendar.HOUR_OF_DAY));
-        setCurrentMinute(cal.get(Calendar.MINUTE));
+        // set to current time
+        setCurrentHour(calendar.get(Calendar.HOUR_OF_DAY));
+        setCurrentMinute(calendar.get(Calendar.MINUTE));
 
         if (!isEnabled()) {
             setEnabled(false);
@@ -197,9 +233,15 @@
         }
         super.setEnabled(enabled);
         mMinuteSpinner.setEnabled(enabled);
-        mDivider.setEnabled(enabled);
+        if (mDivider != null) {
+            mDivider.setEnabled(enabled);
+        }
         mHourSpinner.setEnabled(enabled);
-        mAmPmSpinner.setEnabled(enabled);
+        if (mAmPmSpinner != null) {
+            mAmPmSpinner.setEnabled(enabled);
+        } else {
+            mAmPmButton.setEnabled(enabled);
+        }
         mIsEnabled = enabled;
     }
 
@@ -214,6 +256,7 @@
     private static class SavedState extends BaseSavedState {
 
         private final int mHour;
+
         private final int mMinute;
 
         private SavedState(Parcelable superState, int hour, int minute) {
@@ -221,7 +264,7 @@
             mHour = hour;
             mMinute = minute;
         }
-        
+
         private SavedState(Parcel in) {
             super(in);
             mHour = in.readInt();
@@ -244,8 +287,7 @@
         }
 
         @SuppressWarnings("unused")
-        public static final Parcelable.Creator<SavedState> CREATOR
-                = new Creator<SavedState>() {
+        public static final Parcelable.Creator<SavedState> CREATOR = new Creator<SavedState>() {
             public SavedState createFromParcel(Parcel in) {
                 return new SavedState(in);
             }
@@ -259,7 +301,7 @@
     @Override
     protected Parcelable onSaveInstanceState() {
         Parcelable superState = super.onSaveInstanceState();
-        return new SavedState(superState, mCurrentHour, mCurrentMinute);
+        return new SavedState(superState, getCurrentHour(), getCurrentMinute());
     }
 
     @Override
@@ -272,6 +314,7 @@
 
     /**
      * Set the callback that indicates the time has been adjusted by the user.
+     *
      * @param onTimeChangedListener the callback, should not be null.
      */
     public void setOnTimeChangedListener(OnTimeChangedListener onTimeChangedListener) {
@@ -279,30 +322,58 @@
     }
 
     /**
-     * @return The current hour (0-23).
+     * @return The current hour in the range (0-23).
      */
     public Integer getCurrentHour() {
-        return mCurrentHour;
+        int currentHour = mHourSpinner.getValue();
+        if (is24HourView() || mIsAm) {
+            return currentHour;
+        } else {
+            return (currentHour == HOURS_IN_HALF_DAY) ? 0 : currentHour + HOURS_IN_HALF_DAY;
+        }
     }
 
     /**
      * Set the current hour.
      */
     public void setCurrentHour(Integer currentHour) {
-        this.mCurrentHour = currentHour;
-        updateHourDisplay();
+        // why was Integer used in the first place?
+        if (currentHour == null || currentHour == getCurrentHour()) {
+            return;
+        }
+        if (!is24HourView()) {
+            // convert [0,23] ordinal to wall clock display
+            if (currentHour > HOURS_IN_HALF_DAY) {
+                currentHour -= HOURS_IN_HALF_DAY;
+                mIsAm = false;
+            } else {
+                if (currentHour == 0) {
+                    currentHour = HOURS_IN_HALF_DAY;
+                }
+                mIsAm = true;
+            }
+            updateAmPmControl();
+        }
+        mHourSpinner.setValue(currentHour);
+        onTimeChanged();
     }
 
     /**
      * Set whether in 24 hour or AM/PM mode.
+     *
      * @param is24HourView True = 24 hour mode. False = AM/PM.
      */
     public void setIs24HourView(Boolean is24HourView) {
-        if (mIs24HourView != is24HourView) {
-            mIs24HourView = is24HourView;
-            configurePickerRanges();
-            updateHourDisplay();
+        if (mIs24HourView == is24HourView) {
+            return;
         }
+        mIs24HourView = is24HourView;
+        // cache the current hour since spinner range changes
+        int currentHour = getCurrentHour();
+        updateHourControl();
+        // set value after spinner range is updated
+        setCurrentHour(currentHour);
+        updateAmPmControl();
     }
 
     /**
@@ -311,20 +382,23 @@
     public boolean is24HourView() {
         return mIs24HourView;
     }
-    
+
     /**
      * @return The current minute.
      */
     public Integer getCurrentMinute() {
-        return mCurrentMinute;
+        return mMinuteSpinner.getValue();
     }
 
     /**
      * Set the current minute (0-59).
      */
     public void setCurrentMinute(Integer currentMinute) {
-        this.mCurrentMinute = currentMinute;
-        updateMinuteDisplay();
+        if (currentMinute == getCurrentMinute()) {
+            return;
+        }
+        mMinuteSpinner.setValue(currentMinute);
+        onTimeChanged();
     }
 
     @Override
@@ -332,39 +406,34 @@
         return mHourSpinner.getBaseline();
     }
 
-    /**
-     * Set the state of the spinners appropriate to the current hour.
-     */
-    private void updateHourDisplay() {
-        int currentHour = mCurrentHour;
-        if (!mIs24HourView) {
-            // convert [0,23] ordinal to wall clock display
-            if (currentHour > 12) {
-                currentHour -= 12;
-            } else if (currentHour == 0) {
-                currentHour = 12;
-            }
-        }
-        mHourSpinner.setValue(currentHour);
-        mIsAm = mCurrentHour < 12;
-        mAmPmSpinner.setValue(mIsAm ? Calendar.AM : Calendar.PM);
-        onTimeChanged();
-    }
-
-    private void configurePickerRanges() {
-        if (mIs24HourView) {
+    private void updateHourControl() {
+        if (is24HourView()) {
             mHourSpinner.setMinValue(0);
             mHourSpinner.setMaxValue(23);
             mHourSpinner.setFormatter(NumberPicker.TWO_DIGIT_FORMATTER);
-            mAmPmSpinner.setVisibility(View.GONE);
         } else {
             mHourSpinner.setMinValue(1);
             mHourSpinner.setMaxValue(12);
             mHourSpinner.setFormatter(null);
-            mAmPmSpinner.setVisibility(View.VISIBLE);
-            mAmPmSpinner.setMinValue(0);
-            mAmPmSpinner.setMaxValue(1);
-            mAmPmSpinner.setDisplayedValues(mAmPmStrings);
+        }
+    }
+
+    private void updateAmPmControl() {
+        if (is24HourView()) {
+            if (mAmPmSpinner != null) {
+                mAmPmSpinner.setVisibility(View.GONE);
+            } else {
+                mAmPmButton.setVisibility(View.GONE);
+            }
+        } else {
+            int index = mIsAm ? Calendar.AM : Calendar.PM;
+            if (mAmPmSpinner != null) {
+                mAmPmSpinner.setValue(index);
+                mAmPmSpinner.setVisibility(View.VISIBLE);
+            } else {
+                mAmPmButton.setText(mAmPmStrings[index]);
+                mAmPmButton.setVisibility(View.VISIBLE);
+            }
         }
     }
 
@@ -373,12 +442,4 @@
             mOnTimeChangedListener.onTimeChanged(this, getCurrentHour(), getCurrentMinute());
         }
     }
-
-    /**
-     * Set the state of the spinners appropriate to the current minute.
-     */
-    private void updateMinuteDisplay() {
-        mMinuteSpinner.setValue(mCurrentMinute);
-        onTimeChanged();
-    }
 }
diff --git a/core/java/android/widget/Toast.java b/core/java/android/widget/Toast.java
index 29ca49a..6a7db1f0 100644
--- a/core/java/android/widget/Toast.java
+++ b/core/java/android/widget/Toast.java
@@ -67,15 +67,9 @@
      */
     public static final int LENGTH_LONG = 1;
 
-    final Handler mHandler = new Handler();    
     final Context mContext;
     final TN mTN;
     int mDuration;
-    int mGravity = Gravity.CENTER_HORIZONTAL | Gravity.BOTTOM;
-    int mX, mY;
-    float mHorizontalMargin;
-    float mVerticalMargin;
-    View mView;
     View mNextView;
 
     /**
@@ -88,7 +82,7 @@
     public Toast(Context context) {
         mContext = context;
         mTN = new TN();
-        mY = context.getResources().getDimensionPixelSize(
+        mTN.mY = context.getResources().getDimensionPixelSize(
                 com.android.internal.R.dimen.toast_y_offset);
     }
     
@@ -101,10 +95,9 @@
         }
 
         INotificationManager service = getService();
-
         String pkg = mContext.getPackageName();
-
         TN tn = mTN;
+        tn.mNextView = mNextView;
 
         try {
             service.enqueueToast(pkg, tn, mDuration);
@@ -167,22 +160,22 @@
      *        notification
      */
     public void setMargin(float horizontalMargin, float verticalMargin) {
-        mHorizontalMargin = horizontalMargin;
-        mVerticalMargin = verticalMargin;
+        mTN.mHorizontalMargin = horizontalMargin;
+        mTN.mVerticalMargin = verticalMargin;
     }
 
     /**
      * Return the horizontal margin.
      */
     public float getHorizontalMargin() {
-        return mHorizontalMargin;
+        return mTN.mHorizontalMargin;
     }
 
     /**
      * Return the vertical margin.
      */
     public float getVerticalMargin() {
-        return mVerticalMargin;
+        return mTN.mVerticalMargin;
     }
 
     /**
@@ -191,9 +184,9 @@
      * @see #getGravity
      */
     public void setGravity(int gravity, int xOffset, int yOffset) {
-        mGravity = gravity;
-        mX = xOffset;
-        mY = yOffset;
+        mTN.mGravity = gravity;
+        mTN.mX = xOffset;
+        mTN.mY = yOffset;
     }
 
      /**
@@ -202,21 +195,21 @@
      * @see #getGravity
      */
     public int getGravity() {
-        return mGravity;
+        return mTN.mGravity;
     }
 
     /**
      * Return the X offset in pixels to apply to the gravity's location.
      */
     public int getXOffset() {
-        return mX;
+        return mTN.mX;
     }
     
     /**
      * Return the Y offset in pixels to apply to the gravity's location.
      */
     public int getYOffset() {
-        return mY;
+        return mTN.mY;
     }
     
     /**
@@ -283,21 +276,6 @@
         tv.setText(s);
     }
 
-    private void trySendAccessibilityEvent() {
-        AccessibilityManager accessibilityManager = AccessibilityManager.getInstance(mContext);
-        if (!accessibilityManager.isEnabled()) {
-            return;
-        }
-        // treat toasts as notifications since they are used to
-        // announce a transient piece of information to the user
-        AccessibilityEvent event = AccessibilityEvent.obtain(
-                AccessibilityEvent.TYPE_NOTIFICATION_STATE_CHANGED);
-        event.setClassName(getClass().getName());
-        event.setPackageName(mContext.getPackageName());
-        mView.dispatchPopulateAccessibilityEvent(event);
-        accessibilityManager.sendAccessibilityEvent(event);
-    }
-
     // =======================================================================================
     // All the gunk below is the interaction with the Notification Service, which handles
     // the proper ordering of these system-wide.
@@ -313,7 +291,7 @@
         return sService;
     }
 
-    private class TN extends ITransientNotification.Stub {
+    private static class TN extends ITransientNotification.Stub {
         final Runnable mShow = new Runnable() {
             public void run() {
                 handleShow();
@@ -327,6 +305,16 @@
         };
 
         private final WindowManager.LayoutParams mParams = new WindowManager.LayoutParams();
+        final Handler mHandler = new Handler();    
+
+        int mGravity = Gravity.CENTER_HORIZONTAL | Gravity.BOTTOM;
+        int mX, mY;
+        float mHorizontalMargin;
+        float mVerticalMargin;
+
+       
+        View mView;
+        View mNextView;
         
         WindowManagerImpl mWM;
 
@@ -382,8 +370,7 @@
                 mParams.verticalMargin = mVerticalMargin;
                 mParams.horizontalMargin = mHorizontalMargin;
                 if (mView.getParent() != null) {
-                    if (localLOGV) Log.v(
-                            TAG, "REMOVE! " + mView + " in " + this);
+                    if (localLOGV) Log.v(TAG, "REMOVE! " + mView + " in " + this);
                     mWM.removeView(mView);
                 }
                 if (localLOGV) Log.v(TAG, "ADD! " + mView + " in " + this);
@@ -392,6 +379,22 @@
             }
         }
 
+        private void trySendAccessibilityEvent() {
+            AccessibilityManager accessibilityManager =
+                    AccessibilityManager.getInstance(mView.getContext());
+            if (!accessibilityManager.isEnabled()) {
+                return;
+            }
+            // treat toasts as notifications since they are used to
+            // announce a transient piece of information to the user
+            AccessibilityEvent event = AccessibilityEvent.obtain(
+                    AccessibilityEvent.TYPE_NOTIFICATION_STATE_CHANGED);
+            event.setClassName(getClass().getName());
+            event.setPackageName(mView.getContext().getPackageName());
+            mView.dispatchPopulateAccessibilityEvent(event);
+            accessibilityManager.sendAccessibilityEvent(event);
+        }        
+
         public void handleHide() {
             if (localLOGV) Log.v(TAG, "HANDLE HIDE: " + this + " mView=" + mView);
             if (mView != null) {
@@ -399,12 +402,12 @@
                 // been added...  i have seen cases where we get here when
                 // the view isn't yet added, so let's try not to crash.
                 if (mView.getParent() != null) {
-                    if (localLOGV) Log.v(
-                            TAG, "REMOVE! " + mView + " in " + this);
+                    if (localLOGV) Log.v(TAG, "REMOVE! " + mView + " in " + this);
                     mWM.removeView(mView);
                 }
 
                 mView = null;
+                mNextView = null;
             }
         }
     }
diff --git a/core/java/com/android/internal/app/ActionBarImpl.java b/core/java/com/android/internal/app/ActionBarImpl.java
index 0e31fef..a8eb6fe 100644
--- a/core/java/com/android/internal/app/ActionBarImpl.java
+++ b/core/java/com/android/internal/app/ActionBarImpl.java
@@ -388,6 +388,7 @@
             mActionMode.finish();
         }
 
+        mUpperContextView.killMode();
         ActionMode mode = new ActionModeImpl(callback);
         if (callback.onCreateActionMode(mode, mode.getMenu())) {
             mode.invalidate();
diff --git a/core/java/com/android/internal/app/AlertController.java b/core/java/com/android/internal/app/AlertController.java
index a139d31..71a7a52 100644
--- a/core/java/com/android/internal/app/AlertController.java
+++ b/core/java/com/android/internal/app/AlertController.java
@@ -391,6 +391,7 @@
         View buttonPanel = mWindow.findViewById(R.id.buttonPanel);
         if (!hasButtons) {
             buttonPanel.setVisibility(View.GONE);
+            mWindow.setCloseOnTouchOutsideIfNotSet(true);
         }
 
         FrameLayout customPanel = null;
diff --git a/core/java/com/android/internal/app/ChooserActivity.java b/core/java/com/android/internal/app/ChooserActivity.java
index 9ed4dd8..38ac37d 100644
--- a/core/java/com/android/internal/app/ChooserActivity.java
+++ b/core/java/com/android/internal/app/ChooserActivity.java
@@ -17,7 +17,6 @@
 package com.android.internal.app;
 
 import android.content.Intent;
-import android.content.pm.ResolveInfo;
 import android.os.Bundle;
 import android.os.Parcelable;
 import android.util.Log;
diff --git a/core/java/com/android/internal/app/PlatLogoActivity.java b/core/java/com/android/internal/app/PlatLogoActivity.java
index e1c5564..9fbbb3d 100644
--- a/core/java/com/android/internal/app/PlatLogoActivity.java
+++ b/core/java/com/android/internal/app/PlatLogoActivity.java
@@ -29,11 +29,11 @@
     protected void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
         
-        mToast = Toast.makeText(this, "Zombie art by Jack Larson", Toast.LENGTH_SHORT);
+        mToast = Toast.makeText(this, "REZZZZZZZ...", Toast.LENGTH_SHORT);
 
         ImageView content = new ImageView(this);
         content.setImageResource(com.android.internal.R.drawable.platlogo);
-        content.setScaleType(ImageView.ScaleType.FIT_CENTER);
+        content.setScaleType(ImageView.ScaleType.CENTER_INSIDE);
         
         setContentView(content);
     }
diff --git a/core/java/com/android/internal/appwidget/IAppWidgetService.aidl b/core/java/com/android/internal/appwidget/IAppWidgetService.aidl
index 4d56745..fa0873d 100644
--- a/core/java/com/android/internal/appwidget/IAppWidgetService.aidl
+++ b/core/java/com/android/internal/appwidget/IAppWidgetService.aidl
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2008 The Android Open Source Project
+ * Copyright (C) 2011 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 +17,10 @@
 package com.android.internal.appwidget;
 
 import android.content.ComponentName;
+import android.content.Intent;
 import android.appwidget.AppWidgetProviderInfo;
 import com.android.internal.appwidget.IAppWidgetHost;
+import android.os.IBinder;
 import android.widget.RemoteViews;
 
 /** {@hide} */
@@ -46,6 +48,8 @@
     List<AppWidgetProviderInfo> getInstalledProviders();
     AppWidgetProviderInfo getAppWidgetInfo(int appWidgetId);
     void bindAppWidgetId(int appWidgetId, in ComponentName provider);
+    void bindRemoteViewsService(int appWidgetId, in Intent intent, in IBinder connection);
+    void unbindRemoteViewsService(int appWidgetId, in Intent intent);
     int[] getAppWidgetIds(in ComponentName provider);
 
 }
diff --git a/core/java/com/android/internal/widget/ActionBarContextView.java b/core/java/com/android/internal/widget/ActionBarContextView.java
index 31e7bab..bb0c752 100644
--- a/core/java/com/android/internal/widget/ActionBarContextView.java
+++ b/core/java/com/android/internal/widget/ActionBarContextView.java
@@ -160,10 +160,6 @@
     }
 
     public void initForMode(final ActionMode mode) {
-        if (mAnimationMode != ANIMATE_IDLE || mAnimateInOnLayout) {
-            killMode();
-        }
-
         if (mClose == null) {
             LayoutInflater inflater = LayoutInflater.from(mContext);
             mClose = inflater.inflate(R.layout.action_mode_close_item, this, false);
@@ -198,15 +194,15 @@
             return;
         }
 
-        mAnimationMode = ANIMATE_OUT;
         finishAnimation();
+        mAnimationMode = ANIMATE_OUT;
         mCurrentAnimation = makeOutAnimation();
         mCurrentAnimation.start();
     }
 
     private void finishAnimation() {
         final Animator a = mCurrentAnimation;
-        if (a != null && a.isRunning()) {
+        if (a != null) {
             mCurrentAnimation = null;
             a.end();
         }
@@ -448,7 +444,7 @@
 
     @Override
     public void onAnimationEnd(Animator animation) {
-        if (mAnimationMode != ANIMATE_IN) {
+        if (mAnimationMode == ANIMATE_OUT) {
             killMode();
         }
         mAnimationMode = ANIMATE_IDLE;
diff --git a/core/java/com/android/internal/widget/IRemoteViewsAdapterConnection.aidl b/core/java/com/android/internal/widget/IRemoteViewsAdapterConnection.aidl
new file mode 100644
index 0000000..7eb2aef
--- /dev/null
+++ b/core/java/com/android/internal/widget/IRemoteViewsAdapterConnection.aidl
@@ -0,0 +1,25 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.widget;
+
+import android.os.IBinder;
+
+/** {@hide} */
+interface IRemoteViewsAdapterConnection {
+    void onServiceConnected(IBinder service);
+    void onServiceDisconnected();
+}
diff --git a/core/jni/AndroidRuntime.cpp b/core/jni/AndroidRuntime.cpp
index f023e94..342b884 100644
--- a/core/jni/AndroidRuntime.cpp
+++ b/core/jni/AndroidRuntime.cpp
@@ -568,6 +568,7 @@
     char jniOptsBuf[sizeof("-Xjniopts:")-1 + PROPERTY_VALUE_MAX];
     char heapstartsizeOptsBuf[sizeof("-Xms")-1 + PROPERTY_VALUE_MAX];
     char heapsizeOptsBuf[sizeof("-Xmx")-1 + PROPERTY_VALUE_MAX];
+    char heapgrowthlimitOptsBuf[sizeof("-XX:HeapGrowthLimit=")-1 + PROPERTY_VALUE_MAX];
     char extraOptsBuf[PROPERTY_VALUE_MAX];
     char* stackTraceFile = NULL;
     bool checkJni = false;
@@ -659,6 +660,13 @@
     opt.optionString = heapsizeOptsBuf;
     mOptions.add(opt);
 
+    strcpy(heapgrowthlimitOptsBuf, "-XX:HeapGrowthLimit=");
+    property_get("dalvik.vm.heapgrowthlimit", heapgrowthlimitOptsBuf+20, "");
+    if (heapgrowthlimitOptsBuf[20] != '\0') {
+        opt.optionString = heapgrowthlimitOptsBuf;
+        mOptions.add(opt);
+    }
+
     /*
      * Enable or disable dexopt features, such as bytecode verification and
      * calculation of register maps for precise GC.
diff --git a/core/jni/android/graphics/Region.cpp b/core/jni/android/graphics/Region.cpp
index c43b5ce..2445229 100644
--- a/core/jni/android/graphics/Region.cpp
+++ b/core/jni/android/graphics/Region.cpp
@@ -154,6 +154,16 @@
         scale_rgn(rgn, *rgn, scale);
 }
 
+static jstring Region_toString(JNIEnv* env, jobject clazz, SkRegion* region) {
+    char* str = region->toString();
+    if (str == NULL) {
+        return NULL;
+    }
+    jstring result = env->NewStringUTF(str);
+    free(str);
+    return result;
+}
+
 ////////////////////////////////////////////////////////////////////////////////////////////////////////////
 
 static SkRegion* Region_createFromParcel(JNIEnv* env, jobject clazz, jobject parcel)
@@ -262,6 +272,7 @@
     { "quickReject",            "(Landroid/graphics/Region;)Z",     (void*)Region_quickRejectRgn    },
     { "scale",                  "(FLandroid/graphics/Region;)V",    (void*)Region_scale             },
     { "translate",              "(IILandroid/graphics/Region;)V",   (void*)Region_translate         },
+    { "nativeToString",         "(I)Ljava/lang/String;",            (void*)Region_toString          },
     // parceling methods
     { "nativeCreateFromParcel", "(Landroid/os/Parcel;)I",           (void*)Region_createFromParcel  },
     { "nativeWriteToParcel",    "(ILandroid/os/Parcel;)Z",          (void*)Region_writeToParcel     },
diff --git a/core/jni/android_bluetooth_common.h b/core/jni/android_bluetooth_common.h
index 9222e1a..3364703 100644
--- a/core/jni/android_bluetooth_common.h
+++ b/core/jni/android_bluetooth_common.h
@@ -38,6 +38,7 @@
 #ifdef HAVE_BLUETOOTH
 #define BLUEZ_DBUS_BASE_PATH      "/org/bluez"
 #define BLUEZ_DBUS_BASE_IFC       "org.bluez"
+#define BLUEZ_ERROR_IFC           "org.bluez.Error"
 
 // It would be nicer to retrieve this from bluez using GetDefaultAdapter,
 // but this is only possible when the adapter is up (and hcid is running).
@@ -171,6 +172,30 @@
 
 bool debug_no_encrypt();
 
+
+// Result codes from Bluez DBus calls
+#define BOND_RESULT_ERROR                      -1
+#define BOND_RESULT_SUCCESS                     0
+#define BOND_RESULT_AUTH_FAILED                 1
+#define BOND_RESULT_AUTH_REJECTED               2
+#define BOND_RESULT_AUTH_CANCELED               3
+#define BOND_RESULT_REMOTE_DEVICE_DOWN          4
+#define BOND_RESULT_DISCOVERY_IN_PROGRESS       5
+#define BOND_RESULT_AUTH_TIMEOUT                6
+#define BOND_RESULT_REPEATED_ATTEMPTS           7
+
+#define PAN_DISCONNECT_FAILED_NOT_CONNECTED  1000
+#define PAN_CONNECT_FAILED_ALREADY_CONNECTED 1001
+#define PAN_CONNECT_FAILED_ATTEMPT_FAILED    1002
+#define PAN_OPERATION_GENERIC_FAILURE        1003
+#define PAN_OPERATION_SUCCESS                1004
+
+#define INPUT_DISCONNECT_FAILED_NOT_CONNECTED  5000
+#define INPUT_CONNECT_FAILED_ALREADY_CONNECTED 5001
+#define INPUT_CONNECT_FAILED_ATTEMPT_FAILED    5002
+#define INPUT_OPERATION_GENERIC_FAILURE        5003
+#define INPUT_OPERATION_SUCCESS                5004
+
 #endif
 } /* namespace android */
 
diff --git a/core/jni/android_server_BluetoothEventLoop.cpp b/core/jni/android_server_BluetoothEventLoop.cpp
index b0ba695..fd12c2d7 100644
--- a/core/jni/android_server_BluetoothEventLoop.cpp
+++ b/core/jni/android_server_BluetoothEventLoop.cpp
@@ -134,11 +134,11 @@
     method_onInputDevicePropertyChanged = env->GetMethodID(clazz, "onInputDevicePropertyChanged",
                                                "(Ljava/lang/String;[Ljava/lang/String;)V");
     method_onInputDeviceConnectionResult = env->GetMethodID(clazz, "onInputDeviceConnectionResult",
-                                               "(Ljava/lang/String;Z)V");
+                                               "(Ljava/lang/String;I)V");
     method_onPanDevicePropertyChanged = env->GetMethodID(clazz, "onPanDevicePropertyChanged",
                                                "(Ljava/lang/String;[Ljava/lang/String;)V");
     method_onPanDeviceConnectionResult = env->GetMethodID(clazz, "onPanDeviceConnectionResult",
-                                               "(Ljava/lang/String;Z)V");
+                                               "(Ljava/lang/String;I)V");
     method_onRequestOobData = env->GetMethodID(clazz, "onRequestOobData",
                                                "(Ljava/lang/String;I)V");
 
@@ -1227,16 +1227,6 @@
 
 
 #ifdef HAVE_BLUETOOTH
-//TODO: Unify result codes in a header
-#define BOND_RESULT_ERROR -1000
-#define BOND_RESULT_SUCCESS 0
-#define BOND_RESULT_AUTH_FAILED 1
-#define BOND_RESULT_AUTH_REJECTED 2
-#define BOND_RESULT_AUTH_CANCELED 3
-#define BOND_RESULT_REMOTE_DEVICE_DOWN 4
-#define BOND_RESULT_DISCOVERY_IN_PROGRESS 5
-#define BOND_RESULT_AUTH_TIMEOUT 6
-#define BOND_RESULT_REPEATED_ATTEMPTS 7
 
 void onCreatePairedDeviceResult(DBusMessage *msg, void *user, void *n) {
     LOGV(__FUNCTION__);
@@ -1406,11 +1396,25 @@
     JNIEnv *env;
     nat->vm->GetEnv((void**)&env, nat->envVer);
 
-    bool result = JNI_TRUE;
+    jint result = INPUT_OPERATION_SUCCESS;
     if (dbus_set_error_from_message(&err, msg)) {
+        if (!strcmp(err.name, BLUEZ_ERROR_IFC ".ConnectionAttemptFailed")) {
+            result = INPUT_CONNECT_FAILED_ATTEMPT_FAILED;
+        } else if (!strcmp(err.name, BLUEZ_ERROR_IFC ".AlreadyConnected")) {
+            result = INPUT_CONNECT_FAILED_ALREADY_CONNECTED;
+        } else if (!strcmp(err.name, BLUEZ_ERROR_IFC ".Failed")) {
+            // TODO():This is flaky, need to change Bluez to add new error codes
+            if (!strcmp(err.message, "Transport endpoint is not connected")) {
+              result = INPUT_DISCONNECT_FAILED_NOT_CONNECTED;
+            } else {
+              result = INPUT_OPERATION_GENERIC_FAILURE;
+            }
+        } else {
+            result = INPUT_OPERATION_GENERIC_FAILURE;
+        }
         LOG_AND_FREE_DBUS_ERROR(&err);
-        result = JNI_FALSE;
     }
+
     LOGV("... Device Path = %s, result = %d", path, result);
     jstring jPath = env->NewStringUTF(path);
     env->CallVoidMethod(nat->me,
@@ -1431,11 +1435,25 @@
     JNIEnv *env;
     nat->vm->GetEnv((void**)&env, nat->envVer);
 
-    bool result = JNI_TRUE;
+    jint result = PAN_OPERATION_SUCCESS;
     if (dbus_set_error_from_message(&err, msg)) {
+        if (!strcmp(err.name, BLUEZ_ERROR_IFC ".ConnectionAttemptFailed")) {
+            result = PAN_CONNECT_FAILED_ATTEMPT_FAILED;
+        } else if (!strcmp(err.name, BLUEZ_ERROR_IFC ".Failed")) {
+            // TODO():This is flaky, need to change Bluez to add new error codes
+            if (!strcmp(err.message, "Device already connected")) {
+                result = PAN_CONNECT_FAILED_ALREADY_CONNECTED;
+            } else if (!strcmp(err.message, "Device not connected")) {
+                result = PAN_DISCONNECT_FAILED_NOT_CONNECTED;
+            } else {
+                result = PAN_OPERATION_GENERIC_FAILURE;
+            }
+        } else {
+            result = PAN_OPERATION_GENERIC_FAILURE;
+        }
         LOG_AND_FREE_DBUS_ERROR(&err);
-        result = JNI_FALSE;
     }
+
     LOGV("... Pan Device Path = %s, result = %d", path, result);
     jstring jPath = env->NewStringUTF(path);
     env->CallVoidMethod(nat->me,
diff --git a/core/jni/android_view_Surface.cpp b/core/jni/android_view_Surface.cpp
index 8c30987..e4af33f 100644
--- a/core/jni/android_view_Surface.cpp
+++ b/core/jni/android_view_Surface.cpp
@@ -61,6 +61,7 @@
 
 struct so_t {
     jfieldID surfaceControl;
+    jfieldID surfaceGenerationId;
     jfieldID surface;
     jfieldID saveCount;
     jfieldID canvas;
@@ -189,6 +190,12 @@
         p->decStrong(clazz);
     }
     env->SetIntField(clazz, so.surface, (int)surface.get());
+    // This test is conservative and it would be better to compare the ISurfaces
+    if (p && p != surface.get()) {
+        jint generationId = env->GetIntField(clazz, so.surfaceGenerationId);
+        generationId++;
+        env->SetIntField(clazz, so.surfaceGenerationId, generationId);
+    }
 }
 
 // ----------------------------------------------------------------------------
@@ -785,6 +792,7 @@
 void nativeClassInit(JNIEnv* env, jclass clazz)
 {
     so.surface = env->GetFieldID(clazz, ANDROID_VIEW_SURFACE_JNI_ID, "I");
+    so.surfaceGenerationId = env->GetFieldID(clazz, "mSurfaceGenerationId", "I");
     so.surfaceControl = env->GetFieldID(clazz, "mSurfaceControl", "I");
     so.saveCount = env->GetFieldID(clazz, "mSaveCount", "I");
     so.canvas    = env->GetFieldID(clazz, "mCanvas", "Landroid/graphics/Canvas;");
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 41c911a..9b890fa 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -1210,6 +1210,13 @@
         android:description="@string/permdesc_backup"
         android:protectionLevel="signatureOrSystem" />
 
+    <!-- Must be required by a {@link android.widget.RemoteViewsService},
+         to ensure that only the system can bind to it. -->
+    <permission android:name="android.permission.BIND_REMOTEVIEWS"
+        android:label="@string/permlab_bindRemoteViews"
+        android:description="@string/permdesc_bindRemoteViews"
+        android:protectionLevel="signatureOrSystem" />
+
     <!-- Allows an application to tell the AppWidget service which application
          can access AppWidget's data.  The normal user flow is that a user
          picks an AppWidget to go into a particular host, thereby giving that
diff --git a/core/res/res/drawable-hdpi/ic_menu_moreoverflow_focused_holo_dark.png b/core/res/res/drawable-hdpi/ic_menu_moreoverflow_focused_holo_dark.png
deleted file mode 100644
index 3ecaa9d..0000000
--- a/core/res/res/drawable-hdpi/ic_menu_moreoverflow_focused_holo_dark.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_menu_moreoverflow_focused_holo_light.png b/core/res/res/drawable-hdpi/ic_menu_moreoverflow_focused_holo_light.png
deleted file mode 100644
index 40009af..0000000
--- a/core/res/res/drawable-hdpi/ic_menu_moreoverflow_focused_holo_light.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_menu_moreoverflow_focused_holo_dark.png b/core/res/res/drawable-mdpi/ic_menu_moreoverflow_focused_holo_dark.png
deleted file mode 100644
index c369e6f..0000000
--- a/core/res/res/drawable-mdpi/ic_menu_moreoverflow_focused_holo_dark.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_menu_moreoverflow_focused_holo_light.png b/core/res/res/drawable-mdpi/ic_menu_moreoverflow_focused_holo_light.png
deleted file mode 100644
index a4df2bf..0000000
--- a/core/res/res/drawable-mdpi/ic_menu_moreoverflow_focused_holo_light.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-nodpi/platlogo.png b/core/res/res/drawable-nodpi/platlogo.png
index e5af356..67e6ac3 100644
--- a/core/res/res/drawable-nodpi/platlogo.png
+++ b/core/res/res/drawable-nodpi/platlogo.png
Binary files differ
diff --git a/core/res/res/drawable/ic_menu_moreoverflow_holo_dark.xml b/core/res/res/drawable/ic_menu_moreoverflow_holo_dark.xml
index 4691edf..f2b846a 100644
--- a/core/res/res/drawable/ic_menu_moreoverflow_holo_dark.xml
+++ b/core/res/res/drawable/ic_menu_moreoverflow_holo_dark.xml
@@ -14,6 +14,5 @@
      limitations under the License.
 -->
 <selector xmlns:android="http://schemas.android.com/apk/res/android">
-    <item android:state_focused="true" android:drawable="@drawable/ic_menu_moreoverflow_focused_holo_dark" />
     <item android:drawable="@drawable/ic_menu_moreoverflow_normal_holo_dark" />
 </selector>
diff --git a/core/res/res/drawable/ic_menu_moreoverflow_holo_light.xml b/core/res/res/drawable/ic_menu_moreoverflow_holo_light.xml
index 5c52ff4..34afa71 100644
--- a/core/res/res/drawable/ic_menu_moreoverflow_holo_light.xml
+++ b/core/res/res/drawable/ic_menu_moreoverflow_holo_light.xml
@@ -14,6 +14,5 @@
      limitations under the License.
 -->
 <selector xmlns:android="http://schemas.android.com/apk/res/android">
-    <item android:state_focused="true" android:drawable="@drawable/ic_menu_moreoverflow_focused_holo_light" />
     <item android:drawable="@drawable/ic_menu_moreoverflow_normal_holo_light" />
 </selector>
diff --git a/core/res/res/layout-xlarge/keyguard_screen_glogin_unlock.xml b/core/res/res/layout-xlarge/keyguard_screen_glogin_unlock.xml
index 4f5beff..9779074 100644
--- a/core/res/res/layout-xlarge/keyguard_screen_glogin_unlock.xml
+++ b/core/res/res/layout-xlarge/keyguard_screen_glogin_unlock.xml
@@ -100,6 +100,16 @@
                 android:text="@android:string/lockscreen_glogin_submit_button"
                 />
 
+            <TextView
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:layout_below="@id/ok"
+                android:layout_marginTop="50dip"
+                android:text="@android:string/lockscreen_glogin_account_recovery_hint"
+                android:textAppearance="?android:attr/textAppearanceMedium"
+                android:gravity="center_horizontal"
+                />
+
         </RelativeLayout>
     </ScrollView>
 
diff --git a/core/res/res/layout/date_picker.xml b/core/res/res/layout/date_picker.xml
index e9663b1..1649466 100644
--- a/core/res/res/layout/date_picker.xml
+++ b/core/res/res/layout/date_picker.xml
@@ -40,10 +40,10 @@
         <!-- Month -->
         <NumberPicker
             android:id="@+id/month"
-            android:layout_width="48dip"
+            android:layout_width="80dip"
             android:layout_height="wrap_content"
-            android:layout_marginLeft="22dip"
-            android:layout_marginRight="22dip"
+            android:layout_marginLeft="1dip"
+            android:layout_marginRight="1dip"
             android:focusable="true"
             android:focusableInTouchMode="true"
             />
@@ -51,10 +51,10 @@
         <!-- Day -->
         <NumberPicker
             android:id="@+id/day"
-            android:layout_width="48dip"
+            android:layout_width="80dip"
             android:layout_height="wrap_content"
-            android:layout_marginLeft="22dip"
-            android:layout_marginRight="22dip"
+            android:layout_marginLeft="1dip"
+            android:layout_marginRight="1dip"
             android:focusable="true"
             android:focusableInTouchMode="true"
             />
@@ -62,10 +62,10 @@
         <!-- Year -->
         <NumberPicker
             android:id="@+id/year"
-            android:layout_width="48dip"
+            android:layout_width="95dip"
             android:layout_height="wrap_content"
-            android:layout_marginLeft="22dip"
-            android:layout_marginRight="22dip"
+            android:layout_marginLeft="1dip"
+            android:layout_marginRight="1dip"
             android:focusable="true"
             android:focusableInTouchMode="true"
             />
@@ -81,6 +81,7 @@
         android:layout_weight="1"
         android:focusable="true"
         android:focusableInTouchMode="true"
+        android:visibility="gone"
         />
 
 </LinearLayout>
diff --git a/core/res/res/layout/date_picker_holo.xml b/core/res/res/layout/date_picker_holo.xml
new file mode 100644
index 0000000..026cbfb
--- /dev/null
+++ b/core/res/res/layout/date_picker_holo.xml
@@ -0,0 +1,86 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+**
+** Copyright 2011, 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.
+*/
+-->
+
+<!-- Layout of date picker-->
+
+<!-- Warning: everything within the "pickers" layout is removed and re-ordered
+     depending on the date format selected by the user.
+-->
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="fill_parent"
+    android:layout_height="fill_parent"
+    android:layout_gravity="center_horizontal"
+    android:orientation="horizontal"
+    android:gravity="center">
+
+    <LinearLayout android:id="@+id/pickers"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_marginRight="22dip"
+        android:layout_weight="1"
+        android:orientation="horizontal"
+        android:gravity="center">
+
+        <!-- Month -->
+        <NumberPicker
+            android:id="@+id/month"
+            android:layout_width="48dip"
+            android:layout_height="wrap_content"
+            android:layout_marginLeft="22dip"
+            android:layout_marginRight="22dip"
+            android:focusable="true"
+            android:focusableInTouchMode="true"
+            />
+
+        <!-- Day -->
+        <NumberPicker
+            android:id="@+id/day"
+            android:layout_width="48dip"
+            android:layout_height="wrap_content"
+            android:layout_marginLeft="22dip"
+            android:layout_marginRight="22dip"
+            android:focusable="true"
+            android:focusableInTouchMode="true"
+            />
+
+        <!-- Year -->
+        <NumberPicker
+            android:id="@+id/year"
+            android:layout_width="48dip"
+            android:layout_height="wrap_content"
+            android:layout_marginLeft="22dip"
+            android:layout_marginRight="22dip"
+            android:focusable="true"
+            android:focusableInTouchMode="true"
+            />
+
+    </LinearLayout>
+
+    <!-- calendar view -->
+    <CalendarView
+        android:id="@+id/calendar_view"
+        android:layout_width="245dip"
+        android:layout_height="280dip"
+        android:layout_marginLeft="22dip"
+        android:layout_weight="1"
+        android:focusable="true"
+        android:focusableInTouchMode="true"
+        />
+
+</LinearLayout>
diff --git a/core/res/res/layout/time_picker.xml b/core/res/res/layout/time_picker.xml
index 382b2f6..df46db4 100644
--- a/core/res/res/layout/time_picker.xml
+++ b/core/res/res/layout/time_picker.xml
@@ -28,42 +28,33 @@
     <!-- hour -->
     <NumberPicker
         android:id="@+id/hour"
-        android:layout_width="48dip"
+        android:layout_width="70dip"
         android:layout_height="wrap_content"
-        android:layout_marginLeft="22dip"
-        android:layout_marginRight="20dip"
         android:focusable="true"
         android:focusableInTouchMode="true"
         />
 
-    <!-- divider -->
-    <TextView
-        android:id="@+id/divider"
-        android:layout_width="wrap_content"
-        android:layout_height="wrap_content"
-        android:layout_gravity="center_vertical"
-        />
-
     <!-- minute -->
     <NumberPicker
         android:id="@+id/minute"
-        android:layout_width="48dip"
+        android:layout_width="70dip"
         android:layout_height="wrap_content"
-        android:layout_marginLeft="20dip"
-        android:layout_marginRight="22dip"
+        android:layout_marginLeft="5dip"
         android:focusable="true"
         android:focusableInTouchMode="true"
         />
 
     <!-- AM / PM -->
-    <NumberPicker
+    <Button
         android:id="@+id/amPm"
-        android:layout_width="48dip"
+        android:layout_width="wrap_content"
         android:layout_height="wrap_content"
-        android:layout_marginLeft="22dip"
-        android:layout_marginRight="22dip"
-        android:focusable="true"
-        android:focusableInTouchMode="true"
+        android:layout_marginTop="43dip"
+        android:layout_marginLeft="5dip"
+        android:paddingLeft="20dip"
+        android:paddingRight="20dip"
+        style="?android:attr/textAppearanceLargeInverse"
+        android:textColor="@android:color/primary_text_light_nodisable"
         />
 
 </LinearLayout>
diff --git a/core/res/res/layout/time_picker_holo.xml b/core/res/res/layout/time_picker_holo.xml
new file mode 100644
index 0000000..ca6fe2d
--- /dev/null
+++ b/core/res/res/layout/time_picker_holo.xml
@@ -0,0 +1,69 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+**
+** Copyright 2011, 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.
+*/
+-->
+
+<!-- Layout of time picker -->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:orientation="horizontal"
+    android:layout_gravity="center_horizontal"
+    android:layout_width="wrap_content"
+    android:layout_height="wrap_content">
+
+    <!-- hour -->
+    <NumberPicker
+        android:id="@+id/hour"
+        android:layout_width="48dip"
+        android:layout_height="wrap_content"
+        android:layout_marginLeft="22dip"
+        android:layout_marginRight="20dip"
+        android:focusable="true"
+        android:focusableInTouchMode="true"
+        />
+
+    <!-- divider -->
+    <TextView
+        android:id="@+id/divider"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_gravity="center_vertical"
+        />
+
+    <!-- minute -->
+    <NumberPicker
+        android:id="@+id/minute"
+        android:layout_width="48dip"
+        android:layout_height="wrap_content"
+        android:layout_marginLeft="20dip"
+        android:layout_marginRight="22dip"
+        android:focusable="true"
+        android:focusableInTouchMode="true"
+        />
+
+    <!-- AM / PM -->
+    <NumberPicker
+        android:id="@+id/amPm"
+        android:layout_width="48dip"
+        android:layout_height="wrap_content"
+        android:layout_marginLeft="22dip"
+        android:layout_marginRight="22dip"
+        android:focusable="true"
+        android:focusableInTouchMode="true"
+        />
+
+</LinearLayout>
diff --git a/core/res/res/values-large/config.xml b/core/res/res/values-large/config.xml
index 4449fd0..05dd050 100644
--- a/core/res/res/values-large/config.xml
+++ b/core/res/res/values-large/config.xml
@@ -22,6 +22,4 @@
 <resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <!-- see comment in values/config.xml -->
     <dimen name="config_prefDialogWidth">440dp</dimen>
-    <!-- see comment in values/config.xml -->
-    <bool name="config_closeDialogWhenTouchOutside">true</bool>
 </resources>
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index de233c8..457baa6 100755
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -534,6 +534,12 @@
         <!-- The CalndarView style. -->
         <attr name="calendarViewStyle" format="reference" />
 
+        <!-- The TimePicker style. -->
+        <attr name="timePickerStyle" format="reference" />
+
+        <!-- The DatePicker style. -->
+        <attr name="datePickerStyle" format="reference" />
+
         <!-- Fast scroller styles -->
         <eat-comment />
 
@@ -2869,6 +2875,7 @@
         <!-- Gravity setting for positioning the currently selected item. -->
         <attr name="gravity" />
     </declare-styleable>
+
     <declare-styleable name="DatePicker">
         <!-- The first year (inclusive), for example "1940". -->
         <attr name="startYear" format="integer" />
@@ -2882,6 +2889,8 @@
         <attr name="minDate" format="string" />
         <!-- The minimal date shown by this calendar view in mm/dd/yyyy format. -->
         <attr name="maxDate" format="string" />
+        <!-- @hide The layout of the time picker. -->
+        <attr name="layout" />
     </declare-styleable>
 
     <declare-styleable name="TwoLineListItem">
@@ -3080,9 +3089,20 @@
     </declare-styleable>
 
     <declare-styleable name="NumberPicker">
-        <attr name="orientation" />
-        <!-- Color for the solid color background if such for optimized rendering. -->
+        <!-- @hide Color for the solid color background if such for optimized rendering. -->
         <attr name="solidColor" format="color|reference" />
+        <!-- @hide Whether the number picker supports fligning. -->
+        <attr name="flingable" format="boolean" />
+    </declare-styleable>
+
+    <declare-styleable name="TimePicker">
+        <!-- @hide The layout of the time picker. -->
+        <attr name="layout" />
+    </declare-styleable>
+
+    <declare-styleable name="DatePicker">
+        <!-- @hide The layout of the time picker. -->
+        <attr name="layout" />
     </declare-styleable>
 
     <!-- ========================= -->
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 552c2f7..e0c26d4 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -82,8 +82,7 @@
     <dimen name="config_prefDialogWidth">0px</dimen>
     
     <!-- Whether dialogs should close automatically when the user touches outside
-         of them.  This should not normally be modified; the default value will
-         pick the correct behavior depending on the screen size. -->
+         of them.  This should not normally be modified. -->
     <bool name="config_closeDialogWhenTouchOutside">false</bool>
     
     <!-- The duration (in milliseconds) that the radio will scan for a signal
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index 1b47b54..a30e316 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -1426,6 +1426,8 @@
   <public type="attr" name="fastScrollTextColor" />
   <public type="attr" name="largeHeap" />
   <public type="attr" name="windowCloseOnTouchOutside" />
+  <public type="attr" name="datePickerStyle" />
+  <public type="attr" name="calendarViewStyle" />
 
   <!-- A simple fade-in animation. -->
   <public type="animator" name="fade_in" id="0x010b0000" />
@@ -1627,21 +1629,15 @@
   <public type="style" name="Holo.Light.ButtonBar.AlertDialog" />
   <public type="style" name="Holo.SegmentedButton" />
   <public type="style" name="Holo.Light.SegmentedButton" />
-  <public type="style" name="Widget.ImageButton.NumberPickerUpButton" />
-  <public type="style" name="Widget.EditText.NumberPickerInputText" />
-  <public type="style" name="Widget.ImageButton.NumberPickerDownButton" />
-  <public type="style" name="Widget.Holo.ImageButton.NumberPickerUpButton" />
-  <public type="style" name="Widget.Holo.EditText.NumberPickerInputText" />
-  <public type="style" name="Widget.Holo.ImageButton.NumberPickerDownButton" />
-  <public type="style" name="Widget.Holo.Light.ImageButton.NumberPickerUpButton" />
-  <public type="style" name="Widget.Holo.Light.EditText.NumberPickerInputText" />
-  <public type="style" name="Widget.Holo.Light.ImageButton.NumberPickerDownButton" />
   <public type="style" name="Widget.CalendarView" />
   <public type="style" name="Widget.Holo.CalendarView" />
   <public type="style" name="Widget.Holo.Light.CalendarView" />
+  <public type="style" name="Widget.DatePicker" />
+  <public type="style" name="Widget.Holo.DatePicker" />
 
   <public type="string" name="selectTextMode" />
 
   <!-- Default icon for applications that don't specify an icon. -->
   <public type="mipmap" name="sym_def_app_icon" id="0x010d0000" />
+
 </resources>
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 2658b53..9a1b42d 100755
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -681,6 +681,12 @@
         interface of a wallpaper. Should never be needed for normal applications.</string>
 
     <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
+    <string name="permlab_bindRemoteViews">bind to a widget service</string>
+    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
+    <string name="permdesc_bindRemoteViews">Allows the holder to bind to the top-level
+        interface of a widget service. Should never be needed for normal applications.</string>
+
+    <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permlab_bindDeviceAdmin">interact with a device admin</string>
     <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permdesc_bindDeviceAdmin">Allows the holder to send intents to
@@ -1784,6 +1790,8 @@
     <string name="lockscreen_glogin_submit_button">Sign in</string>
     <!-- Displayed to the user when unlocking the phone with a username and password fails. -->
     <string name="lockscreen_glogin_invalid_input">Invalid username or password.</string>
+    <!-- Hint displayed on account unlock screen to advise the user on how to recover the account. -->
+    <string name="lockscreen_glogin_account_recovery_hint">Forgot your username or password\?\nVisit <b>google.com/accounts/recovery</b></string>
 
     <!-- Displayed in a progress dialog while a username and password are being checked. -->
     <string name="lockscreen_glogin_checking_password">Checking...</string>
diff --git a/core/res/res/values/styles.xml b/core/res/res/values/styles.xml
index 16c80d0..b7b43e0 100644
--- a/core/res/res/values/styles.xml
+++ b/core/res/res/values/styles.xml
@@ -489,7 +489,16 @@
         <item name="android:orientation">vertical</item>
         <item name="android:fadingEdge">vertical</item>
         <item name="android:fadingEdgeLength">50dip</item>
-        <item name="android:solidColor">@android:color/transparent</item>
+        <item name="android:flingable">false</item>
+    </style>
+
+    <style name="Widget.TimePicker">
+        <item name="android:layout">@android:layout/time_picker</item>
+    </style>
+
+    <style name="Widget.DatePicker">
+        <item name="android:layout">@android:layout/date_picker</item>
+        <item name="android:calendarViewShown">false</item>
     </style>
 
     <style name="Widget.ImageButton.NumberPickerUpButton">
@@ -1502,6 +1511,20 @@
         <item name="android:background">@android:drawable/btn_default_holo_dark</item>
     </style>
 
+    <style name="Widget.Holo.NumberPicker" parent="Widget.NumberPicker">
+        <item name="android:solidColor">@android:color/transparent</item>
+        <item name="android:flingable">true</item>
+    </style>
+
+    <style name="Widget.Holo.TimePicker" parent="Widget.TimePicker">
+        <item name="android:layout">@android:layout/time_picker_holo</item>
+    </style>
+
+    <style name="Widget.Holo.DatePicker" parent="Widget.DatePicker">
+        <item name="android:layout">@android:layout/date_picker_holo</item>
+        <item name="android:calendarViewShown">true</item>
+    </style>
+
     <style name="Widget.Holo.ImageButton.NumberPickerUpButton">
         <item name="android:background">@null</item>
         <item name="android:src">@android:drawable/numberpicker_up_btn_holo_dark</item>
@@ -1870,6 +1893,15 @@
         <item name="android:weekDayTextAppearance">@android:style/TextAppearance.Holo.Light.CalendarViewWeekDayView</item>
     </style>
 
+    <style name="Widget.Holo.Light.NumberPicker" parent="Widget.Holo.NumberPicker">
+    </style>
+
+    <style name="Widget.Holo.Light.TimePicker" parent="Widget.Holo.TimePicker">
+    </style>
+
+    <style name="Widget.Holo.Light.DatePicker" parent="Widget.Holo.DatePicker">
+    </style>
+
     <style name="Widget.Holo.Light.ImageButton.NumberPickerUpButton" parent="Widget.Holo.ImageButton.NumberPickerUpButton">
         <item name="android:src">@android:drawable/numberpicker_up_btn_holo_light</item>
     </style>
diff --git a/core/res/res/values/themes.xml b/core/res/res/values/themes.xml
index b257a73..2f8cffc 100644
--- a/core/res/res/values/themes.xml
+++ b/core/res/res/values/themes.xml
@@ -290,6 +290,12 @@
         <!-- CalendarView style-->
         <item name="calendarViewStyle">@style/Widget.CalendarView</item>
 
+        <!-- TimePicker style -->
+        <item name="timePickerStyle">@style/Widget.TimePicker</item>
+
+        <!-- DatePicker style -->
+        <item name="datePickerStyle">@style/Widget.DatePicker</item>
+
         <item name="fastScrollThumbDrawable">@android:drawable/scrollbar_handle_accelerated_anim2</item>
         <item name="fastScrollTrackDrawable">@null</item>
         <item name="fastScrollPreviewBackgroundRight">@android:drawable/menu_submenu_background</item>
@@ -978,10 +984,17 @@
         <item name="numberPickerUpButtonStyle">@style/Widget.Holo.ImageButton.NumberPickerUpButton</item>
         <item name="numberPickerDownButtonStyle">@style/Widget.Holo.ImageButton.NumberPickerDownButton</item>
         <item name="numberPickerInputTextStyle">@style/Widget.Holo.EditText.NumberPickerInputText</item>
+        <item name="numberPickerStyle">@style/Widget.Holo.NumberPicker</item>
 
         <!-- CalendarView style-->
         <item name="calendarViewStyle">@style/Widget.Holo.CalendarView</item>
 
+        <!-- TimePicker style -->
+        <item name="timePickerStyle">@style/Widget.Holo.TimePicker</item>
+
+        <!-- DatePicker style -->
+        <item name="datePickerStyle">@style/Widget.Holo.DatePicker</item>
+
         <item name="fastScrollThumbDrawable">@android:drawable/fastscroll_thumb_holo</item>
         <item name="fastScrollPreviewBackgroundLeft">@android:drawable/fastscroll_label_left_holo_dark</item>
         <item name="fastScrollPreviewBackgroundRight">@android:drawable/fastscroll_label_right_holo_dark</item>
@@ -1003,6 +1016,7 @@
         <item name="disabledAlpha">0.5</item>
         <item name="backgroundDimAmount">0.6</item>
 
+
         <!-- Text styles -->
         <item name="textAppearance">@android:style/TextAppearance.Holo.Light</item>
         <item name="textAppearanceInverse">@android:style/TextAppearance.Holo.Light.Inverse</item>
@@ -1236,10 +1250,17 @@
         <item name="numberPickerUpButtonStyle">@style/Widget.Holo.Light.ImageButton.NumberPickerUpButton</item>
         <item name="numberPickerDownButtonStyle">@style/Widget.Holo.Light.ImageButton.NumberPickerDownButton</item>
         <item name="numberPickerInputTextStyle">@style/Widget.Holo.Light.EditText.NumberPickerInputText</item>
+        <item name="numberPickerStyle">@style/Widget.Holo.Light.NumberPicker</item>
 
         <!-- CalendarView style-->
         <item name="calendarViewStyle">@style/Widget.Holo.Light.CalendarView</item>
 
+        <!-- TimePicker style -->
+        <item name="timePickerStyle">@style/Widget.Holo.Light.TimePicker</item>
+
+        <!-- DatePicker style -->
+        <item name="datePickerStyle">@style/Widget.Holo.Light.DatePicker</item>
+
         <item name="fastScrollThumbDrawable">@android:drawable/fastscroll_thumb_holo</item>
         <item name="fastScrollPreviewBackgroundLeft">@android:drawable/fastscroll_label_left_holo_light</item>
         <item name="fastScrollPreviewBackgroundRight">@android:drawable/fastscroll_label_right_holo_light</item>
diff --git a/core/tests/coretests/src/android/bluetooth/BluetoothStressTest.java b/core/tests/coretests/src/android/bluetooth/BluetoothStressTest.java
index 43cf06a3..96b028a 100644
--- a/core/tests/coretests/src/android/bluetooth/BluetoothStressTest.java
+++ b/core/tests/coretests/src/android/bluetooth/BluetoothStressTest.java
@@ -19,6 +19,16 @@
 import android.content.Context;
 import android.test.InstrumentationTestCase;
 
+/**
+ * Stress test suite for Bluetooth related functions.
+ *
+ * Includes tests for enabling/disabling bluetooth, enabling/disabling discoverable mode,
+ * starting/stopping scans, connecting/disconnecting to HFP, A2DP, HID, PAN profiles, and verifying
+ * that remote connections/disconnections occur for the PAN profile.
+ * <p>
+ * This test suite uses {@link android.bluetooth.BluetoothTestRunner} to for parameters such as the
+ * number of iterations and the addresses of remote Bluetooth devices.
+ */
 public class BluetoothStressTest extends InstrumentationTestCase {
     private static final String TAG = "BluetoothStressTest";
     private static final String OUTPUT_FILE = "BluetoothStressTestOutput.txt";
@@ -40,6 +50,9 @@
         mTestUtils.close();
     }
 
+    /**
+     * Stress test for enabling and disabling Bluetooth.
+     */
     public void testEnable() {
         int iterations = BluetoothTestRunner.sEnableIterations;
         if (iterations == 0) {
@@ -55,6 +68,9 @@
         }
     }
 
+    /**
+     * Stress test for putting the device in and taking the device out of discoverable mode.
+     */
     public void testDiscoverable() {
         int iterations = BluetoothTestRunner.sDiscoverableIterations;
         if (iterations == 0) {
@@ -73,6 +89,9 @@
         mTestUtils.disable(adapter);
     }
 
+    /**
+     * Stress test for starting and stopping Bluetooth scans.
+     */
     public void testScan() {
         int iterations = BluetoothTestRunner.sScanIterations;
         if (iterations == 0) {
@@ -91,6 +110,30 @@
         mTestUtils.disable(adapter);
     }
 
+    /**
+     * Stress test for enabling and disabling the PAN NAP profile.
+     */
+    public void testEnablePan() {
+        int iterations = BluetoothTestRunner.sEnablePanIterations;
+        BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
+        mTestUtils.enable(adapter);
+
+        for (int i = 0; i < iterations; i++) {
+            mTestUtils.writeOutput("testEnablePan iteration " + (i + 1) + " of "
+                    + iterations);
+            mTestUtils.enablePan(adapter);
+            mTestUtils.disablePan(adapter);
+        }
+
+        mTestUtils.disable(adapter);
+    }
+
+    /**
+     * Stress test for pairing and unpairing with a remote device.
+     * <p>
+     * In this test, the local device initiates pairing with a remote device, and then unpairs with
+     * the device after the pairing has successfully completed.
+     */
     public void testPair() {
         int iterations = BluetoothTestRunner.sPairIterations;
         if (iterations == 0) {
@@ -110,6 +153,12 @@
         mTestUtils.disable(adapter);
     }
 
+    /**
+     * Stress test for accepting a pairing request and unpairing with a remote device.
+     * <p>
+     * In this test, the local device waits for a pairing request from a remote device.  It accepts
+     * the request and then unpairs after the paring has successfully completed.
+     */
     public void testAcceptPair() {
         int iterations = BluetoothTestRunner.sPairIterations;
         BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
@@ -125,6 +174,12 @@
         mTestUtils.disable(adapter);
     }
 
+    /**
+     * Stress test for connecting and disconnecting with an A2DP source.
+     * <p>
+     * In this test, the local device plays the role of an A2DP sink, and initiates connections and
+     * disconnections with an A2DP source.
+     */
     public void testConnectA2dp() {
         int iterations = BluetoothTestRunner.sConnectA2dpIterations;
         if (iterations == 0) {
@@ -143,10 +198,16 @@
             mTestUtils.disconnectProfile(adapter, device, BluetoothProfile.A2DP);
         }
 
-        // TODO: Unpair from device if device can accept pairing after unpairing
+        mTestUtils.unpair(adapter, device);
         mTestUtils.disable(adapter);
     }
 
+    /**
+     * Stress test for connecting and disconnecting the HFP with a hands free device.
+     * <p>
+     * In this test, the local device plays the role of an HFP audio gateway, and initiates
+     * connections and disconnections with a hands free device.
+     */
     public void testConnectHeadset() {
         int iterations = BluetoothTestRunner.sConnectHeadsetIterations;
         if (iterations == 0) {
@@ -165,7 +226,94 @@
             mTestUtils.disconnectProfile(adapter, device, BluetoothProfile.HEADSET);
         }
 
-        // TODO: Unpair from device if device can accept pairing after unpairing
+        mTestUtils.unpair(adapter, device);
+        mTestUtils.disable(adapter);
+    }
+
+    /**
+     * Stress test for connecting and disconnecting with a HID device.
+     * <p>
+     * In this test, the local device plays the role of a HID host, and initiates connections and
+     * disconnections with a HID device.
+     */
+    public void testConnectInput() {
+        int iterations = BluetoothTestRunner.sConnectInputIterations;
+        if (iterations == 0) {
+            return;
+        }
+
+        BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
+        BluetoothDevice device = adapter.getRemoteDevice(BluetoothTestRunner.sInputAddress);
+        mTestUtils.enable(adapter);
+        mTestUtils.pair(adapter, device, BluetoothTestRunner.sPairPasskey,
+                BluetoothTestRunner.sPairPin);
+
+        for (int i = 0; i < iterations; i++) {
+            mTestUtils.writeOutput("connectInput iteration " + (i + 1) + " of " + iterations);
+            mTestUtils.connectInput(adapter, device);
+            mTestUtils.disconnectInput(adapter, device);
+        }
+
+        mTestUtils.unpair(adapter, device);
+        mTestUtils.disable(adapter);
+    }
+
+    /**
+     * Stress test for connecting and disconnecting with a PAN NAP.
+     * <p>
+     * In this test, the local device plays the role of a PANU, and initiates connections and
+     * disconnections with a NAP.
+     */
+    public void testConnectPan() {
+        int iterations = BluetoothTestRunner.sConnectPanIterations;
+        if (iterations == 0) {
+            return;
+        }
+
+        BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
+        BluetoothDevice device = adapter.getRemoteDevice(BluetoothTestRunner.sPanAddress);
+        mTestUtils.enable(adapter);
+        mTestUtils.pair(adapter, device, BluetoothTestRunner.sPairPasskey,
+                BluetoothTestRunner.sPairPin);
+
+        for (int i = 0; i < iterations; i++) {
+            mTestUtils.writeOutput("connectPan iteration " + (i + 1) + " of " + iterations);
+            mTestUtils.connectPan(adapter, device);
+            mTestUtils.disconnectPan(adapter, device);
+        }
+
+        mTestUtils.unpair(adapter, device);
+        mTestUtils.disable(adapter);
+    }
+
+    /**
+     * Stress test for verifying a PANU connecting and disconnecting with the device.
+     * <p>
+     * In this test, the local device plays the role of a NAP which a remote PANU connects and
+     * disconnects from.
+     */
+    public void testIncomingPanConnection() {
+        int iterations = BluetoothTestRunner.sConnectPanIterations;
+        if (iterations == 0) {
+            return;
+        }
+
+        BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
+        BluetoothDevice device = adapter.getRemoteDevice(BluetoothTestRunner.sPanAddress);
+        mTestUtils.enable(adapter);
+        mTestUtils.enablePan(adapter);
+        mTestUtils.acceptPair(adapter, device, BluetoothTestRunner.sPairPasskey,
+                BluetoothTestRunner.sPairPin);
+
+        for (int i = 0; i < iterations; i++) {
+            mTestUtils.writeOutput("incomingPanConnection iteration " + (i + 1) + " of "
+                    + iterations);
+            mTestUtils.incomingPanConnection(adapter, device);
+            mTestUtils.incomingPanDisconnection(adapter, device);
+        }
+
+        mTestUtils.unpair(adapter, device);
+        mTestUtils.disablePan(adapter);
         mTestUtils.disable(adapter);
     }
 }
diff --git a/core/tests/coretests/src/android/bluetooth/BluetoothTestRunner.java b/core/tests/coretests/src/android/bluetooth/BluetoothTestRunner.java
index 3e589fc..cede05a 100644
--- a/core/tests/coretests/src/android/bluetooth/BluetoothTestRunner.java
+++ b/core/tests/coretests/src/android/bluetooth/BluetoothTestRunner.java
@@ -23,19 +23,51 @@
 import android.test.InstrumentationTestSuite;
 import android.util.Log;
 
+/**
+ * Instrumentation test runner for Bluetooth tests.
+ * <p>
+ * To run:
+ * <pre>
+ * {@code
+ * adb shell am instrument \
+ *     [-e enable_iterations <iterations>] \
+ *     [-e discoverable_iterations <iterations>] \
+ *     [-e scan_iterations <iterations>] \
+ *     [-e enable_pan_iterations <iterations>] \
+ *     [-e pair_iterations <iterations>] \
+ *     [-e connect_a2dp_iterations <iterations>] \
+ *     [-e connect_headset_iterations <iterations>] \
+ *     [-e connect_input_iterations <iterations>] \
+ *     [-e connect_pan_iterations <iterations>] \
+ *     [-e pair_address <address>] \
+ *     [-e headset_address <address>] \
+ *     [-e a2dp_address <address>] \
+ *     [-e input_address <address>] \
+ *     [-e pan_address <address>] \
+ *     [-e pair_pin <pin>] \
+ *     [-e pair_passkey <passkey>] \
+ *     -w com.android.frameworks.coretests/android.bluetooth.BluetoothTestRunner
+ * }
+ * </pre>
+ */
 public class BluetoothTestRunner extends InstrumentationTestRunner {
     private static final String TAG = "BluetoothTestRunner";
 
     public static int sEnableIterations = 100;
     public static int sDiscoverableIterations = 1000;
     public static int sScanIterations = 1000;
+    public static int sEnablePanIterations = 1000;
     public static int sPairIterations = 100;
     public static int sConnectHeadsetIterations = 100;
     public static int sConnectA2dpIterations = 100;
+    public static int sConnectInputIterations = 100;
+    public static int sConnectPanIterations = 100;
 
     public static String sPairAddress = "";
     public static String sHeadsetAddress = "";
     public static String sA2dpAddress = "";
+    public static String sInputAddress = "";
+    public static String sPanAddress = "";
 
     public static byte[] sPairPin = {'1', '2', '3', '4'};
     public static int sPairPasskey = 123456;
@@ -81,6 +113,15 @@
             }
         }
 
+        val = arguments.getString("enable_pan_iterations");
+        if (val != null) {
+            try {
+                sEnablePanIterations = Integer.parseInt(val);
+            } catch (NumberFormatException e) {
+                // Invalid argument, fall back to default value
+            }
+        }
+
         val = arguments.getString("pair_iterations");
         if (val != null) {
             try {
@@ -108,6 +149,24 @@
             }
         }
 
+        val = arguments.getString("connect_input_iterations");
+        if (val != null) {
+            try {
+                sConnectInputIterations = Integer.parseInt(val);
+            } catch (NumberFormatException e) {
+                // Invalid argument, fall back to default value
+            }
+        }
+
+        val = arguments.getString("connect_pan_iterations");
+        if (val != null) {
+            try {
+                sConnectPanIterations = Integer.parseInt(val);
+            } catch (NumberFormatException e) {
+                // Invalid argument, fall back to default value
+            }
+        }
+
         val = arguments.getString("pair_address");
         if (val != null) {
             sPairAddress = val;
@@ -123,6 +182,16 @@
             sA2dpAddress = val;
         }
 
+        val = arguments.getString("input_address");
+        if (val != null) {
+            sInputAddress = val;
+        }
+
+        val = arguments.getString("pan_address");
+        if (val != null) {
+            sPanAddress = val;
+        }
+
         val = arguments.getString("pair_pin");
         if (val != null) {
             sPairPin = BluetoothDevice.convertPinToBytes(val);
@@ -143,9 +212,13 @@
         Log.i(TAG, String.format("pair_iterations=%d", sPairIterations));
         Log.i(TAG, String.format("connect_a2dp_iterations=%d", sConnectA2dpIterations));
         Log.i(TAG, String.format("connect_headset_iterations=%d", sConnectHeadsetIterations));
+        Log.i(TAG, String.format("connect_input_iterations=%d", sConnectInputIterations));
+        Log.i(TAG, String.format("connect_pan_iterations=%d", sConnectPanIterations));
         Log.i(TAG, String.format("pair_address=%s", sPairAddress));
         Log.i(TAG, String.format("a2dp_address=%s", sA2dpAddress));
         Log.i(TAG, String.format("headset_address=%s", sHeadsetAddress));
+        Log.i(TAG, String.format("input_address=%s", sInputAddress));
+        Log.i(TAG, String.format("pan_address=%s", sPanAddress));
         Log.i(TAG, String.format("pair_pin=%s", new String(sPairPin)));
         Log.i(TAG, String.format("pair_passkey=%d", sPairPasskey));
 
diff --git a/core/tests/coretests/src/android/bluetooth/BluetoothTestUtils.java b/core/tests/coretests/src/android/bluetooth/BluetoothTestUtils.java
index 6da38a7..effed76 100644
--- a/core/tests/coretests/src/android/bluetooth/BluetoothTestUtils.java
+++ b/core/tests/coretests/src/android/bluetooth/BluetoothTestUtils.java
@@ -35,49 +35,29 @@
 public class BluetoothTestUtils extends Assert {
 
     /**
-     * Timeout for {@link BluetoothAdapter#disable()} in ms.
+     * Timeout for enable/disable in ms.
      */
-    private static final int DISABLE_TIMEOUT = 20000;
+    private static final int ENABLE_DISABLE_TIMEOUT = 20000;
 
     /**
-     * Timeout for {@link BluetoothAdapter#enable()} in ms.
+     * Timeout for discoverable/undiscoverable in ms.
      */
-    private static final int ENABLE_TIMEOUT = 20000;
+    private static final int DISCOVERABLE_UNDISCOVERABLE_TIMEOUT = 5000;
 
     /**
-     * Timeout for {@link BluetoothAdapter#setScanMode(int)} in ms.
+     * Timeout for starting/stopping a scan in ms.
      */
-    private static final int SET_SCAN_MODE_TIMEOUT = 5000;
+    private static final int START_STOP_SCAN_TIMEOUT = 5000;
 
     /**
-     * Timeout for {@link BluetoothAdapter#startDiscovery()} in ms.
+     * Timeout for pair/unpair in ms.
      */
-    private static final int START_DISCOVERY_TIMEOUT = 5000;
+    private static final int PAIR_UNPAIR_TIMEOUT = 20000;
 
     /**
-     * Timeout for {@link BluetoothAdapter#cancelDiscovery()} in ms.
+     * Timeout for connecting/disconnecting a profile in ms.
      */
-    private static final int CANCEL_DISCOVERY_TIMEOUT = 5000;
-
-    /**
-     * Timeout for {@link BluetoothDevice#createBond()} in ms.
-     */
-    private static final int PAIR_TIMEOUT = 20000;
-
-    /**
-     * Timeout for {@link BluetoothDevice#removeBond()} in ms.
-     */
-    private static final int UNPAIR_TIMEOUT = 20000;
-
-    /**
-     * Timeout for {@link BluetoothProfile#connect(BluetoothDevice)} in ms.
-     */
-    private static final int CONNECT_PROFILE_TIMEOUT = 20000;
-
-    /**
-     * Timeout for {@link BluetoothProfile#disconnect(BluetoothDevice)} in ms.
-     */
-    private static final int DISCONNECT_PROFILE_TIMEOUT = 20000;
+    private static final int CONNECT_DISCONNECT_PROFILE_TIMEOUT = 20000;
 
     /**
      * Timeout to connect a profile proxy in ms.
@@ -265,7 +245,6 @@
 
         @Override
         public void onReceive(Context context, Intent intent) {
-
             if (mConnectionAction != null && mConnectionAction.equals(intent.getAction())) {
                 if (!mDevice.equals(intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE))) {
                     return;
@@ -291,6 +270,91 @@
         }
     }
 
+    private class ConnectInputReceiver extends FlagReceiver {
+        private static final int STATE_DISCONNECTED_FLAG = 1;
+        private static final int STATE_CONNECTING_FLAG = 1 << 1;
+        private static final int STATE_CONNECTED_FLAG = 1 << 2;
+        private static final int STATE_DISCONNECTING_FLAG = 1 << 3;
+
+        private BluetoothDevice mDevice;
+
+        public ConnectInputReceiver(BluetoothDevice device, int expectedFlags) {
+            super(expectedFlags);
+
+            mDevice = device;
+        }
+
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            if (!mDevice.equals(intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE))) {
+                return;
+            }
+
+            if (BluetoothInputDevice.ACTION_INPUT_DEVICE_STATE_CHANGED.equals(intent.getAction())) {
+                int state = intent.getIntExtra(BluetoothInputDevice.EXTRA_INPUT_DEVICE_STATE, -1);
+                assertNotSame(-1, state);
+                switch (state) {
+                    case BluetoothInputDevice.STATE_DISCONNECTED:
+                        setFiredFlag(STATE_DISCONNECTED_FLAG);
+                        break;
+                    case BluetoothInputDevice.STATE_CONNECTING:
+                        setFiredFlag(STATE_CONNECTING_FLAG);
+                        break;
+                    case BluetoothInputDevice.STATE_CONNECTED:
+                        setFiredFlag(STATE_CONNECTED_FLAG);
+                        break;
+                    case BluetoothInputDevice.STATE_DISCONNECTING:
+                        setFiredFlag(STATE_DISCONNECTING_FLAG);
+                        break;
+                }
+            }
+        }
+    }
+
+    private class ConnectPanReceiver extends FlagReceiver {
+        private static final int STATE_DISCONNECTED_FLAG = 1;
+        private static final int STATE_CONNECTING_FLAG = 1 << 1;
+        private static final int STATE_CONNECTED_FLAG = 1 << 2;
+        private static final int STATE_DISCONNECTING_FLAG = 1 << 3;
+
+        private BluetoothDevice mDevice;
+        private int mRole;
+
+        public ConnectPanReceiver(BluetoothDevice device, int role, int expectedFlags) {
+            super (expectedFlags);
+
+            mDevice = device;
+            mRole = role;
+        }
+
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            if (!mDevice.equals(intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE))
+                    || mRole != intent.getIntExtra(BluetoothPan.EXTRA_LOCAL_ROLE, -1)) {
+                return;
+            }
+
+            if (BluetoothPan.ACTION_PAN_STATE_CHANGED.equals(intent.getAction())) {
+                int state = intent.getIntExtra(BluetoothPan.EXTRA_PAN_STATE, -1);
+                assertNotSame(-1, state);
+                switch (state) {
+                    case BluetoothPan.STATE_DISCONNECTED:
+                        setFiredFlag(STATE_DISCONNECTED_FLAG);
+                        break;
+                    case BluetoothPan.STATE_CONNECTING:
+                        setFiredFlag(STATE_CONNECTING_FLAG);
+                        break;
+                    case BluetoothPan.STATE_CONNECTED:
+                        setFiredFlag(STATE_CONNECTED_FLAG);
+                        break;
+                    case BluetoothPan.STATE_DISCONNECTING:
+                        setFiredFlag(STATE_DISCONNECTING_FLAG);
+                        break;
+                }
+            }
+        }
+    }
+
     private BluetoothProfile.ServiceListener mServiceListener =
             new BluetoothProfile.ServiceListener() {
         public void onServiceConnected(int profile, BluetoothProfile proxy) {
@@ -330,10 +394,24 @@
     private BluetoothA2dp mA2dp;
     private BluetoothHeadset mHeadset;
 
+    /**
+     * Creates a utility instance for testing Bluetooth.
+     *
+     * @param context The context of the application using the utility.
+     * @param tag The log tag of the application using the utility.
+     */
     public BluetoothTestUtils(Context context, String tag) {
         this(context, tag, null);
     }
 
+    /**
+     * Creates a utility instance for testing Bluetooth.
+     *
+     * @param context The context of the application using the utility.
+     * @param tag The log tag of the application using the utility.
+     * @param outputFile The path to an output file if the utility is to write results to a
+     *        separate file.
+     */
     public BluetoothTestUtils(Context context, String tag, String outputFile) {
         mContext = context;
         mTag = tag;
@@ -352,6 +430,9 @@
         }
     }
 
+    /**
+     * Closes the utility instance and unregisters any BroadcastReceivers.
+     */
     public void close() {
         while (!mReceivers.isEmpty()) {
             mContext.unregisterReceiver(mReceivers.remove(0));
@@ -366,6 +447,12 @@
         }
     }
 
+    /**
+     * Enables Bluetooth and checks to make sure that Bluetooth was turned on and that the correct
+     * actions were broadcast.
+     *
+     * @param adapter The BT adapter.
+     */
     public void enable(BluetoothAdapter adapter) {
         int mask = (BluetoothReceiver.STATE_TURNING_ON_FLAG | BluetoothReceiver.STATE_ON_FLAG
                 | BluetoothReceiver.SCAN_MODE_CONNECTABLE_FLAG);
@@ -397,22 +484,19 @@
         }
 
         long s = System.currentTimeMillis();
-        while (System.currentTimeMillis() - s < ENABLE_TIMEOUT) {
+        while (System.currentTimeMillis() - s < ENABLE_DISABLE_TIMEOUT) {
             state = adapter.getState();
-            if (state == BluetoothAdapter.STATE_ON) {
+            if (state == BluetoothAdapter.STATE_ON
+                    && (receiver.getFiredFlags() & mask) == mask) {
                 assertTrue(adapter.isEnabled());
-                if ((receiver.getFiredFlags() & mask) == mask) {
-                    long finish = receiver.getCompletedTime();
-                    if (start != -1 && finish != -1) {
-                        writeOutput(String.format("enable() completed in %d ms", (finish - start)));
-                    } else {
-                        writeOutput("enable() completed");
-                    }
-                    removeReceiver(receiver);
-                    return;
+                long finish = receiver.getCompletedTime();
+                if (start != -1 && finish != -1) {
+                    writeOutput(String.format("enable() completed in %d ms", (finish - start)));
+                } else {
+                    writeOutput("enable() completed");
                 }
-            } else {
-                assertEquals(BluetoothAdapter.STATE_TURNING_ON, state);
+                removeReceiver(receiver);
+                return;
             }
             sleep(POLL_TIME);
         }
@@ -423,6 +507,12 @@
                 state, BluetoothAdapter.STATE_ON, firedFlags, mask));
     }
 
+    /**
+     * Disables Bluetooth and checks to make sure that Bluetooth was turned off and that the correct
+     * actions were broadcast.
+     *
+     * @param adapter The BT adapter.
+     */
     public void disable(BluetoothAdapter adapter) {
         int mask = (BluetoothReceiver.STATE_TURNING_OFF_FLAG | BluetoothReceiver.STATE_OFF_FLAG
                 | BluetoothReceiver.SCAN_MODE_NONE_FLAG);
@@ -454,23 +544,19 @@
         }
 
         long s = System.currentTimeMillis();
-        while (System.currentTimeMillis() - s < DISABLE_TIMEOUT) {
+        while (System.currentTimeMillis() - s < ENABLE_DISABLE_TIMEOUT) {
             state = adapter.getState();
-            if (state == BluetoothAdapter.STATE_OFF) {
+            if (state == BluetoothAdapter.STATE_OFF
+                    && (receiver.getFiredFlags() & mask) == mask) {
                 assertFalse(adapter.isEnabled());
-                if ((receiver.getFiredFlags() & mask) == mask) {
-                    long finish = receiver.getCompletedTime();
-                    if (start != -1 && finish != -1) {
-                        writeOutput(String.format("disable() completed in %d ms",
-                                (finish - start)));
-                    } else {
-                        writeOutput("disable() completed");
-                    }
-                    removeReceiver(receiver);
-                    return;
+                long finish = receiver.getCompletedTime();
+                if (start != -1 && finish != -1) {
+                    writeOutput(String.format("disable() completed in %d ms", (finish - start)));
+                } else {
+                    writeOutput("disable() completed");
                 }
-            } else {
-                assertEquals(BluetoothAdapter.STATE_TURNING_OFF, state);
+                removeReceiver(receiver);
+                return;
             }
             sleep(POLL_TIME);
         }
@@ -481,6 +567,12 @@
                 state, BluetoothAdapter.STATE_OFF, firedFlags, mask));
     }
 
+    /**
+     * Puts the local device into discoverable mode and checks to make sure that the local device
+     * is in discoverable mode and that the correct actions were broadcast.
+     *
+     * @param adapter The BT adapter.
+     */
     public void discoverable(BluetoothAdapter adapter) {
         int mask = BluetoothReceiver.SCAN_MODE_CONNECTABLE_DISCOVERABLE_FLAG;
 
@@ -499,17 +591,14 @@
         long start = System.currentTimeMillis();
         assertTrue(adapter.setScanMode(BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE));
 
-        while (System.currentTimeMillis() - start < SET_SCAN_MODE_TIMEOUT) {
+        while (System.currentTimeMillis() - start < DISCOVERABLE_UNDISCOVERABLE_TIMEOUT) {
             scanMode = adapter.getScanMode();
-            if (scanMode == BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE) {
-                if ((receiver.getFiredFlags() & mask) == mask) {
-                    writeOutput(String.format("discoverable() completed in %d ms",
-                            (receiver.getCompletedTime() - start)));
-                    removeReceiver(receiver);
-                    return;
-                }
-            } else {
-                assertEquals(BluetoothAdapter.SCAN_MODE_CONNECTABLE, scanMode);
+            if (scanMode == BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE
+                    && (receiver.getFiredFlags() & mask) == mask) {
+                writeOutput(String.format("discoverable() completed in %d ms",
+                        (receiver.getCompletedTime() - start)));
+                removeReceiver(receiver);
+                return;
             }
             sleep(POLL_TIME);
         }
@@ -521,6 +610,12 @@
                 firedFlags, mask));
     }
 
+    /**
+     * Puts the local device into connectable only mode and checks to make sure that the local
+     * device is in in connectable mode and that the correct actions were broadcast.
+     *
+     * @param adapter The BT adapter.
+     */
     public void undiscoverable(BluetoothAdapter adapter) {
         int mask = BluetoothReceiver.SCAN_MODE_CONNECTABLE_FLAG;
 
@@ -539,17 +634,14 @@
         long start = System.currentTimeMillis();
         assertTrue(adapter.setScanMode(BluetoothAdapter.SCAN_MODE_CONNECTABLE));
 
-        while (System.currentTimeMillis() - start < SET_SCAN_MODE_TIMEOUT) {
+        while (System.currentTimeMillis() - start < DISCOVERABLE_UNDISCOVERABLE_TIMEOUT) {
             scanMode = adapter.getScanMode();
-            if (scanMode == BluetoothAdapter.SCAN_MODE_CONNECTABLE) {
-                if ((receiver.getFiredFlags() & mask) == mask) {
-                    writeOutput(String.format("undiscoverable() completed in %d ms",
-                            (receiver.getCompletedTime() - start)));
-                    removeReceiver(receiver);
-                    return;
-                }
-            } else {
-                assertEquals(BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE, scanMode);
+            if (scanMode == BluetoothAdapter.SCAN_MODE_CONNECTABLE
+                    && (receiver.getFiredFlags() & mask) == mask) {
+                writeOutput(String.format("undiscoverable() completed in %d ms",
+                        (receiver.getCompletedTime() - start)));
+                removeReceiver(receiver);
+                return;
             }
             sleep(POLL_TIME);
         }
@@ -561,6 +653,12 @@
                 mask));
     }
 
+    /**
+     * Starts a scan for remote devices and checks to make sure that the local device is scanning
+     * and that the correct actions were broadcast.
+     *
+     * @param adapter The BT adapter.
+     */
     public void startScan(BluetoothAdapter adapter) {
         int mask = BluetoothReceiver.DISCOVERY_STARTED_FLAG;
 
@@ -577,7 +675,7 @@
         long start = System.currentTimeMillis();
         assertTrue(adapter.startDiscovery());
 
-        while (System.currentTimeMillis() - start < START_DISCOVERY_TIMEOUT) {
+        while (System.currentTimeMillis() - start < START_STOP_SCAN_TIMEOUT) {
             if (adapter.isDiscovering() && ((receiver.getFiredFlags() & mask) == mask)) {
                 writeOutput(String.format("startScan() completed in %d ms",
                         (receiver.getCompletedTime() - start)));
@@ -593,6 +691,12 @@
                 adapter.isDiscovering(), firedFlags, mask));
     }
 
+    /**
+     * Stops a scan for remote devices and checks to make sure that the local device is not scanning
+     * and that the correct actions were broadcast.
+     *
+     * @param adapter The BT adapter.
+     */
     public void stopScan(BluetoothAdapter adapter) {
         int mask = BluetoothReceiver.DISCOVERY_FINISHED_FLAG;
 
@@ -610,7 +714,7 @@
         // TODO: put assertTrue() around cancelDiscovery() once it starts returning true.
         adapter.cancelDiscovery();
 
-        while (System.currentTimeMillis() - start < CANCEL_DISCOVERY_TIMEOUT) {
+        while (System.currentTimeMillis() - start < START_STOP_SCAN_TIMEOUT) {
             if (!adapter.isDiscovering() && ((receiver.getFiredFlags() & mask) == mask)) {
                 writeOutput(String.format("stopScan() completed in %d ms",
                         (receiver.getCompletedTime() - start)));
@@ -627,20 +731,84 @@
 
     }
 
+    /**
+     * Enables PAN tethering on the local device and checks to make sure that tethering is enabled.
+     *
+     * @param adapter The BT adapter.
+     */
+    public void enablePan(BluetoothAdapter adapter) {
+        BluetoothPan pan = new BluetoothPan(mContext);
+        assertNotNull(pan);
+
+        long start = System.currentTimeMillis();
+        pan.setBluetoothTethering(true);
+        long stop = System.currentTimeMillis();
+        assertTrue(pan.isTetheringOn());
+
+        writeOutput(String.format("enablePan() completed in %d ms", (stop - start)));
+    }
+
+    /**
+     * Disables PAN tethering on the local device and checks to make sure that tethering is
+     * disabled.
+     *
+     * @param adapter The BT adapter.
+     */
+    public void disablePan(BluetoothAdapter adapter) {
+        BluetoothPan pan = new BluetoothPan(mContext);
+        assertNotNull(pan);
+
+        long start = System.currentTimeMillis();
+        pan.setBluetoothTethering(false);
+        long stop = System.currentTimeMillis();
+        assertFalse(pan.isTetheringOn());
+
+        writeOutput(String.format("disablePan() completed in %d ms", (stop - start)));
+    }
+
+    /**
+     * Initiates a pairing with a remote device and checks to make sure that the devices are paired
+     * and that the correct actions were broadcast.
+     *
+     * @param adapter The BT adapter.
+     * @param device The remote device.
+     * @param passkey The pairing passkey if pairing requires a passkey. Any value if not.
+     * @param pin The pairing pin if pairing requires a pin. Any value if not.
+     */
     public void pair(BluetoothAdapter adapter, BluetoothDevice device, int passkey, byte[] pin) {
         pairOrAcceptPair(adapter, device, passkey, pin, true);
     }
 
+    /**
+     * Accepts a pairing with a remote device and checks to make sure that the devices are paired
+     * and that the correct actions were broadcast.
+     *
+     * @param adapter The BT adapter.
+     * @param device The remote device.
+     * @param passkey The pairing passkey if pairing requires a passkey. Any value if not.
+     * @param pin The pairing pin if pairing requires a pin. Any value if not.
+     */
     public void acceptPair(BluetoothAdapter adapter, BluetoothDevice device, int passkey,
             byte[] pin) {
         pairOrAcceptPair(adapter, device, passkey, pin, false);
     }
 
+    /**
+     * Helper method used by {@link #pair(BluetoothAdapter, BluetoothDevice, int, byte[])} and
+     * {@link #acceptPair(BluetoothAdapter, BluetoothDevice, int, byte[])} to either pair or accept
+     * a pairing request.
+     *
+     * @param adapter The BT adapter.
+     * @param device The remote device.
+     * @param passkey The pairing passkey if pairing requires a passkey. Any value if not.
+     * @param pin The pairing pin if pairing requires a pin. Any value if not.
+     * @param shouldPair Whether to pair or accept the pair.
+     */
     private void pairOrAcceptPair(BluetoothAdapter adapter, BluetoothDevice device, int passkey,
-            byte[] pin, boolean pair) {
+            byte[] pin, boolean shouldPair) {
         int mask = PairReceiver.STATE_BONDING_FLAG | PairReceiver.STATE_BONDED_FLAG;
         long start = -1;
-        String methodName = pair ? "pair()" : "acceptPair()";
+        String methodName = shouldPair ? "pair()" : "acceptPair()";
 
         if (!adapter.isEnabled()) {
             fail(methodName + " bluetooth not enabled");
@@ -653,7 +821,7 @@
             case BluetoothDevice.BOND_NONE:
                 assertFalse(adapter.getBondedDevices().contains(device));
                 start = System.currentTimeMillis();
-                if (pair) {
+                if (shouldPair) {
                     assertTrue(device.createBond());
                 }
                 break;
@@ -670,21 +838,19 @@
         }
 
         long s = System.currentTimeMillis();
-        while (System.currentTimeMillis() - s < PAIR_TIMEOUT) {
+        while (System.currentTimeMillis() - s < PAIR_UNPAIR_TIMEOUT) {
             state = device.getBondState();
-            if (state == BluetoothDevice.BOND_BONDED) {
+            if (state == BluetoothDevice.BOND_BONDED && (receiver.getFiredFlags() & mask) == mask) {
                 assertTrue(adapter.getBondedDevices().contains(device));
-                if ((receiver.getFiredFlags() & mask) == mask) {
-                    long finish = receiver.getCompletedTime();
-                    if (start != -1 && finish != -1) {
-                        writeOutput(String.format("%s completed in %d ms: device=%s", methodName,
-                                (finish - start), device));
-                    } else {
-                        writeOutput(String.format("%s completed: device=%s", methodName, device));
-                    }
-                    removeReceiver(receiver);
-                    return;
+                long finish = receiver.getCompletedTime();
+                if (start != -1 && finish != -1) {
+                    writeOutput(String.format("%s completed in %d ms: device=%s", methodName,
+                            (finish - start), device));
+                } else {
+                    writeOutput(String.format("%s completed: device=%s", methodName, device));
                 }
+                removeReceiver(receiver);
+                return;
             }
             sleep(POLL_TIME);
         }
@@ -696,6 +862,13 @@
                 BluetoothDevice.BOND_BONDED, firedFlags, mask));
     }
 
+    /**
+     * Deletes a pairing with a remote device and checks to make sure that the devices are unpaired
+     * and that the correct actions were broadcast.
+     *
+     * @param adapter The BT adapter.
+     * @param device The remote device.
+     */
     public void unpair(BluetoothAdapter adapter, BluetoothDevice device) {
         int mask = PairReceiver.STATE_NONE_FLAG;
         long start = -1;
@@ -727,20 +900,19 @@
         }
 
         long s = System.currentTimeMillis();
-        while (System.currentTimeMillis() - s < UNPAIR_TIMEOUT) {
-            if (device.getBondState() == BluetoothDevice.BOND_NONE) {
+        while (System.currentTimeMillis() - s < PAIR_UNPAIR_TIMEOUT) {
+            if (device.getBondState() == BluetoothDevice.BOND_NONE
+                    && (receiver.getFiredFlags() & mask) == mask) {
                 assertFalse(adapter.getBondedDevices().contains(device));
-                if ((receiver.getFiredFlags() & mask) == mask) {
-                    long finish = receiver.getCompletedTime();
-                    if (start != -1 && finish != -1) {
-                        writeOutput(String.format("unpair() completed in %d ms: device=%s",
-                                (finish - start), device));
-                    } else {
-                        writeOutput(String.format("unpair() completed: device=%s", device));
-                    }
-                    removeReceiver(receiver);
-                    return;
+                long finish = receiver.getCompletedTime();
+                if (start != -1 && finish != -1) {
+                    writeOutput(String.format("unpair() completed in %d ms: device=%s",
+                            (finish - start), device));
+                } else {
+                    writeOutput(String.format("unpair() completed: device=%s", device));
                 }
+                removeReceiver(receiver);
+                return;
             }
         }
 
@@ -751,6 +923,15 @@
                 firedFlags, mask));
     }
 
+    /**
+     * Connects a profile from the local device to a remote device and checks to make sure that the
+     * profile is connected and that the correct actions were broadcast.
+     *
+     * @param adapter The BT adapter.
+     * @param device The remote device.
+     * @param profile The profile to connect. One of {@link BluetoothProfile#A2DP} or
+     *        {@link BluetoothProfile#HEADSET}.
+     */
     public void connectProfile(BluetoothAdapter adapter, BluetoothDevice device, int profile) {
         int mask = (ConnectProfileReceiver.STATE_CONNECTING_FLAG
                 | ConnectProfileReceiver.STATE_CONNECTED_FLAG);
@@ -794,21 +975,20 @@
         }
 
         long s = System.currentTimeMillis();
-        while (System.currentTimeMillis() - s < CONNECT_PROFILE_TIMEOUT) {
+        while (System.currentTimeMillis() - s < CONNECT_DISCONNECT_PROFILE_TIMEOUT) {
             state = proxy.getConnectionState(device);
-            if (state == BluetoothProfile.STATE_CONNECTED) {
-                if ((receiver.getFiredFlags() & mask) == mask) {
-                    long finish = receiver.getCompletedTime();
-                    if (start != -1 && finish != -1) {
-                        writeOutput(String.format("connectProfile() completed in %d ms: "
-                                + "device=%s, profile=%d", (finish - start), device, profile));
-                    } else {
-                        writeOutput(String.format("connectProfile() completed: device=%s, "
-                                + "profile=%d", device, profile));
-                    }
-                    removeReceiver(receiver);
-                    return;
+            if (state == BluetoothProfile.STATE_CONNECTED
+                    && (receiver.getFiredFlags() & mask) == mask) {
+                long finish = receiver.getCompletedTime();
+                if (start != -1 && finish != -1) {
+                    writeOutput(String.format("connectProfile() completed in %d ms: "
+                            + "device=%s, profile=%d", (finish - start), device, profile));
+                } else {
+                    writeOutput(String.format("connectProfile() completed: device=%s, "
+                            + "profile=%d", device, profile));
                 }
+                removeReceiver(receiver);
+                return;
             }
             sleep(POLL_TIME);
         }
@@ -820,6 +1000,15 @@
                 BluetoothProfile.STATE_CONNECTED, firedFlags, mask));
     }
 
+    /**
+     * Disconnects a profile between the local device and a remote device and checks to make sure
+     * that the profile is disconnected and that the correct actions were broadcast.
+     *
+     * @param adapter The BT adapter.
+     * @param device The remote device.
+     * @param profile The profile to disconnect. One of {@link BluetoothProfile#A2DP} or
+     *        {@link BluetoothProfile#HEADSET}.
+     */
     public void disconnectProfile(BluetoothAdapter adapter, BluetoothDevice device, int profile) {
         int mask = (ConnectProfileReceiver.STATE_DISCONNECTING_FLAG
                 | ConnectProfileReceiver.STATE_DISCONNECTED_FLAG);
@@ -863,21 +1052,20 @@
         }
 
         long s = System.currentTimeMillis();
-        while (System.currentTimeMillis() - s < DISCONNECT_PROFILE_TIMEOUT) {
+        while (System.currentTimeMillis() - s < CONNECT_DISCONNECT_PROFILE_TIMEOUT) {
             state = proxy.getConnectionState(device);
-            if (state == BluetoothProfile.STATE_DISCONNECTED) {
-                if ((receiver.getFiredFlags() & mask) == mask) {
-                    long finish = receiver.getCompletedTime();
-                    if (start != -1 && finish != -1) {
-                        writeOutput(String.format("disconnectProfile() completed in %d ms: "
-                                + "device=%s, profile=%d", (finish - start), device, profile));
-                    } else {
-                        writeOutput(String.format("disconnectProfile() completed: device=%s, "
-                                + "profile=%d", device, profile));
-                    }
-                    removeReceiver(receiver);
-                    return;
+            if (state == BluetoothProfile.STATE_DISCONNECTED
+                    && (receiver.getFiredFlags() & mask) == mask) {
+                long finish = receiver.getCompletedTime();
+                if (start != -1 && finish != -1) {
+                    writeOutput(String.format("disconnectProfile() completed in %d ms: "
+                            + "device=%s, profile=%d", (finish - start), device, profile));
+                } else {
+                    writeOutput(String.format("disconnectProfile() completed: device=%s, "
+                            + "profile=%d", device, profile));
                 }
+                removeReceiver(receiver);
+                return;
             }
             sleep(POLL_TIME);
         }
@@ -889,6 +1077,360 @@
                 BluetoothProfile.STATE_DISCONNECTED, firedFlags, mask));
     }
 
+    /**
+     * Connects the local device with a remote HID device and checks to make sure that the profile
+     * is connected and that the correct actions were broadcast.
+     *
+     * @param adapter The BT adapter.
+     * @param device The remote device.
+     */
+    public void connectInput(BluetoothAdapter adapter, BluetoothDevice device) {
+        int mask = (ConnectInputReceiver.STATE_CONNECTING_FLAG
+                | ConnectInputReceiver.STATE_CONNECTED_FLAG);
+        long start = -1;
+
+        if (!adapter.isEnabled()) {
+            fail(String.format("connectInput() bluetooth not enabled: device=%s", device));
+        }
+
+        if (!adapter.getBondedDevices().contains(device)) {
+            fail(String.format("connectInput() device not paired: device=%s", device));
+        }
+
+        BluetoothInputDevice inputDevice = new BluetoothInputDevice(mContext);
+        assertNotNull(inputDevice);
+        ConnectInputReceiver receiver = getConnectInputReceiver(device, mask);
+
+        int state = inputDevice.getInputDeviceState(device);
+        switch (state) {
+            case BluetoothInputDevice.STATE_CONNECTED:
+                removeReceiver(receiver);
+                return;
+            case BluetoothInputDevice.STATE_CONNECTING:
+                mask = 0; // Don't check for received intents since we might have missed them.
+                break;
+            case BluetoothInputDevice.STATE_DISCONNECTED:
+            case BluetoothInputDevice.STATE_DISCONNECTING:
+                start = System.currentTimeMillis();
+                assertTrue(inputDevice.connectInputDevice(device));
+                break;
+            default:
+                removeReceiver(receiver);
+                fail(String.format("connectInput() invalid state: device=%s, state=%d", device,
+                        state));
+        }
+
+        long s = System.currentTimeMillis();
+        while (System.currentTimeMillis() - s < CONNECT_DISCONNECT_PROFILE_TIMEOUT) {
+            state = inputDevice.getInputDeviceState(device);
+            if (state == BluetoothInputDevice.STATE_CONNECTED
+                    && (receiver.getFiredFlags() & mask) == mask) {
+                long finish = receiver.getCompletedTime();
+                if (start != -1 && finish != -1) {
+                    writeOutput(String.format("connectInput() completed in %d ms: device=%s",
+                            (finish - start), device));
+                } else {
+                    writeOutput(String.format("connectInput() completed: device=%s", device));
+                }
+                removeReceiver(receiver);
+                return;
+            }
+            sleep(POLL_TIME);
+        }
+
+        int firedFlags = receiver.getFiredFlags();
+        removeReceiver(receiver);
+        fail(String.format("connectInput() timeout: device=%s, state=%d (expected %d), "
+                + "flags=0x%x (expected 0x%s)", device, state, BluetoothInputDevice.STATE_CONNECTED,
+                firedFlags, mask));
+    }
+
+    /**
+     * Disconnects the local device with a remote HID device and checks to make sure that the
+     * profile is connected and that the correct actions were broadcast.
+     *
+     * @param adapter The BT adapter.
+     * @param device The remote device.
+     */
+    public void disconnectInput(BluetoothAdapter adapter, BluetoothDevice device) {
+        int mask = (ConnectInputReceiver.STATE_DISCONNECTING_FLAG
+                | ConnectInputReceiver.STATE_DISCONNECTED_FLAG);
+        long start = -1;
+
+        if (!adapter.isEnabled()) {
+            fail(String.format("disconnectInput() bluetooth not enabled: device=%s", device));
+        }
+
+        if (!adapter.getBondedDevices().contains(device)) {
+            fail(String.format("disconnectInput() device not paired: device=%s", device));
+        }
+
+        BluetoothInputDevice inputDevice = new BluetoothInputDevice(mContext);
+        assertNotNull(inputDevice);
+        ConnectInputReceiver receiver = getConnectInputReceiver(device, mask);
+
+        int state = inputDevice.getInputDeviceState(device);
+        switch (state) {
+            case BluetoothInputDevice.STATE_CONNECTED:
+            case BluetoothInputDevice.STATE_CONNECTING:
+                start = System.currentTimeMillis();
+                assertTrue(inputDevice.disconnectInputDevice(device));
+                break;
+            case BluetoothInputDevice.STATE_DISCONNECTED:
+                removeReceiver(receiver);
+                return;
+            case BluetoothInputDevice.STATE_DISCONNECTING:
+                mask = 0; // Don't check for received intents since we might have missed them.
+                break;
+            default:
+                removeReceiver(receiver);
+                fail(String.format("disconnectInput() invalid state: device=%s, state=%d", device,
+                        state));
+        }
+
+        long s = System.currentTimeMillis();
+        while (System.currentTimeMillis() - s < CONNECT_DISCONNECT_PROFILE_TIMEOUT) {
+            state = inputDevice.getInputDeviceState(device);
+            if (state == BluetoothInputDevice.STATE_DISCONNECTED
+                    && (receiver.getFiredFlags() & mask) == mask) {
+                long finish = receiver.getCompletedTime();
+                if (start != -1 && finish != -1) {
+                    writeOutput(String.format("disconnectInput() completed in %d ms: device=%s",
+                            (finish - start), device));
+                } else {
+                    writeOutput(String.format("disconnectInput() completed: device=%s", device));
+                }
+                removeReceiver(receiver);
+                return;
+            }
+            sleep(POLL_TIME);
+        }
+
+        int firedFlags = receiver.getFiredFlags();
+        removeReceiver(receiver);
+        fail(String.format("disconnectInput() timeout: device=%s, state=%d (expected %d), "
+                + "flags=0x%x (expected 0x%s)", device, state,
+                BluetoothInputDevice.STATE_DISCONNECTED, firedFlags, mask));
+    }
+
+    /**
+     * Connects the PANU to a remote NAP and checks to make sure that the PANU is connected and that
+     * the correct actions were broadcast.
+     *
+     * @param adapter The BT adapter.
+     * @param device The remote device.
+     */
+    public void connectPan(BluetoothAdapter adapter, BluetoothDevice device) {
+        connectPanOrIncomingPanConnection(adapter, device, true);
+    }
+
+    /**
+     * Checks that a remote PANU connects to the local NAP correctly and that the correct actions
+     * were broadcast.
+     *
+     * @param adapter The BT adapter.
+     * @param device The remote device.
+     */
+    public void incomingPanConnection(BluetoothAdapter adapter, BluetoothDevice device) {
+        connectPanOrIncomingPanConnection(adapter, device, false);
+    }
+
+    /**
+     * Helper method used by {@link #connectPan(BluetoothAdapter, BluetoothDevice)} and
+     * {@link #incomingPanConnection(BluetoothAdapter, BluetoothDevice)} to either connect to a
+     * remote NAP or verify that a remote device connected to the local NAP.
+     *
+     * @param adapter The BT adapter.
+     * @param device The remote device.
+     * @param connect If the method should initiate the connection (is PANU)
+     */
+    private void connectPanOrIncomingPanConnection(BluetoothAdapter adapter, BluetoothDevice device,
+            boolean connect) {
+        long start = -1;
+        int mask, role;
+        String methodName;
+
+        if (connect) {
+            methodName = "connectPan()";
+            mask = (ConnectPanReceiver.STATE_CONNECTED_FLAG |
+                    ConnectPanReceiver.STATE_CONNECTING_FLAG);
+            role = BluetoothPan.LOCAL_PANU_ROLE;
+        } else {
+            methodName = "incomingPanConnection()";
+            mask = ConnectPanReceiver.STATE_CONNECTED_FLAG;
+            role = BluetoothPan.LOCAL_NAP_ROLE;
+        }
+
+        if (!adapter.isEnabled()) {
+            fail(String.format("%s bluetooth not enabled: device=%s", methodName, device));
+        }
+
+        if (!adapter.getBondedDevices().contains(device)) {
+            fail(String.format("%s device not paired: device=%s", methodName, device));
+        }
+
+        BluetoothPan pan = new BluetoothPan(mContext);
+        assertNotNull(pan);
+        ConnectPanReceiver receiver = getConnectPanReceiver(device, role, mask);
+
+        int state = pan.getPanDeviceState(device);
+        switch (state) {
+            case BluetoothPan.STATE_CONNECTED:
+                removeReceiver(receiver);
+                return;
+            case BluetoothPan.STATE_CONNECTING:
+                mask = 0; // Don't check for received intents since we might have missed them.
+                break;
+            case BluetoothPan.STATE_DISCONNECTED:
+            case BluetoothPan.STATE_DISCONNECTING:
+                start = System.currentTimeMillis();
+                if (role == BluetoothPan.LOCAL_PANU_ROLE) {
+                    Log.i("BT", "connect to pan");
+                    assertTrue(pan.connect(device));
+                }
+                break;
+            default:
+                removeReceiver(receiver);
+                fail(String.format("%s invalid state: device=%s, state=%d", methodName, device,
+                        state));
+        }
+
+        long s = System.currentTimeMillis();
+        while (System.currentTimeMillis() - s < CONNECT_DISCONNECT_PROFILE_TIMEOUT) {
+            state = pan.getPanDeviceState(device);
+            if (state == BluetoothPan.STATE_CONNECTED
+                    && (receiver.getFiredFlags() & mask) == mask) {
+                long finish = receiver.getCompletedTime();
+                if (start != -1 && finish != -1) {
+                    writeOutput(String.format("%s completed in %d ms: device=%s", methodName,
+                            (finish - start), device));
+                } else {
+                    writeOutput(String.format("%s completed: device=%s", methodName, device));
+                }
+                removeReceiver(receiver);
+                return;
+            }
+            sleep(POLL_TIME);
+        }
+
+        int firedFlags = receiver.getFiredFlags();
+        removeReceiver(receiver);
+        fail(String.format("%s timeout: device=%s, state=%d (expected %d), "
+                + "flags=0x%x (expected 0x%s)", methodName, device, state,
+                BluetoothPan.STATE_CONNECTED, firedFlags, mask));
+    }
+
+    /**
+     * Disconnects the PANU from a remote NAP and checks to make sure that the PANU is disconnected
+     * and that the correct actions were broadcast.
+     *
+     * @param adapter The BT adapter.
+     * @param device The remote device.
+     */
+    public void disconnectPan(BluetoothAdapter adapter, BluetoothDevice device) {
+        disconnectFromRemoteOrVerifyConnectNap(adapter, device, true);
+    }
+
+    /**
+     * Checks that a remote PANU disconnects from the local NAP correctly and that the correct
+     * actions were broadcast.
+     *
+     * @param adapter The BT adapter.
+     * @param device The remote device.
+     */
+    public void incomingPanDisconnection(BluetoothAdapter adapter, BluetoothDevice device) {
+        disconnectFromRemoteOrVerifyConnectNap(adapter, device, false);
+    }
+
+    /**
+     * Helper method used by {@link #disconnectPan(BluetoothAdapter, BluetoothDevice)} and
+     * {@link #incomingPanDisconnection(BluetoothAdapter, BluetoothDevice)} to either disconnect
+     * from a remote NAP or verify that a remote device disconnected from the local NAP.
+     *
+     * @param adapter The BT adapter.
+     * @param device The remote device.
+     * @param disconnect Whether the method should connect or verify.
+     */
+    private void disconnectFromRemoteOrVerifyConnectNap(BluetoothAdapter adapter,
+            BluetoothDevice device, boolean disconnect) {
+        long start = -1;
+        int mask, role;
+        String methodName;
+
+        if (disconnect) {
+            methodName = "disconnectPan()";
+            mask = (ConnectPanReceiver.STATE_DISCONNECTED_FLAG |
+                    ConnectPanReceiver.STATE_DISCONNECTING_FLAG);
+            role = BluetoothPan.LOCAL_PANU_ROLE;
+        } else {
+            methodName = "incomingPanDisconnection()";
+            mask = ConnectPanReceiver.STATE_DISCONNECTED_FLAG;
+            role = BluetoothPan.LOCAL_NAP_ROLE;
+        }
+
+        if (!adapter.isEnabled()) {
+            fail(String.format("%s bluetooth not enabled: device=%s", methodName, device));
+        }
+
+        if (!adapter.getBondedDevices().contains(device)) {
+            fail(String.format("%s device not paired: device=%s", methodName, device));
+        }
+
+        BluetoothPan pan = new BluetoothPan(mContext);
+        assertNotNull(pan);
+        ConnectPanReceiver receiver = getConnectPanReceiver(device, role, mask);
+
+        int state = pan.getPanDeviceState(device);
+        switch (state) {
+            case BluetoothInputDevice.STATE_CONNECTED:
+            case BluetoothInputDevice.STATE_CONNECTING:
+                start = System.currentTimeMillis();
+                if (role == BluetoothPan.LOCAL_PANU_ROLE) {
+                    assertTrue(pan.disconnect(device));
+                }
+                break;
+            case BluetoothInputDevice.STATE_DISCONNECTED:
+                removeReceiver(receiver);
+                return;
+            case BluetoothInputDevice.STATE_DISCONNECTING:
+                mask = 0; // Don't check for received intents since we might have missed them.
+                break;
+            default:
+                removeReceiver(receiver);
+                fail(String.format("%s invalid state: device=%s, state=%d", methodName, device,
+                        state));
+        }
+
+        long s = System.currentTimeMillis();
+        while (System.currentTimeMillis() - s < CONNECT_DISCONNECT_PROFILE_TIMEOUT) {
+            state = pan.getPanDeviceState(device);
+            if (state == BluetoothInputDevice.STATE_DISCONNECTED
+                    && (receiver.getFiredFlags() & mask) == mask) {
+                long finish = receiver.getCompletedTime();
+                if (start != -1 && finish != -1) {
+                    writeOutput(String.format("%s completed in %d ms: device=%s", methodName,
+                            (finish - start), device));
+                } else {
+                    writeOutput(String.format("%s completed: device=%s", methodName, device));
+                }
+                removeReceiver(receiver);
+                return;
+            }
+            sleep(POLL_TIME);
+        }
+
+        int firedFlags = receiver.getFiredFlags();
+        removeReceiver(receiver);
+        fail(String.format("%s timeout: device=%s, state=%d (expected %d), "
+                + "flags=0x%x (expected 0x%s)", methodName, device, state,
+                BluetoothInputDevice.STATE_DISCONNECTED, firedFlags, mask));
+    }
+
+    /**
+     * Writes a string to the logcat and a file if a file has been specified in the constructor.
+     *
+     * @param s The string to be written.
+     */
     public void writeOutput(String s) {
         Log.i(mTag, s);
         if (mOutputWriter == null) {
@@ -902,38 +1444,60 @@
         }
     }
 
-    private BluetoothReceiver getBluetoothReceiver(int expectedFlags) {
-        BluetoothReceiver receiver = new BluetoothReceiver(expectedFlags);
+    private void addReceiver(BroadcastReceiver receiver, String[] actions) {
         IntentFilter filter = new IntentFilter();
-        filter.addAction(BluetoothAdapter.ACTION_DISCOVERY_FINISHED);
-        filter.addAction(BluetoothAdapter.ACTION_DISCOVERY_STARTED);
-        filter.addAction(BluetoothAdapter.ACTION_SCAN_MODE_CHANGED);
-        filter.addAction(BluetoothAdapter.ACTION_STATE_CHANGED);
+        for (String action: actions) {
+            filter.addAction(action);
+        }
         mContext.registerReceiver(receiver, filter);
         mReceivers.add(receiver);
+    }
+
+    private BluetoothReceiver getBluetoothReceiver(int expectedFlags) {
+        String[] actions = {
+                BluetoothAdapter.ACTION_DISCOVERY_FINISHED,
+                BluetoothAdapter.ACTION_DISCOVERY_STARTED,
+                BluetoothAdapter.ACTION_SCAN_MODE_CHANGED,
+                BluetoothAdapter.ACTION_STATE_CHANGED};
+        BluetoothReceiver receiver = new BluetoothReceiver(expectedFlags);
+        addReceiver(receiver, actions);
         return receiver;
     }
 
     private PairReceiver getPairReceiver(BluetoothDevice device, int passkey, byte[] pin,
             int expectedFlags) {
+        String[] actions = {
+                BluetoothDevice.ACTION_PAIRING_REQUEST,
+                BluetoothDevice.ACTION_BOND_STATE_CHANGED};
         PairReceiver receiver = new PairReceiver(device, passkey, pin, expectedFlags);
-        IntentFilter filter = new IntentFilter();
-        filter.addAction(BluetoothDevice.ACTION_PAIRING_REQUEST);
-        filter.addAction(BluetoothDevice.ACTION_BOND_STATE_CHANGED);
-        mContext.registerReceiver(receiver, filter);
-        mReceivers.add(receiver);
+        addReceiver(receiver, actions);
         return receiver;
     }
 
     private ConnectProfileReceiver getConnectProfileReceiver(BluetoothDevice device, int profile,
             int expectedFlags) {
+        String[] actions = {
+                BluetoothA2dp.ACTION_CONNECTION_STATE_CHANGED,
+                BluetoothHeadset.ACTION_CONNECTION_STATE_CHANGED};
         ConnectProfileReceiver receiver = new ConnectProfileReceiver(device, profile,
                 expectedFlags);
-        IntentFilter filter = new IntentFilter();
-        filter.addAction(BluetoothA2dp.ACTION_CONNECTION_STATE_CHANGED);
-        filter.addAction(BluetoothHeadset.ACTION_CONNECTION_STATE_CHANGED);
-        mContext.registerReceiver(receiver, filter);
-        mReceivers.add(receiver);
+        addReceiver(receiver, actions);
+        return receiver;
+    }
+
+    private ConnectInputReceiver getConnectInputReceiver(BluetoothDevice device,
+            int expectedFlags) {
+        String[] actions = {BluetoothInputDevice.ACTION_INPUT_DEVICE_STATE_CHANGED};
+        ConnectInputReceiver receiver = new ConnectInputReceiver(device, expectedFlags);
+        addReceiver(receiver, actions);
+        return receiver;
+    }
+
+    private ConnectPanReceiver getConnectPanReceiver(BluetoothDevice device, int role,
+            int expectedFlags) {
+        String[] actions = {BluetoothPan.ACTION_PAN_STATE_CHANGED};
+        ConnectPanReceiver receiver = new ConnectPanReceiver(device, role, expectedFlags);
+        addReceiver(receiver, actions);
         return receiver;
     }
 
diff --git a/docs/html/guide/practices/design/performance.jd b/docs/html/guide/practices/design/performance.jd
index 97b31cf..fe69d7d 100644
--- a/docs/html/guide/practices/design/performance.jd
+++ b/docs/html/guide/practices/design/performance.jd
@@ -8,14 +8,13 @@
 <ol>
   <li><a href="#intro">Introduction</a></li>
   <li><a href="#optimize_judiciously">Optimize Judiciously</a></li>
-  <li><a href="#object_creation">Avoid Creating Objects</a></li>
+  <li><a href="#object_creation">Avoid Creating Unnecessary Objects</a></li>
   <li><a href="#myths">Performance Myths</a></li>
   <li><a href="#prefer_static">Prefer Static Over Virtual</a></li>
   <li><a href="#internal_get_set">Avoid Internal Getters/Setters</a></li>
   <li><a href="#use_final">Use Static Final For Constants</a></li>
   <li><a href="#foreach">Use Enhanced For Loop Syntax</a></li>
-  <li><a href="#avoid_enums">Avoid Enums Where You Only Need Ints</a></li>
-  <li><a href="#package_inner">Use Package Scope with Inner Classes</a></li>
+  <li><a href="#package_inner">Consider Package Instead of Private Access with Inner Classes</a></li>
   <li><a href="#avoidfloat">Use Floating-Point Judiciously</a> </li>
   <li><a href="#library">Know And Use The Libraries</a></li>
   <li><a href="#native_methods">Use Native Methods Judiciously</a></li>
@@ -83,27 +82,31 @@
 test on that device.</p>
 
 <a name="object_creation"></a>
-<h2>Avoid Creating Objects</h2>
+<h2>Avoid Creating Unnecessary Objects</h2>
 
 <p>Object creation is never free. A generational GC with per-thread allocation
 pools for temporary objects can make allocation cheaper, but allocating memory
 is always more expensive than not allocating memory.</p>
 
 <p>If you allocate objects in a user interface loop, you will force a periodic
-garbage collection, creating little "hiccups" in the user experience.</p>
+garbage collection, creating little "hiccups" in the user experience. The
+concurrent collector introduced in Gingerbread helps, but unnecessary work
+should always be avoided.</p>
 
 <p>Thus, you should avoid creating object instances you don't need to.  Some
 examples of things that can help:</p>
 
 <ul>
-    <li>When extracting strings from a set of input data, try 
-    to return a substring of the original data, instead of creating a copy.
-    You will create a new String object, but it will share the char[]
-    with the data.</li>
     <li>If you have a method returning a string, and you know that its result
     will always be appended to a StringBuffer anyway, change your signature
     and implementation so that the function does the append directly,
     instead of creating a short-lived temporary object.</li>
+    <li>When extracting strings from a set of input data, try
+    to return a substring of the original data, instead of creating a copy.
+    You will create a new String object, but it will share the char[]
+    with the data. (The trade-off being that if you're only using a small
+    part of the original input, you'll be keeping it all around in memory
+    anyway if you go this route.)</li>
 </ul>
 
 <p>A somewhat more radical idea is to slice up multidimensional arrays into
@@ -119,7 +122,7 @@
     generally much better than a single array of custom (Foo,Bar) objects.
     (The exception to this, of course, is when you're designing an API for
     other code to access;  in those cases, it's usually better to trade
-    correct API design for a small hit in speed. But in your own internal 
+    good API design for a small hit in speed. But in your own internal
     code, you should try and be as efficient as possible.)</li>
 </ul>
 
@@ -127,6 +130,7 @@
 can.  Fewer objects created mean less-frequent garbage collection, which has
 a direct impact on user experience.</p>
 
+<a name="avoid_enums" id="avoid_enums"></a>
 <a name="myths" id="myths"></a>
 <h2>Performance Myths</h2>
 
@@ -265,43 +269,18 @@
 
 <p>(See also <em>Effective Java</em> item 46.)</p>
 
-<a name="avoid_enums" id="avoid_enums"></a>
-<h2>Avoid Enums Where You Only Need Ints</h2>
-
-<p>Enums are very convenient, but unfortunately can be painful when size
-and speed matter.  For example, this:</p>
-
-<pre>public enum Shrubbery { GROUND, CRAWLING, HANGING }</pre>
-
-<p>adds 740 bytes to your .dex file compared to the equivalent class
-with three public static final ints. On first use, the
-class initializer invokes the &lt;init&gt; method on objects representing each
-of the enumerated values. Each object gets its own static field, and the full
-set is stored in an array (a static field called "$VALUES"). That's a lot of
-code and data, just for three integers. Additionally, this:</p>
-
-<pre>Shrubbery shrub = Shrubbery.GROUND;</pre>
-
-<p>causes a static field lookup.  If "GROUND" were a static final int,
-the compiler would treat it as a known constant and inline it.</p>
-
-<p>The flip side, of course, is that with enums you get nicer APIs and
-some compile-time value checking.  So, the usual trade-off applies: you should
-by all means use enums for public APIs, but try to avoid them when performance
-matters.</p>
-
-<p>If you're using <code>Enum.ordinal</code>, that's usually a sign that you
-should be using ints instead. As a rule of thumb, if an enum doesn't have a
-constructor and doesn't define its own methods, and it's used in
-performance-critical code, you should consider <code>static final int</code>
-constants instead.</p>
-
 <a name="package_inner" id="package_inner"></a>
-<h2>Use Package Scope with Inner Classes</h2>
+<h2>Consider Package Instead of Private Access with Private Inner Classes</h2>
 
 <p>Consider the following class definition:</p>
 
 <pre>public class Foo {
+    private class Inner {
+        void stuff() {
+            Foo.this.doStuff(Foo.this.mValue);
+        }
+    }
+
     private int mValue;
 
     public void run() {
@@ -313,24 +292,19 @@
     private void doStuff(int value) {
         System.out.println("Value is " + value);
     }
-
-    private class Inner {
-        void stuff() {
-            Foo.this.doStuff(Foo.this.mValue);
-        }
-    }
 }</pre>
 
-<p>The key things to note here are that we define an inner class (Foo$Inner)
-that directly accesses a private method and a private instance field
-in the outer class.  This is legal, and the code prints "Value is 27" as
-expected.</p>
+<p>The key things to note here are that we define a private inner class
+(<code>Foo$Inner</code>) that directly accesses a private method and a private
+instance field in the outer class. This is legal, and the code prints "Value is
+27" as expected.</p>
 
-<p>The problem is that the VM considers direct access to Foo's private members
-from Foo$Inner to be illegal because Foo and Foo$Inner are different classes,
-even though the Java language allows an inner class to access an outer class'
-private members. To bridge the gap, the compiler generates a couple of
-synthetic methods:</p>
+<p>The problem is that the VM considers direct access to <code>Foo</code>'s
+private members from <code>Foo$Inner</code> to be illegal because
+<code>Foo</code> and <code>Foo$Inner</code> are different classes, even though
+the Java language allows an inner class to access an outer class' private
+members. To bridge the gap, the compiler generates a couple of synthetic
+methods:</p>
 
 <pre>/*package*/ static int Foo.access$100(Foo foo) {
     return foo.mValue;
@@ -339,22 +313,19 @@
     foo.doStuff(value);
 }</pre>
 
-<p>The inner-class code calls these static methods whenever it needs to
-access the "mValue" field or invoke the "doStuff" method in the outer
-class. What this means is that the code above really boils down to a case
-where you're accessing member fields through accessor methods instead of
-directly.  Earlier we talked about how accessors are slower than direct field
+<p>The inner class code calls these static methods whenever it needs to
+access the <code>mValue</code> field or invoke the <code>doStuff</code> method
+in the outer class. What this means is that the code above really boils down to
+a case where you're accessing member fields through accessor methods.
+Earlier we talked about how accessors are slower than direct field
 accesses, so this is an example of a certain language idiom resulting in an
 "invisible" performance hit.</p>
 
-<p>We can avoid this problem by declaring fields and methods accessed
-by inner classes to have package scope, rather than private scope.
-This runs faster and removes the overhead of the generated methods.
-(Unfortunately it also means the fields could be accessed directly by other
-classes in the same package, which runs counter to the standard
-practice of making all fields private. Once again, if you're
-designing a public API you might want to carefully consider using this
-optimization.)</p>
+<p>If you're using code like this in a performance hotspot, you can avoid the
+overhead by declaring fields and methods accessed by inner classes to have
+package access, rather than private access. Unfortunately this means the fields
+can be accessed directly by other classes in the same package, so you shouldn't
+use this in public API.</p>
 
 <a name="avoidfloat" id="avoidfloat"></a>
 <h2>Use Floating-Point Judiciously</h2>
diff --git a/drm/common/IDrmManagerService.cpp b/drm/common/IDrmManagerService.cpp
index 75edac6..ddbd220 100644
--- a/drm/common/IDrmManagerService.cpp
+++ b/drm/common/IDrmManagerService.cpp
@@ -382,7 +382,7 @@
     }
 
     data.writeInt32(playbackStatus);
-    data.writeInt32(position);
+    data.writeInt64(position);
 
     remote()->transact(SET_PLAYBACK_STATUS, data, &reply);
     return reply.readInt32();
@@ -1111,7 +1111,7 @@
         }
 
         const status_t status
-            = setPlaybackStatus(uniqueId, &handle, data.readInt32(), data.readInt32());
+            = setPlaybackStatus(uniqueId, &handle, data.readInt32(), data.readInt64());
         reply->writeInt32(status);
 
         delete handle.decryptInfo; handle.decryptInfo = NULL;
diff --git a/graphics/java/android/graphics/Region.java b/graphics/java/android/graphics/Region.java
index e540806..27ea0f0 100644
--- a/graphics/java/android/graphics/Region.java
+++ b/graphics/java/android/graphics/Region.java
@@ -287,6 +287,10 @@
                         region2.mNativeRegion, op.nativeInt);
     }
 
+    public String toString() {
+        return nativeToString(mNativeRegion);
+    }
+
     //////////////////////////////////////////////////////////////////////////
     
     public static final Parcelable.Creator<Region> CREATOR
@@ -357,6 +361,8 @@
         return mNativeRegion;
     }
 
+    private static native boolean nativeEquals(int native_r1, int native_r2);
+
     private static native int nativeConstructor();
     private static native void nativeDestructor(int native_region);
 
@@ -381,5 +387,5 @@
     private static native boolean nativeWriteToParcel(int native_region,
                                                       Parcel p);
 
-    private static native boolean nativeEquals(int native_r1, int native_r2);
+    private static native String nativeToString(int native_region);
 }
diff --git a/graphics/java/android/renderscript/Allocation.java b/graphics/java/android/renderscript/Allocation.java
index 1789891..74cdf80 100644
--- a/graphics/java/android/renderscript/Allocation.java
+++ b/graphics/java/android/renderscript/Allocation.java
@@ -268,22 +268,105 @@
         }
     }
 
+    /**
+     * Copy an allocation from an array.  This variant is not type
+     * checked which allows an application to fill in structured
+     * data from an array.
+     *
+     * @param d the source data array
+     */
+    public void copyFromUnchecked(int[] d) {
+        mRS.validate();
+        copy1DRangeFromUnchecked(0, mType.getCount(), d);
+    }
+    /**
+     * Copy an allocation from an array.  This variant is not type
+     * checked which allows an application to fill in structured
+     * data from an array.
+     *
+     * @param d the source data array
+     */
+    public void copyFromUnchecked(short[] d) {
+        mRS.validate();
+        copy1DRangeFromUnchecked(0, mType.getCount(), d);
+    }
+    /**
+     * Copy an allocation from an array.  This variant is not type
+     * checked which allows an application to fill in structured
+     * data from an array.
+     *
+     * @param d the source data array
+     */
+    public void copyFromUnchecked(byte[] d) {
+        mRS.validate();
+        copy1DRangeFromUnchecked(0, mType.getCount(), d);
+    }
+    /**
+     * Copy an allocation from an array.  This variant is not type
+     * checked which allows an application to fill in structured
+     * data from an array.
+     *
+     * @param d the source data array
+     */
+    public void copyFromUnchecked(float[] d) {
+        mRS.validate();
+        copy1DRangeFromUnchecked(0, mType.getCount(), d);
+    }
+
+    /**
+     * Copy an allocation from an array.  This variant is type
+     * checked and will generate exceptions if the Allocation type
+     * is not a 32 bit integer type.
+     *
+     * @param d the source data array
+     */
     public void copyFrom(int[] d) {
         mRS.validate();
         copy1DRangeFrom(0, mType.getCount(), d);
     }
+
+    /**
+     * Copy an allocation from an array.  This variant is type
+     * checked and will generate exceptions if the Allocation type
+     * is not a 16 bit integer type.
+     *
+     * @param d the source data array
+     */
     public void copyFrom(short[] d) {
         mRS.validate();
         copy1DRangeFrom(0, mType.getCount(), d);
     }
+
+    /**
+     * Copy an allocation from an array.  This variant is type
+     * checked and will generate exceptions if the Allocation type
+     * is not a 8 bit integer type.
+     *
+     * @param d the source data array
+     */
     public void copyFrom(byte[] d) {
         mRS.validate();
         copy1DRangeFrom(0, mType.getCount(), d);
     }
+
+    /**
+     * Copy an allocation from an array.  This variant is type
+     * checked and will generate exceptions if the Allocation type
+     * is not a 32 bit float type.
+     *
+     * @param d the source data array
+     */
     public void copyFrom(float[] d) {
         mRS.validate();
         copy1DRangeFrom(0, mType.getCount(), d);
     }
+
+    /**
+     * Copy an allocation from a bitmap.  The height, width, and
+     * format of the bitmap must match the existing allocation.
+     *
+     * @param b the source bitmap
+     */
     public void copyFrom(Bitmap b) {
         mRS.validate();
         validateBitmapSize(b);
@@ -369,39 +452,114 @@
         mRS.nAllocationGenerateMipmaps(getID());
     }
 
-    void copy1DRangeFromUnchecked(int off, int count, int[] d) {
+    /**
+     * Copy part of an allocation from an array.  This variant is
+     * not type checked which allows an application to fill in
+     * structured data from an array.
+     *
+     * @param off The offset of the first element to be copied.
+     * @param count The number of elements to be copied.
+     * @param d the source data array
+     */
+    public void copy1DRangeFromUnchecked(int off, int count, int[] d) {
         int dataSize = mType.mElement.getSizeBytes() * count;
         data1DChecks(off, count, d.length * 4, dataSize);
         mRS.nAllocationData1D(getID(), off, 0, count, d, dataSize);
     }
-    void copy1DRangeFromUnchecked(int off, int count, short[] d) {
+    /**
+     * Copy part of an allocation from an array.  This variant is
+     * not type checked which allows an application to fill in
+     * structured data from an array.
+     *
+     * @param off The offset of the first element to be copied.
+     * @param count The number of elements to be copied.
+     * @param d the source data array
+     */
+    public void copy1DRangeFromUnchecked(int off, int count, short[] d) {
         int dataSize = mType.mElement.getSizeBytes() * count;
         data1DChecks(off, count, d.length * 2, dataSize);
         mRS.nAllocationData1D(getID(), off, 0, count, d, dataSize);
     }
-    void copy1DRangeFromUnchecked(int off, int count, byte[] d) {
+    /**
+     * Copy part of an allocation from an array.  This variant is
+     * not type checked which allows an application to fill in
+     * structured data from an array.
+     *
+     * @param off The offset of the first element to be copied.
+     * @param count The number of elements to be copied.
+     * @param d the source data array
+     */
+    public void copy1DRangeFromUnchecked(int off, int count, byte[] d) {
         int dataSize = mType.mElement.getSizeBytes() * count;
         data1DChecks(off, count, d.length, dataSize);
         mRS.nAllocationData1D(getID(), off, 0, count, d, dataSize);
     }
-    void copy1DRangeFromUnchecked(int off, int count, float[] d) {
+    /**
+     * Copy part of an allocation from an array.  This variant is
+     * not type checked which allows an application to fill in
+     * structured data from an array.
+     *
+     * @param off The offset of the first element to be copied.
+     * @param count The number of elements to be copied.
+     * @param d the source data array
+     */
+    public void copy1DRangeFromUnchecked(int off, int count, float[] d) {
         int dataSize = mType.mElement.getSizeBytes() * count;
         data1DChecks(off, count, d.length * 4, dataSize);
         mRS.nAllocationData1D(getID(), off, 0, count, d, dataSize);
     }
 
+    /**
+     * Copy part of an allocation from an array.  This variant is
+     * type checked and will generate exceptions if the Allocation
+     * type is not a 32 bit integer type.
+     *
+     * @param off The offset of the first element to be copied.
+     * @param count The number of elements to be copied.
+     * @param d the source data array
+     */
     public void copy1DRangeFrom(int off, int count, int[] d) {
         validateIsInt32();
         copy1DRangeFromUnchecked(off, count, d);
     }
+
+    /**
+     * Copy part of an allocation from an array.  This variant is
+     * type checked and will generate exceptions if the Allocation
+     * type is not a 16 bit integer type.
+     *
+     * @param off The offset of the first element to be copied.
+     * @param count The number of elements to be copied.
+     * @param d the source data array
+     */
     public void copy1DRangeFrom(int off, int count, short[] d) {
         validateIsInt16();
         copy1DRangeFromUnchecked(off, count, d);
     }
+
+    /**
+     * Copy part of an allocation from an array.  This variant is
+     * type checked and will generate exceptions if the Allocation
+     * type is not a 8 bit integer type.
+     *
+     * @param off The offset of the first element to be copied.
+     * @param count The number of elements to be copied.
+     * @param d the source data array
+     */
     public void copy1DRangeFrom(int off, int count, byte[] d) {
         validateIsInt8();
         copy1DRangeFromUnchecked(off, count, d);
     }
+
+    /**
+     * Copy part of an allocation from an array.  This variant is
+     * type checked and will generate exceptions if the Allocation
+     * type is not a 32 bit float type.
+     *
+     * @param off The offset of the first element to be copied.
+     * @param count The number of elements to be copied.
+     * @param d the source data array
+     */
     public void copy1DRangeFrom(int off, int count, float[] d) {
         validateIsFloat32();
         copy1DRangeFromUnchecked(off, count, d);
diff --git a/graphics/java/android/renderscript/RenderScript.java b/graphics/java/android/renderscript/RenderScript.java
index 28b32d5..bb9fb78 100644
--- a/graphics/java/android/renderscript/RenderScript.java
+++ b/graphics/java/android/renderscript/RenderScript.java
@@ -101,414 +101,515 @@
     }
     native void rsnContextDestroy(int con);
     synchronized void nContextDestroy() {
+        validate();
         rsnContextDestroy(mContext);
     }
     native void rsnContextSetSurface(int con, int w, int h, Surface sur);
     synchronized void nContextSetSurface(int w, int h, Surface sur) {
+        validate();
         rsnContextSetSurface(mContext, w, h, sur);
     }
     native void rsnContextSetPriority(int con, int p);
     synchronized void nContextSetPriority(int p) {
+        validate();
         rsnContextSetPriority(mContext, p);
     }
     native void rsnContextDump(int con, int bits);
     synchronized void nContextDump(int bits) {
+        validate();
         rsnContextDump(mContext, bits);
     }
     native void rsnContextFinish(int con);
     synchronized void nContextFinish() {
+        validate();
         rsnContextFinish(mContext);
     }
 
     native void rsnContextBindRootScript(int con, int script);
     synchronized void nContextBindRootScript(int script) {
+        validate();
         rsnContextBindRootScript(mContext, script);
     }
     native void rsnContextBindSampler(int con, int sampler, int slot);
     synchronized void nContextBindSampler(int sampler, int slot) {
+        validate();
         rsnContextBindSampler(mContext, sampler, slot);
     }
     native void rsnContextBindProgramStore(int con, int pfs);
     synchronized void nContextBindProgramStore(int pfs) {
+        validate();
         rsnContextBindProgramStore(mContext, pfs);
     }
     native void rsnContextBindProgramFragment(int con, int pf);
     synchronized void nContextBindProgramFragment(int pf) {
+        validate();
         rsnContextBindProgramFragment(mContext, pf);
     }
     native void rsnContextBindProgramVertex(int con, int pv);
     synchronized void nContextBindProgramVertex(int pv) {
+        validate();
         rsnContextBindProgramVertex(mContext, pv);
     }
     native void rsnContextBindProgramRaster(int con, int pr);
     synchronized void nContextBindProgramRaster(int pr) {
+        validate();
         rsnContextBindProgramRaster(mContext, pr);
     }
     native void rsnContextPause(int con);
     synchronized void nContextPause() {
+        validate();
         rsnContextPause(mContext);
     }
     native void rsnContextResume(int con);
     synchronized void nContextResume() {
+        validate();
         rsnContextResume(mContext);
     }
 
     native void rsnAssignName(int con, int obj, byte[] name);
     synchronized void nAssignName(int obj, byte[] name) {
+        validate();
         rsnAssignName(mContext, obj, name);
     }
     native String rsnGetName(int con, int obj);
     synchronized String nGetName(int obj) {
+        validate();
         return rsnGetName(mContext, obj);
     }
     native void rsnObjDestroy(int con, int id);
     synchronized void nObjDestroy(int id) {
-        rsnObjDestroy(mContext, id);
+        // There is a race condition here.  The calling code may be run
+        // by the gc while teardown is occuring.  This protects againts
+        // deleting dead objects.
+        if (mContext != 0) {
+            rsnObjDestroy(mContext, id);
+        }
     }
 
     native int  rsnElementCreate(int con, int type, int kind, boolean norm, int vecSize);
     synchronized int nElementCreate(int type, int kind, boolean norm, int vecSize) {
+        validate();
         return rsnElementCreate(mContext, type, kind, norm, vecSize);
     }
     native int  rsnElementCreate2(int con, int[] elements, String[] names, int[] arraySizes);
     synchronized int nElementCreate2(int[] elements, String[] names, int[] arraySizes) {
+        validate();
         return rsnElementCreate2(mContext, elements, names, arraySizes);
     }
     native void rsnElementGetNativeData(int con, int id, int[] elementData);
     synchronized void nElementGetNativeData(int id, int[] elementData) {
+        validate();
         rsnElementGetNativeData(mContext, id, elementData);
     }
     native void rsnElementGetSubElements(int con, int id, int[] IDs, String[] names);
     synchronized void nElementGetSubElements(int id, int[] IDs, String[] names) {
+        validate();
         rsnElementGetSubElements(mContext, id, IDs, names);
     }
 
     native int rsnTypeCreate(int con, int eid, int x, int y, int z, boolean mips, boolean faces);
     synchronized int nTypeCreate(int eid, int x, int y, int z, boolean mips, boolean faces) {
+        validate();
         return rsnTypeCreate(mContext, eid, x, y, z, mips, faces);
     }
     native void rsnTypeGetNativeData(int con, int id, int[] typeData);
     synchronized void nTypeGetNativeData(int id, int[] typeData) {
+        validate();
         rsnTypeGetNativeData(mContext, id, typeData);
     }
 
     native int  rsnAllocationCreateTyped(int con, int type, int mip, int usage);
     synchronized int nAllocationCreateTyped(int type, int mip, int usage) {
+        validate();
         return rsnAllocationCreateTyped(mContext, type, mip, usage);
     }
     native int  rsnAllocationCreateFromBitmap(int con, int type, int mip, Bitmap bmp, int usage);
     synchronized int nAllocationCreateFromBitmap(int type, int mip, Bitmap bmp, int usage) {
+        validate();
         return rsnAllocationCreateFromBitmap(mContext, type, mip, bmp, usage);
     }
     native int  rsnAllocationCubeCreateFromBitmap(int con, int type, int mip, Bitmap bmp, int usage);
     synchronized int nAllocationCubeCreateFromBitmap(int type, int mip, Bitmap bmp, int usage) {
+        validate();
         return rsnAllocationCubeCreateFromBitmap(mContext, type, mip, bmp, usage);
     }
     native int  rsnAllocationCreateBitmapRef(int con, int type, Bitmap bmp);
     synchronized int nAllocationCreateBitmapRef(int type, Bitmap bmp) {
+        validate();
         return rsnAllocationCreateBitmapRef(mContext, type, bmp);
     }
     native int  rsnAllocationCreateFromAssetStream(int con, int mips, int assetStream, int usage);
     synchronized int nAllocationCreateFromAssetStream(int mips, int assetStream, int usage) {
+        validate();
         return rsnAllocationCreateFromAssetStream(mContext, mips, assetStream, usage);
     }
 
     native void  rsnAllocationCopyToBitmap(int con, int alloc, Bitmap bmp);
     synchronized void nAllocationCopyToBitmap(int alloc, Bitmap bmp) {
+        validate();
         rsnAllocationCopyToBitmap(mContext, alloc, bmp);
     }
 
 
     native void rsnAllocationSyncAll(int con, int alloc, int src);
     synchronized void nAllocationSyncAll(int alloc, int src) {
+        validate();
         rsnAllocationSyncAll(mContext, alloc, src);
     }
     native void rsnAllocationGenerateMipmaps(int con, int alloc);
     synchronized void nAllocationGenerateMipmaps(int alloc) {
+        validate();
         rsnAllocationGenerateMipmaps(mContext, alloc);
     }
     native void  rsnAllocationCopyFromBitmap(int con, int alloc, Bitmap bmp);
     synchronized void nAllocationCopyFromBitmap(int alloc, Bitmap bmp) {
+        validate();
         rsnAllocationCopyFromBitmap(mContext, alloc, bmp);
     }
 
 
     native void rsnAllocationData1D(int con, int id, int off, int mip, int count, int[] d, int sizeBytes);
     synchronized void nAllocationData1D(int id, int off, int mip, int count, int[] d, int sizeBytes) {
+        validate();
         rsnAllocationData1D(mContext, id, off, mip, count, d, sizeBytes);
     }
     native void rsnAllocationData1D(int con, int id, int off, int mip, int count, short[] d, int sizeBytes);
     synchronized void nAllocationData1D(int id, int off, int mip, int count, short[] d, int sizeBytes) {
+        validate();
         rsnAllocationData1D(mContext, id, off, mip, count, d, sizeBytes);
     }
     native void rsnAllocationData1D(int con, int id, int off, int mip, int count, byte[] d, int sizeBytes);
     synchronized void nAllocationData1D(int id, int off, int mip, int count, byte[] d, int sizeBytes) {
+        validate();
         rsnAllocationData1D(mContext, id, off, mip, count, d, sizeBytes);
     }
     native void rsnAllocationData1D(int con, int id, int off, int mip, int count, float[] d, int sizeBytes);
     synchronized void nAllocationData1D(int id, int off, int mip, int count, float[] d, int sizeBytes) {
+        validate();
         rsnAllocationData1D(mContext, id, off, mip, count, d, sizeBytes);
     }
 
     native void rsnAllocationElementData1D(int con, int id, int xoff, int mip, int compIdx, byte[] d, int sizeBytes);
     synchronized void nAllocationElementData1D(int id, int xoff, int mip, int compIdx, byte[] d, int sizeBytes) {
+        validate();
         rsnAllocationElementData1D(mContext, id, xoff, mip, compIdx, d, sizeBytes);
     }
 
     native void rsnAllocationData2D(int con, int id, int xoff, int yoff, int mip, int face, int w, int h, byte[] d, int sizeBytes);
     synchronized void nAllocationData2D(int id, int xoff, int yoff, int mip, int face, int w, int h, byte[] d, int sizeBytes) {
+        validate();
         rsnAllocationData2D(mContext, id, xoff, yoff, mip, face, w, h, d, sizeBytes);
     }
     native void rsnAllocationData2D(int con, int id, int xoff, int yoff, int mip, int face, int w, int h, short[] d, int sizeBytes);
     synchronized void nAllocationData2D(int id, int xoff, int yoff, int mip, int face, int w, int h, short[] d, int sizeBytes) {
+        validate();
         rsnAllocationData2D(mContext, id, xoff, yoff, mip, face, w, h, d, sizeBytes);
     }
     native void rsnAllocationData2D(int con, int id, int xoff, int yoff, int mip, int face, int w, int h, int[] d, int sizeBytes);
     synchronized void nAllocationData2D(int id, int xoff, int yoff, int mip, int face, int w, int h, int[] d, int sizeBytes) {
+        validate();
         rsnAllocationData2D(mContext, id, xoff, yoff, mip, face, w, h, d, sizeBytes);
     }
     native void rsnAllocationData2D(int con, int id, int xoff, int yoff, int mip, int face, int w, int h, float[] d, int sizeBytes);
     synchronized void nAllocationData2D(int id, int xoff, int yoff, int mip, int face, int w, int h, float[] d, int sizeBytes) {
+        validate();
         rsnAllocationData2D(mContext, id, xoff, yoff, mip, face, w, h, d, sizeBytes);
     }
     native void rsnAllocationData2D(int con, int id, int xoff, int yoff, int mip, int face, Bitmap b);
     synchronized void nAllocationData2D(int id, int xoff, int yoff, int mip, int face, Bitmap b) {
+        validate();
         rsnAllocationData2D(mContext, id, xoff, yoff, mip, face, b);
     }
 
     native void rsnAllocationRead(int con, int id, byte[] d);
     synchronized void nAllocationRead(int id, byte[] d) {
+        validate();
         rsnAllocationRead(mContext, id, d);
     }
     native void rsnAllocationRead(int con, int id, short[] d);
     synchronized void nAllocationRead(int id, short[] d) {
+        validate();
         rsnAllocationRead(mContext, id, d);
     }
     native void rsnAllocationRead(int con, int id, int[] d);
     synchronized void nAllocationRead(int id, int[] d) {
+        validate();
         rsnAllocationRead(mContext, id, d);
     }
     native void rsnAllocationRead(int con, int id, float[] d);
     synchronized void nAllocationRead(int id, float[] d) {
+        validate();
         rsnAllocationRead(mContext, id, d);
     }
     native int  rsnAllocationGetType(int con, int id);
     synchronized int nAllocationGetType(int id) {
+        validate();
         return rsnAllocationGetType(mContext, id);
     }
 
     native void rsnAllocationResize1D(int con, int id, int dimX);
     synchronized void nAllocationResize1D(int id, int dimX) {
+        validate();
         rsnAllocationResize1D(mContext, id, dimX);
     }
     native void rsnAllocationResize2D(int con, int id, int dimX, int dimY);
     synchronized void nAllocationResize2D(int id, int dimX, int dimY) {
+        validate();
         rsnAllocationResize2D(mContext, id, dimX, dimY);
     }
 
     native int  rsnFileA3DCreateFromAssetStream(int con, int assetStream);
     synchronized int nFileA3DCreateFromAssetStream(int assetStream) {
+        validate();
         return rsnFileA3DCreateFromAssetStream(mContext, assetStream);
     }
     native int  rsnFileA3DCreateFromFile(int con, String path);
     synchronized int nFileA3DCreateFromFile(String path) {
+        validate();
         return rsnFileA3DCreateFromFile(mContext, path);
     }
     native int  rsnFileA3DCreateFromAsset(int con, AssetManager mgr, String path);
     synchronized int nFileA3DCreateFromAsset(AssetManager mgr, String path) {
+        validate();
         return rsnFileA3DCreateFromAsset(mContext, mgr, path);
     }
     native int  rsnFileA3DGetNumIndexEntries(int con, int fileA3D);
     synchronized int nFileA3DGetNumIndexEntries(int fileA3D) {
+        validate();
         return rsnFileA3DGetNumIndexEntries(mContext, fileA3D);
     }
     native void rsnFileA3DGetIndexEntries(int con, int fileA3D, int numEntries, int[] IDs, String[] names);
     synchronized void nFileA3DGetIndexEntries(int fileA3D, int numEntries, int[] IDs, String[] names) {
+        validate();
         rsnFileA3DGetIndexEntries(mContext, fileA3D, numEntries, IDs, names);
     }
     native int  rsnFileA3DGetEntryByIndex(int con, int fileA3D, int index);
     synchronized int nFileA3DGetEntryByIndex(int fileA3D, int index) {
+        validate();
         return rsnFileA3DGetEntryByIndex(mContext, fileA3D, index);
     }
 
     native int  rsnFontCreateFromFile(int con, String fileName, float size, int dpi);
     synchronized int nFontCreateFromFile(String fileName, float size, int dpi) {
+        validate();
         return rsnFontCreateFromFile(mContext, fileName, size, dpi);
     }
     native int  rsnFontCreateFromAssetStream(int con, String name, float size, int dpi, int assetStream);
     synchronized int nFontCreateFromAssetStream(String name, float size, int dpi, int assetStream) {
+        validate();
         return rsnFontCreateFromAssetStream(mContext, name, size, dpi, assetStream);
     }
     native int  rsnFontCreateFromAsset(int con, AssetManager mgr, String path, float size, int dpi);
     synchronized int nFontCreateFromAsset(AssetManager mgr, String path, float size, int dpi) {
+        validate();
         return rsnFontCreateFromAsset(mContext, mgr, path, size, dpi);
     }
 
 
     native void rsnScriptBindAllocation(int con, int script, int alloc, int slot);
     synchronized void nScriptBindAllocation(int script, int alloc, int slot) {
+        validate();
         rsnScriptBindAllocation(mContext, script, alloc, slot);
     }
     native void rsnScriptSetTimeZone(int con, int script, byte[] timeZone);
     synchronized void nScriptSetTimeZone(int script, byte[] timeZone) {
+        validate();
         rsnScriptSetTimeZone(mContext, script, timeZone);
     }
     native void rsnScriptInvoke(int con, int id, int slot);
     synchronized void nScriptInvoke(int id, int slot) {
+        validate();
         rsnScriptInvoke(mContext, id, slot);
     }
     native void rsnScriptInvokeV(int con, int id, int slot, byte[] params);
     synchronized void nScriptInvokeV(int id, int slot, byte[] params) {
+        validate();
         rsnScriptInvokeV(mContext, id, slot, params);
     }
     native void rsnScriptSetVarI(int con, int id, int slot, int val);
     synchronized void nScriptSetVarI(int id, int slot, int val) {
+        validate();
         rsnScriptSetVarI(mContext, id, slot, val);
     }
     native void rsnScriptSetVarJ(int con, int id, int slot, long val);
     synchronized void nScriptSetVarJ(int id, int slot, long val) {
+        validate();
         rsnScriptSetVarJ(mContext, id, slot, val);
     }
     native void rsnScriptSetVarF(int con, int id, int slot, float val);
     synchronized void nScriptSetVarF(int id, int slot, float val) {
+        validate();
         rsnScriptSetVarF(mContext, id, slot, val);
     }
     native void rsnScriptSetVarD(int con, int id, int slot, double val);
     synchronized void nScriptSetVarD(int id, int slot, double val) {
+        validate();
         rsnScriptSetVarD(mContext, id, slot, val);
     }
     native void rsnScriptSetVarV(int con, int id, int slot, byte[] val);
     synchronized void nScriptSetVarV(int id, int slot, byte[] val) {
+        validate();
         rsnScriptSetVarV(mContext, id, slot, val);
     }
     native void rsnScriptSetVarObj(int con, int id, int slot, int val);
     synchronized void nScriptSetVarObj(int id, int slot, int val) {
+        validate();
         rsnScriptSetVarObj(mContext, id, slot, val);
     }
 
     native void rsnScriptCBegin(int con);
     synchronized void nScriptCBegin() {
+        validate();
         rsnScriptCBegin(mContext);
     }
     native void rsnScriptCSetScript(int con, byte[] script, int offset, int length);
     synchronized void nScriptCSetScript(byte[] script, int offset, int length) {
+        validate();
         rsnScriptCSetScript(mContext, script, offset, length);
     }
     native int  rsnScriptCCreate(int con, String packageName, String resName, String cacheDir);
     synchronized int nScriptCCreate(String packageName, String resName, String cacheDir) {
+        validate();
         return rsnScriptCCreate(mContext, packageName, resName, cacheDir);
     }
 
     native void rsnSamplerBegin(int con);
     synchronized void nSamplerBegin() {
+        validate();
         rsnSamplerBegin(mContext);
     }
     native void rsnSamplerSet(int con, int param, int value);
     synchronized void nSamplerSet(int param, int value) {
+        validate();
         rsnSamplerSet(mContext, param, value);
     }
     native void rsnSamplerSet2(int con, int param, float value);
     synchronized void nSamplerSet2(int param, float value) {
+        validate();
         rsnSamplerSet2(mContext, param, value);
     }
     native int  rsnSamplerCreate(int con);
     synchronized int nSamplerCreate() {
+        validate();
         return rsnSamplerCreate(mContext);
     }
 
     native void rsnProgramStoreBegin(int con, int in, int out);
     synchronized void nProgramStoreBegin(int in, int out) {
+        validate();
         rsnProgramStoreBegin(mContext, in, out);
     }
     native void rsnProgramStoreDepthFunc(int con, int func);
     synchronized void nProgramStoreDepthFunc(int func) {
+        validate();
         rsnProgramStoreDepthFunc(mContext, func);
     }
     native void rsnProgramStoreDepthMask(int con, boolean enable);
     synchronized void nProgramStoreDepthMask(boolean enable) {
+        validate();
         rsnProgramStoreDepthMask(mContext, enable);
     }
     native void rsnProgramStoreColorMask(int con, boolean r, boolean g, boolean b, boolean a);
     synchronized void nProgramStoreColorMask(boolean r, boolean g, boolean b, boolean a) {
+        validate();
         rsnProgramStoreColorMask(mContext, r, g, b, a);
     }
     native void rsnProgramStoreBlendFunc(int con, int src, int dst);
     synchronized void nProgramStoreBlendFunc(int src, int dst) {
+        validate();
         rsnProgramStoreBlendFunc(mContext, src, dst);
     }
     native void rsnProgramStoreDither(int con, boolean enable);
     synchronized void nProgramStoreDither(boolean enable) {
+        validate();
         rsnProgramStoreDither(mContext, enable);
     }
     native int  rsnProgramStoreCreate(int con);
     synchronized int nProgramStoreCreate() {
+        validate();
         return rsnProgramStoreCreate(mContext);
     }
 
     native int  rsnProgramRasterCreate(int con, boolean pointSmooth, boolean lineSmooth, boolean pointSprite);
     synchronized int nProgramRasterCreate(boolean pointSmooth, boolean lineSmooth, boolean pointSprite) {
+        validate();
         return rsnProgramRasterCreate(mContext, pointSmooth, lineSmooth, pointSprite);
     }
     native void rsnProgramRasterSetLineWidth(int con, int pr, float v);
     synchronized void nProgramRasterSetLineWidth(int pr, float v) {
+        validate();
         rsnProgramRasterSetLineWidth(mContext, pr, v);
     }
     native void rsnProgramRasterSetCullMode(int con, int pr, int mode);
     synchronized void nProgramRasterSetCullMode(int pr, int mode) {
+        validate();
         rsnProgramRasterSetCullMode(mContext, pr, mode);
     }
 
     native void rsnProgramBindConstants(int con, int pv, int slot, int mID);
     synchronized void nProgramBindConstants(int pv, int slot, int mID) {
+        validate();
         rsnProgramBindConstants(mContext, pv, slot, mID);
     }
     native void rsnProgramBindTexture(int con, int vpf, int slot, int a);
     synchronized void nProgramBindTexture(int vpf, int slot, int a) {
+        validate();
         rsnProgramBindTexture(mContext, vpf, slot, a);
     }
     native void rsnProgramBindSampler(int con, int vpf, int slot, int s);
     synchronized void nProgramBindSampler(int vpf, int slot, int s) {
+        validate();
         rsnProgramBindSampler(mContext, vpf, slot, s);
     }
     native int  rsnProgramFragmentCreate(int con, String shader, int[] params);
     synchronized int nProgramFragmentCreate(String shader, int[] params) {
+        validate();
         return rsnProgramFragmentCreate(mContext, shader, params);
     }
     native int  rsnProgramVertexCreate(int con, String shader, int[] params);
     synchronized int nProgramVertexCreate(String shader, int[] params) {
+        validate();
         return rsnProgramVertexCreate(mContext, shader, params);
     }
 
     native int  rsnMeshCreate(int con, int vtxCount, int indexCount);
     synchronized int nMeshCreate(int vtxCount, int indexCount) {
+        validate();
         return rsnMeshCreate(mContext, vtxCount, indexCount);
     }
     native void rsnMeshBindVertex(int con, int id, int alloc, int slot);
     synchronized void nMeshBindVertex(int id, int alloc, int slot) {
+        validate();
         rsnMeshBindVertex(mContext, id, alloc, slot);
     }
     native void rsnMeshBindIndex(int con, int id, int alloc, int prim, int slot);
     synchronized void nMeshBindIndex(int id, int alloc, int prim, int slot) {
+        validate();
         rsnMeshBindIndex(mContext, id, alloc, prim, slot);
     }
     native void rsnMeshInitVertexAttribs(int con, int id);
     synchronized void nMeshInitVertexAttribs(int id) {
+        validate();
         rsnMeshInitVertexAttribs(mContext, id);
     }
     native int  rsnMeshGetVertexBufferCount(int con, int id);
     synchronized int nMeshGetVertexBufferCount(int id) {
+        validate();
         return rsnMeshGetVertexBufferCount(mContext, id);
     }
     native int  rsnMeshGetIndexCount(int con, int id);
     synchronized int nMeshGetIndexCount(int id) {
+        validate();
         return rsnMeshGetIndexCount(mContext, id);
     }
     native void rsnMeshGetVertices(int con, int id, int[] vtxIds, int vtxIdCount);
     synchronized void nMeshGetVertices(int id, int[] vtxIds, int vtxIdCount) {
+        validate();
         rsnMeshGetVertices(mContext, id, vtxIds, vtxIdCount);
     }
     native void rsnMeshGetIndices(int con, int id, int[] idxIds, int[] primitives, int vtxIdCount);
     synchronized void nMeshGetIndices(int id, int[] idxIds, int[] primitives, int vtxIdCount) {
+        validate();
         rsnMeshGetIndices(mContext, id, idxIds, primitives, vtxIdCount);
     }
 
diff --git a/graphics/java/android/renderscript/ScriptC.java b/graphics/java/android/renderscript/ScriptC.java
index ff8f093..9445283 100644
--- a/graphics/java/android/renderscript/ScriptC.java
+++ b/graphics/java/android/renderscript/ScriptC.java
@@ -56,6 +56,9 @@
     protected ScriptC(RenderScript rs, Resources resources, int resourceID) {
         super(0, rs);
         int id = internalCreate(rs, resources, resourceID);
+        if (id == 0) {
+            throw new RSRuntimeException("Loading of ScriptC script failed.");
+        }
         setID(id);
     }
 
diff --git a/graphics/jni/android_renderscript_RenderScript.cpp b/graphics/jni/android_renderscript_RenderScript.cpp
index 35db786..f86343a 100644
--- a/graphics/jni/android_renderscript_RenderScript.cpp
+++ b/graphics/jni/android_renderscript_RenderScript.cpp
@@ -991,7 +991,7 @@
     jint *paramPtr = _env->GetIntArrayElements(params, NULL);
     jint paramLen = _env->GetArrayLength(params);
 
-    LOG_API("nProgramFragmentCreate, con(%p), shaderLen(%i), paramLen(%i)", con, shaderLen, paramLen);
+    LOG_API("nProgramFragmentCreate, con(%p), paramLen(%i)", con, paramLen);
 
     jint ret = (jint)rsProgramFragmentCreate(con, shaderUTF.c_str(), shaderUTF.length(), (uint32_t *)paramPtr, paramLen);
     _env->ReleaseIntArrayElements(params, paramPtr, JNI_ABORT);
@@ -1008,7 +1008,7 @@
     jint *paramPtr = _env->GetIntArrayElements(params, NULL);
     jint paramLen = _env->GetArrayLength(params);
 
-    LOG_API("nProgramVertexCreate, con(%p), shaderLen(%i), paramLen(%i)", con, shaderLen, paramLen);
+    LOG_API("nProgramVertexCreate, con(%p), paramLen(%i)", con, paramLen);
 
     jint ret = (jint)rsProgramVertexCreate(con, shaderUTF.c_str(), shaderUTF.length(), (uint32_t *)paramPtr, paramLen);
     _env->ReleaseIntArrayElements(params, paramPtr, JNI_ABORT);
diff --git a/include/media/stagefright/MetaData.h b/include/media/stagefright/MetaData.h
index 5170a2c..18fd90e 100644
--- a/include/media/stagefright/MetaData.h
+++ b/include/media/stagefright/MetaData.h
@@ -30,8 +30,10 @@
 // The following keys map to int32_t data unless indicated otherwise.
 enum {
     kKeyMIMEType          = 'mime',  // cstring
-    kKeyWidth             = 'widt',  // int32_t
-    kKeyHeight            = 'heig',  // int32_t
+    kKeyWidth             = 'widt',  // int32_t, image pixel
+    kKeyHeight            = 'heig',  // int32_t, image pixel
+    kKeyDisplayWidth      = 'dWid',  // int32_t, display/presentation
+    kKeyDisplayHeight     = 'dHgt',  // int32_t, display/presentation
 
     // a rectangle, if absent assumed to be (0, 0, width - 1, height - 1)
     kKeyCropRect          = 'crop',
diff --git a/libs/hwui/FontRenderer.cpp b/libs/hwui/FontRenderer.cpp
index c080501..c43e40d 100644
--- a/libs/hwui/FontRenderer.cpp
+++ b/libs/hwui/FontRenderer.cpp
@@ -298,8 +298,10 @@
 // FontRenderer
 ///////////////////////////////////////////////////////////////////////////////
 
+static bool sLogFontRendererCreate = true;
+
 FontRenderer::FontRenderer() {
-    LOGD("Creating FontRenderer");
+    if (sLogFontRendererCreate) LOGD("Creating FontRenderer");
 
     mGammaTable = NULL;
     mInitialized = false;
@@ -317,18 +319,24 @@
 
     char property[PROPERTY_VALUE_MAX];
     if (property_get(PROPERTY_TEXT_CACHE_WIDTH, property, NULL) > 0) {
-        LOGD("  Setting text cache width to %s pixels", property);
+        if (sLogFontRendererCreate) LOGD("  Setting text cache width to %s pixels", property);
         mCacheWidth = atoi(property);
     } else {
-        LOGD("  Using default text cache width of %i pixels", mCacheWidth);
+        if (sLogFontRendererCreate) {
+            LOGD("  Using default text cache width of %i pixels", mCacheWidth);
+        }
     }
 
     if (property_get(PROPERTY_TEXT_CACHE_HEIGHT, property, NULL) > 0) {
-        LOGD("  Setting text cache width to %s pixels", property);
+        if (sLogFontRendererCreate) LOGD("  Setting text cache width to %s pixels", property);
         mCacheHeight = atoi(property);
     } else {
-        LOGD("  Using default text cache height of %i pixels", mCacheHeight);
+        if (sLogFontRendererCreate) {
+            LOGD("  Using default text cache height of %i pixels", mCacheHeight);
+        }
     }
+
+    sLogFontRendererCreate = false;
 }
 
 FontRenderer::~FontRenderer() {
diff --git a/libs/hwui/LayerRenderer.cpp b/libs/hwui/LayerRenderer.cpp
index e6bea78..a167429 100644
--- a/libs/hwui/LayerRenderer.cpp
+++ b/libs/hwui/LayerRenderer.cpp
@@ -29,7 +29,6 @@
 void LayerRenderer::prepare(bool opaque) {
     LAYER_RENDERER_LOGD("Rendering into layer, fbo = %d", mLayer->fbo);
 
-    glGetIntegerv(GL_FRAMEBUFFER_BINDING, (GLint*) &mPreviousFbo);
     glBindFramebuffer(GL_FRAMEBUFFER, mLayer->fbo);
 
     OpenGLRenderer::prepare(opaque);
@@ -37,11 +36,17 @@
 
 void LayerRenderer::finish() {
     OpenGLRenderer::finish();
-    glBindFramebuffer(GL_FRAMEBUFFER, mPreviousFbo);
 
     generateMesh();
 
     LAYER_RENDERER_LOGD("Finished rendering into layer, fbo = %d", mLayer->mFbo);
+
+    // No need to unbind our FBO, this will be taken care of by the caller
+    // who will invoke OpenGLRenderer::resume()
+}
+
+GLint LayerRenderer::getTargetFbo() {
+    return mLayer->fbo;
 }
 
 ///////////////////////////////////////////////////////////////////////////////
diff --git a/libs/hwui/LayerRenderer.h b/libs/hwui/LayerRenderer.h
index f2fb898..1e39847 100644
--- a/libs/hwui/LayerRenderer.h
+++ b/libs/hwui/LayerRenderer.h
@@ -51,6 +51,7 @@
 
     bool hasLayer();
     Region* getRegion();
+    GLint getTargetFbo();
 
     static Layer* createLayer(uint32_t width, uint32_t height, bool isOpaque = false);
     static bool resizeLayer(Layer* layer, uint32_t width, uint32_t height);
@@ -61,8 +62,6 @@
     void generateMesh();
 
     Layer* mLayer;
-    GLuint mPreviousFbo;
-
 }; // class LayerRenderer
 
 }; // namespace uirenderer
diff --git a/libs/hwui/OpenGLRenderer.cpp b/libs/hwui/OpenGLRenderer.cpp
index 2067acc1..6477eb0 100644
--- a/libs/hwui/OpenGLRenderer.cpp
+++ b/libs/hwui/OpenGLRenderer.cpp
@@ -200,7 +200,7 @@
 
     glDisable(GL_DITHER);
 
-    glBindFramebuffer(GL_FRAMEBUFFER, 0);
+    glBindFramebuffer(GL_FRAMEBUFFER, getTargetFbo());
     glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
 
     mCaches.blend = true;
@@ -430,18 +430,18 @@
     } else {
         // Copy the framebuffer into the layer
         glBindTexture(GL_TEXTURE_2D, layer->texture);
-
-        if (layer->empty) {
-            glCopyTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, bounds.left,
-                    snapshot->height - bounds.bottom, layer->width, layer->height, 0);
-            layer->empty = false;
-        } else {
-            glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, bounds.left,
-                    snapshot->height - bounds.bottom, bounds.getWidth(), bounds.getHeight());
+        if (!bounds.isEmpty()) {
+            if (layer->empty) {
+                glCopyTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, bounds.left,
+                        snapshot->height - bounds.bottom, layer->width, layer->height, 0);
+                layer->empty = false;
+            } else {
+                glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, bounds.left,
+                        snapshot->height - bounds.bottom, bounds.getWidth(), bounds.getHeight());
+            }
+            // Enqueue the buffer coordinates to clear the corresponding region later
+            mLayers.push(new Rect(bounds));
         }
-
-        // Enqueue the buffer coordinates to clear the corresponding region later
-        mLayers.push(new Rect(bounds));
     }
 
     return true;
@@ -565,8 +565,10 @@
             resetColorFilter();
         }
     } else {
-        dirtyLayer(rect.left, rect.top, rect.right, rect.bottom);
-        composeLayerRect(layer, rect, true);
+        if (!rect.isEmpty()) {
+            dirtyLayer(rect.left, rect.top, rect.right, rect.bottom);
+            composeLayerRect(layer, rect, true);
+        }
     }
 
     if (fboLayer) {
diff --git a/libs/hwui/OpenGLRenderer.h b/libs/hwui/OpenGLRenderer.h
index 272c5c2..4150ddc 100644
--- a/libs/hwui/OpenGLRenderer.h
+++ b/libs/hwui/OpenGLRenderer.h
@@ -145,14 +145,27 @@
         return mSnapshot;
     }
 
+    /**
+     * Returns the region of the current layer.
+     */
     virtual Region* getRegion() {
         return mSnapshot->region;
     }
 
+    /**
+     * Indicates whether rendering is currently targeted at a layer.
+     */
     virtual bool hasLayer() {
         return (mSnapshot->flags & Snapshot::kFlagFboTarget) && mSnapshot->region;
     }
 
+    /**
+     * Returns the name of the FBO this renderer is rendering into.
+     */
+    virtual GLint getTargetFbo() {
+        return 0;
+    }
+
 private:
     /**
      * Saves the current state of the renderer as a new snapshot.
diff --git a/libs/hwui/Patch.cpp b/libs/hwui/Patch.cpp
index 3f0036a..11eb953 100644
--- a/libs/hwui/Patch.cpp
+++ b/libs/hwui/Patch.cpp
@@ -177,8 +177,10 @@
         previousStepY = stepY;
     }
 
-    generateRow(vertex, y1, bottom - top, v1, 1.0f, stretchX, right - left,
-            bitmapWidth, quadCount);
+    if (previousStepY != bitmapHeight) {
+        generateRow(vertex, y1, bottom - top, v1, 1.0f, stretchX, right - left,
+                bitmapWidth, quadCount);
+    }
 
     if (verticesCount > 0) {
         Caches::getInstance().bindMeshBuffer(meshBuffer);
@@ -225,7 +227,9 @@
         previousStepX = stepX;
     }
 
-    generateQuad(vertex, x1, y1, width, y2, u1, v1, 1.0f, v2, quadCount);
+    if (previousStepX != bitmapWidth) {
+        generateQuad(vertex, x1, y1, width, y2, u1, v1, 1.0f, v2, quadCount);
+    }
 }
 
 void Patch::generateQuad(TextureVertex*& vertex, float x1, float y1, float x2, float y2,
diff --git a/libs/rs/java/tests/src/com/android/rs/test/RSTestCore.java b/libs/rs/java/tests/src/com/android/rs/test/RSTestCore.java
index fc3a065..541bf22 100644
--- a/libs/rs/java/tests/src/com/android/rs/test/RSTestCore.java
+++ b/libs/rs/java/tests/src/com/android/rs/test/RSTestCore.java
@@ -68,6 +68,7 @@
         unitTests.add(new UT_rsdebug(this, mRes, mCtx));
         unitTests.add(new UT_rstime(this, mRes, mCtx));
         unitTests.add(new UT_rstypes(this, mRes, mCtx));
+        unitTests.add(new UT_math(this, mRes, mCtx));
         unitTests.add(new UT_fp_mad(this, mRes, mCtx));
         /*
         unitTests.add(new UnitTest(null, "<Pass>", 1));
diff --git a/libs/rs/java/tests/src/com/android/rs/test/UT_math.java b/libs/rs/java/tests/src/com/android/rs/test/UT_math.java
new file mode 100644
index 0000000..bf133be
--- /dev/null
+++ b/libs/rs/java/tests/src/com/android/rs/test/UT_math.java
@@ -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.
+ */
+
+package com.android.rs.test;
+
+import android.content.Context;
+import android.content.res.Resources;
+import android.renderscript.*;
+
+public class UT_math extends UnitTest {
+    private Resources mRes;
+
+    protected UT_math(RSTestCore rstc, Resources res, Context ctx) {
+        super(rstc, "Math", ctx);
+        mRes = res;
+    }
+
+    public void run() {
+        RenderScript pRS = RenderScript.create(mCtx);
+        ScriptC_math s = new ScriptC_math(pRS, mRes, R.raw.math);
+        pRS.setMessageHandler(mRsMessage);
+        s.invoke_math_test(0, 0);
+        pRS.finish();
+        waitForMessage();
+        pRS.destroy();
+    }
+}
diff --git a/libs/rs/java/tests/src/com/android/rs/test/fp_mad.rs b/libs/rs/java/tests/src/com/android/rs/test/fp_mad.rs
index 4133fda..b02f85d 100644
--- a/libs/rs/java/tests/src/com/android/rs/test/fp_mad.rs
+++ b/libs/rs/java/tests/src/com/android/rs/test/fp_mad.rs
@@ -102,7 +102,8 @@
     start();
 
     // Do ~100 M ops
-    for (int ct=0; ct < 1000 * 100; ct++) {
+    int ct;
+    for (ct=0; ct < 1000 * 100; ct++) {
         for (int i=0; i < (1000); i++) {
             data_f1[i] = clamp(data_f1[i], -1.f, 1.f);
         }
@@ -129,7 +130,8 @@
 
     float total = 0;
     // Do ~100 M ops
-    for (int ct=0; ct < 1000 * 100 /4; ct++) {
+    int ct;
+    for (ct=0; ct < 1000 * 100 /4; ct++) {
         for (int i=0; i < (1000); i++) {
             data_f4[i] = clamp(data_f4[i], -1.f, 1.f);
         }
@@ -140,7 +142,8 @@
 }
 
 void fp_mad_test(uint32_t index, int test_num) {
-    for (int x=0; x < 1025; x++) {
+    int x;
+    for (x=0; x < 1025; x++) {
         data_f1[x] = (x & 0xf) * 0.1f;
         data_f4[x].x = (x & 0xf) * 0.1f;
         data_f4[x].y = (x & 0xf0) * 0.1f;
diff --git a/libs/rs/java/tests/src/com/android/rs/test/math.rs b/libs/rs/java/tests/src/com/android/rs/test/math.rs
new file mode 100644
index 0000000..5b1ad15
--- /dev/null
+++ b/libs/rs/java/tests/src/com/android/rs/test/math.rs
@@ -0,0 +1,65 @@
+#include "shared.rsh"
+
+// Testing math library
+
+volatile float f1;
+volatile float2 f2;
+volatile float3 f3;
+volatile float4 f4;
+
+#define TEST_F(fnc, var)            \
+    rsDebug("Testing " #fnc, 0);    \
+    var##1 = fnc(var##1);           \
+    var##2 = fnc(var##2);           \
+    var##3 = fnc(var##3);           \
+    var##4 = fnc(var##4);
+
+#define TEST_FP(fnc, var)           \
+    rsDebug("Testing " #fnc, 0);    \
+    var##1 = fnc(var##1, (float*) &f1);  \
+    var##2 = fnc(var##2, (float2*) &f2);  \
+    var##3 = fnc(var##3, (float3*) &f3);  \
+    var##4 = fnc(var##4, (float4*) &f4);
+
+#define TEST_F2(fnc, var)           \
+    rsDebug("Testing " #fnc, 0);    \
+    var##1 = fnc(var##1, var##1);   \
+    var##2 = fnc(var##2, var##2);   \
+    var##3 = fnc(var##3, var##3);   \
+    var##4 = fnc(var##4, var##4);
+
+static bool test_math(uint32_t index) {
+    bool failed = false;
+    start();
+
+    TEST_F(cos, f);
+    TEST_FP(modf, f);
+    TEST_F2(pow, f);
+    TEST_F(sin, f);
+    TEST_F(sqrt, f);
+
+
+    float time = end(index);
+
+    if (failed) {
+        rsDebug("test_math FAILED", time);
+    }
+    else {
+        rsDebug("test_math PASSED", time);
+    }
+
+    return failed;
+}
+
+void math_test(uint32_t index, int test_num) {
+    bool failed = false;
+    failed |= test_math(index);
+
+    if (failed) {
+        rsSendToClientBlocking(RS_MSG_TEST_FAILED);
+    }
+    else {
+        rsSendToClientBlocking(RS_MSG_TEST_PASSED);
+    }
+}
+
diff --git a/libs/rs/rsContext.cpp b/libs/rs/rsContext.cpp
index 2e0c491..98f30ae 100644
--- a/libs/rs/rsContext.cpp
+++ b/libs/rs/rsContext.cpp
@@ -253,7 +253,11 @@
     LOGV("%p, deinitEGL", this);
 
     if (mEGL.mContext != EGL_NO_CONTEXT) {
-        eglMakeCurrent(mEGL.mDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, mEGL.mContext);
+        eglMakeCurrent(mEGL.mDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
+        eglDestroySurface(mEGL.mDisplay, mEGL.mSurfaceDefault);
+        if (mEGL.mSurface != EGL_NO_SURFACE) {
+            eglDestroySurface(mEGL.mDisplay, mEGL.mSurface);
+        }
         eglDestroyContext(mEGL.mDisplay, mEGL.mContext);
         checkEglError("eglDestroyContext");
     }
diff --git a/libs/rs/rsLocklessFifo.cpp b/libs/rs/rsLocklessFifo.cpp
index 804c767..eb2af1c 100644
--- a/libs/rs/rsLocklessFifo.cpp
+++ b/libs/rs/rsLocklessFifo.cpp
@@ -210,3 +210,19 @@
 void LocklessCommandFifo::dumpState(const char *s) const {
     LOGV("%s %p  put %p, get %p,  buf %p,  end %p", s, this, mPut, mGet, mBuffer, mEnd);
 }
+
+void LocklessCommandFifo::printDebugData() const {
+    dumpState("printing fifo debug");
+    const uint32_t *pptr = (const uint32_t *)mGet;
+    pptr -= 8 * 4;
+    if (mGet < mBuffer) {
+        pptr = (const uint32_t *)mBuffer;
+    }
+
+
+    for (int ct=0; ct < 16; ct++) {
+        LOGV("fifo %p = 0x%08x  0x%08x  0x%08x  0x%08x", pptr, pptr[0], pptr[1], pptr[2], pptr[3]);
+        pptr += 4;
+    }
+
+}
diff --git a/libs/rs/rsLocklessFifo.h b/libs/rs/rsLocklessFifo.h
index c963963..eabdc3e 100644
--- a/libs/rs/rsLocklessFifo.h
+++ b/libs/rs/rsLocklessFifo.h
@@ -35,6 +35,8 @@
     bool init(uint32_t size);
     void shutdown();
 
+    void printDebugData() const;
+
     LocklessCommandFifo();
     ~LocklessCommandFifo();
 
diff --git a/libs/rs/rsScriptC.cpp b/libs/rs/rsScriptC.cpp
index 9f730bf..1fceb66 100644
--- a/libs/rs/rsScriptC.cpp
+++ b/libs/rs/rsScriptC.cpp
@@ -467,7 +467,7 @@
 extern unsigned rs_runtime_lib_bc_size;
 #endif
 
-void ScriptCState::runCompiler(Context *rsc,
+bool ScriptCState::runCompiler(Context *rsc,
                                ScriptC *s,
                                const char *resName,
                                const char *cacheDir) {
@@ -482,7 +482,7 @@
                   s->mEnviroment.mScriptText,
                   s->mEnviroment.mScriptTextLength, 0) != 0) {
         LOGE("bcc: FAILS to read bitcode");
-        // Handle Fatal Error
+        return false;
     }
 
 #if 1
@@ -493,14 +493,14 @@
                     /*"1" means skip buffer here, and let libbcc decide*/,
                   0) != 0) {
         LOGE("bcc: FAILS to link bitcode");
-        // Handle Fatal Error
+        return false;
     }
 #endif
     char *cachePath = genCacheFileName(cacheDir, resName, ".oBCC");
 
     if (bccPrepareExecutable(s->mBccScript, cachePath, 0) != 0) {
         LOGE("bcc: FAILS to prepare executable");
-        // Handle Fatal Error
+        return false;
     }
 
     free(cachePath);
@@ -547,7 +547,7 @@
                 continue;
             }
             LOGE("Invalid version pragma value: %s\n", values[i]);
-            // Handle Fatal Error
+            return false;
         }
 
         if (!strcmp(keys[i], "stateVertex")) {
@@ -559,7 +559,7 @@
                 continue;
             }
             LOGE("Unrecognized value %s passed to stateVertex", values[i]);
-            // Handle Fatal Error
+            return false;
         }
 
         if (!strcmp(keys[i], "stateRaster")) {
@@ -571,7 +571,7 @@
                 continue;
             }
             LOGE("Unrecognized value %s passed to stateRaster", values[i]);
-            // Handle Fatal Error
+            return false;
         }
 
         if (!strcmp(keys[i], "stateFragment")) {
@@ -583,7 +583,7 @@
                 continue;
             }
             LOGE("Unrecognized value %s passed to stateFragment", values[i]);
-            // Handle Fatal Error
+            return false;
         }
 
         if (!strcmp(keys[i], "stateStore")) {
@@ -595,9 +595,10 @@
                 continue;
             }
             LOGE("Unrecognized value %s passed to stateStore", values[i]);
-            // Handle Fatal Error
+            return false;
         }
     }
+    return true;
 }
 
 namespace android {
@@ -630,7 +631,11 @@
     ss->mScript.clear();
     s->incUserRef();
 
-    ss->runCompiler(rsc, s.get(), resName, cacheDir);
+    if (!ss->runCompiler(rsc, s.get(), resName, cacheDir)) {
+        // Error during compile, destroy s and return null.
+        s->zeroUserRef();
+        return NULL;
+    }
     ss->clear(rsc);
     return s.get();
 }
diff --git a/libs/rs/rsScriptC.h b/libs/rs/rsScriptC.h
index 483481e8..612e38a 100644
--- a/libs/rs/rsScriptC.h
+++ b/libs/rs/rsScriptC.h
@@ -81,7 +81,7 @@
     void init(Context *rsc);
 
     void clear(Context *rsc);
-    void runCompiler(Context *rsc, ScriptC *s, const char *resName, const char *cacheDir);
+    bool runCompiler(Context *rsc, ScriptC *s, const char *resName, const char *cacheDir);
 
     struct SymbolTable_t {
         const char * mName;
diff --git a/libs/rs/rsScriptC_Lib.cpp b/libs/rs/rsScriptC_Lib.cpp
index 0b21669..f550d98 100644
--- a/libs/rs/rsScriptC_Lib.cpp
+++ b/libs/rs/rsScriptC_Lib.cpp
@@ -226,51 +226,51 @@
 }
 
 static void SC_debugF(const char *s, float f) {
-    LOGE("%s %f, 0x%08x", s, f, *((int *) (&f)));
+    LOGD("%s %f, 0x%08x", s, f, *((int *) (&f)));
 }
 static void SC_debugFv2(const char *s, float f1, float f2) {
-    LOGE("%s {%f, %f}", s, f1, f2);
+    LOGD("%s {%f, %f}", s, f1, f2);
 }
 static void SC_debugFv3(const char *s, float f1, float f2, float f3) {
-    LOGE("%s {%f, %f, %f}", s, f1, f2, f3);
+    LOGD("%s {%f, %f, %f}", s, f1, f2, f3);
 }
 static void SC_debugFv4(const char *s, float f1, float f2, float f3, float f4) {
-    LOGE("%s {%f, %f, %f, %f}", s, f1, f2, f3, f4);
+    LOGD("%s {%f, %f, %f, %f}", s, f1, f2, f3, f4);
 }
 static void SC_debugD(const char *s, double d) {
-    LOGE("%s %f, 0x%08llx", s, d, *((long long *) (&d)));
+    LOGD("%s %f, 0x%08llx", s, d, *((long long *) (&d)));
 }
 static void SC_debugFM4v4(const char *s, const float *f) {
-    LOGE("%s {%f, %f, %f, %f", s, f[0], f[4], f[8], f[12]);
-    LOGE("%s  %f, %f, %f, %f", s, f[1], f[5], f[9], f[13]);
-    LOGE("%s  %f, %f, %f, %f", s, f[2], f[6], f[10], f[14]);
-    LOGE("%s  %f, %f, %f, %f}", s, f[3], f[7], f[11], f[15]);
+    LOGD("%s {%f, %f, %f, %f", s, f[0], f[4], f[8], f[12]);
+    LOGD("%s  %f, %f, %f, %f", s, f[1], f[5], f[9], f[13]);
+    LOGD("%s  %f, %f, %f, %f", s, f[2], f[6], f[10], f[14]);
+    LOGD("%s  %f, %f, %f, %f}", s, f[3], f[7], f[11], f[15]);
 }
 static void SC_debugFM3v3(const char *s, const float *f) {
-    LOGE("%s {%f, %f, %f", s, f[0], f[3], f[6]);
-    LOGE("%s  %f, %f, %f", s, f[1], f[4], f[7]);
-    LOGE("%s  %f, %f, %f}",s, f[2], f[5], f[8]);
+    LOGD("%s {%f, %f, %f", s, f[0], f[3], f[6]);
+    LOGD("%s  %f, %f, %f", s, f[1], f[4], f[7]);
+    LOGD("%s  %f, %f, %f}",s, f[2], f[5], f[8]);
 }
 static void SC_debugFM2v2(const char *s, const float *f) {
-    LOGE("%s {%f, %f", s, f[0], f[2]);
-    LOGE("%s  %f, %f}",s, f[1], f[3]);
+    LOGD("%s {%f, %f", s, f[0], f[2]);
+    LOGD("%s  %f, %f}",s, f[1], f[3]);
 }
 
 static void SC_debugI32(const char *s, int32_t i) {
-    LOGE("%s %i  0x%x", s, i, i);
+    LOGD("%s %i  0x%x", s, i, i);
 }
 static void SC_debugU32(const char *s, uint32_t i) {
-    LOGE("%s %u  0x%x", s, i, i);
+    LOGD("%s %u  0x%x", s, i, i);
 }
 static void SC_debugLL64(const char *s, long long ll) {
-    LOGE("%s %lld  0x%llx", s, ll, ll);
+    LOGD("%s %lld  0x%llx", s, ll, ll);
 }
 static void SC_debugULL64(const char *s, unsigned long long ll) {
-    LOGE("%s %llu  0x%llx", s, ll, ll);
+    LOGD("%s %llu  0x%llx", s, ll, ll);
 }
 
 static void SC_debugP(const char *s, const void *p) {
-    LOGE("%s %p", s, p);
+    LOGD("%s %p", s, p);
 }
 
 static uint32_t SC_toClient2(int cmdID, void *data, int len) {
diff --git a/libs/rs/rsScriptC_LibCL.cpp b/libs/rs/rsScriptC_LibCL.cpp
index 6c0e164..28c558d 100644
--- a/libs/rs/rsScriptC_LibCL.cpp
+++ b/libs/rs/rsScriptC_LibCL.cpp
@@ -221,7 +221,7 @@
     { "_Z5log1pf", (void *)&log1pf, true },
     //{ "logb", (void *)&, true },
     //{ "mad", (void *)&, true },
-    { "modf", (void *)&modff, true },
+    { "_Z4modffPf", (void *)&modff, true },
     //{ "nan", (void *)&, true },
     { "_Z9nextafterff", (void *)&nextafterf, true },
     { "_Z3powff", (void *)&powf, true },
diff --git a/libs/rs/rsThreadIO.cpp b/libs/rs/rsThreadIO.cpp
index 001ac55..6cf07de7 100644
--- a/libs/rs/rsThreadIO.cpp
+++ b/libs/rs/rsThreadIO.cpp
@@ -56,6 +56,7 @@
         if (cmdID >= (sizeof(gPlaybackFuncs) / sizeof(void *))) {
             rsAssert(cmdID < (sizeof(gPlaybackFuncs) / sizeof(void *)));
             LOGE("playCoreCommands error con %p, cmd %i", con, cmdID);
+            mToCore.printDebugData();
         }
         gPlaybackFuncs[cmdID](con, data);
         mToCore.next();
diff --git a/libs/rs/scriptc/rs_cl.rsh b/libs/rs/scriptc/rs_cl.rsh
index b9bb1f7..ab8270f40 100644
--- a/libs/rs/scriptc/rs_cl.rsh
+++ b/libs/rs/scriptc/rs_cl.rsh
@@ -1,20 +1,23 @@
 #ifndef __RS_CL_RSH__
 #define __RS_CL_RSH__
 
-#define M_PI        3.14159265358979323846264338327950288f   /* pi */
-
+#ifdef BCC_PREPARE_BC
+#define _RS_STATIC  extern
+#else
+#define _RS_STATIC  static
+#endif
 
 // Conversions
 #define CVT_FUNC_2(typeout, typein) \
-static typeout##2 __attribute__((overloadable)) convert_##typeout##2(typein##2 v) { \
+_RS_STATIC typeout##2 __attribute__((overloadable)) convert_##typeout##2(typein##2 v) { \
     typeout##2 r = {(typeout)v.x, (typeout)v.y}; \
     return r; \
 } \
-static typeout##3 __attribute__((overloadable)) convert_##typeout##3(typein##3 v) { \
+_RS_STATIC typeout##3 __attribute__((overloadable)) convert_##typeout##3(typein##3 v) { \
     typeout##3 r = {(typeout)v.x, (typeout)v.y, (typeout)v.z}; \
     return r; \
 } \
-static typeout##4 __attribute__((overloadable)) convert_##typeout##4(typein##4 v) { \
+_RS_STATIC typeout##4 __attribute__((overloadable)) convert_##typeout##4(typein##4 v) { \
     typeout##4 r = {(typeout)v.x, (typeout)v.y, (typeout)v.z, (typeout)v.w}; \
     return r; \
 }
@@ -40,20 +43,20 @@
 // Float ops, 6.11.2
 
 #define DEF_FUNC_1(fnc) \
-static float2 __attribute__((overloadable)) fnc(float2 v) { \
+_RS_STATIC float2 __attribute__((overloadable)) fnc(float2 v) { \
     float2 r; \
     r.x = fnc(v.x); \
     r.y = fnc(v.y); \
     return r; \
 } \
-static float3 __attribute__((overloadable)) fnc(float3 v) { \
+_RS_STATIC float3 __attribute__((overloadable)) fnc(float3 v) { \
     float3 r; \
     r.x = fnc(v.x); \
     r.y = fnc(v.y); \
     r.z = fnc(v.z); \
     return r; \
 } \
-static float4 __attribute__((overloadable)) fnc(float4 v) { \
+_RS_STATIC float4 __attribute__((overloadable)) fnc(float4 v) { \
     float4 r; \
     r.x = fnc(v.x); \
     r.y = fnc(v.y); \
@@ -63,20 +66,20 @@
 }
 
 #define DEF_FUNC_1_RI(fnc) \
-static int2 __attribute__((overloadable)) fnc(float2 v) { \
+_RS_STATIC int2 __attribute__((overloadable)) fnc(float2 v) { \
     int2 r; \
     r.x = fnc(v.x); \
     r.y = fnc(v.y); \
     return r; \
 } \
-static int3 __attribute__((overloadable)) fnc(float3 v) { \
+_RS_STATIC int3 __attribute__((overloadable)) fnc(float3 v) { \
     int3 r; \
     r.x = fnc(v.x); \
     r.y = fnc(v.y); \
     r.z = fnc(v.z); \
     return r; \
 } \
-static int4 __attribute__((overloadable)) fnc(float4 v) { \
+_RS_STATIC int4 __attribute__((overloadable)) fnc(float4 v) { \
     int4 r; \
     r.x = fnc(v.x); \
     r.y = fnc(v.y); \
@@ -86,43 +89,43 @@
 }
 
 #define DEF_FUNC_2(fnc) \
-static float2 __attribute__((overloadable)) fnc(float2 v1, float2 v2) { \
+_RS_STATIC float2 __attribute__((overloadable)) fnc(float2 v1, float2 v2) { \
     float2 r; \
     r.x = fnc(v1.x, v2.x); \
     r.y = fnc(v1.y, v2.y); \
     return r; \
 } \
-static float3 __attribute__((overloadable)) fnc(float3 v1, float3 v2) { \
+_RS_STATIC float3 __attribute__((overloadable)) fnc(float3 v1, float3 v2) { \
     float3 r; \
     r.x = fnc(v1.x, v2.x); \
     r.y = fnc(v1.y, v2.y); \
     r.z = fnc(v1.z, v2.z); \
     return r; \
 } \
-static float4 __attribute__((overloadable)) fnc(float4 v1, float4 v2) { \
+_RS_STATIC float4 __attribute__((overloadable)) fnc(float4 v1, float4 v2) { \
     float4 r; \
     r.x = fnc(v1.x, v2.x); \
     r.y = fnc(v1.y, v2.y); \
     r.z = fnc(v1.z, v2.z); \
-    r.w = fnc(v1.w, v2.z); \
+    r.w = fnc(v1.w, v2.w); \
     return r; \
 }
 
 #define DEF_FUNC_2F(fnc) \
-static float2 __attribute__((overloadable)) fnc(float2 v1, float v2) { \
+_RS_STATIC float2 __attribute__((overloadable)) fnc(float2 v1, float v2) { \
     float2 r; \
     r.x = fnc(v1.x, v2); \
     r.y = fnc(v1.y, v2); \
     return r; \
 } \
-static float3 __attribute__((overloadable)) fnc(float3 v1, float v2) { \
+_RS_STATIC float3 __attribute__((overloadable)) fnc(float3 v1, float v2) { \
     float3 r; \
     r.x = fnc(v1.x, v2); \
     r.y = fnc(v1.y, v2); \
     r.z = fnc(v1.z, v2); \
     return r; \
 } \
-static float4 __attribute__((overloadable)) fnc(float4 v1, float v2) { \
+_RS_STATIC float4 __attribute__((overloadable)) fnc(float4 v1, float v2) { \
     float4 r; \
     r.x = fnc(v1.x, v2); \
     r.y = fnc(v1.y, v2); \
@@ -131,6 +134,40 @@
     return r; \
 }
 
+#define DEF_FUNC_2P(fnc) \
+_RS_STATIC float2 __attribute__((overloadable)) fnc(float2 v1, float2 *v2) { \
+    float2 r; \
+    float q; \
+    r.x = fnc(v1.x, &q); \
+    v2->x = q; \
+    r.y = fnc(v1.y, &q); \
+    v2->y = q; \
+    return r; \
+} \
+_RS_STATIC float3 __attribute__((overloadable)) fnc(float3 v1, float3 *v2) { \
+    float3 r; \
+    float q; \
+    r.x = fnc(v1.x, &q); \
+    v2->x = q; \
+    r.y = fnc(v1.y, &q); \
+    v2->y = q; \
+    r.z = fnc(v1.z, &q); \
+    v2->z = q; \
+    return r; \
+} \
+_RS_STATIC float4 __attribute__((overloadable)) fnc(float4 v1, float4 *v2) { \
+    float4 r; \
+    float q; \
+    r.x = fnc(v1.x, &q); \
+    v2->x = q; \
+    r.y = fnc(v1.y, &q); \
+    v2->y = q; \
+    r.z = fnc(v1.z, &q); \
+    v2->z = q; \
+    r.w = fnc(v1.w, &q); \
+    v2->w = q; \
+    return r; \
+}
 
 extern float __attribute__((overloadable)) acos(float);
 DEF_FUNC_1(acos)
@@ -138,7 +175,7 @@
 extern float __attribute__((overloadable)) acosh(float);
 DEF_FUNC_1(acosh)
 
-static float __attribute__((overloadable)) acospi(float v) {
+_RS_STATIC float __attribute__((overloadable)) acospi(float v) {
     return acos(v) / M_PI;
 }
 DEF_FUNC_1(acospi)
@@ -149,7 +186,7 @@
 extern float __attribute__((overloadable)) asinh(float);
 DEF_FUNC_1(asinh)
 
-static float __attribute__((overloadable)) asinpi(float v) {
+_RS_STATIC float __attribute__((overloadable)) asinpi(float v) {
     return asin(v) / M_PI;
 }
 DEF_FUNC_1(asinpi)
@@ -163,12 +200,12 @@
 extern float __attribute__((overloadable)) atanh(float);
 DEF_FUNC_1(atanh)
 
-static float __attribute__((overloadable)) atanpi(float v) {
+_RS_STATIC float __attribute__((overloadable)) atanpi(float v) {
     return atan(v) / M_PI;
 }
 DEF_FUNC_1(atanpi)
 
-static float __attribute__((overloadable)) atan2pi(float y, float x) {
+_RS_STATIC float __attribute__((overloadable)) atan2pi(float y, float x) {
     return atan2(y, x) / M_PI;
 }
 DEF_FUNC_2(atan2pi)
@@ -188,7 +225,7 @@
 extern float __attribute__((overloadable)) cosh(float);
 DEF_FUNC_1(cosh)
 
-static float __attribute__((overloadable)) cospi(float v) {
+_RS_STATIC float __attribute__((overloadable)) cospi(float v) {
     return cos(v * M_PI);
 }
 DEF_FUNC_1(cospi)
@@ -206,7 +243,7 @@
 DEF_FUNC_1(exp2)
 
 extern float __attribute__((overloadable)) pow(float, float);
-static float __attribute__((overloadable)) exp10(float v) {
+_RS_STATIC float __attribute__((overloadable)) exp10(float v) {
     return pow(10.f, v);
 }
 DEF_FUNC_1(exp10)
@@ -239,12 +276,12 @@
 extern float __attribute__((overloadable)) fmod(float, float);
 DEF_FUNC_2(fmod)
 
-static float __attribute__((overloadable)) fract(float v, float *iptr) {
+_RS_STATIC float __attribute__((overloadable)) fract(float v, float *iptr) {
     int i = (int)floor(v);
     iptr[0] = i;
     return fmin(v - i, 0x1.fffffep-1f);
 }
-static float2 __attribute__((overloadable)) fract(float2 v, float2 *iptr) {
+_RS_STATIC float2 __attribute__((overloadable)) fract(float2 v, float2 *iptr) {
     float t[2];
     float2 r;
     r.x = fract(v.x, &t[0]);
@@ -253,7 +290,7 @@
     iptr[1] = t[1];
     return r;
 }
-static float3 __attribute__((overloadable)) fract(float3 v, float3 *iptr) {
+_RS_STATIC float3 __attribute__((overloadable)) fract(float3 v, float3 *iptr) {
     float t[3];
     float3 r;
     r.x = fract(v.x, &t[0]);
@@ -264,7 +301,7 @@
     iptr[2] = t[2];
     return r;
 }
-static float4 __attribute__((overloadable)) fract(float4 v, float4 *iptr) {
+_RS_STATIC float4 __attribute__((overloadable)) fract(float4 v, float4 *iptr) {
     float t[4];
     float4 r;
     r.x = fract(v.x, &t[0]);
@@ -311,7 +348,7 @@
 extern float __attribute__((overloadable)) log10(float);
 DEF_FUNC_1(log10)
 
-static float __attribute__((overloadable)) log2(float v) {
+_RS_STATIC float __attribute__((overloadable)) log2(float v) {
     return log10(v) / log10(2.f);
 }
 DEF_FUNC_1(log2)
@@ -328,9 +365,7 @@
 extern float4 __attribute__((overloadable)) mad(float4, float4, float4);
 
 extern float __attribute__((overloadable)) modf(float, float *);
-extern float2 __attribute__((overloadable)) modf(float2, float2 *);
-extern float3 __attribute__((overloadable)) modf(float3, float3 *);
-extern float4 __attribute__((overloadable)) modf(float4, float4 *);
+DEF_FUNC_2P(modf);
 
 //extern float __attribute__((overloadable)) nan(uint);
 
@@ -339,29 +374,29 @@
 
 DEF_FUNC_2(pow)
 
-static float __attribute__((overloadable)) pown(float v, int p) {
+_RS_STATIC float __attribute__((overloadable)) pown(float v, int p) {
     return pow(v, (float)p);
 }
-static float2 __attribute__((overloadable)) pown(float2 v, int2 p) {
+_RS_STATIC float2 __attribute__((overloadable)) pown(float2 v, int2 p) {
     return pow(v, (float2)p);
 }
-static float3 __attribute__((overloadable)) pown(float3 v, int3 p) {
+_RS_STATIC float3 __attribute__((overloadable)) pown(float3 v, int3 p) {
     return pow(v, (float3)p);
 }
-static float4 __attribute__((overloadable)) pown(float4 v, int4 p) {
+_RS_STATIC float4 __attribute__((overloadable)) pown(float4 v, int4 p) {
     return pow(v, (float4)p);
 }
 
-static float __attribute__((overloadable)) powr(float v, float p) {
+_RS_STATIC float __attribute__((overloadable)) powr(float v, float p) {
     return pow(v, p);
 }
-static float2 __attribute__((overloadable)) powr(float2 v, float2 p) {
+_RS_STATIC float2 __attribute__((overloadable)) powr(float2 v, float2 p) {
     return pow(v, p);
 }
-static float3 __attribute__((overloadable)) powr(float3 v, float3 p) {
+_RS_STATIC float3 __attribute__((overloadable)) powr(float3 v, float3 p) {
     return pow(v, p);
 }
-static float4 __attribute__((overloadable)) powr(float4 v, float4 p) {
+_RS_STATIC float4 __attribute__((overloadable)) powr(float4 v, float4 p) {
     return pow(v, p);
 }
 
@@ -376,18 +411,18 @@
 extern float __attribute__((overloadable)) rint(float);
 DEF_FUNC_1(rint)
 
-static float __attribute__((overloadable)) rootn(float v, int r) {
+_RS_STATIC float __attribute__((overloadable)) rootn(float v, int r) {
     return pow(v, 1.f / r);
 }
-static float2 __attribute__((overloadable)) rootn(float2 v, int2 r) {
+_RS_STATIC float2 __attribute__((overloadable)) rootn(float2 v, int2 r) {
     float2 t = {1.f / r.x, 1.f / r.y};
     return pow(v, t);
 }
-static float3 __attribute__((overloadable)) rootn(float3 v, int3 r) {
+_RS_STATIC float3 __attribute__((overloadable)) rootn(float3 v, int3 r) {
     float3 t = {1.f / r.x, 1.f / r.y, 1.f / r.z};
     return pow(v, t);
 }
-static float4 __attribute__((overloadable)) rootn(float4 v, int4 r) {
+_RS_STATIC float4 __attribute__((overloadable)) rootn(float4 v, int4 r) {
     float4 t = {1.f / r.x, 1.f / r.y, 1.f / r.z, 1.f / r.w};
     return pow(v, t);
 }
@@ -396,7 +431,7 @@
 DEF_FUNC_1(round)
 
 extern float __attribute__((overloadable)) sqrt(float);
-static float __attribute__((overloadable)) rsqrt(float v) {
+_RS_STATIC float __attribute__((overloadable)) rsqrt(float v) {
     return 1.f / sqrt(v);
 }
 DEF_FUNC_1(rsqrt)
@@ -404,19 +439,19 @@
 extern float __attribute__((overloadable)) sin(float);
 DEF_FUNC_1(sin)
 
-static float __attribute__((overloadable)) sincos(float v, float *cosptr) {
+_RS_STATIC float __attribute__((overloadable)) sincos(float v, float *cosptr) {
     *cosptr = cos(v);
     return sin(v);
 }
-static float2 __attribute__((overloadable)) sincos(float2 v, float2 *cosptr) {
+_RS_STATIC float2 __attribute__((overloadable)) sincos(float2 v, float2 *cosptr) {
     *cosptr = cos(v);
     return sin(v);
 }
-static float3 __attribute__((overloadable)) sincos(float3 v, float3 *cosptr) {
+_RS_STATIC float3 __attribute__((overloadable)) sincos(float3 v, float3 *cosptr) {
     *cosptr = cos(v);
     return sin(v);
 }
-static float4 __attribute__((overloadable)) sincos(float4 v, float4 *cosptr) {
+_RS_STATIC float4 __attribute__((overloadable)) sincos(float4 v, float4 *cosptr) {
     *cosptr = cos(v);
     return sin(v);
 }
@@ -424,7 +459,7 @@
 extern float __attribute__((overloadable)) sinh(float);
 DEF_FUNC_1(sinh)
 
-static float __attribute__((overloadable)) sinpi(float v) {
+_RS_STATIC float __attribute__((overloadable)) sinpi(float v) {
     return sin(v * M_PI);
 }
 DEF_FUNC_1(sinpi)
@@ -437,7 +472,7 @@
 extern float __attribute__((overloadable)) tanh(float);
 DEF_FUNC_1(tanh)
 
-static float __attribute__((overloadable)) tanpi(float v) {
+_RS_STATIC float __attribute__((overloadable)) tanpi(float v) {
     return tan(v * M_PI);
 }
 DEF_FUNC_1(tanpi)
@@ -452,20 +487,20 @@
 
 #define DEF_RIFUNC_1(typeout, typein, fnc)                          \
 extern typeout __attribute__((overloadable)) fnc(typein);           \
-static typeout##2 __attribute__((overloadable)) fnc(typein##2 v) {  \
+_RS_STATIC typeout##2 __attribute__((overloadable)) fnc(typein##2 v) {  \
     typeout##2 r;                                                   \
     r.x = fnc(v.x);                                                 \
     r.y = fnc(v.y);                                                 \
     return r;                                                       \
 }                                                                   \
-static typeout##3 __attribute__((overloadable)) fnc(typein##3 v) {  \
+_RS_STATIC typeout##3 __attribute__((overloadable)) fnc(typein##3 v) {  \
     typeout##3 r;                                                   \
     r.x = fnc(v.x);                                                 \
     r.y = fnc(v.y);                                                 \
     r.z = fnc(v.z);                                                 \
     return r;                                                       \
 }                                                                   \
-static typeout##4 __attribute__((overloadable)) fnc(typein##4 v) {  \
+_RS_STATIC typeout##4 __attribute__((overloadable)) fnc(typein##4 v) {  \
     typeout##4 r;                                                   \
     r.x = fnc(v.x);                                                 \
     r.y = fnc(v.y);                                                 \
@@ -488,23 +523,23 @@
 DEF_RIFUNC_1(int, int, fnc)
 
 #define DEF_RIFUNC_2(type, fnc, body)                                       \
-static type __attribute__((overloadable)) fnc(type v1, type v2) {           \
+_RS_STATIC type __attribute__((overloadable)) fnc(type v1, type v2) {           \
     return body;                                                            \
 }                                                                           \
-static type##2 __attribute__((overloadable)) fnc(type##2 v1, type##2 v2) {  \
+_RS_STATIC type##2 __attribute__((overloadable)) fnc(type##2 v1, type##2 v2) {  \
     type##2 r;                                                              \
     r.x = fnc(v1.x, v2.x);                                                  \
     r.y = fnc(v1.y, v2.y);                                                  \
     return r;                                                               \
 }                                                                           \
-static type##3 __attribute__((overloadable)) fnc(type##3 v1, type##3 v2) {  \
+_RS_STATIC type##3 __attribute__((overloadable)) fnc(type##3 v1, type##3 v2) {  \
     type##3 r;                                                              \
     r.x = fnc(v1.x, v2.x);                                                  \
     r.y = fnc(v1.y, v2.y);                                                  \
     r.z = fnc(v1.z, v2.z);                                                  \
     return r;                                                               \
 }                                                                           \
-static type##4 __attribute__((overloadable)) fnc(type##4 v1, type##4 v2) {  \
+_RS_STATIC type##4 __attribute__((overloadable)) fnc(type##4 v1, type##4 v2) {  \
     type##4 r;                                                              \
     r.x = fnc(v1.x, v2.x);                                                  \
     r.y = fnc(v1.y, v2.y);                                                  \
@@ -533,23 +568,23 @@
 
 // 6.11.4
 
-static float __attribute__((overloadable)) clamp(float amount, float low, float high) {
+_RS_STATIC float __attribute__((overloadable)) clamp(float amount, float low, float high) {
     return amount < low ? low : (amount > high ? high : amount);
 }
-static float2 __attribute__((overloadable)) clamp(float2 amount, float2 low, float2 high) {
+_RS_STATIC float2 __attribute__((overloadable)) clamp(float2 amount, float2 low, float2 high) {
     float2 r;
     r.x = amount.x < low.x ? low.x : (amount.x > high.x ? high.x : amount.x);
     r.y = amount.y < low.y ? low.y : (amount.y > high.y ? high.y : amount.y);
     return r;
 }
-static float3 __attribute__((overloadable)) clamp(float3 amount, float3 low, float3 high) {
+_RS_STATIC float3 __attribute__((overloadable)) clamp(float3 amount, float3 low, float3 high) {
     float3 r;
     r.x = amount.x < low.x ? low.x : (amount.x > high.x ? high.x : amount.x);
     r.y = amount.y < low.y ? low.y : (amount.y > high.y ? high.y : amount.y);
     r.z = amount.z < low.z ? low.z : (amount.z > high.z ? high.z : amount.z);
     return r;
 }
-static float4 __attribute__((overloadable)) clamp(float4 amount, float4 low, float4 high) {
+_RS_STATIC float4 __attribute__((overloadable)) clamp(float4 amount, float4 low, float4 high) {
     float4 r;
     r.x = amount.x < low.x ? low.x : (amount.x > high.x ? high.x : amount.x);
     r.y = amount.y < low.y ? low.y : (amount.y > high.y ? high.y : amount.y);
@@ -557,20 +592,20 @@
     r.w = amount.w < low.w ? low.w : (amount.w > high.w ? high.w : amount.w);
     return r;
 }
-static float2 __attribute__((overloadable)) clamp(float2 amount, float low, float high) {
+_RS_STATIC float2 __attribute__((overloadable)) clamp(float2 amount, float low, float high) {
     float2 r;
     r.x = amount.x < low ? low : (amount.x > high ? high : amount.x);
     r.y = amount.y < low ? low : (amount.y > high ? high : amount.y);
     return r;
 }
-static float3 __attribute__((overloadable)) clamp(float3 amount, float low, float high) {
+_RS_STATIC float3 __attribute__((overloadable)) clamp(float3 amount, float low, float high) {
     float3 r;
     r.x = amount.x < low ? low : (amount.x > high ? high : amount.x);
     r.y = amount.y < low ? low : (amount.y > high ? high : amount.y);
     r.z = amount.z < low ? low : (amount.z > high ? high : amount.z);
     return r;
 }
-static float4 __attribute__((overloadable)) clamp(float4 amount, float low, float high) {
+_RS_STATIC float4 __attribute__((overloadable)) clamp(float4 amount, float low, float high) {
     float4 r;
     r.x = amount.x < low ? low : (amount.x > high ? high : amount.x);
     r.y = amount.y < low ? low : (amount.y > high ? high : amount.y);
@@ -579,55 +614,55 @@
     return r;
 }
 
-static float __attribute__((overloadable)) degrees(float radians) {
+_RS_STATIC float __attribute__((overloadable)) degrees(float radians) {
     return radians * (180.f / M_PI);
 }
 DEF_FUNC_1(degrees)
 
-static float __attribute__((overloadable)) mix(float start, float stop, float amount) {
+_RS_STATIC float __attribute__((overloadable)) mix(float start, float stop, float amount) {
     return start + (stop - start) * amount;
 }
-static float2 __attribute__((overloadable)) mix(float2 start, float2 stop, float2 amount) {
+_RS_STATIC float2 __attribute__((overloadable)) mix(float2 start, float2 stop, float2 amount) {
     return start + (stop - start) * amount;
 }
-static float3 __attribute__((overloadable)) mix(float3 start, float3 stop, float3 amount) {
+_RS_STATIC float3 __attribute__((overloadable)) mix(float3 start, float3 stop, float3 amount) {
     return start + (stop - start) * amount;
 }
-static float4 __attribute__((overloadable)) mix(float4 start, float4 stop, float4 amount) {
+_RS_STATIC float4 __attribute__((overloadable)) mix(float4 start, float4 stop, float4 amount) {
     return start + (stop - start) * amount;
 }
-static float2 __attribute__((overloadable)) mix(float2 start, float2 stop, float amount) {
+_RS_STATIC float2 __attribute__((overloadable)) mix(float2 start, float2 stop, float amount) {
     return start + (stop - start) * amount;
 }
-static float3 __attribute__((overloadable)) mix(float3 start, float3 stop, float amount) {
+_RS_STATIC float3 __attribute__((overloadable)) mix(float3 start, float3 stop, float amount) {
     return start + (stop - start) * amount;
 }
-static float4 __attribute__((overloadable)) mix(float4 start, float4 stop, float amount) {
+_RS_STATIC float4 __attribute__((overloadable)) mix(float4 start, float4 stop, float amount) {
     return start + (stop - start) * amount;
 }
 
-static float __attribute__((overloadable)) radians(float degrees) {
+_RS_STATIC float __attribute__((overloadable)) radians(float degrees) {
     return degrees * (M_PI / 180.f);
 }
 DEF_FUNC_1(radians)
 
-static float __attribute__((overloadable)) step(float edge, float v) {
+_RS_STATIC float __attribute__((overloadable)) step(float edge, float v) {
     return (v < edge) ? 0.f : 1.f;
 }
-static float2 __attribute__((overloadable)) step(float2 edge, float2 v) {
+_RS_STATIC float2 __attribute__((overloadable)) step(float2 edge, float2 v) {
     float2 r;
     r.x = (v.x < edge.x) ? 0.f : 1.f;
     r.y = (v.y < edge.y) ? 0.f : 1.f;
     return r;
 }
-static float3 __attribute__((overloadable)) step(float3 edge, float3 v) {
+_RS_STATIC float3 __attribute__((overloadable)) step(float3 edge, float3 v) {
     float3 r;
     r.x = (v.x < edge.x) ? 0.f : 1.f;
     r.y = (v.y < edge.y) ? 0.f : 1.f;
     r.z = (v.z < edge.z) ? 0.f : 1.f;
     return r;
 }
-static float4 __attribute__((overloadable)) step(float4 edge, float4 v) {
+_RS_STATIC float4 __attribute__((overloadable)) step(float4 edge, float4 v) {
     float4 r;
     r.x = (v.x < edge.x) ? 0.f : 1.f;
     r.y = (v.y < edge.y) ? 0.f : 1.f;
@@ -635,20 +670,20 @@
     r.w = (v.w < edge.w) ? 0.f : 1.f;
     return r;
 }
-static float2 __attribute__((overloadable)) step(float2 edge, float v) {
+_RS_STATIC float2 __attribute__((overloadable)) step(float2 edge, float v) {
     float2 r;
     r.x = (v < edge.x) ? 0.f : 1.f;
     r.y = (v < edge.y) ? 0.f : 1.f;
     return r;
 }
-static float3 __attribute__((overloadable)) step(float3 edge, float v) {
+_RS_STATIC float3 __attribute__((overloadable)) step(float3 edge, float v) {
     float3 r;
     r.x = (v < edge.x) ? 0.f : 1.f;
     r.y = (v < edge.y) ? 0.f : 1.f;
     r.z = (v < edge.z) ? 0.f : 1.f;
     return r;
 }
-static float4 __attribute__((overloadable)) step(float4 edge, float v) {
+_RS_STATIC float4 __attribute__((overloadable)) step(float4 edge, float v) {
     float4 r;
     r.x = (v < edge.x) ? 0.f : 1.f;
     r.y = (v < edge.y) ? 0.f : 1.f;
@@ -665,7 +700,7 @@
 extern float3 __attribute__((overloadable)) smoothstep(float, float, float3);
 extern float4 __attribute__((overloadable)) smoothstep(float, float, float4);
 
-static float __attribute__((overloadable)) sign(float v) {
+_RS_STATIC float __attribute__((overloadable)) sign(float v) {
     if (v > 0) return 1.f;
     if (v < 0) return -1.f;
     return v;
@@ -673,7 +708,7 @@
 DEF_FUNC_1(sign)
 
 // 6.11.5
-static float3 __attribute__((overloadable)) cross(float3 lhs, float3 rhs) {
+_RS_STATIC float3 __attribute__((overloadable)) cross(float3 lhs, float3 rhs) {
     float3 r;
     r.x = lhs.y * rhs.z  - lhs.z * rhs.y;
     r.y = lhs.z * rhs.x  - lhs.x * rhs.z;
@@ -681,7 +716,7 @@
     return r;
 }
 
-static float4 __attribute__((overloadable)) cross(float4 lhs, float4 rhs) {
+_RS_STATIC float4 __attribute__((overloadable)) cross(float4 lhs, float4 rhs) {
     float4 r;
     r.x = lhs.y * rhs.z  - lhs.z * rhs.y;
     r.y = lhs.z * rhs.x  - lhs.x * rhs.z;
@@ -690,55 +725,55 @@
     return r;
 }
 
-static float __attribute__((overloadable)) dot(float lhs, float rhs) {
+_RS_STATIC float __attribute__((overloadable)) dot(float lhs, float rhs) {
     return lhs * rhs;
 }
-static float __attribute__((overloadable)) dot(float2 lhs, float2 rhs) {
+_RS_STATIC float __attribute__((overloadable)) dot(float2 lhs, float2 rhs) {
     return lhs.x*rhs.x + lhs.y*rhs.y;
 }
-static float __attribute__((overloadable)) dot(float3 lhs, float3 rhs) {
+_RS_STATIC float __attribute__((overloadable)) dot(float3 lhs, float3 rhs) {
     return lhs.x*rhs.x + lhs.y*rhs.y + lhs.z*rhs.z;
 }
-static float __attribute__((overloadable)) dot(float4 lhs, float4 rhs) {
+_RS_STATIC float __attribute__((overloadable)) dot(float4 lhs, float4 rhs) {
     return lhs.x*rhs.x + lhs.y*rhs.y + lhs.z*rhs.z + lhs.w*rhs.w;
 }
 
-static float __attribute__((overloadable)) length(float v) {
+_RS_STATIC float __attribute__((overloadable)) length(float v) {
     return v;
 }
-static float __attribute__((overloadable)) length(float2 v) {
+_RS_STATIC float __attribute__((overloadable)) length(float2 v) {
     return sqrt(v.x*v.x + v.y*v.y);
 }
-static float __attribute__((overloadable)) length(float3 v) {
+_RS_STATIC float __attribute__((overloadable)) length(float3 v) {
     return sqrt(v.x*v.x + v.y*v.y + v.z*v.z);
 }
-static float __attribute__((overloadable)) length(float4 v) {
+_RS_STATIC float __attribute__((overloadable)) length(float4 v) {
     return sqrt(v.x*v.x + v.y*v.y + v.z*v.z + v.w*v.w);
 }
 
-static float __attribute__((overloadable)) distance(float lhs, float rhs) {
+_RS_STATIC float __attribute__((overloadable)) distance(float lhs, float rhs) {
     return length(lhs - rhs);
 }
-static float __attribute__((overloadable)) distance(float2 lhs, float2 rhs) {
+_RS_STATIC float __attribute__((overloadable)) distance(float2 lhs, float2 rhs) {
     return length(lhs - rhs);
 }
-static float __attribute__((overloadable)) distance(float3 lhs, float3 rhs) {
+_RS_STATIC float __attribute__((overloadable)) distance(float3 lhs, float3 rhs) {
     return length(lhs - rhs);
 }
-static float __attribute__((overloadable)) distance(float4 lhs, float4 rhs) {
+_RS_STATIC float __attribute__((overloadable)) distance(float4 lhs, float4 rhs) {
     return length(lhs - rhs);
 }
 
-static float __attribute__((overloadable)) normalize(float v) {
+_RS_STATIC float __attribute__((overloadable)) normalize(float v) {
     return 1.f;
 }
-static float2 __attribute__((overloadable)) normalize(float2 v) {
+_RS_STATIC float2 __attribute__((overloadable)) normalize(float2 v) {
     return v / length(v);
 }
-static float3 __attribute__((overloadable)) normalize(float3 v) {
+_RS_STATIC float3 __attribute__((overloadable)) normalize(float3 v) {
     return v / length(v);
 }
-static float4 __attribute__((overloadable)) normalize(float4 v) {
+_RS_STATIC float4 __attribute__((overloadable)) normalize(float4 v) {
     return v / length(v);
 }
 
@@ -753,5 +788,6 @@
 #undef DEF_IFUNC_1
 #undef DEF_RIFUNC_2
 #undef DEF_IFUNC_2
+#undef _RS_STATIC
 
 #endif
diff --git a/libs/rs/scriptc/rs_core.rsh b/libs/rs/scriptc/rs_core.rsh
index 16482c1..f3e0ab0 100644
--- a/libs/rs/scriptc/rs_core.rsh
+++ b/libs/rs/scriptc/rs_core.rsh
@@ -1,6 +1,12 @@
 #ifndef __RS_CORE_RSH__
 #define __RS_CORE_RSH__
 
+#ifdef BCC_PREPARE_BC
+#define _RS_STATIC  extern
+#else
+#define _RS_STATIC  static
+#endif
+
 // Debugging, print to the LOG a description string and a value.
 extern void __attribute__((overloadable))
     rsDebug(const char *, float);
@@ -35,17 +41,17 @@
 #define RS_DEBUG(a) rsDebug(#a, a)
 #define RS_DEBUG_MARKER rsDebug(__FILE__, __LINE__)
 
-static void __attribute__((overloadable)) rsDebug(const char *s, float2 v) {
+_RS_STATIC void __attribute__((overloadable)) rsDebug(const char *s, float2 v) {
     rsDebug(s, v.x, v.y);
 }
-static void __attribute__((overloadable)) rsDebug(const char *s, float3 v) {
+_RS_STATIC void __attribute__((overloadable)) rsDebug(const char *s, float3 v) {
     rsDebug(s, v.x, v.y, v.z);
 }
-static void __attribute__((overloadable)) rsDebug(const char *s, float4 v) {
+_RS_STATIC void __attribute__((overloadable)) rsDebug(const char *s, float4 v) {
     rsDebug(s, v.x, v.y, v.z, v.w);
 }
 
-static uchar4 __attribute__((overloadable)) rsPackColorTo8888(float r, float g, float b)
+_RS_STATIC uchar4 __attribute__((overloadable)) rsPackColorTo8888(float r, float g, float b)
 {
     uchar4 c;
     c.x = (uchar)(r * 255.f);
@@ -55,7 +61,7 @@
     return c;
 }
 
-static uchar4 __attribute__((overloadable)) rsPackColorTo8888(float r, float g, float b, float a)
+_RS_STATIC uchar4 __attribute__((overloadable)) rsPackColorTo8888(float r, float g, float b, float a)
 {
     uchar4 c;
     c.x = (uchar)(r * 255.f);
@@ -65,21 +71,21 @@
     return c;
 }
 
-static uchar4 __attribute__((overloadable)) rsPackColorTo8888(float3 color)
+_RS_STATIC uchar4 __attribute__((overloadable)) rsPackColorTo8888(float3 color)
 {
     color *= 255.f;
     uchar4 c = {color.x, color.y, color.z, 255};
     return c;
 }
 
-static uchar4 __attribute__((overloadable)) rsPackColorTo8888(float4 color)
+_RS_STATIC uchar4 __attribute__((overloadable)) rsPackColorTo8888(float4 color)
 {
     color *= 255.f;
     uchar4 c = {color.x, color.y, color.z, color.w};
     return c;
 }
 
-static float4 rsUnpackColor8888(uchar4 c)
+_RS_STATIC float4 rsUnpackColor8888(uchar4 c)
 {
     float4 ret = (float4)0.0039156862745f;
     ret *= convert_float4(c);
@@ -95,37 +101,37 @@
 // Matrix ops
 /////////////////////////////////////////////////////
 
-static void __attribute__((overloadable))
+_RS_STATIC void __attribute__((overloadable))
 rsMatrixSet(rs_matrix4x4 *m, uint32_t row, uint32_t col, float v) {
     m->m[row * 4 + col] = v;
 }
 
-static float __attribute__((overloadable))
+_RS_STATIC float __attribute__((overloadable))
 rsMatrixGet(const rs_matrix4x4 *m, uint32_t row, uint32_t col) {
     return m->m[row * 4 + col];
 }
 
-static void __attribute__((overloadable))
+_RS_STATIC void __attribute__((overloadable))
 rsMatrixSet(rs_matrix3x3 *m, uint32_t row, uint32_t col, float v) {
     m->m[row * 3 + col] = v;
 }
 
-static float __attribute__((overloadable))
+_RS_STATIC float __attribute__((overloadable))
 rsMatrixGet(const rs_matrix3x3 *m, uint32_t row, uint32_t col) {
     return m->m[row * 3 + col];
 }
 
-static void __attribute__((overloadable))
+_RS_STATIC void __attribute__((overloadable))
 rsMatrixSet(rs_matrix2x2 *m, uint32_t row, uint32_t col, float v) {
     m->m[row * 2 + col] = v;
 }
 
-static float __attribute__((overloadable))
+_RS_STATIC float __attribute__((overloadable))
 rsMatrixGet(const rs_matrix2x2 *m, uint32_t row, uint32_t col) {
     return m->m[row * 2 + col];
 }
 
-static void __attribute__((overloadable))
+_RS_STATIC void __attribute__((overloadable))
 rsMatrixLoadIdentity(rs_matrix4x4 *m) {
     m->m[0] = 1.f;
     m->m[1] = 0.f;
@@ -145,7 +151,7 @@
     m->m[15] = 1.f;
 }
 
-static void __attribute__((overloadable))
+_RS_STATIC void __attribute__((overloadable))
 rsMatrixLoadIdentity(rs_matrix3x3 *m) {
     m->m[0] = 1.f;
     m->m[1] = 0.f;
@@ -158,7 +164,7 @@
     m->m[8] = 1.f;
 }
 
-static void __attribute__((overloadable))
+_RS_STATIC void __attribute__((overloadable))
 rsMatrixLoadIdentity(rs_matrix2x2 *m) {
     m->m[0] = 1.f;
     m->m[1] = 0.f;
@@ -166,7 +172,7 @@
     m->m[3] = 1.f;
 }
 
-static void __attribute__((overloadable))
+_RS_STATIC void __attribute__((overloadable))
 rsMatrixLoad(rs_matrix4x4 *m, const float *v) {
     m->m[0] = v[0];
     m->m[1] = v[1];
@@ -186,7 +192,7 @@
     m->m[15] = v[15];
 }
 
-static void __attribute__((overloadable))
+_RS_STATIC void __attribute__((overloadable))
 rsMatrixLoad(rs_matrix3x3 *m, const float *v) {
     m->m[0] = v[0];
     m->m[1] = v[1];
@@ -199,7 +205,7 @@
     m->m[8] = v[8];
 }
 
-static void __attribute__((overloadable))
+_RS_STATIC void __attribute__((overloadable))
 rsMatrixLoad(rs_matrix2x2 *m, const float *v) {
     m->m[0] = v[0];
     m->m[1] = v[1];
@@ -207,7 +213,7 @@
     m->m[3] = v[3];
 }
 
-static void __attribute__((overloadable))
+_RS_STATIC void __attribute__((overloadable))
 rsMatrixLoad(rs_matrix4x4 *m, const rs_matrix4x4 *v) {
     m->m[0] = v->m[0];
     m->m[1] = v->m[1];
@@ -227,7 +233,7 @@
     m->m[15] = v->m[15];
 }
 
-static void __attribute__((overloadable))
+_RS_STATIC void __attribute__((overloadable))
 rsMatrixLoad(rs_matrix4x4 *m, const rs_matrix3x3 *v) {
     m->m[0] = v->m[0];
     m->m[1] = v->m[1];
@@ -247,7 +253,7 @@
     m->m[15] = 1.f;
 }
 
-static void __attribute__((overloadable))
+_RS_STATIC void __attribute__((overloadable))
 rsMatrixLoad(rs_matrix4x4 *m, const rs_matrix2x2 *v) {
     m->m[0] = v->m[0];
     m->m[1] = v->m[1];
@@ -267,7 +273,7 @@
     m->m[15] = 1.f;
 }
 
-static void __attribute__((overloadable))
+_RS_STATIC void __attribute__((overloadable))
 rsMatrixLoad(rs_matrix3x3 *m, const rs_matrix3x3 *v) {
     m->m[0] = v->m[0];
     m->m[1] = v->m[1];
@@ -280,7 +286,7 @@
     m->m[8] = v->m[8];
 }
 
-static void __attribute__((overloadable))
+_RS_STATIC void __attribute__((overloadable))
 rsMatrixLoad(rs_matrix2x2 *m, const rs_matrix2x2 *v) {
     m->m[0] = v->m[0];
     m->m[1] = v->m[1];
@@ -288,7 +294,7 @@
     m->m[3] = v->m[3];
 }
 
-static void __attribute__((overloadable))
+_RS_STATIC void __attribute__((overloadable))
 rsMatrixLoadRotate(rs_matrix4x4 *m, float rot, float x, float y, float z) {
     float c, s;
     m->m[3] = 0;
@@ -327,7 +333,7 @@
     m->m[10] = z*z*nc +  c;
 }
 
-static void __attribute__((overloadable))
+_RS_STATIC void __attribute__((overloadable))
 rsMatrixLoadScale(rs_matrix4x4 *m, float x, float y, float z) {
     rsMatrixLoadIdentity(m);
     m->m[0] = x;
@@ -335,7 +341,7 @@
     m->m[10] = z;
 }
 
-static void __attribute__((overloadable))
+_RS_STATIC void __attribute__((overloadable))
 rsMatrixLoadTranslate(rs_matrix4x4 *m, float x, float y, float z) {
     rsMatrixLoadIdentity(m);
     m->m[12] = x;
@@ -343,7 +349,7 @@
     m->m[14] = z;
 }
 
-static void __attribute__((overloadable))
+_RS_STATIC void __attribute__((overloadable))
 rsMatrixLoadMultiply(rs_matrix4x4 *m, const rs_matrix4x4 *lhs, const rs_matrix4x4 *rhs) {
     for (int i=0 ; i<4 ; i++) {
         float ri0 = 0;
@@ -364,14 +370,14 @@
     }
 }
 
-static void __attribute__((overloadable))
+_RS_STATIC void __attribute__((overloadable))
 rsMatrixMultiply(rs_matrix4x4 *m, const rs_matrix4x4 *rhs) {
     rs_matrix4x4 mt;
     rsMatrixLoadMultiply(&mt, m, rhs);
     rsMatrixLoad(m, &mt);
 }
 
-static void __attribute__((overloadable))
+_RS_STATIC void __attribute__((overloadable))
 rsMatrixLoadMultiply(rs_matrix3x3 *m, const rs_matrix3x3 *lhs, const rs_matrix3x3 *rhs) {
     for (int i=0 ; i<3 ; i++) {
         float ri0 = 0;
@@ -389,14 +395,14 @@
     }
 }
 
-static void __attribute__((overloadable))
+_RS_STATIC void __attribute__((overloadable))
 rsMatrixMultiply(rs_matrix3x3 *m, const rs_matrix3x3 *rhs) {
     rs_matrix3x3 mt;
     rsMatrixLoadMultiply(&mt, m, rhs);
     rsMatrixLoad(m, &mt);
 }
 
-static void __attribute__((overloadable))
+_RS_STATIC void __attribute__((overloadable))
 rsMatrixLoadMultiply(rs_matrix2x2 *m, const rs_matrix2x2 *lhs, const rs_matrix2x2 *rhs) {
     for (int i=0 ; i<2 ; i++) {
         float ri0 = 0;
@@ -411,35 +417,35 @@
     }
 }
 
-static void __attribute__((overloadable))
+_RS_STATIC void __attribute__((overloadable))
 rsMatrixMultiply(rs_matrix2x2 *m, const rs_matrix2x2 *rhs) {
     rs_matrix2x2 mt;
     rsMatrixLoadMultiply(&mt, m, rhs);
     rsMatrixLoad(m, &mt);
 }
 
-static void __attribute__((overloadable))
+_RS_STATIC void __attribute__((overloadable))
 rsMatrixRotate(rs_matrix4x4 *m, float rot, float x, float y, float z) {
     rs_matrix4x4 m1;
     rsMatrixLoadRotate(&m1, rot, x, y, z);
     rsMatrixMultiply(m, &m1);
 }
 
-static void __attribute__((overloadable))
+_RS_STATIC void __attribute__((overloadable))
 rsMatrixScale(rs_matrix4x4 *m, float x, float y, float z) {
     rs_matrix4x4 m1;
     rsMatrixLoadScale(&m1, x, y, z);
     rsMatrixMultiply(m, &m1);
 }
 
-static void __attribute__((overloadable))
+_RS_STATIC void __attribute__((overloadable))
 rsMatrixTranslate(rs_matrix4x4 *m, float x, float y, float z) {
     rs_matrix4x4 m1;
     rsMatrixLoadTranslate(&m1, x, y, z);
     rsMatrixMultiply(m, &m1);
 }
 
-static void __attribute__((overloadable))
+_RS_STATIC void __attribute__((overloadable))
 rsMatrixLoadOrtho(rs_matrix4x4 *m, float left, float right, float bottom, float top, float near, float far) {
     rsMatrixLoadIdentity(m);
     m->m[0] = 2.f / (right - left);
@@ -450,7 +456,7 @@
     m->m[14]= -(far + near) / (far - near);
 }
 
-static void __attribute__((overloadable))
+_RS_STATIC void __attribute__((overloadable))
 rsMatrixLoadFrustum(rs_matrix4x4 *m, float left, float right, float bottom, float top, float near, float far) {
     rsMatrixLoadIdentity(m);
     m->m[0] = 2.f * near / (right - left);
@@ -463,7 +469,7 @@
     m->m[15]= 0.f;
 }
 
-static void __attribute__((overloadable))
+_RS_STATIC void __attribute__((overloadable))
 rsMatrixLoadPerspective(rs_matrix4x4* m, float fovy, float aspect, float near, float far) {
     float top = near * tan((float) (fovy * M_PI / 360.0f));
     float bottom = -top;
@@ -472,7 +478,7 @@
     rsMatrixLoadFrustum(m, left, right, bottom, top, near, far);
 }
 
-static float4 __attribute__((overloadable))
+_RS_STATIC float4 __attribute__((overloadable))
 rsMatrixMultiply(rs_matrix4x4 *m, float4 in) {
     float4 ret;
     ret.x = (m->m[0] * in.x) + (m->m[4] * in.y) + (m->m[8] * in.z) + (m->m[12] * in.w);
@@ -482,7 +488,7 @@
     return ret;
 }
 
-static float4 __attribute__((overloadable))
+_RS_STATIC float4 __attribute__((overloadable))
 rsMatrixMultiply(rs_matrix4x4 *m, float3 in) {
     float4 ret;
     ret.x = (m->m[0] * in.x) + (m->m[4] * in.y) + (m->m[8] * in.z) + m->m[12];
@@ -492,7 +498,7 @@
     return ret;
 }
 
-static float4 __attribute__((overloadable))
+_RS_STATIC float4 __attribute__((overloadable))
 rsMatrixMultiply(rs_matrix4x4 *m, float2 in) {
     float4 ret;
     ret.x = (m->m[0] * in.x) + (m->m[4] * in.y) + m->m[12];
@@ -502,7 +508,7 @@
     return ret;
 }
 
-static float3 __attribute__((overloadable))
+_RS_STATIC float3 __attribute__((overloadable))
 rsMatrixMultiply(rs_matrix3x3 *m, float3 in) {
     float3 ret;
     ret.x = (m->m[0] * in.x) + (m->m[3] * in.y) + (m->m[6] * in.z);
@@ -511,7 +517,7 @@
     return ret;
 }
 
-static float3 __attribute__((overloadable))
+_RS_STATIC float3 __attribute__((overloadable))
 rsMatrixMultiply(rs_matrix3x3 *m, float2 in) {
     float3 ret;
     ret.x = (m->m[0] * in.x) + (m->m[3] * in.y);
@@ -520,7 +526,7 @@
     return ret;
 }
 
-static float2 __attribute__((overloadable))
+_RS_STATIC float2 __attribute__((overloadable))
 rsMatrixMultiply(rs_matrix2x2 *m, float2 in) {
     float2 ret;
     ret.x = (m->m[0] * in.x) + (m->m[2] * in.y);
@@ -529,7 +535,7 @@
 }
 
 // Returns true if the matrix was successfully inversed
-static bool __attribute__((overloadable))
+_RS_STATIC bool __attribute__((overloadable))
 rsMatrixInverse(rs_matrix4x4 *m) {
     rs_matrix4x4 result;
 
@@ -571,7 +577,7 @@
 }
 
 // Returns true if the matrix was successfully inversed
-static bool __attribute__((overloadable))
+_RS_STATIC bool __attribute__((overloadable))
 rsMatrixInverseTranspose(rs_matrix4x4 *m) {
     rs_matrix4x4 result;
 
@@ -612,7 +618,7 @@
     return true;
 }
 
-static void __attribute__((overloadable))
+_RS_STATIC void __attribute__((overloadable))
 rsMatrixTranspose(rs_matrix4x4 *m) {
     int i, j;
     float temp;
@@ -625,7 +631,7 @@
     }
 }
 
-static void __attribute__((overloadable))
+_RS_STATIC void __attribute__((overloadable))
 rsMatrixTranspose(rs_matrix3x3 *m) {
     int i, j;
     float temp;
@@ -638,7 +644,7 @@
     }
 }
 
-static void __attribute__((overloadable))
+_RS_STATIC void __attribute__((overloadable))
 rsMatrixTranspose(rs_matrix2x2 *m) {
     float temp = m->m[1];
     m->m[1] = m->m[2];
@@ -649,7 +655,7 @@
 // quaternion ops
 /////////////////////////////////////////////////////
 
-static void __attribute__((overloadable))
+_RS_STATIC void __attribute__((overloadable))
 rsQuaternionSet(rs_quaternion *q, float w, float x, float y, float z) {
     q->w = w;
     q->x = x;
@@ -657,7 +663,7 @@
     q->z = z;
 }
 
-static void __attribute__((overloadable))
+_RS_STATIC void __attribute__((overloadable))
 rsQuaternionSet(rs_quaternion *q, const rs_quaternion *rhs) {
     q->w = rhs->w;
     q->x = rhs->x;
@@ -665,7 +671,7 @@
     q->z = rhs->z;
 }
 
-static void __attribute__((overloadable))
+_RS_STATIC void __attribute__((overloadable))
 rsQuaternionMultiply(rs_quaternion *q, float s) {
     q->w *= s;
     q->x *= s;
@@ -673,7 +679,7 @@
     q->z *= s;
 }
 
-static void __attribute__((overloadable))
+_RS_STATIC void __attribute__((overloadable))
 rsQuaternionMultiply(rs_quaternion *q, const rs_quaternion *rhs) {
     q->w = -q->x*rhs->x - q->y*rhs->y - q->z*rhs->z + q->w*rhs->w;
     q->x =  q->x*rhs->w + q->y*rhs->z - q->z*rhs->y + q->w*rhs->x;
@@ -681,7 +687,7 @@
     q->z =  q->x*rhs->y - q->y*rhs->x + q->z*rhs->w + q->w*rhs->z;
 }
 
-static void
+_RS_STATIC void
 rsQuaternionAdd(rs_quaternion *q, const rs_quaternion *rhs) {
     q->w *= rhs->w;
     q->x *= rhs->x;
@@ -689,7 +695,7 @@
     q->z *= rhs->z;
 }
 
-static void
+_RS_STATIC void
 rsQuaternionLoadRotateUnit(rs_quaternion *q, float rot, float x, float y, float z) {
     rot *= (float)(M_PI / 180.0f) * 0.5f;
     float c = cos(rot);
@@ -701,7 +707,7 @@
     q->z = z * s;
 }
 
-static void
+_RS_STATIC void
 rsQuaternionLoadRotate(rs_quaternion *q, float rot, float x, float y, float z) {
     const float len = x*x + y*y + z*z;
     if (len != 1) {
@@ -713,19 +719,19 @@
     rsQuaternionLoadRotateUnit(q, rot, x, y, z);
 }
 
-static void
+_RS_STATIC void
 rsQuaternionConjugate(rs_quaternion *q) {
     q->x = -q->x;
     q->y = -q->y;
     q->z = -q->z;
 }
 
-static float
+_RS_STATIC float
 rsQuaternionDot(const rs_quaternion *q0, const rs_quaternion *q1) {
     return q0->w*q1->w + q0->x*q1->x + q0->y*q1->y + q0->z*q1->z;
 }
 
-static void
+_RS_STATIC void
 rsQuaternionNormalize(rs_quaternion *q) {
     const float len = rsQuaternionDot(q, q);
     if (len != 1) {
@@ -734,7 +740,7 @@
     }
 }
 
-static void
+_RS_STATIC void
 rsQuaternionSlerp(rs_quaternion *q, const rs_quaternion *q0, const rs_quaternion *q1, float t) {
     if (t <= 0.0f) {
         rsQuaternionSet(q, q0);
@@ -776,7 +782,7 @@
                         tempq0.y*scale + tempq1.y*invScale, tempq0.z*scale + tempq1.z*invScale);
 }
 
-static void rsQuaternionGetMatrixUnit(rs_matrix4x4 *m, const rs_quaternion *q) {
+_RS_STATIC void rsQuaternionGetMatrixUnit(rs_matrix4x4 *m, const rs_quaternion *q) {
     float x2 = 2.0f * q->x * q->x;
     float y2 = 2.0f * q->y * q->y;
     float z2 = 2.0f * q->z * q->z;
@@ -811,7 +817,7 @@
 /////////////////////////////////////////////////////
 // utility funcs
 /////////////////////////////////////////////////////
-__inline__ static void __attribute__((overloadable, always_inline))
+__inline__ _RS_STATIC void __attribute__((overloadable, always_inline))
 rsExtractFrustumPlanes(const rs_matrix4x4 *modelViewProj,
                          float4 *left, float4 *right,
                          float4 *top, float4 *bottom,
@@ -861,7 +867,7 @@
     *far /= len;
 }
 
-__inline__ static bool __attribute__((overloadable, always_inline))
+__inline__ _RS_STATIC bool __attribute__((overloadable, always_inline))
 rsIsSphereInFrustum(float4 *sphere,
                       float4 *left, float4 *right,
                       float4 *top, float4 *bottom,
@@ -899,26 +905,26 @@
 // int ops
 /////////////////////////////////////////////////////
 
-__inline__ static uint __attribute__((overloadable, always_inline)) rsClamp(uint amount, uint low, uint high) {
+__inline__ _RS_STATIC uint __attribute__((overloadable, always_inline)) rsClamp(uint amount, uint low, uint high) {
     return amount < low ? low : (amount > high ? high : amount);
 }
-__inline__ static int __attribute__((overloadable, always_inline)) rsClamp(int amount, int low, int high) {
+__inline__ _RS_STATIC int __attribute__((overloadable, always_inline)) rsClamp(int amount, int low, int high) {
     return amount < low ? low : (amount > high ? high : amount);
 }
-__inline__ static ushort __attribute__((overloadable, always_inline)) rsClamp(ushort amount, ushort low, ushort high) {
+__inline__ _RS_STATIC ushort __attribute__((overloadable, always_inline)) rsClamp(ushort amount, ushort low, ushort high) {
     return amount < low ? low : (amount > high ? high : amount);
 }
-__inline__ static short __attribute__((overloadable, always_inline)) rsClamp(short amount, short low, short high) {
+__inline__ _RS_STATIC short __attribute__((overloadable, always_inline)) rsClamp(short amount, short low, short high) {
     return amount < low ? low : (amount > high ? high : amount);
 }
-__inline__ static uchar __attribute__((overloadable, always_inline)) rsClamp(uchar amount, uchar low, uchar high) {
+__inline__ _RS_STATIC uchar __attribute__((overloadable, always_inline)) rsClamp(uchar amount, uchar low, uchar high) {
     return amount < low ? low : (amount > high ? high : amount);
 }
-__inline__ static char __attribute__((overloadable, always_inline)) rsClamp(char amount, char low, char high) {
+__inline__ _RS_STATIC char __attribute__((overloadable, always_inline)) rsClamp(char amount, char low, char high) {
     return amount < low ? low : (amount > high ? high : amount);
 }
 
-
+#undef _RS_STATIC
 
 #endif
 
diff --git a/libs/rs/scriptc/rs_types.rsh b/libs/rs/scriptc/rs_types.rsh
index 212eb83..a010096 100644
--- a/libs/rs/scriptc/rs_types.rsh
+++ b/libs/rs/scriptc/rs_types.rsh
@@ -1,6 +1,9 @@
 #ifndef __RS_TYPES_RSH__
 #define __RS_TYPES_RSH__
 
+#define M_PI        3.14159265358979323846264338327950288f   /* pi */
+
+#include "stdbool.h"
 typedef char int8_t;
 typedef short int16_t;
 typedef int int32_t;
diff --git a/libs/surfaceflinger_client/SharedBufferStack.cpp b/libs/surfaceflinger_client/SharedBufferStack.cpp
index 3b2ef84..af11f97 100644
--- a/libs/surfaceflinger_client/SharedBufferStack.cpp
+++ b/libs/surfaceflinger_client/SharedBufferStack.cpp
@@ -261,8 +261,7 @@
     // NOTE: if stack.head is messed up, we could crash the client
     // or cause some drawing artifacts. This is okay, as long as it is
     // limited to the client.
-    return (buf != stack.index[stack.head] ||
-            (stack.queued > 0 && stack.inUse != buf));
+    return (buf != stack.index[stack.head]);
 }
 
 SharedBufferServer::BuffersAvailableCondition::BuffersAvailableCondition(
diff --git a/libs/ui/GraphicBufferAllocator.cpp b/libs/ui/GraphicBufferAllocator.cpp
index ce84683..33ef1fc 100644
--- a/libs/ui/GraphicBufferAllocator.cpp
+++ b/libs/ui/GraphicBufferAllocator.cpp
@@ -61,7 +61,7 @@
     const size_t c = list.size();
     for (size_t i=0 ; i<c ; i++) {
         const alloc_rec_t& rec(list.valueAt(i));
-        snprintf(buffer, SIZE, "%10p: %7.2f KiB | %4u (%4u) x %4u | %2d | 0x%08x\n",
+        snprintf(buffer, SIZE, "%10p: %7.2f KiB | %4u (%4u) x %4u | %8X | 0x%08x\n",
             list.keyAt(i), rec.size/1024.0f, 
             rec.w, rec.s, rec.h, rec.format, rec.usage);
         result.append(buffer);
diff --git a/media/java/android/media/MediaScanner.java b/media/java/android/media/MediaScanner.java
index 10c9a9a..33c6385 100644
--- a/media/java/android/media/MediaScanner.java
+++ b/media/java/android/media/MediaScanner.java
@@ -1462,22 +1462,29 @@
         if (lastSlash < 0) throw new IllegalArgumentException("bad path " + path);
         Uri uri, membersUri;
         long rowId = entry.mRowId;
-        if (rowId == 0) {
-            // Create a new playlist
 
-            int lastDot = path.lastIndexOf('.');
-            String name = (lastDot < 0 ? path.substring(lastSlash + 1) : path.substring(lastSlash + 1, lastDot));
-            values.put(MediaStore.Audio.Playlists.NAME, name);
+        // make sure we have a name
+        String name = values.getAsString(MediaStore.Audio.Playlists.NAME);
+        if (name == null) {
+            name = values.getAsString(MediaStore.MediaColumns.TITLE);
+            if (name == null) {
+                // extract name from file name
+                int lastDot = path.lastIndexOf('.');
+                name = (lastDot < 0 ? path.substring(lastSlash + 1)
+                        : path.substring(lastSlash + 1, lastDot));
+            }
+        }
+
+        values.put(MediaStore.Audio.Playlists.NAME, name);
+        values.put(MediaStore.Audio.Playlists.DATE_MODIFIED, entry.mLastModified);
+
+        if (rowId == 0) {
             values.put(MediaStore.Audio.Playlists.DATA, path);
-            values.put(MediaStore.Audio.Playlists.DATE_MODIFIED, entry.mLastModified);
             uri = mMediaProvider.insert(mPlaylistsUri, values);
             rowId = ContentUris.parseId(uri);
             membersUri = Uri.withAppendedPath(uri, Playlists.Members.CONTENT_DIRECTORY);
         } else {
             uri = ContentUris.withAppendedId(mPlaylistsUri, rowId);
-
-            // update lastModified value of existing playlist
-            values.put(MediaStore.Audio.Playlists.DATE_MODIFIED, entry.mLastModified);
             mMediaProvider.update(uri, values, null, null);
 
             // delete members of existing playlist
diff --git a/media/java/android/media/videoeditor/MediaImageItem.java b/media/java/android/media/videoeditor/MediaImageItem.java
index b03588f..1c02878 100755
--- a/media/java/android/media/videoeditor/MediaImageItem.java
+++ b/media/java/android/media/videoeditor/MediaImageItem.java
@@ -93,29 +93,28 @@
      *
      * @throws IOException
      */
-    public MediaImageItem(VideoEditor editor, String mediaItemId,
-                         String filename, long durationMs,
-                         int renderingMode) throws IOException {
+    public MediaImageItem(VideoEditor editor, String mediaItemId, String filename, long durationMs,
+        int renderingMode) throws IOException {
 
         super(editor, mediaItemId, filename, renderingMode);
 
         mMANativeHelper = ((VideoEditorImpl)editor).getNativeContext();
         mVideoEditor = ((VideoEditorImpl)editor);
         try {
-            final Properties properties =
-                                   mMANativeHelper.getMediaProperties(filename);
+            final Properties properties = mMANativeHelper.getMediaProperties(filename);
 
             switch (mMANativeHelper.getFileType(properties.fileType)) {
                 case MediaProperties.FILE_JPEG:
+                case MediaProperties.FILE_PNG: {
                     break;
-                case MediaProperties.FILE_PNG:
-                    break;
+                }
 
-                default:
-                throw new IllegalArgumentException("Unsupported Input File Type");
+                default: {
+                    throw new IllegalArgumentException("Unsupported Input File Type");
+                }
             }
         } catch (Exception e) {
-            throw new IllegalArgumentException("Unsupported file or file not found");
+            throw new IllegalArgumentException("Unsupported file or file not found: " + filename);
         }
 
         /**
@@ -130,13 +129,13 @@
         mDurationMs = durationMs;
         mDecodedFilename = String.format(mMANativeHelper.getProjectPath() +
                 "/" + "decoded" + getId()+ ".rgb");
-        final FileOutputStream fl = new FileOutputStream(mDecodedFilename);
-        final DataOutputStream dos = new DataOutputStream(fl);
+
         try {
             mAspectRatio = mMANativeHelper.getAspectRatio(mWidth, mHeight);
         } catch(IllegalArgumentException e) {
             throw new IllegalArgumentException ("Null width and height");
         }
+
         mGeneratedClipHeight = 0;
         mGeneratedClipWidth = 0;
 
@@ -146,9 +145,12 @@
          */
         final Pair<Integer, Integer>[] resolutions =
             MediaProperties.getSupportedResolutions(mAspectRatio);
+
         /**
          *  Get the highest resolution
          */
+        final FileOutputStream fl = new FileOutputStream(mDecodedFilename);
+        final DataOutputStream dos = new DataOutputStream(fl);
         final Pair<Integer, Integer> maxResolution = resolutions[resolutions.length - 1];
         if (mHeight > maxResolution.second) {
             /**
@@ -171,16 +173,16 @@
             int mNewHeight = 0;
             if ((mScaledWidth % 2 ) != 0) {
                 mNewWidth = mScaledWidth - 1;
-            }
-            else {
+            } else {
                 mNewWidth = mScaledWidth;
             }
+
             if ((mScaledHeight % 2 ) != 0) {
                 mNewHeight = mScaledHeight - 1;
-            }
-            else {
+            } else {
                 mNewHeight = mScaledHeight;
             }
+
             final int [] framingBuffer = new int[mNewWidth];
             final ByteBuffer byteBuffer = ByteBuffer.allocate(framingBuffer.length * 4);
             IntBuffer intBuffer;
@@ -195,6 +197,7 @@
                 dos.write(array);
                 tmp += 1;
             }
+
             mScaledWidth = mNewWidth;
             mScaledHeight = mNewHeight;
             scaledImage.recycle();
@@ -204,10 +207,11 @@
                                 + "/" + "scaled" + getId()+ ".JPG");
             if (!((new File(mScaledFilename)).exists())) {
                 super.mRegenerateClip = true;
-                FileOutputStream f1 = new FileOutputStream(mScaledFilename);
+                final FileOutputStream f1 = new FileOutputStream(mScaledFilename);
                 scaledImage.compress(Bitmap.CompressFormat.JPEG, 50,f1);
                 f1.close();
             }
+
             mScaledWidth = scaledImage.getWidth();
             mScaledHeight = scaledImage.getHeight();
 
@@ -215,17 +219,17 @@
             int mNewheight = 0;
             if ((mScaledWidth % 2 ) != 0) {
                 mNewWidth = mScaledWidth - 1;
-            }
-            else {
+            } else {
                 mNewWidth = mScaledWidth;
             }
+
             if ((mScaledHeight % 2 ) != 0) {
                 mNewheight = mScaledHeight - 1;
-            }
-            else {
+            } else {
                 mNewheight = mScaledHeight;
             }
-            Bitmap imageBitmap = BitmapFactory.decodeFile(mScaledFilename);
+
+            final Bitmap imageBitmap = BitmapFactory.decodeFile(mScaledFilename);
             final int [] framingBuffer = new int[mNewWidth];
             ByteBuffer byteBuffer = ByteBuffer.allocate(framingBuffer.length * 4);
             IntBuffer intBuffer;
@@ -240,10 +244,12 @@
                 dos.write(array);
                 tmp += 1;
             }
+
             mScaledWidth = mNewWidth;
             mScaledHeight = mNewheight;
             imageBitmap.recycle();
         }
+
         fl.close();
         System.gc();
     }
@@ -286,7 +292,7 @@
 
     /**
      * @return The file name of image which is decoded and stored
-     * in rgb format
+     * in RGB format
      */
     String getDecodedImageFileName() {
         return mDecodedFilename;
@@ -447,7 +453,7 @@
                  *  Check if the effect overlaps with the end transition
                  */
                 if (effect.getStartTime() + effect.getDuration() >
-                mDurationMs - transitionDurationMs) {
+                    mDurationMs - transitionDurationMs) {
                     mEndTransition.invalidate();
                     break;
                 }
@@ -464,7 +470,7 @@
                      *  Check if the overlay overlaps with the end transition
                      */
                     if (overlay.getStartTime() + overlay.getDuration() >
-                    mDurationMs - transitionDurationMs) {
+                        mDurationMs - transitionDurationMs) {
                         mEndTransition.invalidate();
                         break;
                     }
@@ -648,23 +654,24 @@
             for (int i = 0; i < thumbnailCount; i++) {
                 thumbnailArray[i] = thumbnail;
             }
+
             return thumbnailArray;
-
-
-        }
-        else {
+        } else {
             if (startMs > endMs) {
                 throw new IllegalArgumentException("Start time is greater than end time");
             }
+
             if (endMs > mDurationMs) {
                 throw new IllegalArgumentException("End time is greater than file duration");
             }
+
             if (startMs == endMs) {
                 Bitmap[] bitmap = new Bitmap[1];
                 bitmap[0] = mMANativeHelper.getPixels(getGeneratedImageClip(),
                     width, height,startMs);
                 return bitmap;
             }
+
             return mMANativeHelper.getPixelsList(getGeneratedImageClip(), width,
                 height,startMs,endMs,thumbnailCount);
         }
@@ -704,31 +711,51 @@
          */
         if (mBeginTransition != null) {
             final long transitionDurationMs = mBeginTransition.getDuration();
+            final boolean oldOverlap = isOverlapping(oldStartTimeMs, oldDurationMs, 0,
+                    transitionDurationMs);
+            final boolean newOverlap = isOverlapping(newStartTimeMs, newDurationMs, 0,
+                    transitionDurationMs);
             /**
-             *  If the start time has changed and if the old or the new item
-             *  overlaps with the begin transition, invalidate the transition.
+             * Invalidate transition if:
+             *
+             * 1. New item overlaps the transition, the old one did not
+             * 2. New item does not overlap the transition, the old one did
+             * 3. New and old item overlap the transition if begin or end
+             * time changed
              */
-            if (((oldStartTimeMs != newStartTimeMs)
-                    || (oldDurationMs != newDurationMs) )&&
-                    (isOverlapping(oldStartTimeMs, oldDurationMs, 0, transitionDurationMs) ||
-                    isOverlapping(newStartTimeMs, newDurationMs, 0,
-                    transitionDurationMs))) {
+            if (newOverlap != oldOverlap) { // Overlap has changed
                 mBeginTransition.invalidate();
+            } else if (newOverlap) { // Both old and new overlap
+                if ((oldStartTimeMs != newStartTimeMs) ||
+                        !(oldStartTimeMs + oldDurationMs > transitionDurationMs &&
+                        newStartTimeMs + newDurationMs > transitionDurationMs)) {
+                    mBeginTransition.invalidate();
+                }
             }
         }
 
         if (mEndTransition != null) {
             final long transitionDurationMs = mEndTransition.getDuration();
+            final boolean oldOverlap = isOverlapping(oldStartTimeMs, oldDurationMs,
+                    mDurationMs - transitionDurationMs, transitionDurationMs);
+            final boolean newOverlap = isOverlapping(newStartTimeMs, newDurationMs,
+                    mDurationMs - transitionDurationMs, transitionDurationMs);
             /**
-             *  If the start time + duration has changed and if the old or the new
-             *  item overlaps the end transition, invalidate the transition
+             * Invalidate transition if:
+             *
+             * 1. New item overlaps the transition, the old one did not
+             * 2. New item does not overlap the transition, the old one did
+             * 3. New and old item overlap the transition if begin or end
+             * time changed
              */
-            if (oldStartTimeMs + oldDurationMs != newStartTimeMs + newDurationMs &&
-                    (isOverlapping(oldStartTimeMs, oldDurationMs,
-                    mDurationMs - transitionDurationMs, transitionDurationMs) ||
-                    isOverlapping(newStartTimeMs, newDurationMs,
-                    mDurationMs - transitionDurationMs, transitionDurationMs))) {
+            if (newOverlap != oldOverlap) { // Overlap has changed
                 mEndTransition.invalidate();
+            } else if (newOverlap) { // Both old and new overlap
+                if ((oldStartTimeMs + oldDurationMs != newStartTimeMs + newDurationMs) ||
+                        ((oldStartTimeMs > mDurationMs - transitionDurationMs) ||
+                        newStartTimeMs > mDurationMs - transitionDurationMs)) {
+                    mEndTransition.invalidate();
+                }
             }
         }
     }
@@ -743,10 +770,12 @@
             setGeneratedImageClip(null);
             setRegenerateClip(true);
         }
+
         if (mScaledFilename != null) {
             new File(mScaledFilename).delete();
             mScaledFilename = null;
         }
+
         if (mDecodedFilename != null) {
             new File(mDecodedFilename).delete();
             mDecodedFilename = null;
diff --git a/media/java/android/media/videoeditor/MediaVideoItem.java b/media/java/android/media/videoeditor/MediaVideoItem.java
index 772b360..2981b41 100755
--- a/media/java/android/media/videoeditor/MediaVideoItem.java
+++ b/media/java/android/media/videoeditor/MediaVideoItem.java
@@ -78,12 +78,9 @@
      *
      * @throws IOException if the file cannot be opened for reading
      */
-    public MediaVideoItem(VideoEditor editor, String mediaItemId,
-            String filename,
-            int renderingMode)
-    throws IOException {
-        this(editor, mediaItemId, filename, renderingMode, 0, END_OF_FILE,
-                100, false, null);
+    public MediaVideoItem(VideoEditor editor, String mediaItemId, String filename,
+            int renderingMode) throws IOException {
+        this(editor, mediaItemId, filename, renderingMode, 0, END_OF_FILE, 100, false, null);
     }
 
     /**
@@ -105,20 +102,22 @@
      * @throws IOException if the file cannot be opened for reading
      */
     MediaVideoItem(VideoEditor editor, String mediaItemId, String filename,
-            int renderingMode,
-            long beginMs, long endMs, int volumePercent, boolean muted,
+            int renderingMode, long beginMs, long endMs, int volumePercent, boolean muted,
             String audioWaveformFilename)  throws IOException {
         super(editor, mediaItemId, filename, renderingMode);
+
         if (editor instanceof VideoEditorImpl) {
             mMANativeHelper = ((VideoEditorImpl)editor).getNativeContext();
             mVideoEditor = ((VideoEditorImpl)editor);
         }
-        Properties properties = null;
+
+        final Properties properties;
         try {
              properties = mMANativeHelper.getMediaProperties(filename);
         } catch ( Exception e) {
-            throw new IllegalArgumentException("Unsupported file or file not found");
+            throw new IllegalArgumentException("Unsupported file or file not found: " + filename);
         }
+
         switch (mMANativeHelper.getFileType(properties.fileType)) {
             case MediaProperties.FILE_3GP:
                 break;
@@ -163,8 +162,7 @@
         mMuted = muted;
         mAudioWaveformFilename = audioWaveformFilename;
         if (audioWaveformFilename != null) {
-            mWaveformData =
-                new SoftReference<WaveformData>(
+            mWaveformData = new SoftReference<WaveformData>(
                         new WaveformData(audioWaveformFilename));
         } else {
             mWaveformData = null;
@@ -190,9 +188,11 @@
         if (beginMs > mDurationMs) {
             throw new IllegalArgumentException("setExtractBoundaries: Invalid start time");
         }
+
         if (endMs > mDurationMs) {
             throw new IllegalArgumentException("setExtractBoundaries: Invalid end time");
         }
+
         if ((endMs != -1) && (beginMs >= endMs) ) {
             throw new IllegalArgumentException("setExtractBoundaries: Start time is greater than end time");
         }
@@ -255,18 +255,18 @@
      */
     @Override
     public Bitmap getThumbnail(int width, int height, long timeMs) {
-        if (timeMs > mDurationMs)
-        {
+        if (timeMs > mDurationMs) {
             throw new IllegalArgumentException("Time Exceeds duration");
         }
-        if (timeMs < 0)
-        {
+
+        if (timeMs < 0) {
             throw new IllegalArgumentException("Invalid Time duration");
         }
-        if ((width <=0) || (height <= 0))
-        {
+
+        if ((width <=0) || (height <= 0)) {
             throw new IllegalArgumentException("Invalid Dimensions");
         }
+
         return mMANativeHelper.getPixels(super.getFilename(),
                 width, height,timeMs);
     }
@@ -280,18 +280,21 @@
         if (startMs > endMs) {
             throw new IllegalArgumentException("Start time is greater than end time");
         }
+
         if (endMs > mDurationMs) {
             throw new IllegalArgumentException("End time is greater than file duration");
         }
+
         if ((height <= 0) || (width <= 0)) {
             throw new IllegalArgumentException("Invalid dimension");
         }
+
         if (startMs == endMs) {
-            Bitmap[] bitmap = new Bitmap[1];
-            bitmap[0] = mMANativeHelper.getPixels(super.getFilename(),
-                    width, height,startMs);
+            final Bitmap[] bitmap = new Bitmap[1];
+            bitmap[0] = mMANativeHelper.getPixels(super.getFilename(), width, height,startMs);
             return bitmap;
         }
+
         return mMANativeHelper.getPixelsList(super.getFilename(), width,
                 height,startMs,endMs,thumbnailCount);
     }
@@ -324,40 +327,58 @@
      * {@inheritDoc}
      */
     @Override
-    void invalidateTransitions(long oldStartTimeMs, long oldDurationMs,
-            long newStartTimeMs,
+    void invalidateTransitions(long oldStartTimeMs, long oldDurationMs, long newStartTimeMs,
             long newDurationMs) {
         /**
          *  Check if the item overlaps with the beginning and end transitions
          */
         if (mBeginTransition != null) {
             final long transitionDurationMs = mBeginTransition.getDuration();
+            final boolean oldOverlap = isOverlapping(oldStartTimeMs, oldDurationMs,
+                    mBeginBoundaryTimeMs, transitionDurationMs);
+            final boolean newOverlap = isOverlapping(newStartTimeMs, newDurationMs,
+                    mBeginBoundaryTimeMs, transitionDurationMs);
             /**
-             *  If the start time has changed and if the old or the new item
-             *  overlaps with the begin transition, invalidate the transition.
+             * Invalidate transition if:
+             *
+             * 1. New item overlaps the transition, the old one did not
+             * 2. New item does not overlap the transition, the old one did
+             * 3. New and old item overlap the transition if begin or end
+             * time changed
              */
-            if (((oldStartTimeMs != newStartTimeMs)
-                    || (oldDurationMs != newDurationMs) )&&
-                    (isOverlapping(oldStartTimeMs, oldDurationMs,
-                            mBeginBoundaryTimeMs, transitionDurationMs) ||
-                            isOverlapping(newStartTimeMs, newDurationMs,
-                                    mBeginBoundaryTimeMs, transitionDurationMs))) {
+            if (newOverlap != oldOverlap) { // Overlap has changed
                 mBeginTransition.invalidate();
+            } else if (newOverlap) { // Both old and new overlap
+                if ((oldStartTimeMs != newStartTimeMs) ||
+                        !(oldStartTimeMs + oldDurationMs > transitionDurationMs &&
+                        newStartTimeMs + newDurationMs > transitionDurationMs)) {
+                    mBeginTransition.invalidate();
+                }
             }
         }
 
         if (mEndTransition != null) {
             final long transitionDurationMs = mEndTransition.getDuration();
+            final boolean oldOverlap = isOverlapping(oldStartTimeMs, oldDurationMs,
+                    mEndBoundaryTimeMs - transitionDurationMs, transitionDurationMs);
+            final boolean newOverlap = isOverlapping(newStartTimeMs, newDurationMs,
+                    mEndBoundaryTimeMs - transitionDurationMs, transitionDurationMs);
             /**
-             *  If the start time + duration has changed and if the old or the new
-             *  item overlaps the end transition, invalidate the transition
+             * Invalidate transition if:
+             *
+             * 1. New item overlaps the transition, the old one did not
+             * 2. New item does not overlap the transition, the old one did
+             * 3. New and old item overlap the transition if begin or end
+             * time changed
              */
-            if (oldStartTimeMs + oldDurationMs != newStartTimeMs + newDurationMs &&
-                    (isOverlapping(oldStartTimeMs, oldDurationMs,
-                            mEndBoundaryTimeMs - transitionDurationMs, transitionDurationMs) ||
-                            isOverlapping(newStartTimeMs, newDurationMs,
-                                    mEndBoundaryTimeMs - transitionDurationMs, transitionDurationMs))) {
+            if (newOverlap != oldOverlap) { // Overlap has changed
                 mEndTransition.invalidate();
+            } else if (newOverlap) { // Both old and new overlap
+                if ((oldStartTimeMs + oldDurationMs != newStartTimeMs + newDurationMs) ||
+                        ((oldStartTimeMs > mEndBoundaryTimeMs - transitionDurationMs) ||
+                        newStartTimeMs > mEndBoundaryTimeMs - transitionDurationMs)) {
+                    mEndTransition.invalidate();
+                }
             }
         }
     }
@@ -434,7 +455,7 @@
             throw new IllegalArgumentException("requested time not correct");
         }
 
-        Surface surface = surfaceHolder.getSurface();
+        final Surface surface = surfaceHolder.getSurface();
         if (surface == null) {
             throw new RuntimeException("Surface could not be retrieved from Surface holder");
         }
@@ -442,8 +463,7 @@
         if (mFilename != null) {
             return mMANativeHelper.renderMediaItemPreviewFrame(surface,
                     mFilename,timeMs,mWidth,mHeight);
-        }
-        else {
+        } else {
             return 0;
         }
     }
@@ -462,7 +482,7 @@
      *             Audio track
      */
     public void extractAudioWaveform(ExtractAudioWaveformProgressListener listener)
-    throws IOException {
+        throws IOException {
         int frameDuration = 0;
         int sampleCount = 0;
         final String projectPath = mMANativeHelper.getProjectPath();
@@ -481,19 +501,17 @@
              * Logic to get frame duration = (no. of frames per sample * 1000)/
              * sampling frequency
              */
-            if ( mMANativeHelper.getAudioCodecType(mAudioType) ==
+            if (mMANativeHelper.getAudioCodecType(mAudioType) ==
                 MediaProperties.ACODEC_AMRNB ) {
                 frameDuration = (MediaProperties.SAMPLES_PER_FRAME_AMRNB*1000)/
                 MediaProperties.DEFAULT_SAMPLING_FREQUENCY;
                 sampleCount = MediaProperties.SAMPLES_PER_FRAME_AMRNB;
-            }
-            else if ( mMANativeHelper.getAudioCodecType(mAudioType) ==
+            } else if (mMANativeHelper.getAudioCodecType(mAudioType) ==
                 MediaProperties.ACODEC_AMRWB ) {
                 frameDuration = (MediaProperties.SAMPLES_PER_FRAME_AMRWB * 1000)/
                 MediaProperties.DEFAULT_SAMPLING_FREQUENCY;
                 sampleCount = MediaProperties.SAMPLES_PER_FRAME_AMRWB;
-            }
-            else if ( mMANativeHelper.getAudioCodecType(mAudioType) ==
+            } else if (mMANativeHelper.getAudioCodecType(mAudioType) ==
                 MediaProperties.ACODEC_AAC_LC ) {
                 frameDuration = (MediaProperties.SAMPLES_PER_FRAME_AAC * 1000)/
                 MediaProperties.DEFAULT_SAMPLING_FREQUENCY;
@@ -682,5 +700,4 @@
 
         return clipSettings;
     }
-
 }
diff --git a/media/jni/android_mtp_MtpServer.cpp b/media/jni/android_mtp_MtpServer.cpp
index 241f18a..8908e67 100644
--- a/media/jni/android_mtp_MtpServer.cpp
+++ b/media/jni/android_mtp_MtpServer.cpp
@@ -62,6 +62,7 @@
     String8         mStoragePath;
     uint64_t        mReserveSpace;
     jobject         mJavaServer;
+    bool            mDone;
     int             mFd;
 
 public:
@@ -72,6 +73,7 @@
             mStoragePath(storagePath),
             mReserveSpace(reserveSpace),
             mJavaServer(javaServer),
+            mDone(false),
             mFd(-1)
     {
     }
@@ -94,27 +96,33 @@
 
     virtual bool threadLoop() {
         sMutex.lock();
-        mFd = open("/dev/mtp_usb", O_RDWR);
-        printf("open returned %d\n", mFd);
-        if (mFd < 0) {
-            LOGE("could not open MTP driver\n");
+
+        while (!mDone) {
+            mFd = open("/dev/mtp_usb", O_RDWR);
+            printf("open returned %d\n", mFd);
+            if (mFd < 0) {
+                LOGE("could not open MTP driver\n");
+                sMutex.unlock();
+                return false;
+            }
+
+            mServer = new MtpServer(mFd, mDatabase, AID_MEDIA_RW, 0664, 0775);
+            mServer->addStorage(mStoragePath, mReserveSpace);
+
             sMutex.unlock();
-            return false;
+
+            LOGD("MtpThread mServer->run");
+            mServer->run();
+            sleep(1);
+
+            sMutex.lock();
+
+            close(mFd);
+            mFd = -1;
+            delete mServer;
+            mServer = NULL;
         }
 
-        mServer = new MtpServer(mFd, mDatabase, AID_MEDIA_RW, 0664, 0775);
-        mServer->addStorage(mStoragePath, mReserveSpace);
-        sMutex.unlock();
-
-        LOGD("MtpThread mServer->run");
-        mServer->run();
-
-        sMutex.lock();
-        close(mFd);
-        mFd = -1;
-        delete mServer;
-        mServer = NULL;
-
         JNIEnv* env = AndroidRuntime::getJNIEnv();
         env->SetIntField(mJavaServer, field_context, 0);
         env->DeleteGlobalRef(mJavaServer);
@@ -124,6 +132,12 @@
         return false;
     }
 
+    void stop() {
+        sMutex.lock();
+        mDone = true;
+        sMutex.unlock();
+    }
+
     void sendObjectAdded(MtpObjectHandle handle) {
         sMutex.lock();
         if (mServer)
@@ -181,6 +195,9 @@
 {
 #ifdef HAVE_ANDROID_OS
     LOGD("stop\n");
+    MtpThread *thread = (MtpThread *)env->GetIntField(thiz, field_context);
+    if (thread)
+        thread->stop();
 #endif
 }
 
@@ -212,7 +229,7 @@
     MtpThread *thread = (MtpThread *)env->GetIntField(thiz, field_context);
     if (thread)
         thread->setPtpMode(usePtp);
- #endif
+#endif
 }
 
 // ----------------------------------------------------------------------------
diff --git a/media/jni/mediaeditor/Android.mk b/media/jni/mediaeditor/Android.mk
index 27c41be..0a01fb2 100755
--- a/media/jni/mediaeditor/Android.mk
+++ b/media/jni/mediaeditor/Android.mk
@@ -85,6 +85,6 @@
 # to add this library to the prelink map and set this to true.
 LOCAL_PRELINK_MODULE := false
 
-LOCAL_MODULE_TAGS := eng development
+LOCAL_MODULE_TAGS := optional
 
 include $(BUILD_SHARED_LIBRARY)
diff --git a/media/jni/mediaeditor/VideoEditorLogging.h b/media/jni/mediaeditor/VideoEditorLogging.h
index ca8c047..c13f6ff 100755
--- a/media/jni/mediaeditor/VideoEditorLogging.h
+++ b/media/jni/mediaeditor/VideoEditorLogging.h
@@ -21,12 +21,13 @@
 
 #define VIDEOEDIT_LOG_INDENTATION                       (3)
 
+#define VIDEOEDIT_LOG_ERROR                             __android_log_print
+#define VIDEOEDIT_LOG_EXCEPTION                         __android_log_print
+
 #ifdef VIDEOEDIT_LOGGING_ENABLED
 
 #define VIDEOEDIT_LOG_ALLOCATION                        __android_log_print
 #define VIDEOEDIT_LOG_API                               __android_log_print
-#define VIDEOEDIT_LOG_ERROR                             __android_log_print
-#define VIDEOEDIT_LOG_EXCEPTION                         __android_log_print
 #define VIDEOEDIT_LOG_FUNCTION                          __android_log_print
 #define VIDEOEDIT_LOG_RESULT(x,y, ...)                     LOGI(y, __VA_ARGS__ )
 #define VIDEOEDIT_LOG_SETTING                           __android_log_print
@@ -40,8 +41,6 @@
 
 #define VIDEOEDIT_LOG_ALLOCATION                        (void)
 #define VIDEOEDIT_LOG_API                               (void)
-#define VIDEOEDIT_LOG_ERROR                             (void)
-#define VIDEOEDIT_LOG_EXCEPTION                         (void)
 #define VIDEOEDIT_LOG_FUNCTION                          (void)
 #define VIDEOEDIT_LOG_RESULT                            (void)
 #define VIDEOEDIT_LOG_SETTING                           (void)
diff --git a/media/jni/mediaeditor/VideoEditorMain.cpp b/media/jni/mediaeditor/VideoEditorMain.cpp
index e66e4b9..643f698 100755
--- a/media/jni/mediaeditor/VideoEditorMain.cpp
+++ b/media/jni/mediaeditor/VideoEditorMain.cpp
@@ -437,7 +437,7 @@
     VideoEditor_renderPreviewFrameStr frameStr;
     M4OSA_Context tnContext = M4OSA_NULL;
     const char* pMessage = NULL;
-    M4VIFI_ImagePlane *yuvPlane;
+    M4VIFI_ImagePlane *yuvPlane = NULL;
 
     VIDEOEDIT_LOG_FUNCTION(ANDROID_LOG_INFO,
         "VIDEO_EDITOR", "surfaceWidth = %d",surfaceWidth);
@@ -1179,7 +1179,7 @@
     }
 
     /** Remove the alpha channel */
-    for (int i = 0, j = 0; i < frameSize_argb; i++) {
+    for (size_t i = 0, j = 0; i < frameSize_argb; i++) {
         if ((i % 4) == 0) continue;
         pFramingCtx->FramingRgb->pac_data[j] = pTmpData[i];
         j++;
@@ -2729,7 +2729,7 @@
 } M4AM_Buffer;
 
 
-M4OSA_UInt8 logLookUp[256]{
+M4OSA_UInt8 logLookUp[256] = {
 0,120,137,146,154,159,163,167,171,173,176,178,181,182,184,186,188,189,190,192,193,
 194,195,196,198,199,199,200,201,202,203,204,205,205,206,207,207,208,209,209,210,
 211,211,212,212,213,213,214,215,215,216,216,216,217,217,218,218,219,219,220,220,
@@ -2788,7 +2788,7 @@
     err = M4OSA_fileReadOpen (&inputFileHandle, pInputFileURL, M4OSA_kFileRead);
     if (inputFileHandle == M4OSA_NULL) {
         VIDEOEDIT_LOG_ERROR(ANDROID_LOG_INFO, "VIDEO_EDITOR",
-            "M4MA_generateAudioGraphFile: Cannot open input file 0x%x", err);
+            "M4MA_generateAudioGraphFile: Cannot open input file 0x%lx", err);
         return err;
     }
 
@@ -2822,7 +2822,7 @@
         bufferIn.m_bufferSize = samplesCountInBytes*sizeof(M4OSA_UInt16);
     } else {
         VIDEOEDIT_LOG_ERROR(ANDROID_LOG_INFO, "VIDEO_EDITOR",
-            "M4MA_generateAudioGraphFile: Malloc failed for bufferIn.m_dataAddress 0x%x",\
+            "M4MA_generateAudioGraphFile: Malloc failed for bufferIn.m_dataAddress 0x%lx",
             M4ERR_ALLOC);
         return M4ERR_ALLOC;
     }
@@ -2862,7 +2862,7 @@
         if (err != M4NO_ERROR) {
             // if out value of bytes-read is 0, break
             if ( numBytesToRead == 0) {
-                VIDEOEDIT_LOG_ERROR(ANDROID_LOG_INFO, "VIDEO_EDITOR", "numBytesToRead 0x%x",\
+                VIDEOEDIT_LOG_ERROR(ANDROID_LOG_INFO, "VIDEO_EDITOR", "numBytesToRead 0x%lx",
                 numBytesToRead);
                 break; /* stop if file is empty or EOF */
             }
@@ -2914,7 +2914,7 @@
 
     } while (numBytesToRead != 0);
 
-    VIDEOEDIT_LOG_ERROR(ANDROID_LOG_INFO, "VIDEO_EDITOR", "loop 0x%x", volumeValuesCount);
+    VIDEOEDIT_LOG_ERROR(ANDROID_LOG_INFO, "VIDEO_EDITOR", "loop 0x%lx", volumeValuesCount);
 
     /* if some error occured in fwrite */
     if (numBytesToRead != 0) {
diff --git a/media/libmedia/IOMX.cpp b/media/libmedia/IOMX.cpp
index 9ce6738..af67175 100644
--- a/media/libmedia/IOMX.cpp
+++ b/media/libmedia/IOMX.cpp
@@ -5,6 +5,7 @@
 #include <binder/IMemory.h>
 #include <binder/Parcel.h>
 #include <media/IOMX.h>
+#include <media/stagefright/foundation/ADebug.h>
 #include <surfaceflinger/ISurface.h>
 #include <surfaceflinger/Surface.h>
 
@@ -449,74 +450,8 @@
         }
 
         case GET_PARAMETER:
-        {
-            CHECK_INTERFACE(IOMX, data, reply);
-
-            node_id node = (void*)data.readIntPtr();
-            OMX_INDEXTYPE index = static_cast<OMX_INDEXTYPE>(data.readInt32());
-
-            size_t size = data.readInt32();
-
-            // XXX I am not happy with this but Parcel::readInplace didn't work.
-            void *params = malloc(size);
-            data.read(params, size);
-
-            status_t err = getParameter(node, index, params, size);
-
-            reply->writeInt32(err);
-
-            if (err == OK) {
-                reply->write(params, size);
-            }
-
-            free(params);
-            params = NULL;
-
-            return NO_ERROR;
-        }
-
         case SET_PARAMETER:
-        {
-            CHECK_INTERFACE(IOMX, data, reply);
-
-            node_id node = (void*)data.readIntPtr();
-            OMX_INDEXTYPE index = static_cast<OMX_INDEXTYPE>(data.readInt32());
-
-            size_t size = data.readInt32();
-            void *params = const_cast<void *>(data.readInplace(size));
-
-            reply->writeInt32(setParameter(node, index, params, size));
-
-            return NO_ERROR;
-        }
-
         case GET_CONFIG:
-        {
-            CHECK_INTERFACE(IOMX, data, reply);
-
-            node_id node = (void*)data.readIntPtr();
-            OMX_INDEXTYPE index = static_cast<OMX_INDEXTYPE>(data.readInt32());
-
-            size_t size = data.readInt32();
-
-            // XXX I am not happy with this but Parcel::readInplace didn't work.
-            void *params = malloc(size);
-            data.read(params, size);
-
-            status_t err = getConfig(node, index, params, size);
-
-            reply->writeInt32(err);
-
-            if (err == OK) {
-                reply->write(params, size);
-            }
-
-            free(params);
-            params = NULL;
-
-            return NO_ERROR;
-        }
-
         case SET_CONFIG:
         {
             CHECK_INTERFACE(IOMX, data, reply);
@@ -525,9 +460,36 @@
             OMX_INDEXTYPE index = static_cast<OMX_INDEXTYPE>(data.readInt32());
 
             size_t size = data.readInt32();
-            void *params = const_cast<void *>(data.readInplace(size));
 
-            reply->writeInt32(setConfig(node, index, params, size));
+            void *params = malloc(size);
+            data.read(params, size);
+
+            status_t err;
+            switch (code) {
+                case GET_PARAMETER:
+                    err = getParameter(node, index, params, size);
+                    break;
+                case SET_PARAMETER:
+                    err = setParameter(node, index, params, size);
+                    break;
+                case GET_CONFIG:
+                    err = getConfig(node, index, params, size);
+                    break;
+                case SET_CONFIG:
+                    err = setConfig(node, index, params, size);
+                    break;
+                default:
+                    TRESPASS();
+            }
+
+            reply->writeInt32(err);
+
+            if ((code == GET_PARAMETER || code == GET_CONFIG) && err == OK) {
+                reply->write(params, size);
+            }
+
+            free(params);
+            params = NULL;
 
             return NO_ERROR;
         }
diff --git a/media/libmediaplayerservice/StagefrightRecorder.cpp b/media/libmediaplayerservice/StagefrightRecorder.cpp
index 54e515a..153b2a6 100644
--- a/media/libmediaplayerservice/StagefrightRecorder.cpp
+++ b/media/libmediaplayerservice/StagefrightRecorder.cpp
@@ -1229,25 +1229,13 @@
     }
     if (mVideoEncoderLevel != -1) {
         enc_meta->setInt32(kKeyVideoLevel, mVideoEncoderLevel);
-    } else if (mCaptureTimeLapse) {
-        // Check if we are using high resolution and/or high bitrate and
-        // set appropriate level for the software AVCEncoder.
-        if ((width * height >= 921600) // 720p
-                || (videoBitRate >= 20000000)) {
-            enc_meta->setInt32(kKeyVideoLevel, OMX_VIDEO_AVCLevel5);
-        }
     }
 
     OMXClient client;
     CHECK_EQ(client.connect(), OK);
 
-    // Use software codec for time lapse
     uint32_t encoder_flags = 0;
-    if (mCaptureTimeLapse) {
-        // Do not use software encoder for timelapse for now
-        // It is _very_ slow and the preview appears sluggish
-        //encoder_flags |= OMXCodec::kPreferSoftwareCodecs;
-    } else if (mIsMetaDataStoredInVideoBuffers) {
+    if (mIsMetaDataStoredInVideoBuffers) {
         encoder_flags |= OMXCodec::kHardwareCodecsOnly;
         encoder_flags |= OMXCodec::kStoreMetaDataInVideoBuffers;
     }
diff --git a/media/libstagefright/AwesomePlayer.cpp b/media/libstagefright/AwesomePlayer.cpp
index 49d05ed..11ac56c 100644
--- a/media/libstagefright/AwesomePlayer.cpp
+++ b/media/libstagefright/AwesomePlayer.cpp
@@ -58,6 +58,8 @@
 
 static int64_t kLowWaterMarkUs = 2000000ll;  // 2secs
 static int64_t kHighWaterMarkUs = 10000000ll;  // 10secs
+static const size_t kLowWaterMarkBytes = 40000;
+static const size_t kHighWaterMarkBytes = 200000;
 
 struct AwesomeEvent : public TimedEventQueue::Event {
     AwesomeEvent(
@@ -165,6 +167,8 @@
       mTimeSource(NULL),
       mVideoRendererIsPreview(false),
       mAudioPlayer(NULL),
+      mDisplayWidth(0),
+      mDisplayHeight(0),
       mFlags(0),
       mExtractorFlags(0),
       mVideoBuffer(NULL),
@@ -329,6 +333,18 @@
         if (!haveVideo && !strncasecmp(mime, "video/", 6)) {
             setVideoSource(extractor->getTrack(i));
             haveVideo = true;
+
+            // Set the presentation/display size
+            int32_t displayWidth, displayHeight;
+            bool success = meta->findInt32(kKeyDisplayWidth, &displayWidth);
+            if (success) {
+                success = meta->findInt32(kKeyDisplayHeight, &displayHeight);
+            }
+            if (success) {
+                mDisplayWidth = displayWidth;
+                mDisplayHeight = displayHeight;
+            }
+
         } else if (!haveAudio && !strncasecmp(mime, "audio/", 6)) {
             setAudioSource(extractor->getTrack(i));
             haveAudio = true;
@@ -370,6 +386,8 @@
 
 void AwesomePlayer::reset_l() {
     LOGI("reset_l");
+    mDisplayWidth = 0;
+    mDisplayHeight = 0;
 
     if (mDecryptHandle != NULL) {
             mDrmManagerClient->setPlaybackStatus(mDecryptHandle,
@@ -594,9 +612,6 @@
                 // We don't know the bitrate of the stream, use absolute size
                 // limits to maintain the cache.
 
-                const size_t kLowWaterMarkBytes = 40000;
-                const size_t kHighWaterMarkBytes = 200000;
-
                 if ((mFlags & PLAYING) && !eos
                         && (cachedDataRemaining < kLowWaterMarkBytes)) {
                     LOGI("cache is running low (< %d) , pausing.",
@@ -862,6 +877,12 @@
 
     int32_t usableWidth = cropRight - cropLeft + 1;
     int32_t usableHeight = cropBottom - cropTop + 1;
+    if (mDisplayWidth != 0) {
+        usableWidth = mDisplayWidth;
+    }
+    if (mDisplayHeight != 0) {
+        usableHeight = mDisplayHeight;
+    }
 
     int32_t rotationDegrees;
     if (!mVideoTrack->getFormat()->findInt32(
@@ -1513,6 +1534,34 @@
         mConnectingDataSource.clear();
 
         dataSource = mCachedSource;
+
+        // We're going to prefill the cache before trying to instantiate
+        // the extractor below, as the latter is an operation that otherwise
+        // could block on the datasource for a significant amount of time.
+        // During that time we'd be unable to abort the preparation phase
+        // without this prefill.
+
+        mLock.unlock();
+
+        for (;;) {
+            status_t finalStatus;
+            size_t cachedDataRemaining =
+                mCachedSource->approxDataRemaining(&finalStatus);
+
+            if (finalStatus != OK || cachedDataRemaining >= kHighWaterMarkBytes
+                    || (mFlags & PREPARE_CANCELLED)) {
+                break;
+            }
+
+            usleep(200000);
+        }
+
+        mLock.lock();
+
+        if (mFlags & PREPARE_CANCELLED) {
+            LOGI("Prepare cancelled while waiting for initial cache fill.");
+            return UNKNOWN_ERROR;
+        }
     } else if (!strncasecmp(mUri.string(), "httplive://", 11)) {
         String8 uri("http://");
         uri.append(mUri.string() + 11);
diff --git a/media/libstagefright/CameraSourceTimeLapse.cpp b/media/libstagefright/CameraSourceTimeLapse.cpp
index 31b6ec9..b58b9d8 100644
--- a/media/libstagefright/CameraSourceTimeLapse.cpp
+++ b/media/libstagefright/CameraSourceTimeLapse.cpp
@@ -66,7 +66,7 @@
         int32_t videoFrameRate,
         const sp<Surface>& surface,
         int64_t timeBetweenTimeLapseFrameCaptureUs)
-    : CameraSource(camera, cameraId, videoSize, videoFrameRate, surface, false),
+    : CameraSource(camera, cameraId, videoSize, videoFrameRate, surface, true),
       mTimeBetweenTimeLapseFrameCaptureUs(timeBetweenTimeLapseFrameCaptureUs),
       mTimeBetweenTimeLapseVideoFramesUs(1E6/videoFrameRate),
       mLastTimeLapseFrameRealTimestampUs(0),
diff --git a/media/libstagefright/HTTPStream.cpp b/media/libstagefright/HTTPStream.cpp
index e7f00aa..057868c 100644
--- a/media/libstagefright/HTTPStream.cpp
+++ b/media/libstagefright/HTTPStream.cpp
@@ -25,13 +25,14 @@
 #include <arpa/inet.h>
 #include <ctype.h>
 #include <errno.h>
+#include <fcntl.h>
 #include <netdb.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 #include <unistd.h>
 
-#include <media/stagefright/MediaDebug.h>
+#include <media/stagefright/foundation/ADebug.h>
 
 namespace android {
 
@@ -47,6 +48,82 @@
     disconnect();
 }
 
+static bool MakeSocketBlocking(int s, bool blocking) {
+    // Make socket non-blocking.
+    int flags = fcntl(s, F_GETFL, 0);
+    if (flags == -1) {
+        return false;
+    }
+
+    if (blocking) {
+        flags &= ~O_NONBLOCK;
+    } else {
+        flags |= O_NONBLOCK;
+    }
+
+    return fcntl(s, F_SETFL, flags) != -1;
+}
+
+static status_t MyConnect(
+        int s, const struct sockaddr *addr, socklen_t addrlen) {
+    status_t result = UNKNOWN_ERROR;
+
+    MakeSocketBlocking(s, false);
+
+    if (connect(s, addr, addrlen) == 0) {
+        result = OK;
+    } else if (errno != EINPROGRESS) {
+        result = -errno;
+    } else {
+        for (;;) {
+            fd_set rs, ws;
+            FD_ZERO(&rs);
+            FD_ZERO(&ws);
+            FD_SET(s, &rs);
+            FD_SET(s, &ws);
+
+            struct timeval tv;
+            tv.tv_sec = 0;
+            tv.tv_usec = 100000ll;
+
+            int nfds = ::select(s + 1, &rs, &ws, NULL, &tv);
+
+            if (nfds < 0) {
+                if (errno == EINTR) {
+                    continue;
+                }
+
+                result = -errno;
+                break;
+            }
+
+            if (FD_ISSET(s, &ws) && !FD_ISSET(s, &rs)) {
+                result = OK;
+                break;
+            }
+
+            if (FD_ISSET(s, &rs) || FD_ISSET(s, &ws)) {
+                // Get the pending error.
+                int error = 0;
+                socklen_t errorLen = sizeof(error);
+                if (getsockopt(s, SOL_SOCKET, SO_ERROR, &error, &errorLen) == -1) {
+                    // Couldn't get the real error, so report why not.
+                    result = -errno;
+                } else {
+                    result = -error;
+                }
+                break;
+            }
+
+            // Timeout expired. Try again.
+        }
+    }
+
+    MakeSocketBlocking(s, true);
+
+    return result;
+}
+
 status_t HTTPStream::connect(const char *server, int port) {
     Mutex::Autolock autoLock(mLock);
 
@@ -82,7 +159,7 @@
     addr.sin_addr.s_addr = *(in_addr_t *)ent->h_addr;
     memset(addr.sin_zero, 0, sizeof(addr.sin_zero));
 
-    int res = ::connect(s, (const struct sockaddr *)&addr, sizeof(addr));
+    status_t res = MyConnect(s, (const struct sockaddr *)&addr, sizeof(addr));
 
     mLock.lock();
 
@@ -90,12 +167,12 @@
         return UNKNOWN_ERROR;
     }
 
-    if (res < 0) {
+    if (res != OK) {
         close(mSocket);
         mSocket = -1;
 
         mState = READY;
-        return UNKNOWN_ERROR;
+        return res;
     }
 
     mState = CONNECTED;
diff --git a/media/libstagefright/MPEG4Extractor.cpp b/media/libstagefright/MPEG4Extractor.cpp
index bafa243..e6e98aa 100644
--- a/media/libstagefright/MPEG4Extractor.cpp
+++ b/media/libstagefright/MPEG4Extractor.cpp
@@ -1040,8 +1040,23 @@
             // have a 4 byte header (0x00 0x00 0x00 0x01) after conversion,
             // and thus will grow by 2 bytes per fragment.
             mLastTrack->meta->setInt32(kKeyMaxInputSize, max_size + 10 * 2);
-
             *offset += chunk_size;
+
+            // Calculate average frame rate.
+            const char *mime;
+            CHECK(mLastTrack->meta->findCString(kKeyMIMEType, &mime));
+            if (!strncasecmp("video/", mime, 6)) {
+                size_t nSamples = mLastTrack->sampleTable->countSamples();
+                int64_t durationUs;
+                if (mLastTrack->meta->findInt64(kKeyDuration, &durationUs)) {
+                    if (durationUs > 0) {
+                        int32_t frameRate = (nSamples * 1000000LL +
+                                    (durationUs >> 1)) / durationUs;
+                        mLastTrack->meta->setInt32(kKeyFrameRate, frameRate);
+                    }
+                }
+            }
+
             break;
         }
 
@@ -1321,10 +1336,12 @@
         mLastTrack->meta->setInt32(kKeyRotation, rotationDegrees);
     }
 
-#if 0
+    // Handle presentation display size, which could be different
+    // from the image size indicated by kKeyWidth and kKeyHeight.
     uint32_t width = U32_AT(&buffer[dynSize + 52]);
     uint32_t height = U32_AT(&buffer[dynSize + 56]);
-#endif
+    mLastTrack->meta->setInt32(kKeyDisplayWidth, width >> 16);
+    mLastTrack->meta->setInt32(kKeyDisplayHeight, height >> 16);
 
     return OK;
 }
diff --git a/media/libstagefright/MPEG4Writer.cpp b/media/libstagefright/MPEG4Writer.cpp
index 06c4c98..a47ee3a 100644
--- a/media/libstagefright/MPEG4Writer.cpp
+++ b/media/libstagefright/MPEG4Writer.cpp
@@ -590,6 +590,7 @@
 
     status_t err = OK;
     int64_t maxDurationUs = 0;
+    int64_t minDurationUs = 0x7fffffffffffffffLL;
     for (List<Track *>::iterator it = mTracks.begin();
          it != mTracks.end(); ++it) {
         status_t status = (*it)->stop();
@@ -601,6 +602,14 @@
         if (durationUs > maxDurationUs) {
             maxDurationUs = durationUs;
         }
+        if (durationUs < minDurationUs) {
+            minDurationUs = durationUs;
+        }
+    }
+
+    if (mTracks.size() > 1) {
+        LOGD("Duration from tracks range is [%lld, %lld] us",
+            minDurationUs, maxDurationUs);
     }
 
     stopWriterThread();
diff --git a/media/libstagefright/NuCachedSource2.cpp b/media/libstagefright/NuCachedSource2.cpp
index 20f1655..741aa1c 100644
--- a/media/libstagefright/NuCachedSource2.cpp
+++ b/media/libstagefright/NuCachedSource2.cpp
@@ -14,6 +14,7 @@
  * limitations under the License.
  */
 
+//#define LOG_NDEBUG 0
 #define LOG_TAG "NuCachedSource2"
 #include <utils/Log.h>
 
@@ -487,4 +488,5 @@
 String8 NuCachedSource2::getUri() {
     return mSource->getUri();
 }
+
 }  // namespace android
diff --git a/media/libstagefright/OMXCodec.cpp b/media/libstagefright/OMXCodec.cpp
index e516cb4..d842f65 100644
--- a/media/libstagefright/OMXCodec.cpp
+++ b/media/libstagefright/OMXCodec.cpp
@@ -2233,7 +2233,11 @@
                 enablePortAsync(portIndex);
 
                 status_t err = allocateBuffersOnPort(portIndex);
-                CHECK_EQ(err, (status_t)OK);
+
+                if (err != OK) {
+                    CODEC_LOGE("allocateBuffersOnPort failed (err = %d)", err);
+                    setState(ERROR);
+                }
             }
             break;
         }
diff --git a/media/libstagefright/httplive/LiveSession.cpp b/media/libstagefright/httplive/LiveSession.cpp
index 5979be6..f20a4cb 100644
--- a/media/libstagefright/httplive/LiveSession.cpp
+++ b/media/libstagefright/httplive/LiveSession.cpp
@@ -438,8 +438,7 @@
 
     if (mSeqNumber < firstSeqNumberInPlaylist
             || mSeqNumber > lastSeqNumberInPlaylist) {
-        if (mSeqNumber < firstSeqNumberInPlaylist
-                && mPrevBandwidthIndex != (ssize_t)bandwidthIndex) {
+        if (mPrevBandwidthIndex != (ssize_t)bandwidthIndex) {
             // Go back to the previous bandwidth.
 
             LOGI("new bandwidth does not have the sequence number "
@@ -493,8 +492,14 @@
 
     CHECK(buffer != NULL);
 
-    CHECK_EQ((status_t)OK,
-             decryptBuffer(mSeqNumber - firstSeqNumberInPlaylist, buffer));
+    err = decryptBuffer(mSeqNumber - firstSeqNumberInPlaylist, buffer);
+
+    if (err != OK) {
+        LOGE("decryptBuffer failed w/ error %d", err);
+
+        mDataSource->queueEOS(err);
+        return;
+    }
 
     if (buffer->size() == 0 || buffer->data()[0] != 0x47) {
         // Not a transport stream???
diff --git a/media/libstagefright/include/AwesomePlayer.h b/media/libstagefright/include/AwesomePlayer.h
index fe008569..41ef181 100644
--- a/media/libstagefright/include/AwesomePlayer.h
+++ b/media/libstagefright/include/AwesomePlayer.h
@@ -150,6 +150,9 @@
     AudioPlayer *mAudioPlayer;
     int64_t mDurationUs;
 
+    int32_t mDisplayWidth;
+    int32_t mDisplayHeight;
+
     uint32_t mFlags;
     uint32_t mExtractorFlags;
     uint32_t mSinceLastDropped;
diff --git a/opengl/java/android/opengl/GLSurfaceView.java b/opengl/java/android/opengl/GLSurfaceView.java
index 4099c4c..32d1a23 100644
--- a/opengl/java/android/opengl/GLSurfaceView.java
+++ b/opengl/java/android/opengl/GLSurfaceView.java
@@ -272,7 +272,6 @@
     }
 
     /**
-     * @hide
      * Control whether the EGL context is preserved when the GLSurfaceView is paused and
      * resumed.
      * <p>
@@ -295,7 +294,6 @@
     }
 
     /**
-     * @hide
      * @return true if the EGL context will be preserved when paused
      */
     public boolean getPreserveEGLContextOnPause() {
diff --git a/packages/SystemUI/res/layout-xlarge/status_bar.xml b/packages/SystemUI/res/layout-xlarge/status_bar.xml
index 0533b6f..852b729 100644
--- a/packages/SystemUI/res/layout-xlarge/status_bar.xml
+++ b/packages/SystemUI/res/layout-xlarge/status_bar.xml
@@ -78,15 +78,14 @@
             </LinearLayout>
 
             <!-- fake space bar zone -->
-            <com.android.systemui.statusbar.policy.KeyButtonView android:id="@+id/fake_space_bar"
+            <com.android.systemui.statusbar.policy.EventHole android:id="@+id/fake_space_bar"
                 android:layout_height="match_parent"
-                android:layout_width="match_parent"
+                android:layout_width="0dp"
                 android:paddingLeft="8dip"
                 android:paddingRight="8dip"
                 android:layout_toRightOf="@+id/navigationArea"
                 android:layout_toLeftOf="@+id/notificationArea"
                 android:visibility="gone"
-                systemui:keyCode="62"
                 />
         </RelativeLayout>
     </FrameLayout>
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/EventHole.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/EventHole.java
new file mode 100644
index 0000000..47e758c
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/EventHole.java
@@ -0,0 +1,99 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.policy;
+
+import android.content.Context;
+import android.content.res.TypedArray;
+import android.graphics.Region;
+import android.graphics.drawable.AnimationDrawable;
+import android.graphics.drawable.Drawable;
+import android.os.RemoteException;
+import android.os.SystemClock;
+import android.os.ServiceManager;
+import android.util.AttributeSet;
+import android.util.Slog;
+import android.view.HapticFeedbackConstants;
+import android.view.IWindowManager;
+import android.view.InputDevice;
+import android.view.KeyCharacterMap;
+import android.view.KeyEvent;
+import android.view.MotionEvent;
+import android.view.View;
+import android.view.ViewConfiguration;
+import android.view.ViewTreeObserver;
+import android.widget.RemoteViews.RemoteView;
+
+import com.android.systemui.R;
+
+public class EventHole extends View implements ViewTreeObserver.OnComputeInternalInsetsListener {
+    private static final String TAG = "StatusBar.EventHole";
+
+    private boolean mWindowVis;
+    private int[] mLoc = new int[2];
+
+    public EventHole(Context context, AttributeSet attrs) {
+        this(context, attrs, 0);
+    }
+
+    public EventHole(Context context, AttributeSet attrs, int defStyle) {
+        super(context, attrs);
+    }
+
+    @Override
+    protected void onWindowVisibilityChanged(int visibility) {
+        super.onWindowVisibilityChanged(visibility);
+        mWindowVis = visibility == View.VISIBLE;
+    }
+
+    @Override
+    protected void onAttachedToWindow() {
+        super.onAttachedToWindow();
+        getViewTreeObserver().addOnComputeInternalInsetsListener(this);
+    }
+
+    @Override
+    protected void onDetachedFromWindow() {
+        super.onDetachedFromWindow();
+        getViewTreeObserver().removeOnComputeInternalInsetsListener(this);
+    }
+
+    public void onComputeInternalInsets(ViewTreeObserver.InternalInsetsInfo info) {
+        final boolean visible = isShown() && mWindowVis && getWidth() > 0 && getHeight() > 0;
+        final int[] loc = mLoc;
+        getLocationInWindow(loc);
+        final int l = loc[0];
+        final int r = l + getWidth();
+        final int t = loc[1];
+        final int b = t + getHeight();
+        
+        View top = this;
+        while (top.getParent() instanceof View) {
+            top = (View)top.getParent();
+        }
+
+        if (visible) {
+            info.setTouchableInsets(
+                    ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_REGION);
+            info.touchableRegion.set(0, 0, top.getWidth(), top.getHeight());
+            info.touchableRegion.op(l, t, r, b, Region.Op.DIFFERENCE);
+        } else {
+            info.setTouchableInsets(
+                    ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_FRAME);
+        }
+    }
+}
+
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/NotificationPanel.java b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/NotificationPanel.java
index 45a22b6..800f4b4 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/NotificationPanel.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/NotificationPanel.java
@@ -52,7 +52,7 @@
     View mNotificationScroller;
     View mNotificationGlow;
     ViewGroup mContentFrame;
-    Rect mContentArea;
+    Rect mContentArea = new Rect();
     View mSettingsView;
     View mScrim, mGlow;
     ViewGroup mContentParent;
@@ -136,7 +136,6 @@
     @Override
     public void onSizeChanged(int w, int h, int oldw, int oldh) {
         super.onSizeChanged(w, h, oldw, oldh);
-        mContentArea = null;
     }
 
     public void onClick(View v) {
@@ -165,13 +164,11 @@
     }
 
     public boolean isInContentArea(int x, int y) {
-        if (mContentArea == null) {
-            mContentArea = new Rect(mContentFrame.getLeft(),
-                    mTitleArea.getTop(),
-                    mContentFrame.getRight(),
-                    mContentFrame.getBottom());
-            offsetDescendantRectToMyCoords(mContentParent, mContentArea);
-        }
+        mContentArea.left = mContentFrame.getLeft();
+        mContentArea.top = mTitleArea.getTop();
+        mContentArea.right = mContentFrame.getRight();
+        mContentArea.bottom = mContentFrame.getBottom();
+        offsetDescendantRectToMyCoords(mContentParent, mContentArea);
         return mContentArea.contains(x, y);
     }
 
diff --git a/packages/VpnServices/src/com/android/server/vpn/VpnService.java b/packages/VpnServices/src/com/android/server/vpn/VpnService.java
index 63b87b1..a618423 100644
--- a/packages/VpnServices/src/com/android/server/vpn/VpnService.java
+++ b/packages/VpnServices/src/com/android/server/vpn/VpnService.java
@@ -328,6 +328,7 @@
             public void run() {
                 Log.i(TAG, "VPN connectivity monitor running");
                 try {
+                    mNotification.update(mStartTime); // to pop up notification
                     for (int i = 10; ; i--) {
                         long now = System.currentTimeMillis();
 
@@ -417,13 +418,27 @@
 
     // Helper class for showing, updating notification.
     private class NotificationHelper {
+        private NotificationManager mNotificationManager = (NotificationManager)
+                mContext.getSystemService(Context.NOTIFICATION_SERVICE);
+        private Notification mNotification =
+                new Notification(R.drawable.vpn_connected, null, 0L);
+        private PendingIntent mPendingIntent = PendingIntent.getActivity(
+                mContext, 0,
+                new VpnManager(mContext).createSettingsActivityIntent(), 0);
+        private String mConnectedTitle;
+
         void update(long now) {
-            String title = getNotificationTitle(true);
-            Notification n = new Notification(R.drawable.vpn_connected, title,
-                    mStartTime);
-            n.setLatestEventInfo(mContext, title,
+            Notification n = mNotification;
+            if (now == mStartTime) {
+                // to pop up the notification for the first time
+                n.when = mStartTime;
+                n.tickerText = mConnectedTitle = getNotificationTitle(true);
+            } else {
+                n.tickerText = null;
+            }
+            n.setLatestEventInfo(mContext, mConnectedTitle,
                     getConnectedNotificationMessage(now),
-                    prepareNotificationIntent());
+                    mPendingIntent);
             n.flags |= Notification.FLAG_NO_CLEAR;
             n.flags |= Notification.FLAG_ONGOING_EVENT;
             enableNotification(n);
@@ -435,25 +450,18 @@
                     title, System.currentTimeMillis());
             n.setLatestEventInfo(mContext, title,
                     getDisconnectedNotificationMessage(),
-                    prepareNotificationIntent());
+                    mPendingIntent);
             n.flags |= Notification.FLAG_AUTO_CANCEL;
             disableNotification();
             enableNotification(n);
         }
 
         void disableNotification() {
-            ((NotificationManager) mContext.getSystemService(
-                    Context.NOTIFICATION_SERVICE)).cancel(NOTIFICATION_ID);
+            mNotificationManager.cancel(NOTIFICATION_ID);
         }
 
         private void enableNotification(Notification n) {
-            ((NotificationManager) mContext.getSystemService(
-                    Context.NOTIFICATION_SERVICE)).notify(NOTIFICATION_ID, n);
-        }
-
-        private PendingIntent prepareNotificationIntent() {
-            return PendingIntent.getActivity(mContext, 0,
-                    new VpnManager(mContext).createSettingsActivityIntent(), 0);
+            mNotificationManager.notify(NOTIFICATION_ID, n);
         }
 
         private String getNotificationTitle(boolean connected) {
diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindow.java b/policy/src/com/android/internal/policy/impl/PhoneWindow.java
index fb20e81..c313713b 100644
--- a/policy/src/com/android/internal/policy/impl/PhoneWindow.java
+++ b/policy/src/com/android/internal/policy/impl/PhoneWindow.java
@@ -1985,6 +1985,7 @@
                 }
 
                 if (mActionModeView != null) {
+                    mActionModeView.killMode();
                     mode = new StandaloneActionMode(getContext(), mActionModeView, wrappedCallback);
                     if (callback.onCreateActionMode(mode, mode.getMenu())) {
                         mode.invalidate();
@@ -2330,12 +2331,10 @@
         
         if (mAlwaysReadCloseOnTouchAttr || getContext().getApplicationInfo().targetSdkVersion
                 >= android.os.Build.VERSION_CODES.HONEYCOMB) {
-            if (!hasSetCloseOnTouchOutside()) {
-                if (a.getBoolean(
-                        com.android.internal.R.styleable.Window_windowCloseOnTouchOutside,
-                        false)) {
-                    setCloseOnTouchOutside(true);
-                }
+            if (a.getBoolean(
+                    com.android.internal.R.styleable.Window_windowCloseOnTouchOutside,
+                    false)) {
+                setCloseOnTouchOutsideIfNotSet(true);
             }
         }
         
diff --git a/services/audioflinger/AudioFlinger.cpp b/services/audioflinger/AudioFlinger.cpp
index 51b5947..16c042d 100644
--- a/services/audioflinger/AudioFlinger.cpp
+++ b/services/audioflinger/AudioFlinger.cpp
@@ -131,18 +131,21 @@
     : BnAudioFlinger(),
         mAudioHardware(0), mMasterVolume(1.0f), mMasterMute(false), mNextUniqueId(1)
 {
+    Mutex::Autolock _l(mLock);
+
     mHardwareStatus = AUDIO_HW_IDLE;
 
     mAudioHardware = AudioHardwareInterface::create();
 
     mHardwareStatus = AUDIO_HW_INIT;
     if (mAudioHardware->initCheck() == NO_ERROR) {
-        // open 16-bit output stream for s/w mixer
+        AutoMutex lock(mHardwareLock);
         mMode = AudioSystem::MODE_NORMAL;
-        setMode(mMode);
-
-        setMasterVolume(1.0f);
-        setMasterMute(false);
+        mHardwareStatus = AUDIO_HW_SET_MODE;
+        mAudioHardware->setMode(mMode);
+        mHardwareStatus = AUDIO_HW_SET_MASTER_VOLUME;
+        mAudioHardware->setMasterVolume(1.0f);
+        mHardwareStatus = AUDIO_HW_IDLE;
     } else {
         LOGE("Couldn't even initialize the stubbed audio hardware!");
     }
@@ -440,13 +443,16 @@
     }
 
     // when hw supports master volume, don't scale in sw mixer
-    AutoMutex lock(mHardwareLock);
-    mHardwareStatus = AUDIO_HW_SET_MASTER_VOLUME;
-    if (mAudioHardware->setMasterVolume(value) == NO_ERROR) {
-        value = 1.0f;
+    { // scope for the lock
+        AutoMutex lock(mHardwareLock);
+        mHardwareStatus = AUDIO_HW_SET_MASTER_VOLUME;
+        if (mAudioHardware->setMasterVolume(value) == NO_ERROR) {
+            value = 1.0f;
+        }
+        mHardwareStatus = AUDIO_HW_IDLE;
     }
-    mHardwareStatus = AUDIO_HW_IDLE;
 
+    Mutex::Autolock _l(mLock);
     mMasterVolume = value;
     for (uint32_t i = 0; i < mPlaybackThreads.size(); i++)
        mPlaybackThreads.valueAt(i)->setMasterVolume(value);
@@ -517,6 +523,7 @@
         return PERMISSION_DENIED;
     }
 
+    Mutex::Autolock _l(mLock);
     mMasterMute = muted;
     for (uint32_t i = 0; i < mPlaybackThreads.size(); i++)
        mPlaybackThreads.valueAt(i)->setMasterMute(muted);
@@ -579,6 +586,7 @@
         return BAD_VALUE;
     }
 
+    AutoMutex lock(mLock);
     mStreamTypes[stream].mute = muted;
     for (uint32_t i = 0; i < mPlaybackThreads.size(); i++)
        mPlaybackThreads.valueAt(i)->setStreamMute(stream, muted);
diff --git a/services/audioflinger/AudioPolicyManagerBase.cpp b/services/audioflinger/AudioPolicyManagerBase.cpp
index eeca7ab..e4086c4 100644
--- a/services/audioflinger/AudioPolicyManagerBase.cpp
+++ b/services/audioflinger/AudioPolicyManagerBase.cpp
@@ -1052,25 +1052,27 @@
 
     updateDeviceForStrategy();
 #ifdef AUDIO_POLICY_TEST
-    AudioParameter outputCmd = AudioParameter();
-    outputCmd.addInt(String8("set_id"), 0);
-    mpClientInterface->setParameters(mHardwareOutput, outputCmd.toString());
+    if (mHardwareOutput != 0) {
+        AudioParameter outputCmd = AudioParameter();
+        outputCmd.addInt(String8("set_id"), 0);
+        mpClientInterface->setParameters(mHardwareOutput, outputCmd.toString());
 
-    mTestDevice = AudioSystem::DEVICE_OUT_SPEAKER;
-    mTestSamplingRate = 44100;
-    mTestFormat = AudioSystem::PCM_16_BIT;
-    mTestChannels =  AudioSystem::CHANNEL_OUT_STEREO;
-    mTestLatencyMs = 0;
-    mCurOutput = 0;
-    mDirectOutput = false;
-    for (int i = 0; i < NUM_TEST_OUTPUTS; i++) {
-        mTestOutputs[i] = 0;
+        mTestDevice = AudioSystem::DEVICE_OUT_SPEAKER;
+        mTestSamplingRate = 44100;
+        mTestFormat = AudioSystem::PCM_16_BIT;
+        mTestChannels =  AudioSystem::CHANNEL_OUT_STEREO;
+        mTestLatencyMs = 0;
+        mCurOutput = 0;
+        mDirectOutput = false;
+        for (int i = 0; i < NUM_TEST_OUTPUTS; i++) {
+            mTestOutputs[i] = 0;
+        }
+
+        const size_t SIZE = 256;
+        char buffer[SIZE];
+        snprintf(buffer, SIZE, "AudioPolicyManagerTest");
+        run(buffer, ANDROID_PRIORITY_AUDIO);
     }
-
-    const size_t SIZE = 256;
-    char buffer[SIZE];
-    snprintf(buffer, SIZE, "AudioPolicyManagerTest");
-    run(buffer, ANDROID_PRIORITY_AUDIO);
 #endif //AUDIO_POLICY_TEST
 }
 
@@ -1091,6 +1093,11 @@
    mInputs.clear();
 }
 
+status_t AudioPolicyManagerBase::initCheck()
+{
+    return (mHardwareOutput == 0) ? NO_INIT : NO_ERROR;
+}
+
 #ifdef AUDIO_POLICY_TEST
 bool AudioPolicyManagerBase::threadLoop()
 {
diff --git a/services/audioflinger/AudioPolicyService.cpp b/services/audioflinger/AudioPolicyService.cpp
index f24e08e..46a01ad 100644
--- a/services/audioflinger/AudioPolicyService.cpp
+++ b/services/audioflinger/AudioPolicyService.cpp
@@ -68,6 +68,8 @@
 {
     char value[PROPERTY_VALUE_MAX];
 
+    Mutex::Autolock _l(mLock);
+
     // start tone playback thread
     mTonePlaybackThread = new AudioCommandThread(String8(""));
     // start audio commands thread
@@ -88,9 +90,18 @@
     }
 #endif
 
-    // load properties
-    property_get("ro.camera.sound.forced", value, "0");
-    mpPolicyManager->setSystemProperty("ro.camera.sound.forced", value);
+    if ((mpPolicyManager != NULL) && (mpPolicyManager->initCheck() != NO_ERROR)) {
+        delete mpPolicyManager;
+        mpPolicyManager = NULL;
+    }
+
+    if (mpPolicyManager == NULL) {
+        LOGE("Could not create AudioPolicyManager");
+    } else {
+        // load properties
+        property_get("ro.camera.sound.forced", value, "0");
+        mpPolicyManager->setSystemProperty("ro.camera.sound.forced", value);
+    }
 }
 
 AudioPolicyService::~AudioPolicyService()
diff --git a/services/java/com/android/server/AppWidgetService.java b/services/java/com/android/server/AppWidgetService.java
index 22dd804..59a540b 100644
--- a/services/java/com/android/server/AppWidgetService.java
+++ b/services/java/com/android/server/AppWidgetService.java
@@ -16,6 +16,23 @@
 
 package com.android.server;
 
+import java.io.File;
+import java.io.FileDescriptor;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Locale;
+
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+import org.xmlpull.v1.XmlSerializer;
+
 import android.app.AlarmManager;
 import android.app.PendingIntent;
 import android.appwidget.AppWidgetManager;
@@ -24,46 +41,37 @@
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
+import android.content.Intent.FilterComparison;
 import android.content.IntentFilter;
+import android.content.ServiceConnection;
 import android.content.pm.ActivityInfo;
 import android.content.pm.ApplicationInfo;
-import android.content.pm.PackageManager;
 import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
 import android.content.pm.ResolveInfo;
+import android.content.pm.ServiceInfo;
 import android.content.res.Resources;
 import android.content.res.TypedArray;
 import android.content.res.XmlResourceParser;
 import android.net.Uri;
 import android.os.Binder;
 import android.os.Bundle;
+import android.os.Handler;
+import android.os.IBinder;
 import android.os.Process;
 import android.os.RemoteException;
 import android.os.SystemClock;
 import android.util.AttributeSet;
+import android.util.Pair;
 import android.util.Slog;
 import android.util.TypedValue;
 import android.util.Xml;
 import android.widget.RemoteViews;
 
-import java.io.IOException;
-import java.io.File;
-import java.io.FileDescriptor;
-import java.io.FileInputStream;
-import java.io.FileOutputStream;
-import java.io.PrintWriter;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Locale;
-import java.util.HashMap;
-import java.util.HashSet;
-
-import com.android.internal.appwidget.IAppWidgetService;
 import com.android.internal.appwidget.IAppWidgetHost;
+import com.android.internal.appwidget.IAppWidgetService;
 import com.android.internal.util.FastXmlSerializer;
-
-import org.xmlpull.v1.XmlPullParser;
-import org.xmlpull.v1.XmlPullParserException;
-import org.xmlpull.v1.XmlSerializer;
+import com.android.internal.widget.IRemoteViewsAdapterConnection;
 
 class AppWidgetService extends IAppWidgetService.Stub
 {
@@ -107,6 +115,56 @@
         Host host;
     }
 
+    /**
+     * Acts as a proxy between the ServiceConnection and the RemoteViewsAdapterConnection.
+     * This needs to be a static inner class since a reference to the ServiceConnection is held
+     * globally and may lead us to leak AppWidgetService instances (if there were more than one).
+     */
+    static class ServiceConnectionProxy implements ServiceConnection {
+        private final AppWidgetService mAppWidgetService;
+        private final Pair<Integer, Intent.FilterComparison> mKey;
+        private final IBinder mConnectionCb;
+
+        ServiceConnectionProxy(AppWidgetService appWidgetService,
+                Pair<Integer, Intent.FilterComparison> key, IBinder connectionCb) {
+            mAppWidgetService = appWidgetService;
+            mKey = key;
+            mConnectionCb = connectionCb;
+        }
+        public void onServiceConnected(ComponentName name, IBinder service) {
+            IRemoteViewsAdapterConnection cb =
+                IRemoteViewsAdapterConnection.Stub.asInterface(mConnectionCb);
+            try {
+                cb.onServiceConnected(service);
+            } catch (RemoteException e) {
+                e.printStackTrace();
+            }
+        }
+        public void onServiceDisconnected(ComponentName name) {
+            IRemoteViewsAdapterConnection cb =
+                IRemoteViewsAdapterConnection.Stub.asInterface(mConnectionCb);
+            try {
+                cb.onServiceDisconnected();
+                mAppWidgetService.mServiceConnectionUpdateHandler.post(new Runnable() {
+                    public void run() {
+                        // We don't want to touch mBoundRemoteViewsServices from any other thread
+                        // so queue this to run on the main thread.
+                        if (mAppWidgetService.mBoundRemoteViewsServices.containsKey(mKey)) {
+                            mAppWidgetService.mBoundRemoteViewsServices.remove(mKey);
+                        }
+                    }
+                });
+            } catch (RemoteException e) {
+                e.printStackTrace();
+            }
+        }
+    }
+
+    // Manages connections to RemoteViewsServices
+    private final HashMap<Pair<Integer, FilterComparison>, ServiceConnection>
+        mBoundRemoteViewsServices = new HashMap<Pair<Integer,FilterComparison>,ServiceConnection>();
+    private final Handler mServiceConnectionUpdateHandler = new Handler();
+
     Context mContext;
     Locale mLocale;
     PackageManager mPackageManager;
@@ -294,6 +352,9 @@
     }
 
     void deleteAppWidgetLocked(AppWidgetId id) {
+        // We first unbind all services that are bound to this id
+        unbindAppWidgetRemoteViewsServicesLocked(id);
+
         Host host = id.host;
         host.instances.remove(id);
         pruneHostLocked(host);
@@ -376,6 +437,77 @@
         }
     }
 
+    public void bindRemoteViewsService(int appWidgetId, Intent intent, IBinder connection) {
+        synchronized (mAppWidgetIds) {
+            AppWidgetId id = lookupAppWidgetIdLocked(appWidgetId);
+            if (id == null) {
+                throw new IllegalArgumentException("bad appWidgetId");
+            }
+            final ComponentName componentName = intent.getComponent();
+            try {
+                final ServiceInfo si = mContext.getPackageManager().getServiceInfo(componentName,
+                        PackageManager.GET_PERMISSIONS);
+                if (!android.Manifest.permission.BIND_REMOTEVIEWS.equals(si.permission)) {
+                    throw new SecurityException("Selected service does not require "
+                            + android.Manifest.permission.BIND_REMOTEVIEWS
+                            + ": " + componentName);
+                }
+            } catch (PackageManager.NameNotFoundException e) {
+                throw new IllegalArgumentException("Unknown component " + componentName);
+            }
+
+            // Bind to the RemoteViewsService (which will trigger a callback to the
+            // RemoteViewsAdapter)
+            Pair<Integer, FilterComparison> key = Pair.create(appWidgetId,
+                    new FilterComparison(intent));
+            final ServiceConnection conn = new ServiceConnectionProxy(this, key, connection);
+            final long token = Binder.clearCallingIdentity();
+            try {
+                mContext.bindService(intent, conn, Context.BIND_AUTO_CREATE);
+                mBoundRemoteViewsServices.put(key, conn);
+            } finally {
+                Binder.restoreCallingIdentity(token);
+            }
+        }
+    }
+
+    public void unbindRemoteViewsService(int appWidgetId, Intent intent) {
+        synchronized (mAppWidgetIds) {
+            AppWidgetId id = lookupAppWidgetIdLocked(appWidgetId);
+            if (id == null) {
+                throw new IllegalArgumentException("bad appWidgetId");
+            }
+
+            // Unbind from the RemoteViewsService (which will trigger a callback to the bound
+            // RemoteViewsAdapter)
+            Pair<Integer, FilterComparison> key = Pair.create(appWidgetId,
+                    new FilterComparison(intent));
+            if (mBoundRemoteViewsServices.containsKey(key)) {
+                final ServiceConnection conn = mBoundRemoteViewsServices.get(key);
+                mBoundRemoteViewsServices.remove(key);
+                conn.onServiceDisconnected(null);
+                mContext.unbindService(conn);
+            }
+        }
+    }
+
+    private void unbindAppWidgetRemoteViewsServicesLocked(AppWidgetId id) {
+        Iterator<Pair<Integer, Intent.FilterComparison>> it =
+            mBoundRemoteViewsServices.keySet().iterator();
+        int appWidgetId = id.appWidgetId;
+
+        // Unbind all connections to AppWidgets bound to this id
+        while (it.hasNext()) {
+            final Pair<Integer, Intent.FilterComparison> key = it.next();
+            if (key.first.intValue() == appWidgetId) {
+                final ServiceConnection conn = mBoundRemoteViewsServices.get(key);
+                it.remove();
+                conn.onServiceDisconnected(null);
+                mContext.unbindService(conn);
+            }
+        }
+    }
+
     public AppWidgetProviderInfo getAppWidgetInfo(int appWidgetId) {
         synchronized (mAppWidgetIds) {
             AppWidgetId id = lookupAppWidgetIdLocked(appWidgetId);
diff --git a/services/java/com/android/server/WindowManagerService.java b/services/java/com/android/server/WindowManagerService.java
index 3e930ae..b7ff64d 100644
--- a/services/java/com/android/server/WindowManagerService.java
+++ b/services/java/com/android/server/WindowManagerService.java
@@ -583,7 +583,7 @@
         void broadcastDragStartedLw(final float touchX, final float touchY) {
             // Cache a base-class instance of the clip metadata so that parceling
             // works correctly in calling out to the apps.
-            mDataDescription = mData.getDescription();
+            mDataDescription = (mData != null) ? mData.getDescription() : null;
             mNotifiedWindows.clear();
             mDragInProgress = true;
 
@@ -708,16 +708,20 @@
 
             // Move the surface to the given touch
             if (SHOW_TRANSACTIONS) Slog.i(TAG, ">>> OPEN TRANSACTION notifyMoveLw");
-            mSurface.openTransaction();
+            Surface.openTransaction();
             try {
                 mSurface.setPosition((int)(x - mThumbOffsetX), (int)(y - mThumbOffsetY));
             } finally {
-                mSurface.closeTransaction();
+                Surface.closeTransaction();
                 if (SHOW_TRANSACTIONS) Slog.i(TAG, "<<< CLOSE TRANSACTION notifyMoveLw");
             }
 
             // Tell the affected window
             WindowState touchedWin = getTouchedWinAtPointLw(x, y);
+            if (touchedWin == null) {
+                if (DEBUG_DRAG) Slog.d(TAG, "No touched win at x=" + x + " y=" + y);
+                return;
+            }
             if ((mFlags & View.DRAG_FLAG_GLOBAL) == 0) {
                 final IBinder touchedBinder = touchedWin.mClient.asBinder();
                 if (touchedBinder != mLocalWin) {
diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java
index dbf9a96..9e9a4f2 100755
--- a/services/java/com/android/server/am/ActivityManagerService.java
+++ b/services/java/com/android/server/am/ActivityManagerService.java
@@ -3060,7 +3060,7 @@
                 }
                 if (uid == pkgUid || checkComponentPermission(
                         android.Manifest.permission.CLEAR_APP_USER_DATA,
-                        pid, uid, -1)
+                        pid, uid, -1, true)
                         == PackageManager.PERMISSION_GRANTED) {
                     forceStopPackageLocked(packageName, pkgUid);
                 } else {
@@ -4151,7 +4151,7 @@
      * This can be called with or without the global lock held.
      */
     int checkComponentPermission(String permission, int pid, int uid,
-            int reqUid) {
+            int owningUid, boolean exported) {
         // We might be performing an operation on behalf of an indirect binder
         // invocation, e.g. via {@link #openContentUri}.  Check and adjust the
         // client identity accordingly before proceeding.
@@ -4168,9 +4168,14 @@
             !Process.supportsProcesses()) {
             return PackageManager.PERMISSION_GRANTED;
         }
-        // If the target requires a specific UID, always fail for others.
-        if (reqUid >= 0 && uid != reqUid) {
-            Slog.w(TAG, "Permission denied: checkComponentPermission() reqUid=" + reqUid);
+        // If there is a uid that owns whatever is being accessed, it has
+        // blanket access to it regardless of the permissions it requires.
+        if (owningUid >= 0 && uid == owningUid) {
+            return PackageManager.PERMISSION_GRANTED;
+        }
+        // If the target is not exported, then nobody else can get to it.
+        if (!exported) {
+            Slog.w(TAG, "Permission denied: checkComponentPermission() owningUid=" + owningUid);
             return PackageManager.PERMISSION_DENIED;
         }
         if (permission == null) {
@@ -4199,7 +4204,7 @@
         if (permission == null) {
             return PackageManager.PERMISSION_DENIED;
         }
-        return checkComponentPermission(permission, pid, uid, -1);
+        return checkComponentPermission(permission, pid, uid, -1, true);
     }
 
     /**
@@ -5322,12 +5327,12 @@
         final int callingPid = (r != null) ? r.pid : Binder.getCallingPid();
         final int callingUid = (r != null) ? r.info.uid : Binder.getCallingUid();
         if (checkComponentPermission(cpi.readPermission, callingPid, callingUid,
-                cpi.exported ? -1 : cpi.applicationInfo.uid)
+                cpi.applicationInfo.uid, cpi.exported)
                 == PackageManager.PERMISSION_GRANTED) {
             return null;
         }
         if (checkComponentPermission(cpi.writePermission, callingPid, callingUid,
-                cpi.exported ? -1 : cpi.applicationInfo.uid)
+                cpi.applicationInfo.uid, cpi.exported)
                 == PackageManager.PERMISSION_GRANTED) {
             return null;
         }
@@ -5339,12 +5344,12 @@
                 i--;
                 PathPermission pp = pps[i];
                 if (checkComponentPermission(pp.getReadPermission(), callingPid, callingUid,
-                        cpi.exported ? -1 : cpi.applicationInfo.uid)
+                        cpi.applicationInfo.uid, cpi.exported)
                         == PackageManager.PERMISSION_GRANTED) {
                     return null;
                 }
                 if (checkComponentPermission(pp.getWritePermission(), callingPid, callingUid,
-                        cpi.exported ? -1 : cpi.applicationInfo.uid)
+                        cpi.applicationInfo.uid, cpi.exported)
                         == PackageManager.PERMISSION_GRANTED) {
                     return null;
                 }
@@ -5360,10 +5365,18 @@
             }
         }
 
-        String msg = "Permission Denial: opening provider " + cpi.name
-                + " from " + (r != null ? r : "(null)") + " (pid=" + callingPid
-                + ", uid=" + callingUid + ") requires "
-                + cpi.readPermission + " or " + cpi.writePermission;
+        String msg;
+        if (!cpi.exported) {
+            msg = "Permission Denial: opening provider " + cpi.name
+                    + " from " + (r != null ? r : "(null)") + " (pid=" + callingPid
+                    + ", uid=" + callingUid + ") that is not exported from uid "
+                    + cpi.applicationInfo.uid;
+        } else {
+            msg = "Permission Denial: opening provider " + cpi.name
+                    + " from " + (r != null ? r : "(null)") + " (pid=" + callingPid
+                    + ", uid=" + callingUid + ") requires "
+                    + cpi.readPermission + " or " + cpi.writePermission;
+        }
         Slog.w(TAG, msg);
         return msg;
     }
@@ -5953,7 +5966,7 @@
             
         final int perm = checkComponentPermission(
                 android.Manifest.permission.STOP_APP_SWITCHES, callingPid,
-                callingUid, -1);
+                callingUid, -1, true);
         if (perm == PackageManager.PERMISSION_GRANTED) {
             return true;
         }
@@ -6804,6 +6817,9 @@
             if (info.durationMillis != -1) {
                 sb.append("Duration-Millis: ").append(info.durationMillis).append("\n");
             }
+            if (info.numInstances != -1) {
+                sb.append("Instance-Count: ").append(info.numInstances).append("\n");
+            }
             if (info.tags != null) {
                 for (String tag : info.tags) {
                     sb.append("Span-Tag: ").append(tag).append("\n");
@@ -8892,8 +8908,16 @@
             int callingPid = Binder.getCallingPid();
             int callingUid = Binder.getCallingUid();
             if (checkComponentPermission(r.permission,
-                    callingPid, callingUid, r.exported ? -1 : r.appInfo.uid)
+                    callingPid, callingUid, r.appInfo.uid, r.exported)
                     != PackageManager.PERMISSION_GRANTED) {
+                if (!r.exported) {
+                    Slog.w(TAG, "Permission Denial: Accessing service " + r.name
+                            + " from pid=" + callingPid
+                            + ", uid=" + callingUid
+                            + " that is not exported from uid " + r.appInfo.uid);
+                    return new ServiceLookupResult(null, "not exported from uid "
+                            + r.appInfo.uid);
+                }
                 Slog.w(TAG, "Permission Denial: Accessing service " + r.name
                         + " from pid=" + callingPid
                         + ", uid=" + callingUid
@@ -8975,11 +8999,19 @@
         }
         if (r != null) {
             if (checkComponentPermission(r.permission,
-                    callingPid, callingUid, r.exported ? -1 : r.appInfo.uid)
+                    callingPid, callingUid, r.appInfo.uid, r.exported)
                     != PackageManager.PERMISSION_GRANTED) {
+                if (!r.exported) {
+                    Slog.w(TAG, "Permission Denial: Accessing service " + r.name
+                            + " from pid=" + callingPid
+                            + ", uid=" + callingUid
+                            + " that is not exported from uid " + r.appInfo.uid);
+                    return new ServiceLookupResult(null, "not exported from uid "
+                            + r.appInfo.uid);
+                }
                 Slog.w(TAG, "Permission Denial: Accessing service " + r.name
-                        + " from pid=" + Binder.getCallingPid()
-                        + ", uid=" + Binder.getCallingUid()
+                        + " from pid=" + callingPid
+                        + ", uid=" + callingUid
                         + " requires " + r.permission);
                 return new ServiceLookupResult(null, r.permission);
             }
@@ -10479,7 +10511,7 @@
                 || uidRemoved) {
             if (checkComponentPermission(
                     android.Manifest.permission.BROADCAST_PACKAGE_REMOVED,
-                    callingPid, callingUid, -1)
+                    callingPid, callingUid, -1, true)
                     == PackageManager.PERMISSION_GRANTED) {
                 if (uidRemoved) {
                     final Bundle intentExtras = intent.getExtras();
@@ -11147,7 +11179,7 @@
         boolean skip = false;
         if (filter.requiredPermission != null) {
             int perm = checkComponentPermission(filter.requiredPermission,
-                    r.callingPid, r.callingUid, -1);
+                    r.callingPid, r.callingUid, -1, true);
             if (perm != PackageManager.PERMISSION_GRANTED) {
                 Slog.w(TAG, "Permission Denial: broadcasting "
                         + r.intent.toString()
@@ -11160,7 +11192,7 @@
         }
         if (r.requiredPermission != null) {
             int perm = checkComponentPermission(r.requiredPermission,
-                    filter.receiverList.pid, filter.receiverList.uid, -1);
+                    filter.receiverList.pid, filter.receiverList.uid, -1, true);
             if (perm != PackageManager.PERMISSION_GRANTED) {
                 Slog.w(TAG, "Permission Denial: receiving "
                         + r.intent.toString()
@@ -11426,17 +11458,26 @@
 
             boolean skip = false;
             int perm = checkComponentPermission(info.activityInfo.permission,
-                    r.callingPid, r.callingUid,
-                    info.activityInfo.exported
-                            ? -1 : info.activityInfo.applicationInfo.uid);
+                    r.callingPid, r.callingUid, info.activityInfo.applicationInfo.uid,
+                    info.activityInfo.exported);
             if (perm != PackageManager.PERMISSION_GRANTED) {
-                Slog.w(TAG, "Permission Denial: broadcasting "
-                        + r.intent.toString()
-                        + " from " + r.callerPackage + " (pid=" + r.callingPid
-                        + ", uid=" + r.callingUid + ")"
-                        + " requires " + info.activityInfo.permission
-                        + " due to receiver " + info.activityInfo.packageName
-                        + "/" + info.activityInfo.name);
+                if (!info.activityInfo.exported) {
+                    Slog.w(TAG, "Permission Denial: broadcasting "
+                            + r.intent.toString()
+                            + " from " + r.callerPackage + " (pid=" + r.callingPid
+                            + ", uid=" + r.callingUid + ")"
+                            + " is not exported from uid " + info.activityInfo.applicationInfo.uid
+                            + " due to receiver " + info.activityInfo.packageName
+                            + "/" + info.activityInfo.name);
+                } else {
+                    Slog.w(TAG, "Permission Denial: broadcasting "
+                            + r.intent.toString()
+                            + " from " + r.callerPackage + " (pid=" + r.callingPid
+                            + ", uid=" + r.callingUid + ")"
+                            + " requires " + info.activityInfo.permission
+                            + " due to receiver " + info.activityInfo.packageName
+                            + "/" + info.activityInfo.name);
+                }
                 skip = true;
             }
             if (r.callingUid != Process.SYSTEM_UID &&
diff --git a/services/java/com/android/server/am/ActivityStack.java b/services/java/com/android/server/am/ActivityStack.java
index bc00478..dd6ddd6 100644
--- a/services/java/com/android/server/am/ActivityStack.java
+++ b/services/java/com/android/server/am/ActivityStack.java
@@ -2035,17 +2035,25 @@
         }
 
         final int perm = mService.checkComponentPermission(aInfo.permission, callingPid,
-                callingUid, aInfo.exported ? -1 : aInfo.applicationInfo.uid);
+                callingUid, aInfo.applicationInfo.uid, aInfo.exported);
         if (perm != PackageManager.PERMISSION_GRANTED) {
             if (resultRecord != null) {
                 sendActivityResultLocked(-1,
                     resultRecord, resultWho, requestCode,
                     Activity.RESULT_CANCELED, null);
             }
-            String msg = "Permission Denial: starting " + intent.toString()
-                    + " from " + callerApp + " (pid=" + callingPid
-                    + ", uid=" + callingUid + ")"
-                    + " requires " + aInfo.permission;
+            String msg;
+            if (!aInfo.exported) {
+                msg = "Permission Denial: starting " + intent.toString()
+                        + " from " + callerApp + " (pid=" + callingPid
+                        + ", uid=" + callingUid + ")"
+                        + " not exported from uid " + aInfo.applicationInfo.uid;
+            } else {
+                msg = "Permission Denial: starting " + intent.toString()
+                        + " from " + callerApp + " (pid=" + callingPid
+                        + ", uid=" + callingUid + ")"
+                        + " requires " + aInfo.permission;
+            }
             Slog.w(TAG, msg);
             throw new SecurityException(msg);
         }
diff --git a/services/surfaceflinger/LayerBase.cpp b/services/surfaceflinger/LayerBase.cpp
index 0c1fcf9..9ddb05f 100644
--- a/services/surfaceflinger/LayerBase.cpp
+++ b/services/surfaceflinger/LayerBase.cpp
@@ -534,6 +534,12 @@
     result.append(buffer);
 }
 
+void LayerBase::shortDump(String8& result, char* scratch, size_t size) const
+{
+    LayerBase::dump(result, scratch, size);
+}
+
+
 // ---------------------------------------------------------------------------
 
 int32_t LayerBaseClient::sIdentity = 1;
@@ -585,6 +591,12 @@
     result.append(buffer);
 }
 
+
+void LayerBaseClient::shortDump(String8& result, char* scratch, size_t size) const
+{
+    LayerBaseClient::dump(result, scratch, size);
+}
+
 // ---------------------------------------------------------------------------
 
 LayerBaseClient::Surface::Surface(
diff --git a/services/surfaceflinger/LayerBase.h b/services/surfaceflinger/LayerBase.h
index f6c49fc..13af223 100644
--- a/services/surfaceflinger/LayerBase.h
+++ b/services/surfaceflinger/LayerBase.h
@@ -211,6 +211,7 @@
     
     /** always call base class first */
     virtual void dump(String8& result, char* scratch, size_t size) const;
+    virtual void shortDump(String8& result, char* scratch, size_t size) const;
 
 
     enum { // flags for doTransaction()
@@ -324,6 +325,7 @@
 
 protected:
     virtual void dump(String8& result, char* scratch, size_t size) const;
+    virtual void shortDump(String8& result, char* scratch, size_t size) const;
 
 private:
     mutable Mutex mLock;
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 65ad956..434e473 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -1491,8 +1491,13 @@
             result.append(buffer);
         }
 
+        /*
+         * Dump the visible layer list
+         */
         const LayerVector& currentLayers = mCurrentState.layersSortedByZ;
         const size_t count = currentLayers.size();
+        snprintf(buffer, SIZE, "Visible layers (count = %d)\n", count);
+        result.append(buffer);
         for (size_t i=0 ; i<count ; i++) {
             const sp<LayerBase>& layer(currentLayers[i]);
             layer->dump(result, buffer, SIZE);
@@ -1502,6 +1507,24 @@
             layer->visibleRegionScreen.dump(result, "visibleRegionScreen");
         }
 
+        /*
+         * Dump the layers in the purgatory
+         */
+
+        const size_t purgatorySize =  mLayerPurgatory.size();
+        snprintf(buffer, SIZE, "Purgatory state (%d entries)\n", purgatorySize);
+        result.append(buffer);
+        for (size_t i=0 ; i<purgatorySize ; i++) {
+            const sp<LayerBase>& layer(mLayerPurgatory.itemAt(i));
+            layer->shortDump(result, buffer, SIZE);
+        }
+
+        /*
+         * Dump SurfaceFlinger global state
+         */
+
+        snprintf(buffer, SIZE, "SurfaceFlinger global state\n");
+        result.append(buffer);
         mWormholeRegion.dump(result, "WormholeRegion");
         const DisplayHardware& hw(graphicPlane(0).displayHardware());
         snprintf(buffer, SIZE,
@@ -1527,6 +1550,9 @@
             result.append(buffer);
         }
 
+        /*
+         * Dump HWComposer state
+         */
         HWComposer& hwc(hw.getHwComposer());
         snprintf(buffer, SIZE, "  h/w composer %s and %s\n",
                 hwc.initCheck()==NO_ERROR ? "present" : "not present",
@@ -1534,6 +1560,9 @@
         result.append(buffer);
         hwc.dump(result, buffer, SIZE);
 
+        /*
+         * Dump gralloc state
+         */
         const GraphicBufferAllocator& alloc(GraphicBufferAllocator::get());
         alloc.dump(result);
         hw.dump(result);
diff --git a/tests/DumpRenderTree/src/com/android/dumprendertree/LoadTestsAutoTest.java b/tests/DumpRenderTree/src/com/android/dumprendertree/LoadTestsAutoTest.java
index e5a46b9..5bcf727 100644
--- a/tests/DumpRenderTree/src/com/android/dumprendertree/LoadTestsAutoTest.java
+++ b/tests/DumpRenderTree/src/com/android/dumprendertree/LoadTestsAutoTest.java
@@ -89,13 +89,12 @@
     }
 
     private void freeMem() {
-        Log.v(LOGTAG, "freeMem: calling gc/finalization...");
+        Log.v(LOGTAG, "freeMem: calling gc...");
         final VMRuntime runtime = VMRuntime.getRuntime();
 
         runtime.gcSoftReferences();
         runtime.gcSoftReferences();
         runtime.gcSoftReferences();
-        Runtime.getRuntime().runFinalization();
         Runtime.getRuntime().gc();
         Runtime.getRuntime().gc();
 
diff --git a/tests/HwAccelerationTest/AndroidManifest.xml b/tests/HwAccelerationTest/AndroidManifest.xml
index 691aff28..7a61b3c 100644
--- a/tests/HwAccelerationTest/AndroidManifest.xml
+++ b/tests/HwAccelerationTest/AndroidManifest.xml
@@ -53,6 +53,15 @@
         </activity>
         
         <activity
+                android:name="ViewLayersActivity3"
+                android:label="_ViewLayers3">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.LAUNCHER" />
+            </intent-filter>
+        </activity>
+        
+        <activity
                 android:name="AlphaLayersActivity"
                 android:label="_αLayers">
             <intent-filter>
diff --git a/tests/HwAccelerationTest/res/layout/view_layers_3.xml b/tests/HwAccelerationTest/res/layout/view_layers_3.xml
new file mode 100644
index 0000000..a820f5f
--- /dev/null
+++ b/tests/HwAccelerationTest/res/layout/view_layers_3.xml
@@ -0,0 +1,48 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2011 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:layout_width="match_parent"
+    android:layout_height="match_parent">
+
+    <LinearLayout
+        android:background="#30ff0000"
+        android:layout_width="0dip"
+        android:layout_height="match_parent"
+        android:layout_weight="1" />
+
+    <LinearLayout
+        android:background="#3000ff00"
+        android:layout_width="0dip"
+        android:layout_height="match_parent"
+        android:layout_weight="1"
+        android:padding="12dip">
+
+        <ListView
+            android:id="@+id/list1"
+            android:layout_width="match_parent"
+            android:layout_height="match_parent" />
+
+    </LinearLayout>
+
+    <LinearLayout
+        android:background="#300000ff"
+        android:layout_width="0dip"
+        android:layout_height="match_parent"
+        android:layout_weight="1" />
+
+</LinearLayout>
diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/ViewLayersActivity3.java b/tests/HwAccelerationTest/src/com/android/test/hwui/ViewLayersActivity3.java
new file mode 100644
index 0000000..c8ae75b
--- /dev/null
+++ b/tests/HwAccelerationTest/src/com/android/test/hwui/ViewLayersActivity3.java
@@ -0,0 +1,108 @@
+/*
+ * Copyright (C) 2011 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.test.hwui;
+
+import android.app.Activity;
+import android.content.Context;
+import android.content.res.Resources;
+import android.os.Bundle;
+import android.util.DisplayMetrics;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.ArrayAdapter;
+import android.widget.ListView;
+import android.widget.TextView;
+
+@SuppressWarnings({"UnusedDeclaration"})
+public class ViewLayersActivity3 extends Activity {
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        
+        setContentView(R.layout.view_layers_3);
+
+        setupList(R.id.list1);
+    }
+
+    private void setupList(int listId) {
+        final ListView list = (ListView) findViewById(listId);
+        list.setAdapter(new SimpleListAdapter(this));
+        list.setLayerType(View.LAYER_TYPE_HARDWARE, null);
+        ((View) list.getParent()).setLayerType(View.LAYER_TYPE_HARDWARE, null);
+    }
+
+    private static class SimpleListAdapter extends ArrayAdapter<String> {
+        public SimpleListAdapter(Context context) {
+            super(context, android.R.layout.simple_list_item_1, DATA_LIST);
+        }
+
+        @Override
+        public View getView(int position, View convertView, ViewGroup parent) {
+            TextView v = (TextView) super.getView(position, convertView, parent);
+            final Resources r = getContext().getResources();
+            final DisplayMetrics metrics = r.getDisplayMetrics();
+            v.setCompoundDrawablePadding((int) (6 * metrics.density + 0.5f));
+            v.setCompoundDrawablesWithIntrinsicBounds(r.getDrawable(R.drawable.icon),
+                    null, null, null);
+            return v;
+        }
+    }
+
+    private static final String[] DATA_LIST = {
+            "Afghanistan", "Albania", "Algeria", "American Samoa", "Andorra",
+            "Angola", "Anguilla", "Antarctica", "Antigua and Barbuda", "Argentina",
+            "Armenia", "Aruba", "Australia", "Austria", "Azerbaijan",
+            "Bahrain", "Bangladesh", "Barbados", "Belarus", "Belgium",
+            "Belize", "Benin", "Bermuda", "Bhutan", "Bolivia",
+            "Bosnia and Herzegovina", "Botswana", "Bouvet Island", "Brazil",
+            "British Indian Ocean Territory", "British Virgin Islands", "Brunei", "Bulgaria",
+            "Burkina Faso", "Burundi", "Cote d'Ivoire", "Cambodia", "Cameroon", "Canada", "Cape Verde",
+            "Cayman Islands", "Central African Republic", "Chad", "Chile", "China",
+            "Christmas Island", "Cocos (Keeling) Islands", "Colombia", "Comoros", "Congo",
+            "Cook Islands", "Costa Rica", "Croatia", "Cuba", "Cyprus", "Czech Republic",
+            "Democratic Republic of the Congo", "Denmark", "Djibouti", "Dominica", "Dominican Republic",
+            "East Timor", "Ecuador", "Egypt", "El Salvador", "Equatorial Guinea", "Eritrea",
+            "Estonia", "Ethiopia", "Faeroe Islands", "Falkland Islands", "Fiji", "Finland",
+            "Former Yugoslav Republic of Macedonia", "France", "French Guiana", "French Polynesia",
+            "French Southern Territories", "Gabon", "Georgia", "Germany", "Ghana", "Gibraltar",
+            "Greece", "Greenland", "Grenada", "Guadeloupe", "Guam", "Guatemala", "Guinea", "Guinea-Bissau",
+            "Guyana", "Haiti", "Heard Island and McDonald Islands", "Honduras", "Hong Kong", "Hungary",
+            "Iceland", "India", "Indonesia", "Iran", "Iraq", "Ireland", "Israel", "Italy", "Jamaica",
+            "Japan", "Jordan", "Kazakhstan", "Kenya", "Kiribati", "Kuwait", "Kyrgyzstan", "Laos",
+            "Latvia", "Lebanon", "Lesotho", "Liberia", "Libya", "Liechtenstein", "Lithuania", "Luxembourg",
+            "Macau", "Madagascar", "Malawi", "Malaysia", "Maldives", "Mali", "Malta", "Marshall Islands",
+            "Martinique", "Mauritania", "Mauritius", "Mayotte", "Mexico", "Micronesia", "Moldova",
+            "Monaco", "Mongolia", "Montserrat", "Morocco", "Mozambique", "Myanmar", "Namibia",
+            "Nauru", "Nepal", "Netherlands", "Netherlands Antilles", "New Caledonia", "New Zealand",
+            "Nicaragua", "Niger", "Nigeria", "Niue", "Norfolk Island", "North Korea", "Northern Marianas",
+            "Norway", "Oman", "Pakistan", "Palau", "Panama", "Papua New Guinea", "Paraguay", "Peru",
+            "Philippines", "Pitcairn Islands", "Poland", "Portugal", "Puerto Rico", "Qatar",
+            "Reunion", "Romania", "Russia", "Rwanda", "Sqo Tome and Principe", "Saint Helena",
+            "Saint Kitts and Nevis", "Saint Lucia", "Saint Pierre and Miquelon",
+            "Saint Vincent and the Grenadines", "Samoa", "San Marino", "Saudi Arabia", "Senegal",
+            "Seychelles", "Sierra Leone", "Singapore", "Slovakia", "Slovenia", "Solomon Islands",
+            "Somalia", "South Africa", "South Georgia and the South Sandwich Islands", "South Korea",
+            "Spain", "Sri Lanka", "Sudan", "Suriname", "Svalbard and Jan Mayen", "Swaziland", "Sweden",
+            "Switzerland", "Syria", "Taiwan", "Tajikistan", "Tanzania", "Thailand", "The Bahamas",
+            "The Gambia", "Togo", "Tokelau", "Tonga", "Trinidad and Tobago", "Tunisia", "Turkey",
+            "Turkmenistan", "Turks and Caicos Islands", "Tuvalu", "Virgin Islands", "Uganda",
+            "Ukraine", "United Arab Emirates", "United Kingdom",
+            "United States", "United States Minor Outlying Islands", "Uruguay", "Uzbekistan",
+            "Vanuatu", "Vatican City", "Venezuela", "Vietnam", "Wallis and Futuna", "Western Sahara",
+            "Yemen", "Yugoslavia", "Zambia", "Zimbabwe"
+    };
+}
diff --git a/wifi/java/android/net/wifi/WifiStateMachine.java b/wifi/java/android/net/wifi/WifiStateMachine.java
index 0548b4d..df21399 100644
--- a/wifi/java/android/net/wifi/WifiStateMachine.java
+++ b/wifi/java/android/net/wifi/WifiStateMachine.java
@@ -61,7 +61,6 @@
 import android.provider.Settings;
 import android.util.EventLog;
 import android.util.Log;
-import android.util.Slog;
 import android.app.backup.IBackupManager;
 import android.bluetooth.BluetoothAdapter;
 import android.content.BroadcastReceiver;
@@ -1671,10 +1670,18 @@
                         nwService.startAccessPoint((WifiConfiguration) message.obj,
                                     mInterfaceName,
                                     SOFTAP_IFACE);
-                    } catch(Exception e) {
-                        Log.e(TAG, "Exception in startAccessPoint()");
-                        sendMessage(obtainMessage(CMD_UNLOAD_DRIVER, WIFI_AP_STATE_FAILED, 0));
-                        break;
+                    } catch (Exception e) {
+                        Log.e(TAG, "Exception in softap start " + e);
+                        try {
+                            nwService.stopAccessPoint();
+                            nwService.startAccessPoint((WifiConfiguration) message.obj,
+                                    mInterfaceName,
+                                    SOFTAP_IFACE);
+                        } catch (Exception ee) {
+                            Log.e(TAG, "Exception during softap restart : " + ee);
+                            sendMessage(obtainMessage(CMD_UNLOAD_DRIVER, WIFI_AP_STATE_FAILED, 0));
+                            break;
+                        }
                     }
                     Log.d(TAG, "Soft AP start successful");
                     setWifiApState(WIFI_AP_STATE_ENABLED);
@@ -2824,13 +2831,16 @@
                                     mInterfaceName,
                                     SOFTAP_IFACE);
                     } catch(Exception e) {
-                        Log.e(TAG, "Exception in nwService during soft AP set");
+                        Log.e(TAG, "Exception in softap set " + e);
                         try {
                             nwService.stopAccessPoint();
+                            nwService.startAccessPoint((WifiConfiguration) message.obj,
+                                    mInterfaceName,
+                                    SOFTAP_IFACE);
                         } catch (Exception ee) {
-                            Slog.e(TAG, "Could not stop AP, :" + ee);
+                            Log.e(TAG, "Could not restart softap after set failed " + ee);
+                            sendMessage(obtainMessage(CMD_UNLOAD_DRIVER, WIFI_AP_STATE_FAILED, 0));
                         }
-                        sendMessage(obtainMessage(CMD_UNLOAD_DRIVER, WIFI_AP_STATE_FAILED, 0));
                     }
                     break;
                 /* Fail client mode operation when soft AP is enabled */