auto import from //branches/cupcake/...@131421
diff --git a/Android.mk b/Android.mk
index 764e88b..45f0f18 100644
--- a/Android.mk
+++ b/Android.mk
@@ -167,7 +167,7 @@
 	frameworks/base/core/java/android/content/Intent.aidl \
 	frameworks/base/core/java/android/content/SyncStats.aidl \
 	frameworks/base/core/java/android/content/res/Configuration.aidl \
-	frameworks/base/core/java/android/gadget/GadgetInfo.aidl \
+	frameworks/base/core/java/android/gadget/GadgetProviderInfo.aidl \
 	frameworks/base/core/java/android/net/Uri.aidl \
 	frameworks/base/core/java/android/os/Bundle.aidl \
 	frameworks/base/core/java/android/os/ParcelFileDescriptor.aidl \
diff --git a/api/current.xml b/api/current.xml
index 55994fb..2e8db51 100644
--- a/api/current.xml
+++ b/api/current.xml
@@ -3562,6 +3562,17 @@
  visibility="public"
 >
 </field>
+<field name="hapticFeedbackEnabled"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="16843358"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
 <field name="hasCode"
  type="int"
  transient="false"
@@ -3859,6 +3870,17 @@
  visibility="public"
 >
 </field>
+<field name="innerRadius"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="16843359"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
 <field name="innerRadiusRatio"
  type="int"
  transient="false"
@@ -7434,6 +7456,17 @@
  visibility="public"
 >
 </field>
+<field name="thickness"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="16843360"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
 <field name="thicknessRatio"
  type="int"
  transient="false"
@@ -41922,6 +41955,757 @@
 </method>
 </class>
 </package>
+<package name="android.gadget"
+>
+<class name="GadgetHost"
+ extends="java.lang.Object"
+ abstract="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<constructor name="GadgetHost"
+ type="android.gadget.GadgetHost"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="context" type="android.content.Context">
+</parameter>
+<parameter name="hostId" type="int">
+</parameter>
+</constructor>
+<method name="allocateGadgetId"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="createView"
+ return="android.gadget.GadgetHostView"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="context" type="android.content.Context">
+</parameter>
+<parameter name="gadgetId" type="int">
+</parameter>
+<parameter name="gadget" type="android.gadget.GadgetProviderInfo">
+</parameter>
+</method>
+<method name="deleteAllHosts"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="deleteGadgetId"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="gadgetId" type="int">
+</parameter>
+</method>
+<method name="deleteHost"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="onCreateView"
+ return="android.gadget.GadgetHostView"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="protected"
+>
+<parameter name="context" type="android.content.Context">
+</parameter>
+<parameter name="gadgetId" type="int">
+</parameter>
+<parameter name="gadget" type="android.gadget.GadgetProviderInfo">
+</parameter>
+</method>
+<method name="onProviderChanged"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="protected"
+>
+<parameter name="gadgetId" type="int">
+</parameter>
+<parameter name="gadget" type="android.gadget.GadgetProviderInfo">
+</parameter>
+</method>
+<method name="startListening"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="stopListening"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+</class>
+<class name="GadgetHostView"
+ extends="android.widget.ViewAnimator"
+ abstract="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<implements name="android.view.animation.Animation.AnimationListener">
+</implements>
+<constructor name="GadgetHostView"
+ type="android.gadget.GadgetHostView"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="context" type="android.content.Context">
+</parameter>
+</constructor>
+<constructor name="GadgetHostView"
+ type="android.gadget.GadgetHostView"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="context" type="android.content.Context">
+</parameter>
+<parameter name="animationIn" type="int">
+</parameter>
+<parameter name="animationOut" type="int">
+</parameter>
+</constructor>
+<method name="getDefaultView"
+ return="android.view.View"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="protected"
+>
+</method>
+<method name="getErrorView"
+ return="android.view.View"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="protected"
+>
+</method>
+<method name="getGadgetId"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getGadgetInfo"
+ return="android.gadget.GadgetProviderInfo"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="onAnimationEnd"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="animation" type="android.view.animation.Animation">
+</parameter>
+</method>
+<method name="onAnimationRepeat"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="animation" type="android.view.animation.Animation">
+</parameter>
+</method>
+<method name="onAnimationStart"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="animation" type="android.view.animation.Animation">
+</parameter>
+</method>
+<method name="prepareView"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="protected"
+>
+<parameter name="view" type="android.view.View">
+</parameter>
+</method>
+<method name="setGadget"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="gadgetId" type="int">
+</parameter>
+<parameter name="info" type="android.gadget.GadgetProviderInfo">
+</parameter>
+</method>
+<method name="updateGadget"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="remoteViews" type="android.widget.RemoteViews">
+</parameter>
+</method>
+</class>
+<class name="GadgetManager"
+ extends="java.lang.Object"
+ abstract="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<method name="bindGadgetId"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="gadgetId" type="int">
+</parameter>
+<parameter name="provider" type="android.content.ComponentName">
+</parameter>
+</method>
+<method name="getGadgetInfo"
+ return="android.gadget.GadgetProviderInfo"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="gadgetId" type="int">
+</parameter>
+</method>
+<method name="getInstalledProviders"
+ return="java.util.List&lt;android.gadget.GadgetProviderInfo&gt;"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getInstance"
+ return="android.gadget.GadgetManager"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="context" type="android.content.Context">
+</parameter>
+</method>
+<method name="updateGadget"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="gadgetIds" type="int[]">
+</parameter>
+<parameter name="views" type="android.widget.RemoteViews">
+</parameter>
+</method>
+<method name="updateGadget"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="gadgetId" type="int">
+</parameter>
+<parameter name="views" type="android.widget.RemoteViews">
+</parameter>
+</method>
+<method name="updateGadget"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="provider" type="android.content.ComponentName">
+</parameter>
+<parameter name="views" type="android.widget.RemoteViews">
+</parameter>
+</method>
+<field name="ACTION_GADGET_CONFIGURE"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;android.gadget.action.GADGET_CONFIGURE&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="ACTION_GADGET_DELETED"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;android.gadget.action.GADGET_DELETED&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="ACTION_GADGET_DISABLED"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;android.gadget.action.GADGET_DISABLED&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="ACTION_GADGET_ENABLED"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;android.gadget.action.GADGET_ENABLED&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="ACTION_GADGET_PICK"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;android.gadget.action.GADGET_PICK&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="ACTION_GADGET_UPDATE"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;android.gadget.action.GADGET_UPDATE&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="EXTRA_GADGET_ID"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;gadgetId&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="EXTRA_GADGET_IDS"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;gadgetIds&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="INVALID_GADGET_ID"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="0"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="META_DATA_GADGET_PROVIDER"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;android.gadget.provider&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+</class>
+<class name="GadgetProvider"
+ extends="android.content.BroadcastReceiver"
+ abstract="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<constructor name="GadgetProvider"
+ type="android.gadget.GadgetProvider"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</constructor>
+<method name="onDeleted"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="context" type="android.content.Context">
+</parameter>
+<parameter name="gadgetIds" type="int[]">
+</parameter>
+</method>
+<method name="onDisabled"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="context" type="android.content.Context">
+</parameter>
+</method>
+<method name="onEnabled"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="context" type="android.content.Context">
+</parameter>
+</method>
+<method name="onReceive"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="context" type="android.content.Context">
+</parameter>
+<parameter name="intent" type="android.content.Intent">
+</parameter>
+</method>
+<method name="onUpdate"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="context" type="android.content.Context">
+</parameter>
+<parameter name="gadgetManager" type="android.gadget.GadgetManager">
+</parameter>
+<parameter name="gadgetIds" type="int[]">
+</parameter>
+</method>
+</class>
+<class name="GadgetProviderInfo"
+ extends="java.lang.Object"
+ abstract="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<implements name="android.os.Parcelable">
+</implements>
+<constructor name="GadgetProviderInfo"
+ type="android.gadget.GadgetProviderInfo"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</constructor>
+<constructor name="GadgetProviderInfo"
+ type="android.gadget.GadgetProviderInfo"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="in" type="android.os.Parcel">
+</parameter>
+</constructor>
+<method name="describeContents"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="writeToParcel"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="out" type="android.os.Parcel">
+</parameter>
+<parameter name="flags" type="int">
+</parameter>
+</method>
+<field name="CREATOR"
+ type="android.os.Parcelable.Creator"
+ transient="false"
+ volatile="false"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="configure"
+ type="android.content.ComponentName"
+ transient="false"
+ volatile="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="icon"
+ type="int"
+ transient="false"
+ volatile="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="initialLayout"
+ type="int"
+ transient="false"
+ volatile="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="label"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="minHeight"
+ type="int"
+ transient="false"
+ volatile="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="minWidth"
+ type="int"
+ transient="false"
+ volatile="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="provider"
+ type="android.content.ComponentName"
+ transient="false"
+ volatile="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="updatePeriodMillis"
+ type="int"
+ transient="false"
+ volatile="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+</class>
+</package>
 <package name="android.graphics"
 >
 <class name="AvoidXfermode"
@@ -54461,6 +55245,17 @@
 <parameter name="canvas" type="android.graphics.Canvas">
 </parameter>
 </method>
+<method name="getDrawable"
+ return="android.graphics.drawable.Drawable"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
 <method name="getOpacity"
  return="int"
  abstract="false"
@@ -54583,6 +55378,17 @@
 <parameter name="canvas" type="android.graphics.Canvas">
 </parameter>
 </method>
+<method name="getDrawable"
+ return="android.graphics.drawable.Drawable"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
 <method name="getOpacity"
  return="int"
  abstract="false"
@@ -57537,6 +58343,17 @@
  visibility="public"
 >
 </method>
+<method name="hideStatusIcon"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
 <method name="hideWindow"
  return="void"
  abstract="false"
@@ -57992,6 +58809,28 @@
 <parameter name="candidatesEnd" type="int">
 </parameter>
 </method>
+<method name="onWindowHidden"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="onWindowShown"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
 <method name="setCandidatesView"
  return="void"
  abstract="false"
@@ -58044,7 +58883,7 @@
 <parameter name="view" type="android.view.View">
 </parameter>
 </method>
-<method name="setStatusIcon"
+<method name="showStatusIcon"
  return="void"
  abstract="false"
  native="false"
@@ -58370,6 +59209,16 @@
  visibility="public"
 >
 </field>
+<field name="contentTopInsets"
+ type="int"
+ transient="false"
+ volatile="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
 <field name="touchableInsets"
  type="int"
  transient="false"
@@ -58380,6 +59229,16 @@
  visibility="public"
 >
 </field>
+<field name="visibleTopInsets"
+ type="int"
+ transient="false"
+ volatile="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
 </class>
 <class name="Keyboard"
  extends="java.lang.Object"
@@ -64898,7 +65757,7 @@
 <method name="prepare"
  return="void"
  abstract="false"
- native="true"
+ native="false"
  synchronized="false"
  static="false"
  final="false"
@@ -64962,7 +65821,7 @@
 <exception name="IllegalStateException" type="java.lang.IllegalStateException">
 </exception>
 </method>
-<method name="setOutputFile"
+<method name="setCamera"
  return="void"
  abstract="false"
  native="true"
@@ -64972,6 +65831,34 @@
  deprecated="not deprecated"
  visibility="public"
 >
+<parameter name="c" type="android.hardware.Camera">
+</parameter>
+</method>
+<method name="setOutputFile"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="fd" type="java.io.FileDescriptor">
+</parameter>
+<exception name="IllegalStateException" type="java.lang.IllegalStateException">
+</exception>
+</method>
+<method name="setOutputFile"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
 <parameter name="path" type="java.lang.String">
 </parameter>
 <exception name="IllegalStateException" type="java.lang.IllegalStateException">
@@ -65005,6 +65892,68 @@
 <parameter name="sv" type="android.view.Surface">
 </parameter>
 </method>
+<method name="setVideoEncoder"
+ return="void"
+ abstract="false"
+ native="true"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="video_encoder" type="int">
+</parameter>
+<exception name="IllegalStateException" type="java.lang.IllegalStateException">
+</exception>
+</method>
+<method name="setVideoFrameRate"
+ return="void"
+ abstract="false"
+ native="true"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="rate" type="int">
+</parameter>
+<exception name="IllegalStateException" type="java.lang.IllegalStateException">
+</exception>
+</method>
+<method name="setVideoSize"
+ return="void"
+ abstract="false"
+ native="true"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="width" type="int">
+</parameter>
+<parameter name="height" type="int">
+</parameter>
+<exception name="IllegalStateException" type="java.lang.IllegalStateException">
+</exception>
+</method>
+<method name="setVideoSource"
+ return="void"
+ abstract="false"
+ native="true"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="video_source" type="int">
+</parameter>
+<exception name="IllegalStateException" type="java.lang.IllegalStateException">
+</exception>
+</method>
 <method name="start"
  return="void"
  abstract="false"
@@ -65147,6 +66096,90 @@
 >
 </field>
 </class>
+<class name="MediaRecorder.VideoEncoder"
+ extends="java.lang.Object"
+ abstract="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<field name="DEFAULT"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="0"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="H263"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="1"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="H264"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="2"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="MPEG_4_SP"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="3"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+</class>
+<class name="MediaRecorder.VideoSource"
+ extends="java.lang.Object"
+ abstract="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<field name="CAMERA"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="1"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="DEFAULT"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="0"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+</class>
 <class name="MediaScannerConnection"
  extends="java.lang.Object"
  abstract="false"
@@ -90383,6 +91416,17 @@
  visibility="public"
 >
 </field>
+<field name="HAPTIC_FEEDBACK_ENABLED"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;haptic_feedback_enabled&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
 <field name="HTTP_PROXY"
  type="java.lang.String"
  transient="false"
@@ -116836,6 +117880,48 @@
 >
 </field>
 </class>
+<class name="HapticFeedbackConstants"
+ extends="java.lang.Object"
+ abstract="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<field name="FLAG_IGNORE_GLOBAL_SETTING"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="2"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="FLAG_IGNORE_VIEW_SETTING"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="1"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="LONG_PRESS"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="0"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+</class>
 <class name="InflateException"
  extends="java.lang.RuntimeException"
  abstract="false"
@@ -123480,6 +124566,17 @@
  visibility="public"
 >
 </method>
+<method name="isHapticFeedbackEnabled"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
 <method name="isHorizontalFadingEdgeEnabled"
  return="boolean"
  abstract="false"
@@ -124095,6 +125192,34 @@
  visibility="public"
 >
 </method>
+<method name="performHapticFeedback"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="feedbackConstant" type="int">
+</parameter>
+</method>
+<method name="performHapticFeedback"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="feedbackConstant" type="int">
+</parameter>
+<parameter name="flags" type="int">
+</parameter>
+</method>
 <method name="performLongClick"
  return="boolean"
  abstract="false"
@@ -124114,7 +125239,7 @@
  static="false"
  final="false"
  deprecated="not deprecated"
- visibility="protected"
+ visibility="public"
 >
 <parameter name="soundConstant" type="int">
 </parameter>
@@ -124581,6 +125706,19 @@
 <parameter name="focusableInTouchMode" type="boolean">
 </parameter>
 </method>
+<method name="setHapticFeedbackEnabled"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="hapticFeedbackEnabled" type="boolean">
+</parameter>
+</method>
 <method name="setHorizontalFadingEdgeEnabled"
  return="void"
  abstract="false"
@@ -125358,6 +126496,17 @@
  visibility="public"
 >
 </field>
+<field name="HAPTIC_FEEDBACK_ENABLED"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="268435456"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
 <field name="INVISIBLE"
  type="int"
  transient="false"
@@ -133630,17 +134779,6 @@
 <parameter name="flags" type="int">
 </parameter>
 </method>
-<method name="hideStatusIcon"
- return="boolean"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-</method>
 <method name="performContextMenuAction"
  return="boolean"
  abstract="false"
@@ -133682,6 +134820,19 @@
 <parameter name="text" type="android.text.Spannable">
 </parameter>
 </method>
+<method name="reportFullscreenMode"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="enabled" type="boolean">
+</parameter>
+</method>
 <method name="sendKeyEvent"
  return="boolean"
  abstract="false"
@@ -133738,21 +134889,6 @@
 <parameter name="end" type="int">
 </parameter>
 </method>
-<method name="showStatusIcon"
- return="boolean"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="packageName" type="java.lang.String">
-</parameter>
-<parameter name="resId" type="int">
-</parameter>
-</method>
 </class>
 <class name="CompletionInfo"
  extends="java.lang.Object"
@@ -134561,17 +135697,6 @@
 <parameter name="flags" type="int">
 </parameter>
 </method>
-<method name="hideStatusIcon"
- return="boolean"
- abstract="true"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-</method>
 <method name="performContextMenuAction"
  return="boolean"
  abstract="true"
@@ -134600,6 +135725,19 @@
 <parameter name="data" type="android.os.Bundle">
 </parameter>
 </method>
+<method name="reportFullscreenMode"
+ return="boolean"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="enabled" type="boolean">
+</parameter>
+</method>
 <method name="sendKeyEvent"
  return="boolean"
  abstract="true"
@@ -134643,21 +135781,6 @@
 <parameter name="end" type="int">
 </parameter>
 </method>
-<method name="showStatusIcon"
- return="boolean"
- abstract="true"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="packageName" type="java.lang.String">
-</parameter>
-<parameter name="resId" type="int">
-</parameter>
-</method>
 <field name="GET_EXTRACTED_TEXT_MONITOR"
  type="int"
  transient="false"
@@ -135158,6 +136281,19 @@
 <parameter name="flags" type="int">
 </parameter>
 </method>
+<method name="hideStatusIcon"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="imeToken" type="android.os.IBinder">
+</parameter>
+</method>
 <method name="isAcceptingText"
  return="boolean"
  abstract="false"
@@ -135193,6 +136329,17 @@
  visibility="public"
 >
 </method>
+<method name="isFullscreenMode"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
 <method name="isWatchingCursor"
  return="boolean"
  abstract="false"
@@ -135277,6 +136424,23 @@
 <parameter name="flags" type="int">
 </parameter>
 </method>
+<method name="showStatusIcon"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="imeToken" type="android.os.IBinder">
+</parameter>
+<parameter name="packageName" type="java.lang.String">
+</parameter>
+<parameter name="iconId" type="int">
+</parameter>
+</method>
 <method name="updateCursor"
  return="void"
  abstract="false"
@@ -135336,21 +136500,6 @@
 <parameter name="candidatesEnd" type="int">
 </parameter>
 </method>
-<method name="updateStatusIcon"
- return="void"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="iconId" type="int">
-</parameter>
-<parameter name="iconPackage" type="java.lang.String">
-</parameter>
-</method>
 <field name="HIDE_IMPLICIT_ONLY"
  type="int"
  transient="false"
@@ -150635,6 +151784,23 @@
 <parameter name="level" type="int">
 </parameter>
 </method>
+<method name="setFlipping"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="viewId" type="int">
+</parameter>
+<parameter name="flipping" type="boolean">
+</parameter>
+<parameter name="milliseconds" type="int">
+</parameter>
+</method>
 <method name="setImageViewBitmap"
  return="void"
  abstract="false"
diff --git a/core/java/android/app/LauncherActivity.java b/core/java/android/app/LauncherActivity.java
index c363f04..d6fcbb1 100644
--- a/core/java/android/app/LauncherActivity.java
+++ b/core/java/android/app/LauncherActivity.java
@@ -18,7 +18,6 @@
 
 import android.content.Context;
 import android.content.Intent;
-import android.content.pm.ActivityInfo;
 import android.content.pm.PackageManager;
 import android.content.pm.ResolveInfo;
 import android.content.res.Resources;
@@ -31,9 +30,7 @@
 import android.graphics.drawable.BitmapDrawable;
 import android.graphics.drawable.Drawable;
 import android.graphics.drawable.PaintDrawable;
-import android.os.AsyncTask;
 import android.os.Bundle;
-import android.view.KeyEvent;
 import android.view.LayoutInflater;
 import android.view.View;
 import android.view.ViewGroup;
@@ -145,17 +142,6 @@
             return view;
         }
 
-        private char getCandidateLetter(ResolveInfo info) {
-            PackageManager pm = LauncherActivity.this.getPackageManager();
-            CharSequence label = info.loadLabel(pm);
-
-            if (label == null) {
-                label = info.activityInfo.name;
-            }
-
-            return Character.toLowerCase(label.charAt(0));
-        }
-
         private void bindView(View view, ListItem item) {
             TextView text = (TextView) view;
             text.setText(item.label);
@@ -191,7 +177,6 @@
                         results.count = list.size();
                     }
                 } else {
-                    final PackageManager pm = LauncherActivity.this.getPackageManager();
                     final String prefixString = prefix.toString().toLowerCase();
 
                     ArrayList<ListItem> values = mOriginalValues;
@@ -243,8 +228,6 @@
         private int mIconWidth = -1;
         private int mIconHeight = -1;
 
-        private final Paint mPaint = new Paint();
-        private final Rect mBounds = new Rect();
         private final Rect mOldBounds = new Rect();
         private Canvas mCanvas = new Canvas();
         
diff --git a/core/java/android/app/SearchDialog.java b/core/java/android/app/SearchDialog.java
index 64f1ba2..5744ddc 100644
--- a/core/java/android/app/SearchDialog.java
+++ b/core/java/android/app/SearchDialog.java
@@ -835,9 +835,6 @@
         // also guard against possible race conditions (late arrival after dismiss)
         if (mSearchable != null) {
             handled = doSuggestionsKey(v, keyCode, event);
-            if (!handled) {
-                handled = refocusingKeyListener(v, keyCode, event);
-            }
         }
         return handled;
     }
@@ -1024,6 +1021,11 @@
      * @param jamQuery True means to set the query, false means to reset it to the user's choice
      */
     private void jamSuggestionQuery(boolean jamQuery, AdapterView<?> parent, int position) {
+        // quick check against race conditions
+        if (mSearchable == null) {
+            return;
+        }
+        
         mSuggestionsAdapter.setNonUserQuery(true);       // disables any suggestions processing
         if (jamQuery) {
             CursorAdapter ca = getSuggestionsAdapter(parent);
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index 52aae0d..c4d3f9d 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -1112,6 +1112,8 @@
      * <p>My include the following extras:
      * <ul>
      * <li> {@link #EXTRA_UID} containing the integer uid assigned to the new package.
+     * <li> {@link #EXTRA_REPLACING} is set to true if this is following
+     * an {@link #ACTION_PACKAGE_REMOVED} broadcast for the same package.
      * </ul>
      */
     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
diff --git a/core/java/android/gadget/GadgetHost.java b/core/java/android/gadget/GadgetHost.java
index 9176d18..31aed32 100644
--- a/core/java/android/gadget/GadgetHost.java
+++ b/core/java/android/gadget/GadgetHost.java
@@ -38,6 +38,7 @@
 public class GadgetHost {
 
     static final int HANDLE_UPDATE = 1;
+    static final int HANDLE_PROVIDER_CHANGED = 2;
 
     static Object sServiceLock = new Object();
     static IGadgetService sService;
@@ -52,6 +53,13 @@
             msg.obj = views;
             msg.sendToTarget();
         }
+
+        public void providerChanged(int gadgetId, GadgetProviderInfo info) {
+            Message msg = mHandler.obtainMessage(HANDLE_PROVIDER_CHANGED);
+            msg.arg1 = gadgetId;
+            msg.obj = info;
+            msg.sendToTarget();
+        }
     }
 
     Handler mHandler = new Handler() {
@@ -61,6 +69,10 @@
                     updateGadgetView(msg.arg1, (RemoteViews)msg.obj);
                     break;
                 }
+                case HANDLE_PROVIDER_CHANGED: {
+                    onProviderChanged(msg.arg1, (GadgetProviderInfo)msg.obj);
+                    break;
+                }
             }
         }
     };
@@ -183,7 +195,8 @@
         }
     }
 
-    public final GadgetHostView createView(Context context, int gadgetId, GadgetInfo gadget) {
+    public final GadgetHostView createView(Context context, int gadgetId,
+            GadgetProviderInfo gadget) {
         GadgetHostView view = onCreateView(context, gadgetId, gadget);
         view.setGadget(gadgetId, gadget);
         synchronized (mViews) {
@@ -203,9 +216,16 @@
      * Called to create the GadgetHostView.  Override to return a custom subclass if you
      * need it.  {@more}
      */
-    protected GadgetHostView onCreateView(Context context, int gadgetId, GadgetInfo gadget) {
+    protected GadgetHostView onCreateView(Context context, int gadgetId,
+            GadgetProviderInfo gadget) {
         return new GadgetHostView(context);
     }
+    
+    /**
+     * Called when the gadget provider for a gadget has been upgraded to a new apk.
+     */
+    protected void onProviderChanged(int gadgetId, GadgetProviderInfo gadget) {
+    }
 
     void updateGadgetView(int gadgetId, RemoteViews views) {
         GadgetHostView v;
diff --git a/core/java/android/gadget/GadgetHostView.java b/core/java/android/gadget/GadgetHostView.java
index d92c123..a985bd4 100644
--- a/core/java/android/gadget/GadgetHostView.java
+++ b/core/java/android/gadget/GadgetHostView.java
@@ -18,7 +18,6 @@
 
 import android.content.Context;
 import android.content.pm.PackageManager;
-import android.gadget.GadgetInfo;
 import android.graphics.Color;
 import android.util.Config;
 import android.util.Log;
@@ -26,12 +25,18 @@
 import android.view.LayoutInflater;
 import android.view.View;
 import android.view.ViewGroup;
+import android.view.animation.Animation;
 import android.widget.FrameLayout;
 import android.widget.RemoteViews;
 import android.widget.TextView;
 import android.widget.ViewAnimator;
 
-public class GadgetHostView extends ViewAnimator {
+/**
+ * Provides the glue to show gadget views. This class offers automatic animation
+ * between updates, and will try recycling old views for each incoming
+ * {@link RemoteViews}.
+ */
+public class GadgetHostView extends ViewAnimator implements Animation.AnimationListener {
     static final String TAG = "GadgetHostView";
     static final boolean LOGD = Config.LOGD || true;
 
@@ -42,57 +47,93 @@
             return clazz.isAnnotationPresent(RemoteViews.RemoteView.class);
         }
     };
-
-    int mGadgetId;
-    GadgetInfo mInfo;
-    View mActiveView;
-    View mStaleView;
     
-    protected int mDefaultGravity = Gravity.CENTER;
-
+    Context mLocalContext;
+    
+    int mGadgetId;
+    GadgetProviderInfo mInfo;
+    
+    View mActiveView = null;
+    View mStaleView = null;
+    
+    int mActiveLayoutId = -1;
+    int mStaleLayoutId = -1;
+    
+    /**
+     * Last set of {@link RemoteViews} applied to {@link #mActiveView}
+     */
+    RemoteViews mActiveActions = null;
+    
+    /**
+     * Flag indicating that {@link #mActiveActions} has been applied to
+     * {@link #mStaleView}, meaning it's readyto recycle.
+     */
+    boolean mStalePrepared = false;
+    
+    /**
+     * Create a host view.  Uses default fade animations.
+     */
     public GadgetHostView(Context context) {
-        super(context);
+        this(context, android.R.anim.fade_in, android.R.anim.fade_out);
     }
 
-    public void setGadget(int gadgetId, GadgetInfo info) {
-        if (LOGD) Log.d(TAG, "setGadget is incoming with info=" + info);
+    /**
+     * Create a host view. Uses specified animations when pushing
+     * {@link #updateGadget(RemoteViews)}.
+     * 
+     * @param animationIn Resource ID of in animation to use
+     * @param animationOut Resource ID of out animation to use
+     */
+    public GadgetHostView(Context context, int animationIn, int animationOut) {
+        super(context);
+        mLocalContext = context;
+        
+        // Prepare our default transition animations
+        setAnimateFirstView(true);
+        setInAnimation(context, animationIn);
+        setOutAnimation(context, animationOut);
+
+        // Watch for animation events to prepare recycling
+        Animation inAnimation = getInAnimation();
+        if (inAnimation != null) {
+            inAnimation.setAnimationListener(this);
+        }
+    }
+    
+    /**
+     * Set the gadget that will be displayed by this view.
+     */
+    public void setGadget(int gadgetId, GadgetProviderInfo info) {
         if (mInfo != null) {
             // TODO: remove the old view, or whatever
         }
         mGadgetId = gadgetId;
         mInfo = info;
-        
-        View defaultView = getDefaultView();
-        flipUpdate(defaultView);
     }
     
-    /**
-     * Trigger actual animation between current and new content in the
-     * {@link ViewAnimator}.
-     */
-    protected void flipUpdate(View newContent) {
-        if (LOGD) Log.d(TAG, "pushing an update to surface");
-        
-        // Take requested dimensions from parent, but apply default gravity.
-        ViewGroup.LayoutParams requested = newContent.getLayoutParams();
-        if (requested == null) {
-            requested = new FrameLayout.LayoutParams(LayoutParams.FILL_PARENT,
-                    LayoutParams.FILL_PARENT);
+    public int getGadgetId() {
+        return mGadgetId;
+    }
+    
+    public GadgetProviderInfo getGadgetInfo() {
+        return mInfo;
+    }
+
+    public void onAnimationEnd(Animation animation) {
+        // When our transition animation finishes, we should try bringing our
+        // newly-stale view up to the current view.
+        if (mActiveActions != null &&
+                mStaleLayoutId == mActiveActions.getLayoutId()) {
+            if (LOGD) Log.d(TAG, "after animation, layoutId matched so we're recycling old view");
+            mActiveActions.reapply(mLocalContext, mStaleView);
+            mStalePrepared = true;
         }
-        
-        FrameLayout.LayoutParams params =
-            new FrameLayout.LayoutParams(requested.width, requested.height);
-        params.gravity = mDefaultGravity;
-        newContent.setLayoutParams(params);
-        
-        // Add new content and animate to it
-        addView(newContent);
-        showNext();
-        
-        // Dispose old stale view
-        removeView(mStaleView);
-        mStaleView = mActiveView;
-        mActiveView = newContent;
+    }
+
+    public void onAnimationRepeat(Animation animation) {
+    }
+
+    public void onAnimationStart(Animation animation) {
     }
 
     /**
@@ -100,26 +141,42 @@
      * gadget provider. Will animate into these new views as needed.
      */
     public void updateGadget(RemoteViews remoteViews) {
-        if (LOGD) Log.d(TAG, "updateGadget() with remoteViews = " + remoteViews);
+        if (LOGD) Log.d(TAG, "updateGadget called");
         
+        boolean recycled = false;
         View newContent = null;
         Exception exception = null;
         
-        try {
-            if (remoteViews == null) {
-                // there is no remoteViews (yet), so use the initial layout
-                newContent = getDefaultView();
-            } else {
-                // use the RemoteViews
-                // TODO: try applying RemoteViews to existing staleView if available 
-                newContent = remoteViews.apply(mContext, this);
+        if (remoteViews == null) {
+            newContent = getDefaultView();
+        }
+        
+        // If our stale view has been prepared to match active, and the new
+        // layout matches, try recycling it
+        if (newContent == null && mStalePrepared &&
+                remoteViews.getLayoutId() == mStaleLayoutId) {
+            try {
+                remoteViews.reapply(mLocalContext, mStaleView);
+                newContent = mStaleView;
+                recycled = true;
+                if (LOGD) Log.d(TAG, "was able to recycled existing layout");
+            } catch (RuntimeException e) {
+                exception = e;
             }
-        } catch (RuntimeException e) {
-            exception = e;
+        }
+        
+        // Try normal RemoteView inflation
+        if (newContent == null) {
+            try {
+                newContent = remoteViews.apply(mLocalContext, this);
+                if (LOGD) Log.d(TAG, "had to inflate new layout");
+            } catch (RuntimeException e) {
+                exception = e;
+            }
         }
         
         if (exception != null && LOGD) {
-            Log.w(TAG, "Error inflating gadget " + mInfo, exception);
+            Log.w(TAG, "Error inflating gadget " + getGadgetInfo(), exception);
         }
         
         if (newContent == null) {
@@ -128,8 +185,44 @@
             if (LOGD) Log.d(TAG, "updateGadget couldn't find any view, so inflating error");
             newContent = getErrorView();
         }
-
-        flipUpdate(newContent);
+        
+        if (!recycled) {
+            prepareView(newContent);
+            addView(newContent);
+        }
+        
+        showNext();
+        
+        if (!recycled) {
+            removeView(mStaleView);
+        }
+        
+        mStalePrepared = false;
+        mActiveActions = remoteViews;
+        
+        mStaleView = mActiveView;
+        mActiveView = newContent;
+        
+        mStaleLayoutId = mActiveLayoutId;
+        mActiveLayoutId = (remoteViews == null) ? -1 : remoteViews.getLayoutId();
+    }
+    
+    /**
+     * Prepare the given view to be shown. This might include adjusting
+     * {@link FrameLayout.LayoutParams} before inserting.
+     */
+    protected void prepareView(View view) {
+        // Take requested dimensions from parent, but apply default gravity.
+        ViewGroup.LayoutParams requested = view.getLayoutParams();
+        if (requested == null) {
+            requested = new FrameLayout.LayoutParams(LayoutParams.FILL_PARENT,
+                    LayoutParams.FILL_PARENT);
+        }
+        
+        FrameLayout.LayoutParams params =
+            new FrameLayout.LayoutParams(requested.width, requested.height);
+        params.gravity = Gravity.CENTER;
+        view.setLayoutParams(params);
     }
     
     /**
@@ -141,7 +234,7 @@
         
         try {
             if (mInfo != null) {
-                Context theirContext = mContext.createPackageContext(
+                Context theirContext = mLocalContext.createPackageContext(
                         mInfo.provider.getPackageName(), 0 /* no flags */);
                 LayoutInflater inflater = (LayoutInflater)
                         theirContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
@@ -173,11 +266,10 @@
      * Inflate and return a view that represents an error state.
      */
     protected View getErrorView() {
-        TextView tv = new TextView(mContext);
+        TextView tv = new TextView(mLocalContext);
         // TODO: move this error string and background color into resources
         tv.setText("Error inflating gadget");
         tv.setBackgroundColor(Color.argb(127, 0, 0, 0));
         return tv;
     }
 }
-
diff --git a/core/java/android/gadget/GadgetInfo.java b/core/java/android/gadget/GadgetInfo.java
deleted file mode 100644
index 5ac3da9..0000000
--- a/core/java/android/gadget/GadgetInfo.java
+++ /dev/null
@@ -1,140 +0,0 @@
-/*
- * Copyright (C) 2006 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.gadget;
-
-import android.os.Parcel;
-import android.os.Parcelable;
-import android.content.ComponentName;
-
-/**
- * Describes the meta data for an installed gadget.
- */
-public class GadgetInfo implements Parcelable {
-    /**
-     * Identity of this gadget component.  This component should be a {@link
-     * android.content.BroadcastReceiver}, and it will be sent the Gadget intents
-     * {@link android.gadget as described in the gadget package documentation}.
-     */
-    public ComponentName provider;
-
-    /**
-     * Minimum width of the gadget, in dp.
-     */
-    public int minWidth;
-
-    /**
-     * Minimum height of the gadget, in dp.
-     */
-    public int minHeight;
-
-    /**
-     * How often, in milliseconds, that this gadget wants to be updated.
-     * The gadget manager may place a limit on how often a gadget is updated.
-     */
-    public int updatePeriodMillis;
-
-    /**
-     * The resource id of the initial layout for this gadget.  This should be
-     * displayed until the RemoteViews for the gadget is available.
-     */
-    public int initialLayout;
-
-    /**
-     * The activity to launch that will configure the gadget.
-     */
-    public ComponentName configure;
-
-    /**
-     * The label to display to the user.
-     */
-    public String label;
-
-    /**
-     * The icon to display for this gadget in the picker list.
-     */
-    public int icon;
-
-    public GadgetInfo() {
-    }
-
-    /**
-     * Unflatten the GadgetInfo from a parcel.
-     */
-    public GadgetInfo(Parcel in) {
-        if (0 != in.readInt()) {
-            this.provider = new ComponentName(in);
-        }
-        this.minWidth = in.readInt();
-        this.minHeight = in.readInt();
-        this.updatePeriodMillis = in.readInt();
-        this.initialLayout = in.readInt();
-        if (0 != in.readInt()) {
-            this.configure = new ComponentName(in);
-        }
-        this.label = in.readString();
-        this.icon = in.readInt();
-    }
-
-
-    public void writeToParcel(android.os.Parcel out, int flags) {
-        if (this.provider != null) {
-            out.writeInt(1);
-            this.provider.writeToParcel(out, flags);
-        } else {
-            out.writeInt(0);
-        }
-        out.writeInt(this.minWidth);
-        out.writeInt(this.minHeight);
-        out.writeInt(this.updatePeriodMillis);
-        out.writeInt(this.initialLayout);
-        if (this.configure != null) {
-            out.writeInt(1);
-            this.configure.writeToParcel(out, flags);
-        } else {
-            out.writeInt(0);
-        }
-        out.writeString(this.label);
-        out.writeInt(this.icon);
-    }
-
-    public int describeContents() {
-        return 0;
-    }
-
-    /**
-     * Parcelable.Creator that instantiates GadgetInfo objects
-     */
-    public static final Parcelable.Creator<GadgetInfo> CREATOR
-            = new Parcelable.Creator<GadgetInfo>()
-    {
-        public GadgetInfo createFromParcel(Parcel parcel)
-        {
-            return new GadgetInfo(parcel);
-        }
-
-        public GadgetInfo[] newArray(int size)
-        {
-            return new GadgetInfo[size];
-        }
-    };
-
-    public String toString() {
-        return "GadgetInfo(provider=" + this.provider + ")";
-    }
-}
-
-
diff --git a/core/java/android/gadget/GadgetManager.java b/core/java/android/gadget/GadgetManager.java
index 20f4014..a9a2c80 100644
--- a/core/java/android/gadget/GadgetManager.java
+++ b/core/java/android/gadget/GadgetManager.java
@@ -38,68 +38,142 @@
     static final String TAG = "GadgetManager";
 
     /**
-     * Send this when you want to pick a gadget to display.
+     * Send this from your gadget host activity when you want to pick a gadget to display.
+     * The gadget picker activity will be launched.
+     * <p>
+     * You must supply the following extras:
+     * <table>
+     *   <tr>
+     *     <td>{@link #EXTRA_GADGET_ID}</td>
+     *     <td>A newly allocated gadgetId, which will be bound to the gadget provider
+     *         once the user has selected one.</td>
+     *  </tr>
+     * </table>
      *
      * <p>
      * The system will respond with an onActivityResult call with the following extras in
      * the intent:
-     * <ul>
-     *   <li><b>gadgetIds</b></li>
-     *   <li><b>hostId</b></li>
-     * </ul>
-     * TODO: Add constants for these.
-     * TODO: Where does this go?
+     * <table>
+     *   <tr>
+     *     <td>{@link #EXTRA_GADGET_ID}</td>
+     *     <td>The gadgetId that you supplied in the original intent.</td>
+     *  </tr>
+     * </table>
+     * <p>
+     * When you receive the result from the gadget pick activity, if the resultCode is
+     * {@link android.app.Activity#RESULT_OK}, a gadget has been selected.  You should then
+     * check the GadgetProviderInfo for the returned gadget, and if it has one, launch its configuration
+     * activity.  If {@link android.app.Activity#RESULT_CANCELED} is returned, you should delete
+     * the gadgetId.
+     *
+     * @see #ACTION_GADGET_CONFIGURE
      */
-    public static final String GADGET_PICK_ACTION = "android.gadget.action.PICK_GADGET";
+    public static final String ACTION_GADGET_PICK = "android.gadget.action.GADGET_PICK";
 
+    /**
+     * Sent when it is time to configure your gadget while it is being added to a host.
+     * This action is not sent as a broadcast to the gadget provider, but as a startActivity
+     * to the activity specified in the {@link GadgetProviderInfo GadgetProviderInfo meta-data}.
+     *
+     * <p>
+     * The intent will contain the following extras:
+     * <table>
+     *   <tr>
+     *     <td>{@link #EXTRA_GADGET_ID}</td>
+     *     <td>The gadgetId to configure.</td>
+     *  </tr>
+     * </table>
+     *
+     * <p>If you return {@link android.app.Activity#RESULT_OK} using
+     * {@link android.app.Activity#setResult Activity.setResult()}, the gadget will be added,
+     * and you will receive an {@link #ACTION_GADGET_UPDATE} broadcast for this gadget.
+     * If you return {@link android.app.Activity#RESULT_CANCELED}, the host will cancel the add
+     * and not display this gadget, and you will receive a {@link #ACTION_GADGET_DELETED} broadcast.
+     */
+    public static final String ACTION_GADGET_CONFIGURE = "android.gadget.action.GADGET_CONFIGURE";
+
+    /**
+     * An intent extra that contains one gadgetId.
+     * <p>
+     * The value will be an int that can be retrieved like this:
+     * {@sample frameworks/base/tests/gadgets/GadgetHostTest/src/com/android/tests/gadgethost/GadgetHostActivity.java getExtra_EXTRA_GADGET_ID}
+     */
     public static final String EXTRA_GADGET_ID = "gadgetId";
+
+    /**
+     * An intent extra that contains multiple gadgetIds.
+     * <p>
+     * The value will be an int array that can be retrieved like this:
+     * {@sample frameworks/base/tests/gadgets/GadgetHostTest/src/com/android/tests/gadgethost/TestGadgetProvider.java getExtra_EXTRA_GADGET_IDS}
+     */
     public static final String EXTRA_GADGET_IDS = "gadgetIds";
-    public static final String EXTRA_HOST_ID = "hostId";
+
+    /**
+     * A sentiel value that the gadget manager will never return as a gadgetId.
+     */
+    public static final int INVALID_GADGET_ID = 0;
 
     /**
      * Sent when it is time to update your gadget.
      *
      * <p>This may be sent in response to a new instance for this gadget provider having
-     * been instantiated, the requested {@link GadgetInfo#updatePeriodMillis update interval}
+     * been instantiated, the requested {@link GadgetProviderInfo#updatePeriodMillis update interval}
      * having lapsed, or the system booting.
-     */
-    public static final String GADGET_UPDATE_ACTION = "android.gadget.action.GADGET_UPDATE";
-
-    /**
-     * Sent when it is time to configure your gadget.  This action is not sent as a broadcast
-     * to the gadget provider, but as a startActivity to the activity specified in the
-     * {@link GadgetInfo GadgetInfo meta-data}.
      *
-     * <p>The {@link #EXTRA_GADGET_ID} extra contains the gadget ID.
+     * <p>
+     * The intent will contain the following extras:
+     * <table>
+     *   <tr>
+     *     <td>{@link #EXTRA_GADGET_IDS}</td>
+     *     <td>The gadgetIds to update.  This may be all of the gadgets created for this
+     *     provider, or just a subset.  The system tries to send updates for as few gadget
+     *     instances as possible.</td>
+     *  </tr>
+     * </table>
+     * 
+     * @see GadgetProvider#onUpdate GadgetProvider.onUpdate(Context context, GadgetManager gadgetManager, int[] gadgetIds)
      */
-    public static final String GADGET_CONFIGURE_ACTION = "android.gadget.action.GADGET_CONFIGURE";
+    public static final String ACTION_GADGET_UPDATE = "android.gadget.action.GADGET_UPDATE";
 
     /**
-     * Sent when the gadget is added to a host for the first time.  This broadcast is sent at
-     * boot time if there is a gadget host installed with an instance for this provider.
+     * Sent when an instance of a gadget is deleted from its host.
+     *
+     * @see GadgetProvider#onDeleted GadgetProvider.onDeleted(Context context, int[] gadgetIds)
      */
-    public static final String GADGET_ENABLED_ACTION = "android.gadget.action.GADGET_ENABLED";
+    public static final String ACTION_GADGET_DELETED = "android.gadget.action.GADGET_DELETED";
 
     /**
-     * Sent when an instances of a gadget is deleted from the host.
+     * Sent when an instance of a gadget is removed from the last host.
+     * 
+     * @see GadgetProvider#onEnabled GadgetProvider.onEnabled(Context context)
      */
-    public static final String GADGET_DELETED_ACTION = "android.gadget.action.GADGET_DELETED";
+    public static final String ACTION_GADGET_DISABLED = "android.gadget.action.GADGET_DISABLED";
 
     /**
-     * Sent when the gadget is removed from the last host.
+     * Sent when an instance of a gadget is added to a host for the first time.
+     * This broadcast is sent at boot time if there is a gadget host installed with
+     * an instance for this provider.
+     * 
+     * @see GadgetProvider#onEnabled GadgetProvider.onEnabled(Context context)
      */
-    public static final String GADGET_DISABLED_ACTION = "android.gadget.action.GADGET_DISABLED";
+    public static final String ACTION_GADGET_ENABLED = "android.gadget.action.GADGET_ENABLED";
 
     /**
      * Field for the manifest meta-data tag.
+     *
+     * @see GadgetProviderInfo
      */
-    public static final String GADGET_PROVIDER_META_DATA = "android.gadget.provider";
+    public static final String META_DATA_GADGET_PROVIDER = "android.gadget.provider";
 
     static WeakHashMap<Context, WeakReference<GadgetManager>> sManagerCache = new WeakHashMap();
     static IGadgetService sService;
     
     Context mContext;
 
+    /**
+     * Get the GadgetManager instance to use for the supplied {@link android.content.Context
+     * Context} object.
+     */
     public static GadgetManager getInstance(Context context) {
         synchronized (sManagerCache) {
             if (sService == null) {
@@ -125,9 +199,11 @@
     }
 
     /**
-     * Call this with the new RemoteViews for your gadget whenever you need to.
+     * Set the RemoteViews to use for the specified gadgetIds.
      *
      * <p>
+     * It is okay to call this method both inside an {@link #ACTION_GADGET_UPDATE} broadcast,
+     * and outside of the handler.
      * This method will only work when called from the uid that owns the gadget provider.
      *
      * @param gadgetIds     The gadget instances for which to set the RemoteViews.
@@ -143,9 +219,26 @@
     }
 
     /**
-     * Call this with the new RemoteViews for your gadget whenever you need to.
+     * Set the RemoteViews to use for the specified gadgetId.
      *
      * <p>
+     * It is okay to call this method both inside an {@link #ACTION_GADGET_UPDATE} broadcast,
+     * and outside of the handler.
+     * This method will only work when called from the uid that owns the gadget provider.
+     *
+     * @param gadgetId      The gadget instance for which to set the RemoteViews.
+     * @param views         The RemoteViews object to show.
+     */
+    public void updateGadget(int gadgetId, RemoteViews views) {
+        updateGadget(new int[] { gadgetId }, views);
+    }
+
+    /**
+     * Set the RemoteViews to use for all gadget instances for the supplied gadget provider.
+     *
+     * <p>
+     * It is okay to call this method both inside an {@link #ACTION_GADGET_UPDATE} broadcast,
+     * and outside of the handler.
      * This method will only work when called from the uid that owns the gadget provider.
      *
      * @param provider      The {@link ComponentName} for the {@link
@@ -165,7 +258,7 @@
     /**
      * Return a list of the gadget providers that are currently installed.
      */
-    public List<GadgetInfo> getInstalledProviders() {
+    public List<GadgetProviderInfo> getInstalledProviders() {
         try {
             return sService.getInstalledProviders();
         }
@@ -175,12 +268,12 @@
     }
 
     /**
-     * Get the available info about the gadget.  If the gadgetId has not been bound yet,
-     * this method will return null.
+     * Get the available info about the gadget.
      *
-     * TODO: throws GadgetNotFoundException ??? if not valid
+     * @return A gadgetId.  If the gadgetId has not been bound to a provider yet, or
+     * you don't have access to that gadgetId, null is returned.
      */
-    public GadgetInfo getGadgetInfo(int gadgetId) {
+    public GadgetProviderInfo getGadgetInfo(int gadgetId) {
         try {
             return sService.getGadgetInfo(gadgetId);
         }
@@ -190,7 +283,14 @@
     }
 
     /**
-     * Set the component for a given gadgetId.  You need the GADGET_LIST permission.
+     * Set the component for a given gadgetId.
+     *
+     * <p class="note">You need the GADGET_LIST permission.  This method is to be used by the
+     * gadget picker.
+     *
+     * @param gadgetId     The gadget instance for which to set the RemoteViews.
+     * @param provider      The {@link android.content.BroadcastReceiver} that will be the gadget
+     *                      provider for this gadget.
      */
     public void bindGadgetId(int gadgetId, ComponentName provider) {
         try {
diff --git a/core/java/android/gadget/GadgetProvider.java b/core/java/android/gadget/GadgetProvider.java
index 1ddfe3f..7e10e78 100755
--- a/core/java/android/gadget/GadgetProvider.java
+++ b/core/java/android/gadget/GadgetProvider.java
@@ -55,7 +55,7 @@
         // Protect against rogue update broadcasts (not really a security issue,
         // just filter bad broacasts out so subclasses are less likely to crash).
         String action = intent.getAction();
-        if (GadgetManager.GADGET_UPDATE_ACTION.equals(action)) {
+        if (GadgetManager.ACTION_GADGET_UPDATE.equals(action)) {
             Bundle extras = intent.getExtras();
             if (extras != null) {
                 int[] gadgetIds = extras.getIntArray(GadgetManager.EXTRA_GADGET_IDS);
@@ -64,7 +64,7 @@
                 }
             }
         }
-        else if (GadgetManager.GADGET_DELETED_ACTION.equals(action)) {
+        else if (GadgetManager.ACTION_GADGET_DELETED.equals(action)) {
             Bundle extras = intent.getExtras();
             if (extras != null) {
                 int[] gadgetIds = extras.getIntArray(GadgetManager.EXTRA_GADGET_IDS);
@@ -73,102 +73,81 @@
                 }
             }
         }
-        else if (GadgetManager.GADGET_ENABLED_ACTION.equals(action)) {
+        else if (GadgetManager.ACTION_GADGET_ENABLED.equals(action)) {
             this.onEnabled(context);
         }
-        else if (GadgetManager.GADGET_DISABLED_ACTION.equals(action)) {
+        else if (GadgetManager.ACTION_GADGET_DISABLED.equals(action)) {
             this.onDisabled(context);
         }
     }
     // END_INCLUDE(onReceive)
     
     /**
-     * Called in response to the {@link GadgetManager#GADGET_UPDATE_ACTION} broadcast when
+     * Called in response to the {@link GadgetManager#ACTION_GADGET_UPDATE} broadcast when
      * this gadget provider is being asked to provide {@link android.widget.RemoteViews RemoteViews}
      * for a set of gadgets.  Override this method to implement your own gadget functionality.
      *
      * {@more}
-     * <p class="note">If you want this method called, you must declare in an intent-filter in
-     * your AndroidManifest.xml file that you accept the GADGET_UPDATE_ACTION intent action.
-     * For example:
-     * <font color=red>TODO: SAMPLE CODE GOES HERE</font>
-     * </p>
      * 
      * @param context   The {@link android.content.Context Context} in which this receiver is
      *                  running.
      * @param gadgetManager A {@link GadgetManager} object you can call {@link
-     *                  GadgetManager#updateGadgets} on.
+     *                  GadgetManager#updateGadget} on.
      * @param gadgetIds The gadgetsIds for which an update is needed.  Note that this
      *                  may be all of the gadget instances for this provider, or just
      *                  a subset of them.
      *
-     * @see GadgetManager#GADGET_UPDATE_ACTION
+     * @see GadgetManager#ACTION_GADGET_UPDATE
      */
     public void onUpdate(Context context, GadgetManager gadgetManager, int[] gadgetIds) {
     }
     
     /**
-     * Called in response to the {@link GadgetManager#GADGET_DELETED_ACTION} broadcast when
+     * Called in response to the {@link GadgetManager#ACTION_GADGET_DELETED} broadcast when
      * one or more gadget instances have been deleted.  Override this method to implement
      * your own gadget functionality.
      *
      * {@more}
-     * <p class="note">If you want this method called, you must declare in an intent-filter in
-     * your AndroidManifest.xml file that you accept the GADGET_DELETED_ACTION intent action.
-     * For example:
-     * <font color=red>TODO: SAMPLE CODE GOES HERE</font>
-     * </p>
      * 
      * @param context   The {@link android.content.Context Context} in which this receiver is
      *                  running.
      * @param gadgetIds The gadgetsIds that have been deleted from their host.
      *
-     * @see GadgetManager#GADGET_DELETED_ACTION
+     * @see GadgetManager#ACTION_GADGET_DELETED
      */
     public void onDeleted(Context context, int[] gadgetIds) {
     }
 
     /**
-     * Called in response to the {@link GadgetManager#GADGET_ENABLED_ACTION} broadcast when
+     * Called in response to the {@link GadgetManager#ACTION_GADGET_ENABLED} broadcast when
      * the a gadget for this provider is instantiated.  Override this method to implement your
      * own gadget functionality.
      *
      * {@more}
      * When the last gadget for this provider is deleted,
-     * {@link GadgetManager#GADGET_DISABLED_ACTION} is sent and {@link #onDisabled}
-     * is called.  If after that, a gadget for this provider is created again, onEnabled() will
-     * be called again.
+     * {@link GadgetManager#ACTION_GADGET_DISABLED} is sent by the gadget manager, and
+     * {@link #onDisabled} is called.  If after that, a gadget for this provider is created
+     * again, onEnabled() will be called again.
      *
-     * <p class="note">If you want this method called, you must declare in an intent-filter in
-     * your AndroidManifest.xml file that you accept the GADGET_ENABLED_ACTION intent action.
-     * For example:
-     * <font color=red>TODO: SAMPLE CODE GOES HERE</font>
-     * </p>
-     * 
      * @param context   The {@link android.content.Context Context} in which this receiver is
      *                  running.
      *
-     * @see GadgetManager#GADGET_ENABLED_ACTION
+     * @see GadgetManager#ACTION_GADGET_ENABLED
      */
     public void onEnabled(Context context) {
     }
 
     /**
-     * Called in response to the {@link GadgetManager#GADGET_DISABLED_ACTION} broadcast, which
+     * Called in response to the {@link GadgetManager#ACTION_GADGET_DISABLED} broadcast, which
      * is sent when the last gadget instance for this provider is deleted.  Override this method
      * to implement your own gadget functionality.
      *
      * {@more}
-     * <p class="note">If you want this method called, you must declare in an intent-filter in
-     * your AndroidManifest.xml file that you accept the GADGET_DISABLED_ACTION intent action.
-     * For example:
-     * <font color=red>TODO: SAMPLE CODE GOES HERE</font>
-     * </p>
      * 
      * @param context   The {@link android.content.Context Context} in which this receiver is
      *                  running.
      *
-     * @see GadgetManager#GADGET_DISABLED_ACTION
+     * @see GadgetManager#ACTION_GADGET_DISABLED
      */
     public void onDisabled(Context context) {
     }
diff --git a/core/java/android/gadget/GadgetInfo.aidl b/core/java/android/gadget/GadgetProviderInfo.aidl
similarity index 95%
rename from core/java/android/gadget/GadgetInfo.aidl
rename to core/java/android/gadget/GadgetProviderInfo.aidl
index 7231545..589f886 100644
--- a/core/java/android/gadget/GadgetInfo.aidl
+++ b/core/java/android/gadget/GadgetProviderInfo.aidl
@@ -16,4 +16,4 @@
 
 package android.gadget;
 
-parcelable GadgetInfo;
+parcelable GadgetProviderInfo;
diff --git a/core/java/android/gadget/GadgetProviderInfo.java b/core/java/android/gadget/GadgetProviderInfo.java
new file mode 100644
index 0000000..95c0432
--- /dev/null
+++ b/core/java/android/gadget/GadgetProviderInfo.java
@@ -0,0 +1,168 @@
+/*
+ * Copyright (C) 2006 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.gadget;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.content.ComponentName;
+
+/**
+ * Describes the meta data for an installed gadget provider.  The fields in this class
+ * correspond to the fields in the <code>&lt;gadget-provider&gt;</code> xml tag.
+ */
+public class GadgetProviderInfo implements Parcelable {
+    /**
+     * Identity of this gadget component.  This component should be a {@link
+     * android.content.BroadcastReceiver}, and it will be sent the Gadget intents
+     * {@link android.gadget as described in the gadget package documentation}.
+     *
+     * <p>This field corresponds to the <code>android:name</code> attribute in
+     * the <code>&lt;receiver&gt;</code> element in the AndroidManifest.xml file.
+     */
+    public ComponentName provider;
+
+    /**
+     * Minimum width of the gadget, in dp.
+     *
+     * <p>This field corresponds to the <code>android:minWidth</code> attribute in
+     * the gadget meta-data file.
+     */
+    public int minWidth;
+
+    /**
+     * Minimum height of the gadget, in dp.
+     *
+     * <p>This field corresponds to the <code>android:minHeight</code> attribute in
+     * the gadget meta-data file.
+     */
+    public int minHeight;
+
+    /**
+     * How often, in milliseconds, that this gadget wants to be updated.
+     * The gadget manager may place a limit on how often a gadget is updated.
+     *
+     * <p>This field corresponds to the <code>android:updatePeriodMillis</code> attribute in
+     * the gadget meta-data file.
+     */
+    public int updatePeriodMillis;
+
+    /**
+     * The resource id of the initial layout for this gadget.  This should be
+     * displayed until the RemoteViews for the gadget is available.
+     *
+     * <p>This field corresponds to the <code>android:initialLayout</code> attribute in
+     * the gadget meta-data file.
+     */
+    public int initialLayout;
+
+    /**
+     * The activity to launch that will configure the gadget.
+     *
+     * <p>This class name of field corresponds to the <code>android:configure</code> attribute in
+     * the gadget meta-data file.  The package name always corresponds to the package containing
+     * the gadget provider.
+     */
+    public ComponentName configure;
+
+    /**
+     * The label to display to the user in the gadget picker.  If not supplied in the
+     * xml, the application label will be used.
+     *
+     * <p>This field corresponds to the <code>android:label</code> attribute in
+     * the <code>&lt;receiver&gt;</code> element in the AndroidManifest.xml file.
+     */
+    public String label;
+
+    /**
+     * The icon to display for this gadget in the gadget picker.  If not supplied in the
+     * xml, the application icon will be used.
+     *
+     * <p>This field corresponds to the <code>android:icon</code> attribute in
+     * the <code>&lt;receiver&gt;</code> element in the AndroidManifest.xml file.
+     */
+    public int icon;
+
+    public GadgetProviderInfo() {
+    }
+
+    /**
+     * Unflatten the GadgetProviderInfo from a parcel.
+     */
+    public GadgetProviderInfo(Parcel in) {
+        if (0 != in.readInt()) {
+            this.provider = new ComponentName(in);
+        }
+        this.minWidth = in.readInt();
+        this.minHeight = in.readInt();
+        this.updatePeriodMillis = in.readInt();
+        this.initialLayout = in.readInt();
+        if (0 != in.readInt()) {
+            this.configure = new ComponentName(in);
+        }
+        this.label = in.readString();
+        this.icon = in.readInt();
+    }
+
+
+    public void writeToParcel(android.os.Parcel out, int flags) {
+        if (this.provider != null) {
+            out.writeInt(1);
+            this.provider.writeToParcel(out, flags);
+        } else {
+            out.writeInt(0);
+        }
+        out.writeInt(this.minWidth);
+        out.writeInt(this.minHeight);
+        out.writeInt(this.updatePeriodMillis);
+        out.writeInt(this.initialLayout);
+        if (this.configure != null) {
+            out.writeInt(1);
+            this.configure.writeToParcel(out, flags);
+        } else {
+            out.writeInt(0);
+        }
+        out.writeString(this.label);
+        out.writeInt(this.icon);
+    }
+
+    public int describeContents() {
+        return 0;
+    }
+
+    /**
+     * Parcelable.Creator that instantiates GadgetProviderInfo objects
+     */
+    public static final Parcelable.Creator<GadgetProviderInfo> CREATOR
+            = new Parcelable.Creator<GadgetProviderInfo>()
+    {
+        public GadgetProviderInfo createFromParcel(Parcel parcel)
+        {
+            return new GadgetProviderInfo(parcel);
+        }
+
+        public GadgetProviderInfo[] newArray(int size)
+        {
+            return new GadgetProviderInfo[size];
+        }
+    };
+
+    public String toString() {
+        return "GadgetProviderInfo(provider=" + this.provider + ")";
+    }
+}
+
+
diff --git a/core/java/android/gadget/package.html b/core/java/android/gadget/package.html
index 4b8b9d9..4c04396 100644
--- a/core/java/android/gadget/package.html
+++ b/core/java/android/gadget/package.html
@@ -1,41 +1,126 @@
 <body>
-{@hide}
 <p>Android allows applications to publish views to be embedded in other applications.  These
 views are called gadgets, and are published by "gadget providers."  The component that can
-contain gadgets is called a "gadget host."  See the links below for more information.
+contain gadgets is called a "gadget host."
 </p>
-<h3><a href="{@toroot}reference/android/gadget/package-descr.html#providers">Gadget Providers</a></h3>
+<h3><a href="package-descr.html#providers">Gadget Providers</a></h3>
 <ul>
-  <li><a href="{@toroot}reference/android/gadget/package-descr.html#provider_manifest">Declaring a gadget in the AndroidManifest</a></li>
-  <li><a href="{@toroot}reference/android/gadget/package-descr.html#provider_meta_data">Adding the {@link android.gadget.GadgetInfo GadgetInfo} meta-data</a></li>
-  <li><a href="{@toroot}reference/android/gadget/package-descr.html#provider_GadgetProvider">Using the {@link android.gadget.GadgetProvider GadgetProvider} class</a></li>
-  <li><a href="{@toroot}reference/android/gadget/package-descr.html#provider_configuration">Gadget Configuration UI</a></li>
-  <li><a href="{@toroot}reference/android/gadget/package-descr.html#provider_broadcasts">Gadget Broadcast Intents</a></li>
+  <li><a href="package-descr.html#provider_manifest">Declaring a gadget in the AndroidManifest</a></li>
+  <li><a href="package-descr.html#provider_meta_data">Adding the GadgetProviderInfo meta-data</a></li>
+  <li><a href="package-descr.html#provider_GadgetProvider">Using the GadgetProvider class</a></li>
+  <li><a href="package-descr.html#provider_configuration">Gadget Configuration UI</a></li>
+  <li><a href="package-descr.html#provider_broadcasts">Gadget Broadcast Intents</a></li>
 </ul>
-<h3><a href="{@toroot}reference/android/gadget/package-descr.html#">Gadget Hosts</a></h3>
-<ul>
-  <li><a href="{@toroot}reference/android/gadget/package-descr.html#">asdf</a></li>
-</ul>
+<h3><a href="package-descr.html#">Gadget Hosts</a></h3>
+
+
 {@more}
+
+
 <h2><a name="providers"></a>Gadget Providers</h2>
-<p>Any application can publish gadgets.  All an application needs to do to publish a gadget is
+<p>
+Any application can publish gadgets.  All an application needs to do to publish a gadget is
 to have a {@link android.content.BroadcastReceiver} that receives the {@link
-android.gadget.GadgetManager#GADGET_UPDATE_ACTION GadgetManager.GADGET_UPDATE_ACTION} intent,
-and provide some meta-data about the gadget.
+android.gadget.GadgetManager#ACTION_GADGET_UPDATE GadgetManager.ACTION_GADGET_UPDATE} intent,
+and provide some meta-data about the gadget.  Android provides the
+{@link android.gadget.GadgetProvider} class, which extends BroadcastReceiver, as a convenience
+class to aid in handling the broadcasts.
 
 <h3><a name="provider_manifest"></a>Declaring a gadget in the AndroidManifest</h3>
 
-<h3><a name="provider_meta_data"></a>Adding the {@link android.gadget.GadgetInfo GadgetInfo} meta-data</h3>
+<p>
+First, declare the {@link android.content.BroadcastReceiver} in your application's
+<code>AndroidManifest.xml</code> file.
+
+{@sample frameworks/base/tests/gadgets/GadgetHostTest/AndroidManifest.xml GadgetProvider}
+
+<p>
+The <b><code>&lt;receiver&gt;</b> element has the following attributes:
+<ul>
+  <li><b><code>android:name</code> -</b> which specifies the
+        {@link android.content.BroadcastReceiver} or {@link android.gadget.GadgetProvider}
+        class.</li>
+  <li><b><code>android:label</code> -</b> which specifies the string resource that
+        will be shown by the gadget picker as the label.</li>
+  <li><b><code>android:icon</code> -</b> which specifies the drawable resource that
+        will be shown by the gadget picker as the icon.</li>
+</ul>
+
+<p>
+The <b><code>&lt;intent-filter&gt;</b> element tells the {@link android.content.pm.PackageManager}
+that this {@link android.content.BroadcastReceiver} receives the {@link
+android.gadget.GadgetManager#ACTION_GADGET_UPDATE GadgetManager.ACTION_GADGET_UPDATE} broadcast.
+The gadget manager will send other broadcasts directly to your gadget provider as required.
+It is only necessary to explicitly declare that you accept the {@link
+android.gadget.GadgetManager#ACTION_GADGET_UPDATE GadgetManager.ACTION_GADGET_UPDATE} broadcast.
+
+<p>
+The <b><code>&lt;meta-data&gt;</code></b> element tells the gadget manager which xml resource to
+read to find the {@link android.gadget.GadgetProviderInfo} for your gadget provider.  It has the following
+attributes:
+<ul>
+  <li><b><code>android:name="android.gadget.provider"</code> -</b> identifies this meta-data
+        as the {@link android.gadget.GadgetProviderInfo} descriptor.</li>
+  <li><b><code>android:resource</code> -</b> is the xml resource to use as that descriptor.</li>
+</ul>
+
+
+<h3><a name="provider_meta_data"></a>Adding the {@link android.gadget.GadgetProviderInfo GadgetProviderInfo} meta-data</h3>
+
+<p>
+For a gadget, the values in the {@link android.gadget.GadgetProviderInfo} structure are supplied
+in an XML resource.  In the example above, the xml resource is referenced with
+<code>android:resource="@xml/gadget_info"</code>.  That XML file would go in your application's
+directory at <code>res/xml/gadget_info.xml</code>.  Here is a simple example.
+
+{@sample frameworks/base/tests/gadgets/GadgetHostTest/res/xml/gadget_info.xml GadgetProviderInfo}
+
+<p>
+The attributes are as documented in the {@link android.gadget.GadgetProviderInfo GagetInfo} class.  (86400000 milliseconds means once per day)
+
 
 <h3><a name="provider_GadgetProvider"></a>Using the {@link android.gadget.GadgetProvider GadgetProvider} class</h3>
 
+<p>The GadgetProvider class is the easiest way to handle the gadget provider intent broadcasts.
+See the <code>src/com/example/android/apis/gadget/ExampleGadgetProvider.java</code>
+sample class in ApiDemos for an example.
+
+<p class="note">Keep in mind that since the the GadgetProvider is a BroadcastReceiver,
+your process is not guaranteed to keep running after the callback methods return.  See
+<a href="../../../guide/topics/fundamentals.html#broadlife">Application Fundamentals &gt;
+Broadcast Receiver Lifecycle</a> for more information.
+
+
+
 <h3><a name="provider_configuration"></a>Gadget Configuration UI</h3>
 
+<p>
+Gadget hosts have the ability to start a configuration activity when a gadget is instantiated.
+The activity should be declared as normal in AndroidManifest.xml, and it should be listed in
+the GadgetProviderInfo XML file in the <code>android:configure</code> attribute.
+
+<p>The activity you specified will be launched with the {@link
+android.gadget.GadgetManager#ACTION_GADGET_CONFIGURE} action.  See the documentation for that
+action for more info.
+
+<p>See the <code>src/com/example/android/apis/gadget/ExampleGadgetConfigure.java</code>
+sample class in ApiDemos for an example.
+
+
+
 <h3><a name="providers_broadcasts"></a>Gadget Broadcast Intents</h3>
 
-<p>{@link GadgetProvider} is just a convenience class.  If you would like to receive the
-gadget broadcasts directly, you can.  By way of example, the implementation of
-{@link GadgetProvider.onReceive} is quite simple:</p>
+<p>{@link android.gadget.GadgetProvider} is just a convenience class.  If you would like
+to receive the gadget broadcasts directly, you can.  The four intents you need to care about are:
+<ul>
+  <li>{@link android.gadget.GadgetManager#ACTION_GADGET_UPDATE}</li>
+  <li>{@link android.gadget.GadgetManager#ACTION_GADGET_DELETED}</li>
+  <li>{@link android.gadget.GadgetManager#ACTION_GADGET_ENABLED}</li>
+  <li>{@link android.gadget.GadgetManager#ACTION_GADGET_DISABLED}</li>
+</ul>
+
+<p>By way of example, the implementation of
+{@link android.gadget.GadgetProvider#onReceive} is quite simple:</p>
 
 {@sample frameworks/base/core/java/android/gadget/GadgetProvider.java onReceive}
 
diff --git a/core/java/android/hardware/Camera.java b/core/java/android/hardware/Camera.java
index c09567c..40a5b47 100644
--- a/core/java/android/hardware/Camera.java
+++ b/core/java/android/hardware/Camera.java
@@ -18,6 +18,7 @@
 
 import java.lang.ref.WeakReference;
 import java.util.HashMap;
+import java.util.StringTokenizer;
 import java.io.IOException;
 
 import android.util.Log;
@@ -494,11 +495,17 @@
          */
         public void unflatten(String flattened) {
             mMap.clear();
-            String[] pairs = flattened.split(";");
-            for (String p : pairs) {
-                String[] kv = p.split("=");
-                if (kv.length == 2)
-                    mMap.put(kv[0], kv[1]);
+            
+            StringTokenizer tokenizer = new StringTokenizer(flattened, ";");
+            while (tokenizer.hasMoreElements()) {
+                String kv = tokenizer.nextToken();
+                int pos = kv.indexOf('=');
+                if (pos == -1) {
+                    continue;
+                }
+                String k = kv.substring(0, pos);
+                String v = kv.substring(pos + 1);
+                mMap.put(k, v);
             }
         }
         
diff --git a/core/java/android/inputmethodservice/InputMethodService.java b/core/java/android/inputmethodservice/InputMethodService.java
index ea5f741..c884120 100644
--- a/core/java/android/inputmethodservice/InputMethodService.java
+++ b/core/java/android/inputmethodservice/InputMethodService.java
@@ -206,6 +206,8 @@
     static final String TAG = "InputMethodService";
     static final boolean DEBUG = false;
     
+    InputMethodManager mImm;
+    
     LayoutInflater mInflater;
     View mRootView;
     SoftInputWindow mWindow;
@@ -293,6 +295,8 @@
             mInputConnection = binding.getConnection();
             if (DEBUG) Log.v(TAG, "bindInput(): binding=" + binding
                     + " ic=" + mInputConnection);
+            InputConnection ic = getCurrentInputConnection();
+            if (ic != null) ic.reportFullscreenMode(mIsFullscreen);
             initialize();
             onBindInput();
         }
@@ -423,7 +427,7 @@
          * of the application behind.  This value is relative to the top edge
          * of the input method window.
          */
-        int contentTopInsets;
+        public int contentTopInsets;
         
         /**
          * This is the top part of the UI that is visibly covering the
@@ -436,7 +440,7 @@
          * needed to make the focus visible.  This value is relative to the top edge
          * of the input method window.
          */
-        int visibleTopInsets;
+        public int visibleTopInsets;
         
         /**
          * Option for {@link #touchableInsets}: the entire window frame
@@ -469,6 +473,7 @@
     
     @Override public void onCreate() {
         super.onCreate();
+        mImm = (InputMethodManager)getSystemService(INPUT_METHOD_SERVICE);
         mInflater = (LayoutInflater)getSystemService(
                 Context.LAYOUT_INFLATER_SERVICE);
         mWindow = new SoftInputWindow(this);
@@ -554,7 +559,6 @@
         boolean visible = mWindowVisible;
         boolean showingInput = mShowInputRequested;
         boolean showingForced = mShowInputForced;
-        boolean showingCandidates = mCandidatesVisibility == View.VISIBLE;
         initViews();
         mInputViewStarted = false;
         mCandidatesViewStarted = false;
@@ -577,9 +581,6 @@
                 // Otherwise just put it back for its candidates.
                 showWindow(false);
             }
-            if (showingCandidates) {
-                setCandidatesViewShown(true);
-            }
         }
     }
 
@@ -670,6 +671,8 @@
         if (mIsFullscreen != isFullscreen || !mFullscreenApplied) {
             changed = true;
             mIsFullscreen = isFullscreen;
+            InputConnection ic = getCurrentInputConnection();
+            if (ic != null) ic.reportFullscreenMode(isFullscreen);
             mFullscreenApplied = true;
             initialize();
             Drawable bg = onCreateBackgroundDrawable();
@@ -860,12 +863,14 @@
         return isFullscreenMode() ? View.GONE : View.INVISIBLE;
     }
     
-    public void setStatusIcon(int iconResId) {
+    public void showStatusIcon(int iconResId) {
         mStatusIcon = iconResId;
-        InputConnection ic = getCurrentInputConnection();
-        if (ic != null && mWindowVisible) {
-            ic.showStatusIcon(getPackageName(), iconResId);
-        }
+        mImm.showStatusIcon(mToken, getPackageName(), iconResId);
+    }
+    
+    public void hideStatusIcon() {
+        mStatusIcon = 0;
+        mImm.hideStatusIcon(mToken);
     }
     
     /**
@@ -876,8 +881,7 @@
      * @param id Unique identifier of the new input method ot start.
      */
     public void switchInputMethod(String id) {
-        ((InputMethodManager)getSystemService(INPUT_METHOD_SERVICE))
-                .setInputMethod(mToken, id);
+        mImm.setInputMethod(mToken, id);
     }
     
     public void setExtractView(View view) {
@@ -1149,15 +1153,9 @@
         
         if (!wasVisible) {
             if (DEBUG) Log.v(TAG, "showWindow: showing!");
+            onWindowShown();
             mWindow.show();
         }
-        
-        if (!wasVisible || !wasCreated) {
-            InputConnection ic = getCurrentInputConnection();
-            if (ic != null) {
-                ic.showStatusIcon(getPackageName(), mStatusIcon);
-            }
-        }
     }
     
     public void hideWindow() {
@@ -1173,14 +1171,26 @@
         if (mWindowVisible) {
             mWindow.hide();
             mWindowVisible = false;
-            InputConnection ic = getCurrentInputConnection();
-            if (ic != null) {
-                ic.hideStatusIcon();
-            }
+            onWindowHidden();
         }
     }
     
     /**
+     * Called when the input method window has been shown to the user, after
+     * previously not being visible.  This is done after all of the UI setup
+     * for the window has occurred (creating its views etc).
+     */
+    public void onWindowShown() {
+    }
+    
+    /**
+     * Called when the input method window has been hidden from the user,
+     * after previously being visible.
+     */
+    public void onWindowHidden() {
+    }
+    
+    /**
      * Called when a new client has bound to the input method.  This
      * may be followed by a series of {@link #onStartInput(EditorInfo, boolean)}
      * and {@link #onFinishInput()} calls as the user navigates through its
@@ -1341,8 +1351,7 @@
      * InputMethodManager.HIDE_IMPLICIT_ONLY} bit set.
      */
     public void dismissSoftInput(int flags) {
-        ((InputMethodManager)getSystemService(INPUT_METHOD_SERVICE))
-                .hideSoftInputFromInputMethod(mToken, flags);
+        mImm.hideSoftInputFromInputMethod(mToken, flags);
     }
     
     /**
@@ -1447,17 +1456,19 @@
                         return true;
                     }
                 } else {
-                    KeyEvent down = new KeyEvent(event, KeyEvent.ACTION_DOWN);
-                    if (movement.onKeyDown(eet,
-                            (Spannable)eet.getText(), keyCode, down)) {
-                        KeyEvent up = new KeyEvent(event, KeyEvent.ACTION_UP);
-                        movement.onKeyUp(eet,
-                                (Spannable)eet.getText(), keyCode, up);
-                        while (--count > 0) {
-                            movement.onKeyDown(eet,
-                                    (Spannable)eet.getText(), keyCode, down);
+                    if (!movement.onKeyOther(eet, (Spannable)eet.getText(), event)) {
+                        KeyEvent down = new KeyEvent(event, KeyEvent.ACTION_DOWN);
+                        if (movement.onKeyDown(eet,
+                                (Spannable)eet.getText(), keyCode, down)) {
+                            KeyEvent up = new KeyEvent(event, KeyEvent.ACTION_UP);
                             movement.onKeyUp(eet,
                                     (Spannable)eet.getText(), keyCode, up);
+                            while (--count > 0) {
+                                movement.onKeyDown(eet,
+                                        (Spannable)eet.getText(), keyCode, down);
+                                movement.onKeyUp(eet,
+                                        (Spannable)eet.getText(), keyCode, up);
+                            }
                         }
                     }
                 }
@@ -1593,5 +1604,9 @@
         p.println("  mExtractedToken=" + mExtractedToken);
         p.println("  mIsInputViewShown=" + mIsInputViewShown
                 + " mStatusIcon=" + mStatusIcon);
+        p.println("Last computed insets:");
+        p.println("  contentTopInsets=" + mTmpInsets.contentTopInsets
+                + " visibleTopInsets=" + mTmpInsets.visibleTopInsets
+                + " touchableInsets=" + mTmpInsets.touchableInsets);
     }
 }
diff --git a/core/java/android/inputmethodservice/KeyboardView.java b/core/java/android/inputmethodservice/KeyboardView.java
index b2c74f2..b8bd10dc 100755
--- a/core/java/android/inputmethodservice/KeyboardView.java
+++ b/core/java/android/inputmethodservice/KeyboardView.java
@@ -1084,6 +1084,10 @@
         if (mPreviewPopup.isShowing()) {
             mPreviewPopup.dismiss();
         }
+        mHandler.removeMessages(MSG_REPEAT);
+        mHandler.removeMessages(MSG_LONGPRESS);
+        mHandler.removeMessages(MSG_SHOW_PREVIEW);
+        
         dismissPopupKeyboard();
     }
     
diff --git a/core/java/android/net/UrlQuerySanitizer.java b/core/java/android/net/UrlQuerySanitizer.java
index 70e50b7..a6efcdd 100644
--- a/core/java/android/net/UrlQuerySanitizer.java
+++ b/core/java/android/net/UrlQuerySanitizer.java
@@ -23,7 +23,7 @@
 import java.util.StringTokenizer;
 
 /**
- * 
+ *
  * Sanitizes the Query portion of a URL. Simple example:
  * <code>
  * UrlQuerySanitizer sanitizer = new UrlQuerySanitizer();
@@ -32,7 +32,7 @@
  * String name = sanitizer.getValue("name"));
  * // name now contains "Joe_User"
  * </code>
- * 
+ *
  * Register ValueSanitizers to customize the way individual
  * parameters are sanitized:
  * <code>
@@ -46,7 +46,7 @@
  * unregistered parameter sanitizer does not allow any special characters,
  * and ' ' is a special character.)
  * </code>
- * 
+ *
  * There are several ways to create ValueSanitizers. In order of increasing
  * sophistication:
  * <ol>
@@ -56,7 +56,7 @@
  * <li>Subclass UrlQuerySanitizer.ValueSanitizer to define your own value
  * sanitizer.
  * </ol>
- * 
+ *
  */
 public class UrlQuerySanitizer {
 
@@ -84,7 +84,7 @@
          */
         public String mValue;
     }
-    
+
     final private HashMap<String, ValueSanitizer> mSanitizers =
         new HashMap<String, ValueSanitizer>();
     final private HashMap<String, String> mEntries =
@@ -95,9 +95,9 @@
     private boolean mPreferFirstRepeatedParameter;
     private ValueSanitizer mUnregisteredParameterValueSanitizer =
         getAllIllegal();
-   
+
     /**
-     * A functor used to sanitize a single query value. 
+     * A functor used to sanitize a single query value.
      *
      */
     public static interface ValueSanitizer {
@@ -108,7 +108,7 @@
          */
         public String sanitize(String value);
     }
-    
+
     /**
      * Sanitize values based on which characters they contain. Illegal
      * characters are replaced with either space or '_', depending upon
@@ -117,7 +117,7 @@
     public static class IllegalCharacterValueSanitizer implements
         ValueSanitizer {
         private int mFlags;
-        
+
         /**
          * Allow space (' ') characters.
          */
@@ -165,21 +165,21 @@
          * such as "javascript:" or "vbscript:"
          */
         public final static int SCRIPT_URL_OK =         1 << 10;
-        
+
         /**
          * Mask with all fields set to OK
          */
         public final static int ALL_OK =                0x7ff;
-        
+
         /**
          * Mask with both regular space and other whitespace OK
          */
         public final static int ALL_WHITESPACE_OK =
             SPACE_OK | OTHER_WHITESPACE_OK;
 
-        
+
         // Common flag combinations:
-        
+
         /**
          * <ul>
          * <li>Deny all special characters.
@@ -262,18 +262,18 @@
          */
         public final static int ALL_BUT_NUL_AND_ANGLE_BRACKETS_LEGAL =
             ALL_OK & ~(NUL_OK | LT_OK | GT_OK);
-        
+
         /**
          *  Script URL definitions
          */
-        
+
         private final static String JAVASCRIPT_PREFIX = "javascript:";
-        
+
         private final static String VBSCRIPT_PREFIX = "vbscript:";
-        
+
         private final static int MIN_SCRIPT_PREFIX_LENGTH = Math.min(
                 JAVASCRIPT_PREFIX.length(), VBSCRIPT_PREFIX.length());
-        
+
         /**
          * Construct a sanitizer. The parameters set the behavior of the
          * sanitizer.
@@ -312,7 +312,7 @@
                     }
                 }
             }
-            
+
             // If whitespace isn't OK, get rid of whitespace at beginning
             // and end of value.
             if ( (mFlags & ALL_WHITESPACE_OK) == 0) {
@@ -337,7 +337,7 @@
             }
             return stringBuilder.toString();
         }
-        
+
         /**
          * Trim whitespace from the beginning and end of a string.
          * <p>
@@ -361,7 +361,7 @@
             }
             return value.substring(start, end + 1);
         }
-        
+
         /**
          * Check if c is whitespace.
          * @param c character to test
@@ -380,7 +380,7 @@
                 return false;
             }
         }
-        
+
         /**
          * Check whether an individual character is legal. Uses the
          * flag bit-set passed into the constructor.
@@ -400,11 +400,11 @@
             case '%' : return (mFlags & PCT_OK) != 0;
             case '\0': return (mFlags & NUL_OK) != 0;
             default  : return (c >= 32 && c < 127) ||
-                (c >= 128 && c <= 255 && ((mFlags & NON_7_BIT_ASCII_OK) != 0));
-            }    
+                ((c >= 128) && ((mFlags & NON_7_BIT_ASCII_OK) != 0));
+            }
         }
     }
-    
+
     /**
      * Get the current value sanitizer used when processing
      * unregistered parameter values.
@@ -412,14 +412,14 @@
      * <b>Note:</b> The default unregistered parameter value sanitizer is
      * one that doesn't allow any special characters, similar to what
      * is returned by calling createAllIllegal.
-     * 
+     *
      * @return the current ValueSanitizer used to sanitize unregistered
      * parameter values.
      */
     public ValueSanitizer getUnregisteredParameterValueSanitizer() {
         return mUnregisteredParameterValueSanitizer;
     }
-    
+
     /**
      * Set the value sanitizer used when processing unregistered
      * parameter values.
@@ -430,46 +430,46 @@
             ValueSanitizer sanitizer) {
         mUnregisteredParameterValueSanitizer = sanitizer;
     }
-    
-    
+
+
     // Private fields for singleton sanitizers:
-    
+
     private static final ValueSanitizer sAllIllegal =
         new IllegalCharacterValueSanitizer(
                 IllegalCharacterValueSanitizer.ALL_ILLEGAL);
-    
+
     private static final ValueSanitizer sAllButNulLegal =
         new IllegalCharacterValueSanitizer(
                 IllegalCharacterValueSanitizer.ALL_BUT_NUL_LEGAL);
-    
+
     private static final ValueSanitizer sAllButWhitespaceLegal =
         new IllegalCharacterValueSanitizer(
                 IllegalCharacterValueSanitizer.ALL_BUT_WHITESPACE_LEGAL);
-    
+
     private static final ValueSanitizer sURLLegal =
         new IllegalCharacterValueSanitizer(
                 IllegalCharacterValueSanitizer.URL_LEGAL);
-    
+
     private static final ValueSanitizer sUrlAndSpaceLegal =
         new IllegalCharacterValueSanitizer(
                 IllegalCharacterValueSanitizer.URL_AND_SPACE_LEGAL);
-    
+
     private static final ValueSanitizer sAmpLegal =
         new IllegalCharacterValueSanitizer(
-                IllegalCharacterValueSanitizer.AMP_LEGAL);   
-    
+                IllegalCharacterValueSanitizer.AMP_LEGAL);
+
     private static final ValueSanitizer sAmpAndSpaceLegal =
         new IllegalCharacterValueSanitizer(
                 IllegalCharacterValueSanitizer.AMP_AND_SPACE_LEGAL);
-    
+
     private static final ValueSanitizer sSpaceLegal =
         new IllegalCharacterValueSanitizer(
                 IllegalCharacterValueSanitizer.SPACE_LEGAL);
-    
+
     private static final ValueSanitizer sAllButNulAndAngleBracketsLegal =
         new IllegalCharacterValueSanitizer(
                 IllegalCharacterValueSanitizer.ALL_BUT_NUL_AND_ANGLE_BRACKETS_LEGAL);
-    
+
     /**
      * Return a value sanitizer that does not allow any special characters,
      * and also does not allow script URLs.
@@ -478,7 +478,7 @@
     public static final ValueSanitizer getAllIllegal() {
         return sAllIllegal;
     }
-    
+
     /**
      * Return a value sanitizer that allows everything except Nul ('\0')
      * characters. Script URLs are allowed.
@@ -547,7 +547,7 @@
     public static final ValueSanitizer getAllButNulAndAngleBracketsLegal() {
         return sAllButNulAndAngleBracketsLegal;
     }
-    
+
     /**
      * Constructs a UrlQuerySanitizer.
      * <p>
@@ -560,7 +560,7 @@
      */
     public UrlQuerySanitizer() {
     }
-    
+
     /**
      * Constructs a UrlQuerySanitizer and parse a URL.
      * This constructor is provided for convenience when the
@@ -585,7 +585,7 @@
         setAllowUnregisteredParamaters(true);
         parseUrl(url);
     }
-    
+
     /**
      * Parse the query parameters out of an encoded URL.
      * Works by extracting the query portion from the URL and then
@@ -604,7 +604,7 @@
         }
         parseQuery(query);
     }
-    
+
     /**
      * Parse a query. A query string is any number of parameter-value clauses
      * separated by any non-zero number of ampersands. A parameter-value clause
@@ -631,7 +631,7 @@
             }
         }
     }
-    
+
     /**
      * Get a set of all of the parameters found in the sanitized query.
      * <p>
@@ -641,7 +641,7 @@
     public Set<String> getParameterSet() {
         return mEntries.keySet();
     }
-    
+
     /**
      * An array list of all of the parameter value pairs in the sanitized
      * query, in the order they appeared in the query. May contain duplicate
@@ -691,7 +691,7 @@
         }
         mSanitizers.put(parameter, valueSanitizer);
     }
-    
+
     /**
      * Register a value sanitizer for an array of parameters.
      * @param parameters An array of unencoded parameter names.
@@ -705,7 +705,7 @@
             mSanitizers.put(parameters[i], valueSanitizer);
         }
     }
-    
+
     /**
      * Set whether or not unregistered parameters are allowed. If they
      * are not allowed, then they will be dropped when a query is sanitized.
@@ -718,7 +718,7 @@
             boolean allowUnregisteredParamaters) {
         mAllowUnregisteredParamaters = allowUnregisteredParamaters;
     }
-    
+
     /**
      * Get whether or not unregistered parameters are allowed. If not
      * allowed, they will be dropped when a query is parsed.
@@ -728,10 +728,10 @@
     public boolean getAllowUnregisteredParamaters() {
         return mAllowUnregisteredParamaters;
     }
-    
+
     /**
      * Set whether or not the first occurrence of a repeated parameter is
-     * preferred. True means the first repeated parameter is preferred. 
+     * preferred. True means the first repeated parameter is preferred.
      * False means that the last repeated parameter is preferred.
      * <p>
      * The preferred parameter is the one that is returned when getParameter
@@ -746,7 +746,7 @@
             boolean preferFirstRepeatedParameter) {
         mPreferFirstRepeatedParameter = preferFirstRepeatedParameter;
     }
-    
+
     /**
      * Get whether or not the first occurrence of a repeated parameter is
      * preferred.
@@ -757,10 +757,10 @@
     public boolean getPreferFirstRepeatedParameter() {
         return mPreferFirstRepeatedParameter;
     }
-    
+
     /**
      * Parse an escaped parameter-value pair. The default implementation
-     * unescapes both the parameter and the value, then looks up the 
+     * unescapes both the parameter and the value, then looks up the
      * effective value sanitizer for the parameter and uses it to sanitize
      * the value. If all goes well then addSanitizedValue is called with
      * the unescaped parameter and the sanitized unescaped value.
@@ -779,7 +779,7 @@
         String sanitizedValue = valueSanitizer.sanitize(unescapedValue);
         addSanitizedEntry(unescapedParameter, sanitizedValue);
     }
-    
+
     /**
      * Record a sanitized parameter-value pair. Override if you want to
      * do additional filtering or validation.
@@ -796,7 +796,7 @@
         }
         mEntries.put(parameter, value);
     }
-    
+
     /**
      * Get the value sanitizer for a parameter. Returns null if there
      * is no value sanitizer registered for the parameter.
@@ -807,7 +807,7 @@
     public ValueSanitizer getValueSanitizer(String parameter) {
         return mSanitizers.get(parameter);
     }
-    
+
     /**
      * Get the effective value sanitizer for a parameter. Like getValueSanitizer,
      * except if there is no value sanitizer registered for a parameter, and
@@ -823,7 +823,7 @@
         }
         return sanitizer;
     }
-    
+
     /**
      * Unescape an escaped string.
      * <ul>
@@ -867,7 +867,7 @@
         }
         return stringBuilder.toString();
     }
-    
+
     /**
      * Test if a character is a hexidecimal digit. Both upper case and lower
      * case hex digits are allowed.
@@ -877,7 +877,7 @@
     protected boolean isHexDigit(char c) {
         return decodeHexDigit(c) >= 0;
     }
-    
+
     /**
      * Convert a character that represents a hexidecimal digit into an integer.
      * If the character is not a hexidecimal digit, then -1 is returned.
@@ -885,7 +885,7 @@
      * @param c the hexidecimal digit.
      * @return the integer value of the hexidecimal digit.
      */
-    
+
     protected int decodeHexDigit(char c) {
         if (c >= '0' && c <= '9') {
             return c - '0';
@@ -900,7 +900,7 @@
             return -1;
         }
     }
-    
+
     /**
      * Clear the existing entries. Called to get ready to parse a new
      * query string.
diff --git a/core/java/android/pim/RecurrenceSet.java b/core/java/android/pim/RecurrenceSet.java
index c6615da..1a287c8 100644
--- a/core/java/android/pim/RecurrenceSet.java
+++ b/core/java/android/pim/RecurrenceSet.java
@@ -140,7 +140,6 @@
             recurrence = recurrence.substring(tzidx + 1);
         }
         Time time = new Time(tz);
-        boolean rdateNotInUtc = !tz.equals(Time.TIMEZONE_UTC);
         String[] rawDates = recurrence.split(",");
         int n = rawDates.length;
         long[] dates = new long[n];
diff --git a/core/java/android/preference/PreferenceGroupAdapter.java b/core/java/android/preference/PreferenceGroupAdapter.java
index 05c2952..02ab1da 100644
--- a/core/java/android/preference/PreferenceGroupAdapter.java
+++ b/core/java/android/preference/PreferenceGroupAdapter.java
@@ -88,6 +88,9 @@
 
     public PreferenceGroupAdapter(PreferenceGroup preferenceGroup) {
         mPreferenceGroup = preferenceGroup;
+        // If this group gets or loses any children, let us know
+        mPreferenceGroup.setOnPreferenceChangeInternalListener(this);
+        
         mPreferenceList = new ArrayList<Preference>();
         mPreferenceClassNames = new ArrayList<String>();
         
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 054da1d..c6a7b40 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -879,15 +879,6 @@
         public static final String AIRPLANE_MODE_RADIOS = "airplane_mode_radios";
 
         /**
-         * The interval in milliseconds after which Wi-Fi is considered idle.
-         * When idle, it is possible for the device to be switched from Wi-Fi to
-         * the mobile data network.
-         * 
-         * @hide pending API Council approval
-         */
-        public static final String WIFI_IDLE_MS = "wifi_idle_ms";
-
-        /**
          * The policy for deciding when Wi-Fi should go to sleep (which will in
          * turn switch to using the mobile data as an Internet connection).
          * <p>
@@ -1288,6 +1279,12 @@
          */
         public static final String SOUND_EFFECTS_ENABLED = "sound_effects_enabled";
         
+        /**
+         * Whether the haptic feedback (long presses, ...) are enabled. The value is
+         * boolean (1 or 0).
+         */
+        public static final String HAPTIC_FEEDBACK_ENABLED = "haptic_feedback_enabled";
+        
         // Settings moved to Settings.Secure
 
         /**
@@ -2732,6 +2729,13 @@
                 "gprs_register_check_period_ms";
 
         /**
+         * The interval in milliseconds after which Wi-Fi is considered idle.
+         * When idle, it is possible for the device to be switched from Wi-Fi to
+         * the mobile data network.
+         */
+        public static final String WIFI_IDLE_MS = "wifi_idle_ms";
+
+        /**
          * Screen timeout in milliseconds corresponding to the
          * PowerManager's POKE_LOCK_SHORT_TIMEOUT flag (i.e. the fastest
          * possible screen timeout behavior.)
diff --git a/core/java/android/server/BluetoothDeviceService.java b/core/java/android/server/BluetoothDeviceService.java
index d149761..7c15045 100644
--- a/core/java/android/server/BluetoothDeviceService.java
+++ b/core/java/android/server/BluetoothDeviceService.java
@@ -25,8 +25,8 @@
 package android.server;
 
 import android.bluetooth.BluetoothDevice;
-import android.bluetooth.BluetoothHeadset;  // just for dump()
 import android.bluetooth.BluetoothError;
+import android.bluetooth.BluetoothHeadset;
 import android.bluetooth.BluetoothIntent;
 import android.bluetooth.IBluetoothDevice;
 import android.bluetooth.IBluetoothDeviceCallback;
@@ -35,23 +35,20 @@
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
-import android.content.pm.PackageManager;
-import android.os.RemoteException;
-import android.provider.Settings;
-import android.util.Log;
 import android.os.Binder;
 import android.os.Handler;
 import android.os.Message;
+import android.os.RemoteException;
 import android.os.SystemService;
+import android.provider.Settings;
+import android.util.Log;
 
-import java.io.IOException;
 import java.io.FileDescriptor;
-import java.io.FileNotFoundException;
-import java.io.FileWriter;
 import java.io.PrintWriter;
 import java.io.UnsupportedEncodingException;
 import java.util.ArrayList;
 import java.util.HashMap;
+import java.util.List;
 import java.util.Map;
 
 public class BluetoothDeviceService extends IBluetoothDevice.Stub {
@@ -119,7 +116,7 @@
     public synchronized boolean disable() {
         mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
                                                 "Need BLUETOOTH_ADMIN permission");
-        
+
         if (mEnableThread != null && mEnableThread.isAlive()) {
             return false;
         }
@@ -229,9 +226,9 @@
         long origCallerIdentityToken = Binder.clearCallingIdentity();
         Settings.Secure.putInt(mContext.getContentResolver(), Settings.Secure.BLUETOOTH_ON,
                 bluetoothOn ? 1 : 0);
-        Binder.restoreCallingIdentity(origCallerIdentityToken);        
+        Binder.restoreCallingIdentity(origCallerIdentityToken);
     }
-    
+
     private native int enableNative();
     private native int disableNative();
 
@@ -247,6 +244,7 @@
     public class BondState {
         private final HashMap<String, Integer> mState = new HashMap<String, Integer>();
         private final HashMap<String, Integer> mPinAttempt = new HashMap<String, Integer>();
+        private final ArrayList<String> mAutoPairingFailures = new ArrayList<String>();
 
         public synchronized void loadBondState() {
             if (!mIsEnabled) {
@@ -281,8 +279,8 @@
             intent.putExtra(BluetoothIntent.BOND_PREVIOUS_STATE, oldState);
             if (state == BluetoothDevice.BOND_NOT_BONDED) {
                 if (reason <= 0) {
-                    Log.w(TAG, "setBondState() called to unbond device with invalid reason code " +
-                          "Setting reason = BOND_RESULT_REMOVED");
+                    Log.w(TAG, "setBondState() called to unbond device, but reason code is " +
+                          "invalid. Overriding reason code with BOND_RESULT_REMOVED");
                     reason = BluetoothDevice.UNBOND_REASON_REMOVED;
                 }
                 intent.putExtra(BluetoothIntent.REASON, reason);
@@ -290,11 +288,7 @@
             } else {
                 mState.put(address, state);
             }
-            if (state == BluetoothDevice.BOND_BONDING) {
-                mPinAttempt.put(address, Integer.valueOf(0));
-            } else {
-                mPinAttempt.remove(address);
-            }
+
             mContext.sendBroadcast(intent, BLUETOOTH_PERM);
         }
 
@@ -316,6 +310,24 @@
             return result.toArray(new String[result.size()]);
         }
 
+        public synchronized void addAutoPairingFailure(String address) {
+            if (!mAutoPairingFailures.contains(address)) {
+                mAutoPairingFailures.add(address);
+            }
+        }
+
+        public synchronized boolean isAutoPairingAttemptsInProgress(String address) {
+            return getAttempt(address) != 0;
+        }
+
+        public synchronized void clearPinAttempts(String address) {
+            mPinAttempt.remove(address);
+        }
+
+        public synchronized boolean hasAutoPairingFailed(String address) {
+            return mAutoPairingFailures.contains(address);
+        }
+
         public synchronized int getAttempt(String address) {
             Integer attempt = mPinAttempt.get(address);
             if (attempt == null) {
@@ -326,10 +338,13 @@
 
         public synchronized void attempt(String address) {
             Integer attempt = mPinAttempt.get(address);
+            int newAttempt;
             if (attempt == null) {
-                return;
+                newAttempt = 1;
+            } else {
+                newAttempt = attempt.intValue() + 1;
             }
-            mPinAttempt.put(address, new Integer(attempt.intValue() + 1));
+            mPinAttempt.put(address, new Integer(newAttempt));
         }
 
     }
@@ -508,7 +523,11 @@
             return false;
         }
         address = address.toUpperCase();
-        if (mBondState.getBondState(address) != BluetoothDevice.BOND_NOT_BONDED) {
+
+        // Check for bond state only if we are not performing auto
+        // pairing exponential back-off attempts.
+        if (!mBondState.isAutoPairingAttemptsInProgress(address) &&
+            mBondState.getBondState(address) != BluetoothDevice.BOND_NOT_BONDED) {
             return false;
         }
 
diff --git a/core/java/android/server/BluetoothEventLoop.java b/core/java/android/server/BluetoothEventLoop.java
index 0f60fae..b5e4090 100644
--- a/core/java/android/server/BluetoothEventLoop.java
+++ b/core/java/android/server/BluetoothEventLoop.java
@@ -24,6 +24,8 @@
 import android.bluetooth.IBluetoothDeviceCallback;
 import android.content.Context;
 import android.content.Intent;
+import android.os.Handler;
+import android.os.Message;
 import android.os.RemoteException;
 import android.util.Log;
 
@@ -48,9 +50,33 @@
     private BluetoothDeviceService mBluetoothService;
     private Context mContext;
 
+    private static final int EVENT_AUTO_PAIRING_FAILURE_ATTEMPT_DELAY = 1;
+
+    // The time (in millisecs) to delay the pairing attempt after the first
+    // auto pairing attempt fails. We use an exponential delay with
+    // INIT_AUTO_PAIRING_FAILURE_ATTEMPT_DELAY as the initial value and
+    // MAX_AUTO_PAIRING_FAILURE_ATTEMPT_DELAY as the max value.
+    private static final long INIT_AUTO_PAIRING_FAILURE_ATTEMPT_DELAY = 3000;
+    private static final long MAX_AUTO_PAIRING_FAILURE_ATTEMPT_DELAY = 12000;
+
     private static final String BLUETOOTH_ADMIN_PERM = android.Manifest.permission.BLUETOOTH_ADMIN;
     private static final String BLUETOOTH_PERM = android.Manifest.permission.BLUETOOTH;
 
+    private final Handler mHandler = new Handler() {
+        @Override
+        public void handleMessage(Message msg) {
+            switch (msg.what) {
+            case EVENT_AUTO_PAIRING_FAILURE_ATTEMPT_DELAY:
+                String address = (String)msg.obj;
+                if (address != null) {
+                    mBluetoothService.createBond(address);
+                    return;
+                }
+                break;
+            }
+        }
+    };
+
     static { classInitNative(); }
     private static native void classInitNative();
 
@@ -149,16 +175,6 @@
         mContext.sendBroadcast(intent, BLUETOOTH_PERM);
     }
 
-    private void onPairingRequest() {
-        Intent intent = new Intent(BluetoothIntent.PAIRING_REQUEST_ACTION);
-        mContext.sendBroadcast(intent, BLUETOOTH_ADMIN_PERM);
-    }
-    
-    private void onPairingCancel() {
-        Intent intent = new Intent(BluetoothIntent.PAIRING_CANCEL_ACTION);
-        mContext.sendBroadcast(intent, BLUETOOTH_ADMIN_PERM);
-    }
-
     private void onRemoteDeviceFound(String address, int deviceClass, short rssi) {
         Intent intent = new Intent(BluetoothIntent.REMOTE_DEVICE_FOUND_ACTION);
         intent.putExtra(BluetoothIntent.ADDRESS, address);
@@ -214,12 +230,55 @@
         address = address.toUpperCase();
         if (result == BluetoothError.SUCCESS) {
             mBluetoothService.getBondState().setBondState(address, BluetoothDevice.BOND_BONDED);
+            if (mBluetoothService.getBondState().isAutoPairingAttemptsInProgress(address)) {
+                mBluetoothService.getBondState().clearPinAttempts(address);
+            }
+        } else if (result == BluetoothDevice.UNBOND_REASON_AUTH_FAILED &&
+                mBluetoothService.getBondState().getAttempt(address) == 1) {
+            mBluetoothService.getBondState().addAutoPairingFailure(address);
+            pairingAttempt(address, result);
+        } else if (result == BluetoothDevice.UNBOND_REASON_REMOTE_DEVICE_DOWN &&
+                mBluetoothService.getBondState().isAutoPairingAttemptsInProgress(address)) {
+            pairingAttempt(address, result);
         } else {
             mBluetoothService.getBondState().setBondState(address,
                                                           BluetoothDevice.BOND_NOT_BONDED, result);
+            if (mBluetoothService.getBondState().isAutoPairingAttemptsInProgress(address)) {
+                mBluetoothService.getBondState().clearPinAttempts(address);
+            }
         }
     }
 
+    private void pairingAttempt(String address, int result) {
+        // This happens when our initial guess of "0000" as the pass key
+        // fails. Try to create the bond again and display the pin dialog
+        // to the user. Use back-off while posting the delayed
+        // message. The initial value is
+        // INIT_AUTO_PAIRING_FAILURE_ATTEMPT_DELAY and the max value is
+        // MAX_AUTO_PAIRING_FAILURE_ATTEMPT_DELAY. If the max value is
+        // reached, display an error to the user.
+        int attempt = mBluetoothService.getBondState().getAttempt(address);
+        if (attempt * INIT_AUTO_PAIRING_FAILURE_ATTEMPT_DELAY >
+                    MAX_AUTO_PAIRING_FAILURE_ATTEMPT_DELAY) {
+            mBluetoothService.getBondState().clearPinAttempts(address);
+            mBluetoothService.getBondState().setBondState(address,
+                    BluetoothDevice.BOND_NOT_BONDED, result);
+            return;
+        }
+
+        Message message = mHandler.obtainMessage(EVENT_AUTO_PAIRING_FAILURE_ATTEMPT_DELAY);
+        message.obj = address;
+        boolean postResult =  mHandler.sendMessageDelayed(message,
+                                        attempt * INIT_AUTO_PAIRING_FAILURE_ATTEMPT_DELAY);
+        if (!postResult) {
+            mBluetoothService.getBondState().clearPinAttempts(address);
+            mBluetoothService.getBondState().setBondState(address,
+                    BluetoothDevice.BOND_NOT_BONDED, result);
+            return;
+        }
+        mBluetoothService.getBondState().attempt(address);
+    }
+
     private void onBondingCreated(String address) {
         mBluetoothService.getBondState().setBondState(address.toUpperCase(),
                                                       BluetoothDevice.BOND_BONDED);
@@ -253,12 +312,12 @@
             case BluetoothClass.Device.AUDIO_VIDEO_PORTABLE_AUDIO:
             case BluetoothClass.Device.AUDIO_VIDEO_CAR_AUDIO:
             case BluetoothClass.Device.AUDIO_VIDEO_HIFI_AUDIO:
-                if (mBluetoothService.getBondState().getAttempt(address) < 1) {
+                if (!mBluetoothService.getBondState().hasAutoPairingFailed(address)) {
                     mBluetoothService.getBondState().attempt(address);
                     mBluetoothService.setPin(address, BluetoothDevice.convertPinToBytes("0000"));
                     return;
                 }
-            }
+           }
         }
         Intent intent = new Intent(BluetoothIntent.PAIRING_REQUEST_ACTION);
         intent.putExtra(BluetoothIntent.ADDRESS, address);
diff --git a/core/java/android/text/method/ArrowKeyMovementMethod.java b/core/java/android/text/method/ArrowKeyMovementMethod.java
index a559b9d..6df0b35 100644
--- a/core/java/android/text/method/ArrowKeyMovementMethod.java
+++ b/core/java/android/text/method/ArrowKeyMovementMethod.java
@@ -16,6 +16,7 @@
 
 package android.text.method;
 
+import android.util.Log;
 import android.view.KeyEvent;
 import android.text.*;
 import android.widget.TextView;
@@ -185,15 +186,9 @@
         if (code != KeyEvent.KEYCODE_UNKNOWN
                 && event.getAction() == KeyEvent.ACTION_MULTIPLE) {
             int repeat = event.getRepeatCount();
-            boolean first = true;
             boolean handled = false;
             while ((--repeat) > 0) {
-                if (first && executeDown(view, text, code)) {
-                    handled = true;
-                    MetaKeyKeyListener.adjustMetaAfterKeypress(text);
-                    MetaKeyKeyListener.resetLockedMeta(text);
-                }
-                first = false;
+                handled |= executeDown(view, text, code);
             }
             return handled;
         }
diff --git a/core/java/android/text/method/MetaKeyKeyListener.java b/core/java/android/text/method/MetaKeyKeyListener.java
index d89fbec..39ad976 100644
--- a/core/java/android/text/method/MetaKeyKeyListener.java
+++ b/core/java/android/text/method/MetaKeyKeyListener.java
@@ -287,10 +287,10 @@
     }
 
     public static void clearMetaKeyState(Editable content, int states) {
-        if ((states&META_SHIFT_ON) != 0) resetLock(content, CAP);
-        if ((states&META_ALT_ON) != 0) resetLock(content, ALT);
-        if ((states&META_SYM_ON) != 0) resetLock(content, SYM);
-        if ((states&META_SELECTING) != 0) resetLock(content, SELECTING);
+        if ((states&META_SHIFT_ON) != 0) content.removeSpan(CAP);
+        if ((states&META_ALT_ON) != 0) content.removeSpan(ALT);
+        if ((states&META_SYM_ON) != 0) content.removeSpan(SYM);
+        if ((states&META_SELECTING) != 0) content.removeSpan(SELECTING);
     }
 
     /**
diff --git a/core/java/android/text/method/PasswordTransformationMethod.java b/core/java/android/text/method/PasswordTransformationMethod.java
index 85adabd..fad4f64 100644
--- a/core/java/android/text/method/PasswordTransformationMethod.java
+++ b/core/java/android/text/method/PasswordTransformationMethod.java
@@ -105,8 +105,10 @@
                         sp.removeSpan(old[i]);
                     }
 
-                    sp.setSpan(new Visible(sp, this), start, start + count,
-                               Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
+                    if (count == 1) {
+                        sp.setSpan(new Visible(sp, this), start, start + count,
+                                   Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
+                    }
                 }
             }
         }
diff --git a/core/java/android/view/HapticFeedbackConstants.java b/core/java/android/view/HapticFeedbackConstants.java
new file mode 100644
index 0000000..cc3563c
--- /dev/null
+++ b/core/java/android/view/HapticFeedbackConstants.java
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.view;
+
+/**
+ * Constants to be used to perform haptic feedback effects via
+ * {@link View#performHapticFeedback(int)} 
+ */
+public class HapticFeedbackConstants {
+
+    private HapticFeedbackConstants() {}
+
+    public static final int LONG_PRESS = 0;
+    
+    /** @hide pending API council */
+    public static final int ZOOM_RING_TICK = 1;
+    
+    /**
+     * Flag for {@link View#performHapticFeedback(int, int)
+     * View.performHapticFeedback(int, int)}: Ignore the setting in the
+     * view for whether to perform haptic feedback, do it always.
+     */
+    public static final int FLAG_IGNORE_VIEW_SETTING = 0x0001;
+    
+    /**
+     * Flag for {@link View#performHapticFeedback(int, int)
+     * View.performHapticFeedback(int, int)}: Ignore the global setting
+     * for whether to perform haptic feedback, do it always.
+     */
+    public static final int FLAG_IGNORE_GLOBAL_SETTING = 0x0002;
+}
diff --git a/core/java/android/view/IWindowSession.aidl b/core/java/android/view/IWindowSession.aidl
index 7276f17..1156856 100644
--- a/core/java/android/view/IWindowSession.aidl
+++ b/core/java/android/view/IWindowSession.aidl
@@ -106,5 +106,6 @@
     
     void setInTouchMode(boolean showFocus);
     boolean getInTouchMode();
+    
+    boolean performHapticFeedback(IWindow window, int effectId, boolean always);
 }
-
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index a51b564..1d5e7cd 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -836,6 +836,12 @@
     public static final int SOUND_EFFECTS_ENABLED = 0x08000000;
 
     /**
+     * View flag indicating whether this view should have haptic feedback
+     * enabled for events such as long presses.
+     */
+    public static final int HAPTIC_FEEDBACK_ENABLED = 0x10000000;
+
+    /**
      * Use with {@link #focusSearch}. Move focus to the previous selectable
      * item.
      */
@@ -1637,6 +1643,7 @@
     public View(Context context) {
         mContext = context;
         mResources = context != null ? context.getResources() : null;
+        mViewFlags = SOUND_EFFECTS_ENABLED|HAPTIC_FEEDBACK_ENABLED;
         ++sInstanceCount;
     }
 
@@ -1703,9 +1710,6 @@
 
         int scrollbarStyle = SCROLLBARS_INSIDE_OVERLAY;
 
-        viewFlagValues |= SOUND_EFFECTS_ENABLED;
-        viewFlagMasks |= SOUND_EFFECTS_ENABLED;
-
         final int N = a.getIndexCount();
         for (int i = 0; i < N; i++) {
             int attr = a.getIndex(i);
@@ -1801,6 +1805,11 @@
                         viewFlagValues &= ~SOUND_EFFECTS_ENABLED;
                         viewFlagMasks |= SOUND_EFFECTS_ENABLED;
                     }
+                case com.android.internal.R.styleable.View_hapticFeedbackEnabled:
+                    if (!a.getBoolean(attr, true)) {
+                        viewFlagValues &= ~HAPTIC_FEEDBACK_ENABLED;
+                        viewFlagMasks |= HAPTIC_FEEDBACK_ENABLED;
+                    }
                 case R.styleable.View_scrollbars:
                     final int scrollbars = a.getInt(attr, SCROLLBARS_NONE);
                     if (scrollbars != SCROLLBARS_NONE) {
@@ -2182,6 +2191,9 @@
         if (!handled) {
             handled = showContextMenu();
         }
+        if (handled) {
+            performHapticFeedback(HapticFeedbackConstants.LONG_PRESS);
+        }
         return handled;
     }
 
@@ -2742,7 +2754,7 @@
      * Set whether this view should have sound effects enabled for events such as
      * clicking and touching.
      *
-     * You may wish to disable sound effects for a view if you already play sounds,
+     * <p>You may wish to disable sound effects for a view if you already play sounds,
      * for instance, a dial key that plays dtmf tones.
      *
      * @param soundEffectsEnabled whether sound effects are enabled for this view.
@@ -2768,6 +2780,35 @@
     }
 
     /**
+     * Set whether this view should have haptic feedback for events such as
+     * long presses.
+     *
+     * <p>You may wish to disable haptic feedback if your view already controls
+     * its own haptic feedback.
+     *
+     * @param hapticFeedbackEnabled whether haptic feedback enabled for this view.
+     * @see #isHapticFeedbackEnabled()
+     * @see #performHapticFeedback(int)
+     * @attr ref android.R.styleable#View_hapticFeedbackEnabled
+     */
+    public void setHapticFeedbackEnabled(boolean hapticFeedbackEnabled) {
+        setFlags(hapticFeedbackEnabled ? HAPTIC_FEEDBACK_ENABLED: 0, HAPTIC_FEEDBACK_ENABLED);
+    }
+
+    /**
+     * @return whether this view should have haptic feedback enabled for events
+     * long presses.
+     *
+     * @see #setHapticFeedbackEnabled(boolean)
+     * @see #performHapticFeedback(int)
+     * @attr ref android.R.styleable#View_hapticFeedbackEnabled
+     */
+    @ViewDebug.ExportedProperty
+    public boolean isHapticFeedbackEnabled() {
+        return HAPTIC_FEEDBACK_ENABLED == (mViewFlags & HAPTIC_FEEDBACK_ENABLED);
+    }
+
+    /**
      * If this view doesn't do any drawing on its own, set this flag to
      * allow further optimizations. By default, this flag is not set on
      * View, but could be set on some View subclasses such as ViewGroup.
@@ -7312,20 +7353,57 @@
     /**
      * Play a sound effect for this view.
      *
-     * The framework will play sound effects for some built in actions, such as
+     * <p>The framework will play sound effects for some built in actions, such as
      * clicking, but you may wish to play these effects in your widget,
      * for instance, for internal navigation.
      *
-     * The sound effect will only be played if sound effects are enabled by the user, and
+     * <p>The sound effect will only be played if sound effects are enabled by the user, and
      * {@link #isSoundEffectsEnabled()} is true.
      *
      * @param soundConstant One of the constants defined in {@link SoundEffectConstants}
      */
-    protected void playSoundEffect(int soundConstant) {
-        if (mAttachInfo == null || mAttachInfo.mSoundEffectPlayer == null || !isSoundEffectsEnabled()) {
+    public void playSoundEffect(int soundConstant) {
+        if (mAttachInfo == null || mAttachInfo.mRootCallbacks == null || !isSoundEffectsEnabled()) {
             return;
         }
-        mAttachInfo.mSoundEffectPlayer.playSoundEffect(soundConstant);
+        mAttachInfo.mRootCallbacks.playSoundEffect(soundConstant);
+    }
+
+    /**
+     * Provide haptic feedback to the user for this view.
+     *
+     * <p>The framework will provide haptic feedback for some built in actions,
+     * such as long presses, but you may wish to provide feedback for your
+     * own widget.
+     *
+     * <p>The feedback will only be performed if
+     * {@link #isHapticFeedbackEnabled()} is true.
+     *
+     * @param feedbackConstant One of the constants defined in
+     * {@link HapticFeedbackConstants}
+     */
+    public boolean performHapticFeedback(int feedbackConstant) {
+        return performHapticFeedback(feedbackConstant, 0);
+    }
+
+    /**
+     * Like {@link #performHapticFeedback(int)}, with additional options.
+     *
+     * @param feedbackConstant One of the constants defined in
+     * {@link HapticFeedbackConstants}
+     * @param flags Additional flags as per {@link HapticFeedbackConstants}.
+     */
+    public boolean performHapticFeedback(int feedbackConstant, int flags) {
+        if (mAttachInfo == null) {
+            return false;
+        }
+        if ((flags&HapticFeedbackConstants.FLAG_IGNORE_VIEW_SETTING) == 0
+                && !isHapticFeedbackEnabled()) {
+            return false;
+        }
+        return mAttachInfo.mRootCallbacks.performHapticFeedback(
+                feedbackConstant,
+                (flags&HapticFeedbackConstants.FLAG_IGNORE_GLOBAL_SETTING) != 0);
     }
 
     /**
@@ -7704,8 +7782,9 @@
      */
     static class AttachInfo {
 
-        interface SoundEffectPlayer {
+        interface Callbacks {
             void playSoundEffect(int effectId);
+            boolean performHapticFeedback(int effectId, boolean always);
         }
 
         /**
@@ -7775,7 +7854,7 @@
 
         final IBinder mWindowToken;
 
-        final SoundEffectPlayer mSoundEffectPlayer;
+        final Callbacks mRootCallbacks;
 
         /**
          * The top view of the hierarchy.
@@ -7922,12 +8001,12 @@
          * @param handler the events handler the view must use
          */
         AttachInfo(IWindowSession session, IWindow window,
-                Handler handler, SoundEffectPlayer effectPlayer) {
+                Handler handler, Callbacks effectPlayer) {
             mSession = session;
             mWindow = window;
             mWindowToken = window.asBinder();
             mHandler = handler;
-            mSoundEffectPlayer = effectPlayer;
+            mRootCallbacks = effectPlayer;
         }
     }
 
diff --git a/core/java/android/view/ViewRoot.java b/core/java/android/view/ViewRoot.java
index 4e46397..ccfa6bf 100644
--- a/core/java/android/view/ViewRoot.java
+++ b/core/java/android/view/ViewRoot.java
@@ -61,7 +61,7 @@
  */
 @SuppressWarnings({"EmptyCatchBlock"})
 public final class ViewRoot extends Handler implements ViewParent,
-        View.AttachInfo.SoundEffectPlayer {
+        View.AttachInfo.Callbacks {
     private static final String TAG = "ViewRoot";
     private static final boolean DBG = false;
     @SuppressWarnings({"ConstantConditionalExpression"})
@@ -1637,7 +1637,7 @@
             dispatchDetachedFromWindow();
             break;
         case DISPATCH_KEY_FROM_IME:
-            if (true) Log.v(
+            if (LOCAL_LOGV) Log.v(
                 "ViewRoot", "Dispatching key "
                 + msg.obj + " from IME to " + mView);
             deliverKeyEventToViewHierarchy((KeyEvent)msg.obj, false);
@@ -2238,6 +2238,17 @@
     /**
      * {@inheritDoc}
      */
+    public boolean performHapticFeedback(int effectId, boolean always) {
+        try {
+            return sWindowSession.performHapticFeedback(mWindow, effectId, always);
+        } catch (RemoteException e) {
+            return false;
+        }
+    }
+
+    /**
+     * {@inheritDoc}
+     */
     public View focusSearch(View focused, int direction) {
         checkThread();
         if (!(mView instanceof ViewGroup)) {
diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java
index d08a6fa..406af3e3 100644
--- a/core/java/android/view/WindowManager.java
+++ b/core/java/android/view/WindowManager.java
@@ -925,7 +925,7 @@
                 sb.append(Integer.toHexString(windowAnimations));
             }
             if (screenOrientation != ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED) {
-                sb.append("or=");
+                sb.append(" or=");
                 sb.append(screenOrientation);
             }
             sb.append('}');
diff --git a/core/java/android/view/WindowManagerPolicy.java b/core/java/android/view/WindowManagerPolicy.java
index 542b35f..051f823 100644
--- a/core/java/android/view/WindowManagerPolicy.java
+++ b/core/java/android/view/WindowManagerPolicy.java
@@ -771,4 +771,15 @@
     public boolean isCheekPressedAgainstScreen(MotionEvent ev);
     
     public void setCurrentOrientation(int newOrientation);
+    
+    /**
+     * Call from application to perform haptic feedback on its window.
+     */
+    public boolean performHapticFeedback(WindowState win, int effectId, boolean always);
+    
+    /**
+     * Called when we have stopped keeping the screen on because a window
+     * requesting this is no longer visible.
+     */
+    public void screenOnStopped();
 }
diff --git a/core/java/android/view/inputmethod/BaseInputConnection.java b/core/java/android/view/inputmethod/BaseInputConnection.java
index 56c6c92..9509b15 100644
--- a/core/java/android/view/inputmethod/BaseInputConnection.java
+++ b/core/java/android/view/inputmethod/BaseInputConnection.java
@@ -371,6 +371,14 @@
         if (DEBUG) Log.v(TAG, "setSelection " + start + ", " + end);
         final Editable content = getEditable();
         if (content == null) return false;
+        int len = content.length();
+        if (start > len || end > len) {
+            // If the given selection is out of bounds, just ignore it.
+            // Most likely the text was changed out from under the IME,
+            // the the IME is going to have to update all of its state
+            // anyway.
+            return true;
+        }
         Selection.setSelection(content, start, end);
         return true;
     }
@@ -396,20 +404,10 @@
     }
     
     /**
-     * Provides standard implementation for hiding the status icon associated
-     * with the current input method.
+     * Updates InputMethodManager with the current fullscreen mode.
      */
-    public boolean hideStatusIcon() {
-        mIMM.updateStatusIcon(0, null);
-        return true;
-    }
-    
-    /**
-     * Provides standard implementation for showing the status icon associated
-     * with the current input method.
-     */
-    public boolean showStatusIcon(String packageName, int resId) {
-        mIMM.updateStatusIcon(resId, packageName);
+    public boolean reportFullscreenMode(boolean enabled) {
+        mIMM.setFullscreenMode(enabled);
         return true;
     }
     
@@ -420,7 +418,11 @@
         
         Editable content = getEditable();
         if (content != null) {
-            if (content.length() == 1) {
+            final int N = content.length();
+            if (N == 0) {
+                return;
+            }
+            if (N == 1) {
                 // If it's 1 character, we have a chance of being
                 // able to generate normal key events...
                 if (mKeyCharacterMap == null) {
diff --git a/core/java/android/view/inputmethod/InputConnection.java b/core/java/android/view/inputmethod/InputConnection.java
index 8c30d3f..13173f6 100644
--- a/core/java/android/view/inputmethod/InputConnection.java
+++ b/core/java/android/view/inputmethod/InputConnection.java
@@ -267,6 +267,13 @@
     public boolean clearMetaKeyStates(int states);
     
     /**
+     * Called by the IME to tell the client when it switches between fullscreen
+     * and normal modes.  This will normally be called for you by the standard
+     * implementation of {@link android.inputmethodservice.InputMethodService}.
+     */
+    public boolean reportFullscreenMode(boolean enabled);
+    
+    /**
      * API to send private commands from an input method to its connected
      * editor.  This can be used to provide domain-specific features that are
      * only known between certain input methods and their clients.  Note that
@@ -284,23 +291,4 @@
      * valid.
      */
     public boolean performPrivateCommand(String action, Bundle data);
-    
-    /**
-     * Show an icon in the status bar.
-     * 
-     * @param packageName The package holding the icon resource to be shown.
-     * @param resId The resource id of the icon to show.
-     *        
-     * @return Returns true on success, false if the input connection is no longer
-     * valid.
-     */
-    public boolean showStatusIcon(String packageName, int resId);
-    
-    /**
-     * Hide the icon shown in the status bar.
-     *        
-     * @return Returns true on success, false if the input connection is no longer
-     * valid.
-     */
-    public boolean hideStatusIcon();
 }
diff --git a/core/java/android/view/inputmethod/InputMethodManager.java b/core/java/android/view/inputmethod/InputMethodManager.java
index 99d5aa5..fe141668 100644
--- a/core/java/android/view/inputmethod/InputMethodManager.java
+++ b/core/java/android/view/inputmethod/InputMethodManager.java
@@ -214,6 +214,11 @@
      */
     boolean mActive = false;
     
+    /**
+     * As reported by IME through InputConnection.
+     */
+    boolean mFullscreenMode;
+    
     // -----------------------------------------------------------
     
     /**
@@ -374,6 +379,7 @@
         
         public void setActive(boolean active) {
             mActive = active;
+            mFullscreenMode = false;
         }
     };    
     
@@ -443,14 +449,36 @@
         }
     }
 
-    public void updateStatusIcon(int iconId, String iconPackage) {
+    public void showStatusIcon(IBinder imeToken, String packageName, int iconId) {
         try {
-            mService.updateStatusIcon(iconId, iconPackage);
+            mService.updateStatusIcon(imeToken, packageName, iconId);
         } catch (RemoteException e) {
             throw new RuntimeException(e);
         }
     }
 
+    public void hideStatusIcon(IBinder imeToken) {
+        try {
+            mService.updateStatusIcon(imeToken, null, 0);
+        } catch (RemoteException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    /** @hide */
+    public void setFullscreenMode(boolean enabled) {
+        mFullscreenMode = true;
+    }
+    
+    /**
+     * Allows you to discover whether the attached input method is running
+     * in fullscreen mode.  Return true if it is fullscreen, entirely covering
+     * your UI, else returns false.
+     */
+    public boolean isFullscreenMode() {
+        return mFullscreenMode;
+    }
+    
     /**
      * Return true if the given view is the currently active view for the
      * input method.
@@ -503,7 +531,6 @@
     void finishInputLocked() {
         if (mServedView != null) {
             if (DEBUG) Log.v(TAG, "FINISH INPUT: " + mServedView);
-            updateStatusIcon(0, null);
             
             if (mCurrentTextBoxAttribute != null) {
                 try {
diff --git a/core/java/android/webkit/CookieManager.java b/core/java/android/webkit/CookieManager.java
index 5a37f04..07c1a5d 100644
--- a/core/java/android/webkit/CookieManager.java
+++ b/core/java/android/webkit/CookieManager.java
@@ -171,6 +171,10 @@
         boolean pathMatch(String urlPath) {
             if (urlPath.startsWith(path)) {
                 int len = path.length();
+                if (len == 0) {
+                    Log.w(LOGTAG, "Empty cookie path");
+                    return false;
+                }
                 int urlLen = urlPath.length();
                 if (path.charAt(len-1) != PATH_DELIM && urlLen > len) {
                     // make sure /wee doesn't match /we
@@ -864,7 +868,10 @@
                                     "illegal format for max-age: " + value);
                         }
                     } else if (name.equals(PATH)) {
-                        cookie.path = value;
+                        // only allow non-empty path value
+                        if (value.length() > 0) {
+                            cookie.path = value;
+                        }
                     } else if (name.equals(DOMAIN)) {
                         int lastPeriod = value.lastIndexOf(PERIOD);
                         if (lastPeriod == 0) {
diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java
index 3306700..bdbf38a 100644
--- a/core/java/android/webkit/WebView.java
+++ b/core/java/android/webkit/WebView.java
@@ -260,19 +260,8 @@
     // Whether we are in the drag tap mode, which exists starting at the second
     // tap's down, through its move, and includes its up. These events should be
     // given to the method on the zoom controller.
-    private boolean mInZoomTapDragMode;
-    
-    // The event time of the previous touch up. 
-    private long mPreviousUpTime;
-    
-    private Runnable mRemoveReleaseSingleTap = new Runnable() {
-        public void run() {
-            mPrivateHandler.removeMessages(RELEASE_SINGLE_TAP);
-            mPrivateHandler.removeMessages(SWITCH_TO_LONGPRESS);
-            mPrivateHandler.removeMessages(SWITCH_TO_SHORTPRESS);
-        }
-    };
-    
+    private boolean mInZoomTapDragMode = false;
+
     // Whether to prevent drag during touch. The initial value depends on
     // mForwardTouchEvents. If WebCore wants touch events, we assume it will
     // take control of touch events unless it says no for touch down event.
@@ -517,6 +506,11 @@
     
     private ZoomRingController mZoomRingController;
 
+    // These keep track of the center point of the zoom ring.  They are used to
+    // determine the point around which we should zoom.
+    private float mZoomCenterX;
+    private float mZoomCenterY;
+
     private ZoomRingController.OnZoomListener mZoomListener =
             new ZoomRingController.OnZoomListener() {
         
@@ -554,12 +548,9 @@
                     deltaZoomLevel == 0) {
                 return false;
             }
-            
-            int deltaX = centerX - getViewWidth() / 2;
-            int deltaY = centerY - getViewHeight() / 2;
+            mZoomCenterX = (float) centerX;
+            mZoomCenterY = (float) centerY;
 
-            pinScrollBy(deltaX, deltaY, false, 0);
-            
             while (deltaZoomLevel != 0) {
                 if (deltaZoomLevel > 0) {
                     if (!zoomIn()) return false;
@@ -569,15 +560,16 @@
                     deltaZoomLevel++;
                 }
             }
-            
-            pinScrollBy(-deltaX, -deltaY, false, 0);
-                    
+
             return true;
         }
         
         public void onSimpleZoom(boolean zoomIn) {
-            if (zoomIn) zoomIn();
-            else zoomOut();
+            if (zoomIn) {
+                zoomIn();
+            } else {
+                zoomOut();
+            }
         }
     };
     
@@ -1586,8 +1578,8 @@
                 int oldX = mScrollX;
                 int oldY = mScrollY;
                 float ratio = scale * mInvActualScale;   // old inverse
-                float sx = ratio * oldX + (ratio - 1) * getViewWidth() * 0.5f;
-                float sy = ratio * oldY + (ratio - 1) * getViewHeight() * 0.5f;
+                float sx = ratio * oldX + (ratio - 1) * mZoomCenterX;
+                float sy = ratio * oldY + (ratio - 1) * mZoomCenterY;
 
                 // now update our new scale and inverse
                 if (scale != mActualScale && !mPreviewZoomOnly) {
@@ -2264,8 +2256,8 @@
                 zoomScale = mZoomScale;
             }
             float scale = (mActualScale - zoomScale) * mInvActualScale;
-            float tx = scale * ((getLeft() + getRight()) * 0.5f + mScrollX);
-            float ty = scale * ((getTop() + getBottom()) * 0.5f + mScrollY);
+            float tx = scale * (mZoomCenterX + mScrollX);
+            float ty = scale * (mZoomCenterY + mScrollY);
 
             // this block pins the translate to "legal" bounds. This makes the
             // animation a bit non-obvious, but it means we won't pop when the
@@ -3025,8 +3017,8 @@
                             (keyCode == KeyEvent.KEYCODE_7) ? 1 : 0, 0);
                     break;
                 case KeyEvent.KEYCODE_9:
-                    debugDump();
-                    break;
+                    nativeInstrumentReport();
+                    return true;
             }
         }
 
@@ -3161,6 +3153,7 @@
      * @hide
      */
     public void emulateShiftHeld() {
+        mExtendSelection = false;
         mShiftIsPressed = true;
     }
 
@@ -3176,6 +3169,7 @@
                 mWebViewCore.sendMessage(EventHub.GET_SELECTION, selection);
                 copiedSomething = true;
             }
+            mExtendSelection = false;
         }
         mShiftIsPressed = false;
         if (mTouchMode == TOUCH_SELECT_MODE) {
@@ -3218,6 +3212,11 @@
         }
     }
 
+    /**
+     * @deprecated WebView should not have implemented
+     * ViewTreeObserver.OnGlobalFocusChangeListener.  This method
+     * does nothing now.
+     */
     @Deprecated
     public void onGlobalFocusChanged(View oldFocus, View newFocus) {
     }
@@ -3281,7 +3280,11 @@
     @Override
     protected void onSizeChanged(int w, int h, int ow, int oh) {
         super.onSizeChanged(w, h, ow, oh);
-
+        // Center zooming to the center of the screen.  This is appropriate for
+        // this case of zooming, and it also sets us up properly if we remove
+        // the new zoom ring controller
+        mZoomCenterX = getViewWidth() * .5f;
+        mZoomCenterY = getViewHeight() * .5f;
         // we always force, in case our height changed, in which case we still
         // want to send the notification over to webkit
         setNewZoomScale(mActualScale, true);
@@ -3342,25 +3345,12 @@
                     + mTouchMode);
         }
 
-        if (mZoomRingController.isVisible()) {
-            if (mInZoomTapDragMode) {
-                mZoomRingController.handleDoubleTapEvent(ev);
-                if (ev.getAction() == MotionEvent.ACTION_UP) {
-                    // Just released the second tap, no longer in tap-drag mode
-                    mInZoomTapDragMode = false;
-                }
-                return true;
-            } else {
-                // TODO: properly do this.
-                /*
-                 * When the zoom widget is showing, the user can tap outside of
-                 * it to dismiss it. Furthermore, he can drag outside of it to
-                 * pan the browser. However, we do not want a tap on a link to
-                 * open the link.
-                 */
-                post(mRemoveReleaseSingleTap);
-                // Continue through to normal processing
+        if (mZoomRingController.isVisible() && mInZoomTapDragMode) {
+            if (ev.getAction() == MotionEvent.ACTION_UP) {
+                // Just released the second tap, no longer in tap-drag mode
+                mInZoomTapDragMode = false;
             }
+            return mZoomRingController.handleDoubleTapEvent(ev);
         }
 
         int action = ev.getAction();
@@ -3418,21 +3408,19 @@
                             , viewToContent(mSelectY), false);
                     mTouchSelection = mExtendSelection = true;
                 } else if (!ZoomRingController.useOldZoom(mContext) &&
-                        eventTime - mPreviousUpTime < DOUBLE_TAP_TIMEOUT &&
-                        getSettings().supportZoom() &&
-                        mMinZoomScale < mMaxZoomScale) {
+                        mPrivateHandler.hasMessages(RELEASE_SINGLE_TAP)) {
                     // Found doubletap, invoke the zoom controller
-                    mPrivateHandler.removeMessages(SWITCH_TO_LONGPRESS);
-                    mPrivateHandler.removeMessages(SWITCH_TO_SHORTPRESS);
                     mPrivateHandler.removeMessages(RELEASE_SINGLE_TAP);
                     mZoomRingController.setVisible(true);
                     mInZoomTapDragMode = true;
-                    mZoomRingController.handleDoubleTapEvent(ev);
+                    return mZoomRingController.handleDoubleTapEvent(ev);
                 } else {
                     mTouchMode = TOUCH_INIT_MODE;
                     mPreventDrag = mForwardTouchEvents;
                 }
-                if (mTouchMode == TOUCH_INIT_MODE) {
+                // don't trigger the link if zoom ring is visible
+                if (mTouchMode == TOUCH_INIT_MODE
+                        && !mZoomRingController.isVisible()) {
                     mPrivateHandler.sendMessageDelayed(mPrivateHandler
                             .obtainMessage(SWITCH_TO_SHORTPRESS), TAP_TIMEOUT);
                 }
@@ -3485,9 +3473,6 @@
                         mPrivateHandler.removeMessages(SWITCH_TO_SHORTPRESS);
                     }
 
-                    // Prevent double-tap from being invoked
-                    mPreviousUpTime = 0;
-                    
                     // if it starts nearly horizontal or vertical, enforce it
                     int ax = Math.abs(deltaX);
                     int ay = Math.abs(deltaY);
@@ -3597,6 +3582,10 @@
             case MotionEvent.ACTION_UP: {
                 switch (mTouchMode) {
                     case TOUCH_INIT_MODE: // tap
+                        if (mZoomRingController.isVisible()) {
+                            // don't trigger the link if zoom ring is visible
+                            break;
+                        }
                         mPrivateHandler.removeMessages(SWITCH_TO_SHORTPRESS);
                         if (getSettings().supportZoom()
                                 && (mMinZoomScale < mMaxZoomScale)) {
@@ -3611,7 +3600,7 @@
                         break;
                     case TOUCH_SELECT_MODE:
                         commitCopy();
-                        mTouchSelection = mExtendSelection = false;
+                        mTouchSelection = false;
                         break;
                     case SCROLL_ZOOM_ANIMATION_IN:
                     case SCROLL_ZOOM_ANIMATION_OUT:
@@ -3679,7 +3668,6 @@
                     mVelocityTracker.recycle();
                     mVelocityTracker = null;
                 }
-                mPreviousUpTime = eventTime;
                 break;
             }
             case MotionEvent.ACTION_CANCEL: {
@@ -4110,6 +4098,14 @@
     }
 
     /**
+     * @hide pending API council? Assuming we make ZoomRingController itself
+     *       public, which I think we will.
+     */
+    public ZoomRingController getZoomRingController() {
+        return mZoomRingController;    
+    }
+    
+    /**
      * Perform zoom in in the webview
      * @return TRUE if zoom in succeeds. FALSE if no zoom changes.
      */
@@ -4193,16 +4189,15 @@
             return;
         }
         switchOutDrawHistory();
-        // FIXME: we don't know if the current (x,y) is on a focus node or
-        // not -- so playing the sound effect here is premature
-        if (nativeUpdateFocusNode()) {
-            playSoundEffect(SoundEffectConstants.CLICK);
-        }
         // mLastTouchX and mLastTouchY are the point in the current viewport
         int contentX = viewToContent((int) mLastTouchX + mScrollX);
         int contentY = viewToContent((int) mLastTouchY + mScrollY);
         int contentSize = ViewConfiguration.get(getContext()).getScaledTouchSlop();
         nativeMotionUp(contentX, contentY, contentSize, true);
+        if (nativeUpdateFocusNode() && !mFocusNode.mIsTextField
+                && !mFocusNode.mIsTextArea) {
+            playSoundEffect(SoundEffectConstants.CLICK);
+        }
     }
 
     @Override
@@ -5013,6 +5008,7 @@
     private native boolean  nativeUpdateFocusNode();
     private native Rect     nativeGetFocusRingBounds();
     private native Rect     nativeGetNavBounds();
+    private native void     nativeInstrumentReport();
     private native void     nativeMarkNodeInvalid(int node);
     private native void     nativeMotionUp(int x, int y, int slop, boolean isClick);
     // returns false if it handled the key
diff --git a/core/java/android/webkit/WebViewCore.java b/core/java/android/webkit/WebViewCore.java
index 8f78887..b979032 100644
--- a/core/java/android/webkit/WebViewCore.java
+++ b/core/java/android/webkit/WebViewCore.java
@@ -330,8 +330,7 @@
             String currentText, int keyCode, int keyValue, boolean down,
             boolean cap, boolean fn, boolean sym);
 
-    private native void nativeSaveDocumentState(int frame, int node, int x,
-            int y);
+    private native void nativeSaveDocumentState(int frame);
 
     private native void nativeSetFinalFocus(int framePtr, int nodePtr, int x,
             int y, boolean block);
@@ -777,8 +776,7 @@
 
                         case SAVE_DOCUMENT_STATE: {
                             FocusData fDat = (FocusData) msg.obj;
-                            nativeSaveDocumentState(fDat.mFrame, fDat.mNode,
-                                    fDat.mX, fDat.mY);
+                            nativeSaveDocumentState(fDat.mFrame);
                             break;
                         }
 
diff --git a/core/java/android/webkit/WebViewDatabase.java b/core/java/android/webkit/WebViewDatabase.java
index 96f3698..1004e30 100644
--- a/core/java/android/webkit/WebViewDatabase.java
+++ b/core/java/android/webkit/WebViewDatabase.java
@@ -531,33 +531,34 @@
      * @param url The url
      * @return CacheResult The CacheManager.CacheResult
      */
-    @SuppressWarnings("deprecation")
     CacheResult getCache(String url) {
         if (url == null || mCacheDatabase == null) {
             return null;
         }
 
-        CacheResult ret = null;
-        final String s = "SELECT filepath, lastmodify, etag, expires, mimetype, encoding, httpstatus, location, contentlength FROM cache WHERE url = ";
-        StringBuilder sb = new StringBuilder(256);
-        sb.append(s);
-        DatabaseUtils.appendEscapedSQLString(sb, url);
-        Cursor cursor = mCacheDatabase.rawQuery(sb.toString(), null);
+        Cursor cursor = mCacheDatabase.rawQuery("SELECT filepath, lastmodify, etag, expires, "
+                    + "mimetype, encoding, httpstatus, location, contentlength "
+                    + "FROM cache WHERE url = ?",
+                new String[] { url });
 
-        if (cursor.moveToFirst()) {
-            ret = new CacheResult();
-            ret.localPath = cursor.getString(0);
-            ret.lastModified = cursor.getString(1);
-            ret.etag = cursor.getString(2);
-            ret.expires = cursor.getLong(3);
-            ret.mimeType = cursor.getString(4);
-            ret.encoding = cursor.getString(5);
-            ret.httpStatusCode = cursor.getInt(6);
-            ret.location = cursor.getString(7);
-            ret.contentLength = cursor.getLong(8);
+        try {
+            if (cursor.moveToFirst()) {
+                CacheResult ret = new CacheResult();
+                ret.localPath = cursor.getString(0);
+                ret.lastModified = cursor.getString(1);
+                ret.etag = cursor.getString(2);
+                ret.expires = cursor.getLong(3);
+                ret.mimeType = cursor.getString(4);
+                ret.encoding = cursor.getString(5);
+                ret.httpStatusCode = cursor.getInt(6);
+                ret.location = cursor.getString(7);
+                ret.contentLength = cursor.getLong(8);
+                return ret;
+            }
+        } finally {
+            if (cursor != null) cursor.close();
         }
-        cursor.close();
-        return ret;
+        return null;
     }
 
     /**
@@ -565,16 +566,12 @@
      * 
      * @param url The url
      */
-    @SuppressWarnings("deprecation")
     void removeCache(String url) {
         if (url == null || mCacheDatabase == null) {
             return;
         }
 
-        StringBuilder sb = new StringBuilder(256);
-        sb.append("DELETE FROM cache WHERE url = ");
-        DatabaseUtils.appendEscapedSQLString(sb, url);
-        mCacheDatabase.execSQL(sb.toString());
+        mCacheDatabase.execSQL("DELETE FROM cache WHERE url = ?", new String[] { url });
     }
 
     /**
diff --git a/core/java/android/widget/AbsListView.java b/core/java/android/widget/AbsListView.java
index 378d218..c012e25 100644
--- a/core/java/android/widget/AbsListView.java
+++ b/core/java/android/widget/AbsListView.java
@@ -31,6 +31,7 @@
 import android.text.TextWatcher;
 import android.util.AttributeSet;
 import android.view.Gravity;
+import android.view.HapticFeedbackConstants;
 import android.view.KeyEvent;
 import android.view.LayoutInflater;
 import android.view.MotionEvent;
@@ -1622,6 +1623,9 @@
             mContextMenuInfo = createContextMenuInfo(child, longPressPosition, longPressId);
             handled = super.showContextMenuForChild(AbsListView.this);
         }
+        if (handled) {
+            performHapticFeedback(HapticFeedbackConstants.LONG_PRESS);
+        }
         return handled;
     }
 
diff --git a/core/java/android/widget/CursorFilter.java b/core/java/android/widget/CursorFilter.java
index afd5b10..dbded69 100644
--- a/core/java/android/widget/CursorFilter.java
+++ b/core/java/android/widget/CursorFilter.java
@@ -60,11 +60,10 @@
     }
 
     @Override
-    protected void publishResults(CharSequence constraint,
-            FilterResults results) {
+    protected void publishResults(CharSequence constraint, FilterResults results) {
         Cursor oldCursor = mClient.getCursor();
         
-        if (results.values != oldCursor) {
+        if (results.values != null && results.values != oldCursor) {
             mClient.changeCursor((Cursor) results.values);
         }
     }
diff --git a/core/java/android/widget/DatePicker.java b/core/java/android/widget/DatePicker.java
index 67010b2..54f2707 100644
--- a/core/java/android/widget/DatePicker.java
+++ b/core/java/android/widget/DatePicker.java
@@ -47,11 +47,8 @@
     /* UI Components */
     private final NumberPicker mDayPicker;
     private final NumberPicker mMonthPicker;
-    private final NumberPicker mYearPicker;    
-    
-    private final int mStartYear;
-    private final int mEndYear;
-    
+    private final NumberPicker mYearPicker;
+
     /**
      * How we notify users the date has changed.
      */
@@ -87,12 +84,9 @@
     public DatePicker(Context context, AttributeSet attrs, int defStyle) {
         super(context, attrs, defStyle);
 
-        LayoutInflater inflater =
-                (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
-        inflater.inflate(R.layout.date_picker,
-            this, // we are the parent
-            true);
-        
+        LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
+        inflater.inflate(R.layout.date_picker, this, true);
+
         mDayPicker = (NumberPicker) findViewById(R.id.day);
         mDayPicker.setFormatter(NumberPicker.TWO_DIGIT_FORMATTER);
         mDayPicker.setSpeed(100);
@@ -134,20 +128,17 @@
         });
         
         // attributes
-        TypedArray a = context
-                .obtainStyledAttributes(attrs, R.styleable.DatePicker);
+        TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.DatePicker);
 
-        mStartYear = a.getInt(R.styleable.DatePicker_startYear, DEFAULT_START_YEAR);
-        mEndYear = a.getInt(R.styleable.DatePicker_endYear, DEFAULT_END_YEAR);
+        int mStartYear = a.getInt(R.styleable.DatePicker_startYear, DEFAULT_START_YEAR);
+        int mEndYear = a.getInt(R.styleable.DatePicker_endYear, DEFAULT_END_YEAR);
         mYearPicker.setRange(mStartYear, mEndYear);
         
         a.recycle();
         
         // initialize to current date
         Calendar cal = Calendar.getInstance();
-        init(cal.get(Calendar.YEAR), 
-                cal.get(Calendar.MONTH), 
-                cal.get(Calendar.DAY_OF_MONTH), null);
+        init(cal.get(Calendar.YEAR), cal.get(Calendar.MONTH), cal.get(Calendar.DAY_OF_MONTH), null);
         
         // re-order the number pickers to match the current date format
         reorderPickers();
diff --git a/core/java/android/widget/Filter.java b/core/java/android/widget/Filter.java
index 7f1601e..a2316cf 100644
--- a/core/java/android/widget/Filter.java
+++ b/core/java/android/widget/Filter.java
@@ -20,6 +20,7 @@
 import android.os.HandlerThread;
 import android.os.Looper;
 import android.os.Message;
+import android.util.Log;
 
 /**
  * <p>A filter constrains data with a filtering pattern.</p>
@@ -36,6 +37,8 @@
  * @see android.widget.Filterable
  */
 public abstract class Filter {
+    private static final String LOG_TAG = "Filter";
+    
     private static final String THREAD_NAME = "Filter";
     private static final int FILTER_TOKEN = 0xD0D0F00D;
     private static final int FINISH_TOKEN = 0xDEADBEEF;
@@ -221,6 +224,9 @@
                     RequestArguments args = (RequestArguments) msg.obj;
                     try {
                         args.results = performFiltering(args.constraint);
+                    } catch (Exception e) {
+                        args.results = new FilterResults();
+                        Log.w(LOG_TAG, "An exception occured during performFiltering()!", e);
                     } finally {
                         message = mResultHandler.obtainMessage(what);
                         message.obj = args;
diff --git a/core/java/android/widget/Gallery.java b/core/java/android/widget/Gallery.java
index ffabb02..e7b303a 100644
--- a/core/java/android/widget/Gallery.java
+++ b/core/java/android/widget/Gallery.java
@@ -27,6 +27,7 @@
 import android.util.Log;
 import android.view.GestureDetector;
 import android.view.Gravity;
+import android.view.HapticFeedbackConstants;
 import android.view.KeyEvent;
 import android.view.MotionEvent;
 import android.view.View;
@@ -994,6 +995,7 @@
             return;
         }
         
+        performHapticFeedback(HapticFeedbackConstants.LONG_PRESS);
         long id = getItemIdAtPosition(mDownTouchPosition);
         dispatchLongPress(mDownTouchView, mDownTouchPosition, id);
     }
@@ -1086,6 +1088,10 @@
             handled = super.showContextMenuForChild(this);
         }
 
+        if (handled) {
+            performHapticFeedback(HapticFeedbackConstants.LONG_PRESS);
+        }
+        
         return handled;
     }
     
diff --git a/core/java/android/widget/ImageView.java b/core/java/android/widget/ImageView.java
index b5d4e2d5..4ae322e 100644
--- a/core/java/android/widget/ImageView.java
+++ b/core/java/android/widget/ImageView.java
@@ -48,6 +48,7 @@
  * @attr ref android.R.styleable#ImageView_maxHeight
  * @attr ref android.R.styleable#ImageView_tint
  * @attr ref android.R.styleable#ImageView_scaleType
+ * @attr ref android.R.styleable#ImageView_cropToPadding
  */
 @RemoteView
 public class ImageView extends View {
diff --git a/core/java/android/widget/RemoteViews.java b/core/java/android/widget/RemoteViews.java
index a1023bd..25afee8 100644
--- a/core/java/android/widget/RemoteViews.java
+++ b/core/java/android/widget/RemoteViews.java
@@ -35,6 +35,8 @@
 import android.view.ViewGroup;
 import android.view.LayoutInflater.Filter;
 import android.view.View.OnClickListener;
+import android.view.animation.Animation;
+import android.view.animation.AnimationUtils;
 
 import java.lang.annotation.ElementType;
 import java.lang.annotation.Retention;
@@ -548,6 +550,54 @@
     }
     
     /**
+     * Equivalent to calling {@link android.widget.ViewFlipper#startFlipping()}
+     * or {@link android.widget.ViewFlipper#stopFlipping()} along with
+     * {@link android.widget.ViewFlipper#setFlipInterval(int)}.
+     */
+    private class SetFlipping extends Action {
+        public SetFlipping(int id, boolean flipping, int milliseconds) {
+            this.viewId = id;
+            this.flipping = flipping;
+            this.milliseconds = milliseconds;
+        }
+        
+        public SetFlipping(Parcel parcel) {
+            viewId = parcel.readInt();
+            flipping = parcel.readInt() != 0;
+            milliseconds = parcel.readInt();
+        }
+        
+        public void writeToParcel(Parcel dest, int flags) {
+            dest.writeInt(TAG);
+            dest.writeInt(viewId);
+            dest.writeInt(flipping ? 1 : 0);
+            dest.writeInt(milliseconds);
+        }
+        
+        @Override
+        public void apply(View root) {
+            final View target = root.findViewById(viewId);
+            if (target instanceof ViewFlipper) {
+                final ViewFlipper flipper = (ViewFlipper) target;
+                if (milliseconds != -1) {
+                    flipper.setFlipInterval(milliseconds);
+                }
+                if (flipping) {
+                    flipper.startFlipping();
+                } else {
+                    flipper.stopFlipping();
+                }
+            }
+        }
+        
+        int viewId;
+        boolean flipping;
+        int milliseconds;
+
+        public final static int TAG = 10;
+    }
+
+    /**
      * Create a new RemoteViews object that will display the views contained
      * in the specified layout file.
      * 
@@ -603,6 +653,9 @@
                 case SetTextColor.TAG:
                     mActions.add(new SetTextColor(parcel));
                     break;
+                case SetFlipping.TAG:
+                    mActions.add(new SetFlipping(parcel));
+                    break;
                 default:
                     throw new ActionException("Tag " + tag + "not found");
                 }
@@ -769,6 +822,22 @@
     }
 
     /**
+     * Equivalent to calling {@link android.widget.ViewFlipper#startFlipping()}
+     * or {@link android.widget.ViewFlipper#stopFlipping()} along with
+     * {@link android.widget.ViewFlipper#setFlipInterval(int)}.
+     * 
+     * @param viewId The id of the view to apply changes to
+     * @param flipping True means we should
+     *            {@link android.widget.ViewFlipper#startFlipping()}, otherwise
+     *            {@link android.widget.ViewFlipper#stopFlipping()}.
+     * @param milliseconds How long to wait before flipping to the next view, or
+     *            -1 to leave unchanged.
+     */
+    public void setFlipping(int viewId, boolean flipping, int milliseconds) {
+        addAction(new SetFlipping(viewId, flipping, milliseconds));
+    }
+
+    /**
      * Inflates the view hierarchy represented by this object and applies
      * all of the actions.
      * 
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index d21c017..2ae5d4e 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -3844,7 +3844,7 @@
             boolean doDown = true;
             if (otherEvent != null) {
                 try {
-                    boolean handled = mMovement.onKeyOther(this, (Editable) mText,
+                    boolean handled = mMovement.onKeyOther(this, (Spannable) mText,
                             otherEvent);
                     doDown = false;
                     if (handled) {
diff --git a/core/java/android/widget/ViewAnimator.java b/core/java/android/widget/ViewAnimator.java
index 8c652e5..fa8935e3 100644
--- a/core/java/android/widget/ViewAnimator.java
+++ b/core/java/android/widget/ViewAnimator.java
@@ -28,6 +28,9 @@
 /**
  * Base class for a {@link FrameLayout} container that will perform animations
  * when switching between its views.
+ *
+ * @attr ref android.R.styleable#ViewAnimator_inAnimation
+ * @attr ref android.R.styleable#ViewAnimator_outAnimation
  */
 public class ViewAnimator extends FrameLayout {
 
diff --git a/core/java/android/widget/ViewFlipper.java b/core/java/android/widget/ViewFlipper.java
index a3c15d9..e20bfdf 100644
--- a/core/java/android/widget/ViewFlipper.java
+++ b/core/java/android/widget/ViewFlipper.java
@@ -22,12 +22,16 @@
 import android.os.Handler;
 import android.os.Message;
 import android.util.AttributeSet;
+import android.widget.RemoteViews.RemoteView;
 
 /**
  * Simple {@link ViewAnimator} that will animate between two or more views
  * that have been added to it.  Only one child is shown at a time.  If
  * requested, can automatically flip between each child at a regular interval.
+ *
+ * @attr ref android.R.styleable#ViewFlipper_flipInterval
  */
+@RemoteView
 public class ViewFlipper extends ViewAnimator {
     private int mFlipInterval = 3000;
     private boolean mKeepFlipping = false;
diff --git a/core/java/android/widget/ZoomButton.java b/core/java/android/widget/ZoomButton.java
index df3f307..0df919d 100644
--- a/core/java/android/widget/ZoomButton.java
+++ b/core/java/android/widget/ZoomButton.java
@@ -20,6 +20,7 @@
 import android.os.Handler;
 import android.util.AttributeSet;
 import android.view.GestureDetector;
+import android.view.HapticFeedbackConstants;
 import android.view.KeyEvent;
 import android.view.MotionEvent;
 import android.view.View;
@@ -57,6 +58,7 @@
         mGestureDetector = new GestureDetector(context, new SimpleOnGestureListener() {
             @Override
             public void onLongPress(MotionEvent e) {
+                performHapticFeedback(HapticFeedbackConstants.LONG_PRESS);
                 onLongClick(ZoomButton.this);
             }
         });
diff --git a/core/java/android/widget/ZoomRing.java b/core/java/android/widget/ZoomRing.java
index 20d6056..be3b1fb 100644
--- a/core/java/android/widget/ZoomRing.java
+++ b/core/java/android/widget/ZoomRing.java
@@ -6,10 +6,9 @@
 import android.content.res.Resources;
 import android.graphics.Canvas;
 import android.graphics.drawable.Drawable;
-import android.os.Handler;
+import android.graphics.drawable.RotateDrawable;
 import android.util.AttributeSet;
-import android.util.Log;
-import android.view.KeyEvent;
+import android.view.HapticFeedbackConstants;
 import android.view.MotionEvent;
 import android.view.View;
 import android.view.ViewConfiguration;
@@ -18,17 +17,20 @@
  * @hide
  */
 public class ZoomRing extends View {
-    
+
     // TODO: move to ViewConfiguration?
-    private static final int DOUBLE_TAP_DISMISS_TIMEOUT = ViewConfiguration.getJumpTapTimeout();
+    static final int DOUBLE_TAP_DISMISS_TIMEOUT = ViewConfiguration.getJumpTapTimeout();
     // TODO: get from theme
     private static final int DISABLED_ALPHA = 160;
-    
+
     private static final String TAG = "ZoomRing";
 
+    // TODO: Temporary until the trail is done
+    private static final boolean DRAW_TRAIL = false;
+
     // TODO: xml
-    private static final int THUMB_DISTANCE = 63; 
-    
+    private static final int THUMB_DISTANCE = 63;
+
     /** To avoid floating point calculations, we multiply radians by this value. */
     public static final int RADIAN_INT_MULTIPLIER = 100000000;
     /** PI using our multiplier. */
@@ -36,68 +38,81 @@
     /** PI/2 using our multiplier. */
     private static final int HALF_PI_INT_MULTIPLIED = PI_INT_MULTIPLIED / 2;
 
+    private int mZeroAngle = HALF_PI_INT_MULTIPLIED * 3;
+
     private static final int THUMB_GRAB_SLOP = PI_INT_MULTIPLIED / 4;
-    
+
     /** The cached X of our center. */
     private int mCenterX;
-    /** The cached Y of our center. */ 
+    /** The cached Y of our center. */
     private int mCenterY;
 
     /** The angle of the thumb (in int radians) */
     private int mThumbAngle;
     private boolean mIsThumbAngleValid;
-    private int mThumbCenterX;
-    private int mThumbCenterY;
     private int mThumbHalfWidth;
     private int mThumbHalfHeight;
-    
-    private int mCallbackThreshold = Integer.MAX_VALUE;
-    
-    /** The accumulated amount of drag for the thumb (in int radians). */
-    private int mAcculumalatedThumbDrag = 0;
-   
+
     /** The inner radius of the track. */
     private int mBoundInnerRadiusSquared = 0;
     /** The outer radius of the track. */
     private int mBoundOuterRadiusSquared = Integer.MAX_VALUE;
-    
+
     private int mPreviousWidgetDragX;
     private int mPreviousWidgetDragY;
-    
+
     private boolean mDrawThumb = true;
     private Drawable mThumbDrawable;
-    
+
     private static final int MODE_IDLE = 0;
     private static final int MODE_DRAG_THUMB = 1;
+    /**
+     * User has his finger down, but we are waiting for him to pass the touch
+     * slop before going into the #MODE_MOVE_ZOOM_RING. This is a good time to
+     * show the movable hint.
+     */
+    private static final int MODE_WAITING_FOR_MOVE_ZOOM_RING = 4;
     private static final int MODE_MOVE_ZOOM_RING = 2;
     private static final int MODE_TAP_DRAG = 3;
     private int mMode;
 
-    private long mPreviousTapTime;
-    
-    private Handler mHandler = new Handler();
-    
+    private long mPreviousDownTime;
+    private int mPreviousDownX;
+    private int mPreviousDownY;
+
     private Disabler mDisabler = new Disabler();
-    
+
     private OnZoomRingCallback mCallback;
-    
+    private int mPreviousCallbackAngle;
+    private int mCallbackThreshold = Integer.MAX_VALUE;
+
     private boolean mResetThumbAutomatically = true;
     private int mThumbDragStartAngle;
-    
+    private final int mTouchSlop;
+    private Drawable mTrail;
+    private double mAcculumalatedTrailAngle;
+
     public ZoomRing(Context context, AttributeSet attrs, int defStyle) {
         super(context, attrs, defStyle);
-        // TODO get drawable from style instead
+
+        ViewConfiguration viewConfiguration = ViewConfiguration.get(context);
+        mTouchSlop = viewConfiguration.getScaledTouchSlop();
+
+        // TODO get drawables from style instead
         Resources res = context.getResources();
         mThumbDrawable = res.getDrawable(R.drawable.zoom_ring_thumb);
-        
+        if (DRAW_TRAIL) {
+            mTrail = res.getDrawable(R.drawable.zoom_ring_trail).mutate();
+        }
+
         // TODO: add padding to drawable
         setBackgroundResource(R.drawable.zoom_ring_track);
         // TODO get from style
         setBounds(30, Integer.MAX_VALUE);
-        
+
         mThumbHalfHeight = mThumbDrawable.getIntrinsicHeight() / 2;
         mThumbHalfWidth = mThumbDrawable.getIntrinsicWidth() / 2;
-        
+
         mCallbackThreshold = PI_INT_MULTIPLIED / 6;
     }
 
@@ -108,7 +123,7 @@
     public ZoomRing(Context context) {
         this(context, null);
     }
-    
+
     public void setCallback(OnZoomRingCallback callback) {
         mCallback = callback;
     }
@@ -132,26 +147,49 @@
             mBoundOuterRadiusSquared = Integer.MAX_VALUE;
         }
     }
-    
+
     public void setThumbAngle(int angle) {
         mThumbAngle = angle;
-        mThumbCenterX = (int) (Math.cos(1f * angle / RADIAN_INT_MULTIPLIER) * THUMB_DISTANCE)
-                + mCenterX;
-        mThumbCenterY = (int) (Math.sin(1f * angle / RADIAN_INT_MULTIPLIER) * THUMB_DISTANCE)
-                * -1 + mCenterY;
+        int unoffsetAngle = angle + mZeroAngle;
+        int thumbCenterX = (int) (Math.cos(1f * unoffsetAngle / RADIAN_INT_MULTIPLIER) *
+                THUMB_DISTANCE) + mCenterX;
+        int thumbCenterY = (int) (Math.sin(1f * unoffsetAngle / RADIAN_INT_MULTIPLIER) *
+                THUMB_DISTANCE) * -1 + mCenterY;
+
+        mThumbDrawable.setBounds(thumbCenterX - mThumbHalfWidth,
+                thumbCenterY - mThumbHalfHeight,
+                thumbCenterX + mThumbHalfWidth,
+                thumbCenterY + mThumbHalfHeight);
+
+        if (DRAW_TRAIL) {
+            double degrees;
+            degrees = Math.min(359.0, Math.abs(mAcculumalatedTrailAngle));
+            int level = (int) (10000.0 * degrees / 360.0);
+
+            mTrail.setLevel((int) (10000.0 *
+                    (-Math.toDegrees(angle / (double) RADIAN_INT_MULTIPLIER) -
+                            degrees + 90) / 360.0));
+            ((RotateDrawable) mTrail).getDrawable().setLevel(level);
+        }
+
         invalidate();
     }
-    
+
+    public void resetThumbAngle(int angle) {
+        mPreviousCallbackAngle = angle;
+        setThumbAngle(angle);
+    }
+
     public void resetThumbAngle() {
         if (mResetThumbAutomatically) {
-            setThumbAngle(HALF_PI_INT_MULTIPLIED);
+            resetThumbAngle(0);
         }
     }
-    
+
     public void setResetThumbAutomatically(boolean resetThumbAutomatically) {
         mResetThumbAutomatically = resetThumbAutomatically;
     }
-    
+
     @Override
     protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
         setMeasuredDimension(resolveSize(getSuggestedMinimumWidth(), widthMeasureSpec),
@@ -162,7 +200,7 @@
     protected void onLayout(boolean changed, int left, int top, int right,
             int bottom) {
         super.onLayout(changed, left, top, right, bottom);
-        
+
         // Cache the center point
         mCenterX = (right - left) / 2;
         mCenterY = (bottom - top) / 2;
@@ -172,8 +210,12 @@
         if (mThumbAngle == Integer.MIN_VALUE) {
             resetThumbAngle();
         }
+
+        if (DRAW_TRAIL) {
+            mTrail.setBounds(0, 0, right - left, bottom - top);
+        }
     }
-    
+
     @Override
     public boolean onTouchEvent(MotionEvent event) {
         return handleTouch(event.getAction(), event.getEventTime(),
@@ -184,61 +226,66 @@
     private void resetState() {
         mMode = MODE_IDLE;
         mPreviousWidgetDragX = mPreviousWidgetDragY = Integer.MIN_VALUE;
-        mAcculumalatedThumbDrag = 0;
+        mAcculumalatedTrailAngle = 0.0;
         mIsThumbAngleValid = false;
     }
-    
+
     public void setTapDragMode(boolean tapDragMode, int x, int y) {
         resetState();
         mMode = tapDragMode ? MODE_TAP_DRAG : MODE_IDLE;
         mIsThumbAngleValid = false;
-        
+
         if (tapDragMode && mCallback != null) {
             onThumbDragStarted(getAngle(x - mCenterX, y - mCenterY));
         }
     }
-    
+
     public boolean handleTouch(int action, long time, int x, int y, int rawX, int rawY) {
         switch (action) {
-        
+
             case MotionEvent.ACTION_DOWN:
-                if (mPreviousTapTime + DOUBLE_TAP_DISMISS_TIMEOUT >= time) {
+                if (mPreviousDownTime + DOUBLE_TAP_DISMISS_TIMEOUT >= time) {
                     if (mCallback != null) {
                         mCallback.onZoomRingDismissed();
                     }
                 } else {
-                    mPreviousTapTime = time;
+                    mPreviousDownTime = time;
+                    mPreviousDownX = x;
+                    mPreviousDownY = y;
                 }
                 resetState();
                 return true;
-                
+
             case MotionEvent.ACTION_MOVE:
                 // Fall through to code below switch
                 break;
-                
+
             case MotionEvent.ACTION_CANCEL:
             case MotionEvent.ACTION_UP:
                 if (mCallback != null) {
-                    if (mMode == MODE_MOVE_ZOOM_RING) {
-                        mCallback.onZoomRingMovingStopped();
+                    if (mMode == MODE_MOVE_ZOOM_RING || mMode == MODE_WAITING_FOR_MOVE_ZOOM_RING) {
+                        mCallback.onZoomRingSetMovableHintVisible(false);
+                        if (mMode == MODE_MOVE_ZOOM_RING) {
+                            mCallback.onZoomRingMovingStopped();
+                        }
                     } else if (mMode == MODE_DRAG_THUMB || mMode == MODE_TAP_DRAG) {
                         onThumbDragStopped(getAngle(x - mCenterX, y - mCenterY));
                     }
                 }
                 mDisabler.setEnabling(true);
                 return true;
-                
+
             default:
                 return false;
         }
-        
+
         // local{X,Y} will be where the center of the widget is (0,0)
         int localX = x - mCenterX;
         int localY = y - mCenterY;
         boolean isTouchingThumb = true;
         boolean isInBounds = true;
         int touchAngle = getAngle(localX, localY);
-        
+
         int radiusSquared = localX * localX + localY * localY;
         if (radiusSquared < mBoundInnerRadiusSquared ||
                 radiusSquared > mBoundOuterRadiusSquared) {
@@ -246,7 +293,7 @@
             isTouchingThumb = false;
             isInBounds = false;
         }
-        
+
         int deltaThumbAndTouch = getDelta(touchAngle, mThumbAngle);
         int absoluteDeltaThumbAndTouch = deltaThumbAndTouch >= 0 ?
                 deltaThumbAndTouch : -deltaThumbAndTouch;
@@ -255,19 +302,35 @@
             // Didn't grab close enough to the thumb
             isTouchingThumb = false;
         }
-        
+
         if (mMode == MODE_IDLE) {
-            mMode = isTouchingThumb ? MODE_DRAG_THUMB : MODE_MOVE_ZOOM_RING;
-            
+            if (isTouchingThumb) {
+                mMode = MODE_DRAG_THUMB;
+            } else {
+                mMode = MODE_WAITING_FOR_MOVE_ZOOM_RING;
+            }
+
             if (mCallback != null) {
                 if (mMode == MODE_DRAG_THUMB) {
                     onThumbDragStarted(touchAngle);
-                } else if (mMode == MODE_MOVE_ZOOM_RING) {
+                } else if (mMode == MODE_WAITING_FOR_MOVE_ZOOM_RING) {
+                    mCallback.onZoomRingSetMovableHintVisible(true);
+                }
+            }
+
+        } else if (mMode == MODE_WAITING_FOR_MOVE_ZOOM_RING) {
+            if (Math.abs(x - mPreviousDownX) > mTouchSlop ||
+                    Math.abs(y - mPreviousDownY) > mTouchSlop) {
+                /* Make sure the user has moved the slop amount before going into that mode. */
+                mMode = MODE_MOVE_ZOOM_RING;
+
+                if (mCallback != null) {
                     mCallback.onZoomRingMovingStarted();
                 }
             }
         }
-        
+
+        // Purposefully not an "else if"
         if (mMode == MODE_DRAG_THUMB || mMode == MODE_TAP_DRAG) {
             if (isInBounds) {
                 onThumbDragged(touchAngle, mIsThumbAngleValid ? deltaThumbAndTouch : 0);
@@ -277,13 +340,13 @@
         } else if (mMode == MODE_MOVE_ZOOM_RING) {
             onZoomRingMoved(rawX, rawY);
         }
-        
+
         return true;
     }
-    
+
     private int getDelta(int angle1, int angle2) {
         int delta = angle1 - angle2;
-                
+
         // Assume this is a result of crossing over the discontinuous 0 -> 2pi
         if (delta > PI_INT_MULTIPLIED || delta < -PI_INT_MULTIPLIED) {
             // Bring both the radians and previous angle onto a continuous range
@@ -295,7 +358,7 @@
                 delta -= PI_INT_MULTIPLIED * 2;
             }
         }
-       
+
         return delta;
     }
 
@@ -303,46 +366,69 @@
         mThumbDragStartAngle = startAngle;
         mCallback.onZoomRingThumbDraggingStarted(startAngle);
     }
-    
+
     private void onThumbDragged(int touchAngle, int deltaAngle) {
-        mAcculumalatedThumbDrag += deltaAngle;
-        if (mAcculumalatedThumbDrag > mCallbackThreshold
-                || mAcculumalatedThumbDrag < -mCallbackThreshold) {
+        mAcculumalatedTrailAngle += Math.toDegrees(deltaAngle / (double) RADIAN_INT_MULTIPLIER);
+        int totalDeltaAngle = getDelta(touchAngle, mPreviousCallbackAngle);
+        if (totalDeltaAngle > mCallbackThreshold
+                || totalDeltaAngle < -mCallbackThreshold) {
             if (mCallback != null) {
                 boolean canStillZoom = mCallback.onZoomRingThumbDragged(
-                        mAcculumalatedThumbDrag / mCallbackThreshold,
-                        mAcculumalatedThumbDrag, mThumbDragStartAngle, touchAngle);
+                        totalDeltaAngle / mCallbackThreshold,
+                        mThumbDragStartAngle, touchAngle);
                 mDisabler.setEnabling(canStillZoom);
+
+                if (canStillZoom) {
+                    // TODO: we're trying the haptics to see how it goes with
+                    // users, so we're ignoring the settings (for now)
+                    performHapticFeedback(HapticFeedbackConstants.ZOOM_RING_TICK,
+                            HapticFeedbackConstants.FLAG_IGNORE_GLOBAL_SETTING |
+                            HapticFeedbackConstants.FLAG_IGNORE_VIEW_SETTING);
+                }
             }
-            mAcculumalatedThumbDrag = 0;
+
+            // Get the closest tick and lock on there
+            mPreviousCallbackAngle = getClosestTickAngle(touchAngle);
         }
-    
+
         setThumbAngle(touchAngle);
         mIsThumbAngleValid = true;
     }
-    
+
+    private int getClosestTickAngle(int angle) {
+        int smallerAngleDistance = angle % mCallbackThreshold;
+        int smallerAngle = angle - smallerAngleDistance;
+        if (smallerAngleDistance < mCallbackThreshold / 2) {
+            // Closer to the smaller angle
+            return smallerAngle;
+        } else {
+            // Closer to the bigger angle (premodding)
+            return (smallerAngle + mCallbackThreshold) % (PI_INT_MULTIPLIED * 2);
+        }
+    }
+
     private void onThumbDragStopped(int stopAngle) {
         mCallback.onZoomRingThumbDraggingStopped(stopAngle);
     }
-    
+
     private void onZoomRingMoved(int x, int y) {
         if (mPreviousWidgetDragX != Integer.MIN_VALUE) {
             int deltaX = x - mPreviousWidgetDragX;
             int deltaY = y - mPreviousWidgetDragY;
-            
+
             if (mCallback != null) {
                 mCallback.onZoomRingMoved(deltaX, deltaY);
             }
         }
-        
+
         mPreviousWidgetDragX = x;
         mPreviousWidgetDragY = y;
     }
-    
+
     @Override
     public void onWindowFocusChanged(boolean hasWindowFocus) {
         super.onWindowFocusChanged(hasWindowFocus);
-        
+
         if (!hasWindowFocus && mCallback != null) {
             mCallback.onZoomRingDismissed();
         }
@@ -353,22 +439,25 @@
 
         // Convert from [-pi,pi] to {0,2pi]
         if (radians < 0) {
-            return -radians;
+            radians = -radians;
         } else if (radians > 0) {
-            return 2 * PI_INT_MULTIPLIED - radians;
+            radians = 2 * PI_INT_MULTIPLIED - radians;
         } else {
-            return 0;
+            radians = 0;
         }
+
+        radians = radians - mZeroAngle;
+        return radians >= 0 ? radians : radians + 2 * PI_INT_MULTIPLIED;
     }
 
     @Override
     protected void onDraw(Canvas canvas) {
         super.onDraw(canvas);
-        
+
         if (mDrawThumb) {
-            mThumbDrawable.setBounds(mThumbCenterX - mThumbHalfWidth, mThumbCenterY
-                    - mThumbHalfHeight, mThumbCenterX + mThumbHalfWidth, mThumbCenterY
-                    + mThumbHalfHeight);
+            if (DRAW_TRAIL) {
+                mTrail.draw(canvas);
+            }
             mThumbDrawable.draw(canvas);
         }
     }
@@ -409,12 +498,14 @@
     }
     
     public interface OnZoomRingCallback {
+        void onZoomRingSetMovableHintVisible(boolean visible);
+        
         void onZoomRingMovingStarted();
         boolean onZoomRingMoved(int deltaX, int deltaY);
         void onZoomRingMovingStopped();
         
         void onZoomRingThumbDraggingStarted(int startAngle);
-        boolean onZoomRingThumbDragged(int numLevels, int dragAmount, int startAngle, int curAngle);
+        boolean onZoomRingThumbDragged(int numLevels, int startAngle, int curAngle);
         void onZoomRingThumbDraggingStopped(int endAngle);
         
         void onZoomRingDismissed();
diff --git a/core/java/android/widget/ZoomRingController.java b/core/java/android/widget/ZoomRingController.java
index 2ca0374..eb28767 100644
--- a/core/java/android/widget/ZoomRingController.java
+++ b/core/java/android/widget/ZoomRingController.java
@@ -17,14 +17,17 @@
 package android.widget;
 
 import android.content.BroadcastReceiver;
+import android.content.ContentResolver;
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
+import android.content.SharedPreferences;
 import android.graphics.PixelFormat;
 import android.graphics.Rect;
 import android.os.Handler;
 import android.os.Message;
 import android.os.SystemClock;
+import android.os.Vibrator;
 import android.provider.Settings;
 import android.util.Log;
 import android.view.Gravity;
@@ -42,6 +45,7 @@
 
 /**
  * TODO: Docs
+ * 
  * @hide
  */
 public class ZoomRingController implements ZoomRing.OnZoomRingCallback,
@@ -222,7 +226,7 @@
     public ZoomRingController(Context context, View ownerView) {
         mContext = context;
         mWindowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
-        
+
         mOwnerView = ownerView;
         
         mZoomRing = new ZoomRing(context);
@@ -437,7 +441,15 @@
                     
                         case MotionEvent.ACTION_UP:
                             mTouchMode = TOUCH_MODE_IDLE;
+                            
+                            /*
+                             * This is a power-user feature that only shows the
+                             * zoom while the user is performing the tap-drag.
+                             * That means once it is released, the zoom ring
+                             * should disappear.
+                             */  
                             mZoomRing.setTapDragMode(false, (int) event.getX(), (int) event.getY());
+                            dismissZoomRingDelayed(0);
                             break;
                     }
                     break;
@@ -560,10 +572,13 @@
         mZoomRing.handleTouch(event.getAction(), event.getEventTime(), x, y, rawX, rawY);
     }
     
+    public void onZoomRingSetMovableHintVisible(boolean visible) {
+        setPanningArrowsVisible(visible); 
+    }
+
     public void onZoomRingMovingStarted() {
         mHandler.removeMessages(MSG_DISMISS_ZOOM_RING);
         mScroller.abortAnimation();
-        setPanningArrowsVisible(true); 
     }
     
     private void setPanningArrowsVisible(boolean visible) {
@@ -641,8 +656,7 @@
         }
     }
     
-    public boolean onZoomRingThumbDragged(int numLevels, int dragAmount, int startAngle,
-            int curAngle) {
+    public boolean onZoomRingThumbDragged(int numLevels, int startAngle, int curAngle) {
         if (mCallback != null) {
             int deltaZoomLevel = -numLevels;
             int globalZoomCenterX = mContainerLayoutParams.x + mZoomRing.getLeft() +
@@ -650,7 +664,8 @@
             int globalZoomCenterY = mContainerLayoutParams.y + mZoomRing.getTop() +
                     mZoomRingHeight / 2;
             
-            return mCallback.onDragZoom(deltaZoomLevel, globalZoomCenterX - mOwnerViewBounds.left,
+            return mCallback.onDragZoom(deltaZoomLevel,
+                    globalZoomCenterX - mOwnerViewBounds.left,
                     globalZoomCenterY - mOwnerViewBounds.top,
                     (float) startAngle / ZoomRing.RADIAN_INT_MULTIPLIER,
                     (float) curAngle / ZoomRing.RADIAN_INT_MULTIPLIER);
@@ -719,6 +734,45 @@
         ensureZoomRingIsCentered();
     }
 
+    /**
+     * Shows a "tutorial" (some text) to the user teaching her the new zoom
+     * invocation method.
+     * <p>
+     * It checks the global system setting to ensure this has not been seen
+     * before. Furthermore, if the application does not have privilege to write
+     * to the system settings, it will store this bit locally in a shared
+     * preference.
+     * 
+     * @hide This should only be used by our main apps--browser, maps, and
+     *       gallery
+     */
+    public static void showZoomTutorialOnce(Context context) {
+        ContentResolver cr = context.getContentResolver();
+        if (Settings.System.getInt(cr, SETTING_NAME_SHOWN_TOAST, 0) == 1) {
+            return;
+        }
+        
+        SharedPreferences sp = context.getSharedPreferences("_zoom", Context.MODE_PRIVATE);
+        if (sp.getInt(SETTING_NAME_SHOWN_TOAST, 0) == 1) {
+            return;
+        }
+        
+        try {
+            Settings.System.putInt(cr, SETTING_NAME_SHOWN_TOAST, 1);
+        } catch (SecurityException e) {
+            /*
+             * The app does not have permission to clear this global flag, make
+             * sure the user does not see the message when he comes back to this
+             * same app at least.
+             */
+            sp.edit().putInt(SETTING_NAME_SHOWN_TOAST, 1).commit();
+        }
+
+        Toast.makeText(context,
+                com.android.internal.R.string.tutorial_double_tap_to_zoom_message_short,
+                Toast.LENGTH_LONG).show();
+    }
+    
     private class Panner implements Runnable {
         private static final int RUN_DELAY = 15;
         private static final float STOP_SLOWDOWN = 0.8f;
diff --git a/core/java/com/android/internal/gadget/IGadgetHost.aidl b/core/java/com/android/internal/gadget/IGadgetHost.aidl
index a5b8654..e7b5a1e 100644
--- a/core/java/com/android/internal/gadget/IGadgetHost.aidl
+++ b/core/java/com/android/internal/gadget/IGadgetHost.aidl
@@ -17,11 +17,12 @@
 package com.android.internal.gadget;
 
 import android.content.ComponentName;
-import android.gadget.GadgetInfo;
+import android.gadget.GadgetProviderInfo;
 import android.widget.RemoteViews;
 
 /** {@hide} */
 oneway interface IGadgetHost {
     void updateGadget(int gadgetId, in RemoteViews views);
+    void providerChanged(int gadgetId, in GadgetProviderInfo info);
 }
 
diff --git a/core/java/com/android/internal/gadget/IGadgetService.aidl b/core/java/com/android/internal/gadget/IGadgetService.aidl
index 1b3946f..a22f3f3 100644
--- a/core/java/com/android/internal/gadget/IGadgetService.aidl
+++ b/core/java/com/android/internal/gadget/IGadgetService.aidl
@@ -17,7 +17,7 @@
 package com.android.internal.gadget;
 
 import android.content.ComponentName;
-import android.gadget.GadgetInfo;
+import android.gadget.GadgetProviderInfo;
 import com.android.internal.gadget.IGadgetHost;
 import android.widget.RemoteViews;
 
@@ -41,8 +41,8 @@
     //
     void updateGadgetIds(in int[] gadgetIds, in RemoteViews views);
     void updateGadgetProvider(in ComponentName provider, in RemoteViews views);
-    List<GadgetInfo> getInstalledProviders();
-    GadgetInfo getGadgetInfo(int gadgetId);
+    List<GadgetProviderInfo> getInstalledProviders();
+    GadgetProviderInfo getGadgetInfo(int gadgetId);
     void bindGadgetId(int gadgetId, in ComponentName provider);
 
 }
diff --git a/core/java/com/android/internal/view/IInputConnectionWrapper.java b/core/java/com/android/internal/view/IInputConnectionWrapper.java
index b0b00b2..ac72a20 100644
--- a/core/java/com/android/internal/view/IInputConnectionWrapper.java
+++ b/core/java/com/android/internal/view/IInputConnectionWrapper.java
@@ -32,8 +32,7 @@
     private static final int DO_DELETE_SURROUNDING_TEXT = 80;
     private static final int DO_BEGIN_BATCH_EDIT = 90;
     private static final int DO_END_BATCH_EDIT = 95;
-    private static final int DO_HIDE_STATUS_ICON = 100;
-    private static final int DO_SHOW_STATUS_ICON = 110;
+    private static final int DO_REPORT_FULLSCREEN_MODE = 100;
     private static final int DO_PERFORM_PRIVATE_COMMAND = 120;
     private static final int DO_CLEAR_META_KEY_STATES = 130;
         
@@ -133,12 +132,8 @@
         dispatchMessage(obtainMessage(DO_END_BATCH_EDIT));
     }
 
-    public void hideStatusIcon() {
-        dispatchMessage(obtainMessage(DO_HIDE_STATUS_ICON));
-    }
-
-    public void showStatusIcon(String packageName, int resId) {
-        dispatchMessage(obtainMessageIO(DO_SHOW_STATUS_ICON, resId, packageName));
+    public void reportFullscreenMode(boolean enabled) {
+        dispatchMessage(obtainMessageII(DO_REPORT_FULLSCREEN_MODE, enabled ? 1 : 0, 0));
     }
 
     public void performPrivateCommand(String action, Bundle data) {
@@ -323,22 +318,13 @@
                 ic.endBatchEdit();
                 return;
             }
-            case DO_HIDE_STATUS_ICON: {
-                InputConnection ic = mInputConnection.get();
-                if (ic == null || !isActive()) {
-                    Log.w(TAG, "hideStatusIcon on inactive InputConnection");
-                    return;
-                }
-                ic.hideStatusIcon();
-                return;
-            }
-            case DO_SHOW_STATUS_ICON: {
+            case DO_REPORT_FULLSCREEN_MODE: {
                 InputConnection ic = mInputConnection.get();
                 if (ic == null || !isActive()) {
                     Log.w(TAG, "showStatusIcon on inactive InputConnection");
                     return;
                 }
-                ic.showStatusIcon((String)msg.obj, msg.arg1);
+                ic.reportFullscreenMode(msg.arg1 != 1);
                 return;
             }
             case DO_PERFORM_PRIVATE_COMMAND: {
diff --git a/core/java/com/android/internal/view/IInputContext.aidl b/core/java/com/android/internal/view/IInputContext.aidl
index 7cc8ada..02b6044 100644
--- a/core/java/com/android/internal/view/IInputContext.aidl
+++ b/core/java/com/android/internal/view/IInputContext.aidl
@@ -56,13 +56,11 @@
     
     void endBatchEdit();
     
+    void reportFullscreenMode(boolean enabled);
+    
     void sendKeyEvent(in KeyEvent event);
     
     void clearMetaKeyStates(int states);
     
     void performPrivateCommand(String action, in Bundle data);
-    
-    void showStatusIcon(String packageName, int resId);
-
-    void hideStatusIcon();
 }
diff --git a/core/java/com/android/internal/view/IInputMethodManager.aidl b/core/java/com/android/internal/view/IInputMethodManager.aidl
index 2f5cd14..1b1c7f7 100644
--- a/core/java/com/android/internal/view/IInputMethodManager.aidl
+++ b/core/java/com/android/internal/view/IInputMethodManager.aidl
@@ -47,7 +47,7 @@
     void showInputMethodPickerFromClient(in IInputMethodClient client);
     void setInputMethod(in IBinder token, String id);
     void hideMySoftInput(in IBinder token, int flags);
-    void updateStatusIcon(int iconId, String iconPackage);
+    void updateStatusIcon(in IBinder token, String packageName, int iconId);
     
     boolean setInputMethodEnabled(String id, boolean enabled);
 }
diff --git a/core/java/com/android/internal/view/InputConnectionWrapper.java b/core/java/com/android/internal/view/InputConnectionWrapper.java
index af4ad25..32d9f3d 100644
--- a/core/java/com/android/internal/view/InputConnectionWrapper.java
+++ b/core/java/com/android/internal/view/InputConnectionWrapper.java
@@ -322,18 +322,9 @@
         }
     }
 
-    public boolean hideStatusIcon() {
+    public boolean reportFullscreenMode(boolean enabled) {
         try {
-            mIInputContext.showStatusIcon(null, 0);
-            return true;
-        } catch (RemoteException e) {
-            return false;
-        }
-    }
-
-    public boolean showStatusIcon(String packageName, int resId) {
-        try {
-            mIInputContext.showStatusIcon(packageName, resId);
+            mIInputContext.reportFullscreenMode(enabled);
             return true;
         } catch (RemoteException e) {
             return false;
diff --git a/core/java/com/android/internal/widget/NumberPicker.java b/core/java/com/android/internal/widget/NumberPicker.java
index 20ea6a6..1647c20 100644
--- a/core/java/com/android/internal/widget/NumberPicker.java
+++ b/core/java/com/android/internal/widget/NumberPicker.java
@@ -28,12 +28,8 @@
 import android.view.View.OnClickListener;
 import android.view.View.OnFocusChangeListener;
 import android.view.View.OnLongClickListener;
-import android.view.animation.Animation;
-import android.view.animation.TranslateAnimation;
-import android.widget.EditText;
-import android.widget.LinearLayout;
 import android.widget.TextView;
-import android.widget.ViewSwitcher;
+import android.widget.LinearLayout;
 
 import com.android.internal.R;
 
@@ -71,25 +67,18 @@
     private final Runnable mRunnable = new Runnable() {
         public void run() {
             if (mIncrement) {
-                changeCurrent(mCurrent + 1, mSlideUpInAnimation, mSlideUpOutAnimation);
+                changeCurrent(mCurrent + 1);
                 mHandler.postDelayed(this, mSpeed);
             } else if (mDecrement) {
-                changeCurrent(mCurrent - 1, mSlideDownInAnimation, mSlideDownOutAnimation);
+                changeCurrent(mCurrent - 1);
                 mHandler.postDelayed(this, mSpeed);
             }
         }
     };
-    
-    private final LayoutInflater mInflater;
+
     private final TextView mText;
-    private final InputFilter mInputFilter;
     private final InputFilter mNumberInputFilter;
-    
-    private final Animation mSlideUpOutAnimation;
-    private final Animation mSlideUpInAnimation;
-    private final Animation mSlideDownOutAnimation;
-    private final Animation mSlideDownInAnimation;
-    
+
     private String[] mDisplayedValues;
     private int mStart;
     private int mEnd;
@@ -110,14 +99,14 @@
         this(context, attrs, 0);
     }
 
-    public NumberPicker(Context context, AttributeSet attrs,
-            int defStyle) {
+    @SuppressWarnings({"UnusedDeclaration"})
+    public NumberPicker(Context context, AttributeSet attrs, int defStyle) {
         super(context, attrs);
         setOrientation(VERTICAL);
-        mInflater = (LayoutInflater) mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);        
-        mInflater.inflate(R.layout.number_picker, this, true);
+        LayoutInflater inflater = (LayoutInflater) mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
+        inflater.inflate(R.layout.number_picker, this, true);
         mHandler = new Handler();
-        mInputFilter = new NumberPickerInputFilter();
+        InputFilter inputFilter = new NumberPickerInputFilter();
         mNumberInputFilter = new NumberRangeKeyListener();
         mIncrementButton = (NumberPickerButton) findViewById(R.id.increment);
         mIncrementButton.setOnClickListener(this);
@@ -130,30 +119,9 @@
         
         mText = (TextView) findViewById(R.id.timepicker_input);
         mText.setOnFocusChangeListener(this);
-        mText.setFilters(new InputFilter[] { mInputFilter });
+        mText.setFilters(new InputFilter[] {inputFilter});
         mText.setRawInputType(InputType.TYPE_CLASS_NUMBER);
-        
-        mSlideUpOutAnimation = new TranslateAnimation(
-                Animation.RELATIVE_TO_SELF, 0, Animation.RELATIVE_TO_SELF,
-                0, Animation.RELATIVE_TO_SELF, 0,
-                Animation.RELATIVE_TO_SELF, -100);
-        mSlideUpOutAnimation.setDuration(200);
-        mSlideUpInAnimation = new TranslateAnimation(
-                Animation.RELATIVE_TO_SELF, 0, Animation.RELATIVE_TO_SELF,
-                0, Animation.RELATIVE_TO_SELF, 100,
-                Animation.RELATIVE_TO_SELF, 0);
-        mSlideUpInAnimation.setDuration(200);
-        mSlideDownOutAnimation = new TranslateAnimation(
-                Animation.RELATIVE_TO_SELF, 0, Animation.RELATIVE_TO_SELF,
-                0, Animation.RELATIVE_TO_SELF, 0,
-                Animation.RELATIVE_TO_SELF, 100);
-        mSlideDownOutAnimation.setDuration(200);
-        mSlideDownInAnimation = new TranslateAnimation(
-                Animation.RELATIVE_TO_SELF, 0, Animation.RELATIVE_TO_SELF,
-                0, Animation.RELATIVE_TO_SELF, -100,
-                Animation.RELATIVE_TO_SELF, 0);
-        mSlideDownInAnimation.setDuration(200);
-        
+
         if (!isEnabled()) {
             setEnabled(false);
         }
@@ -228,9 +196,9 @@
 
         // now perform the increment/decrement
         if (R.id.increment == v.getId()) {
-            changeCurrent(mCurrent + 1, mSlideUpInAnimation, mSlideUpOutAnimation);
+            changeCurrent(mCurrent + 1);
         } else if (R.id.decrement == v.getId()) {
-            changeCurrent(mCurrent - 1, mSlideDownInAnimation, mSlideDownOutAnimation);
+            changeCurrent(mCurrent - 1);
         }
     }
     
@@ -240,7 +208,7 @@
                 : String.valueOf(value);
     }
  
-    private void changeCurrent(int current, Animation in, Animation out) {
+    private void changeCurrent(int current) {
         
         // Wrap around the values if we go past the start or end
         if (current > mEnd) {
diff --git a/core/jni/android_media_AudioRecord.cpp b/core/jni/android_media_AudioRecord.cpp
index 307c6fd..288433a 100644
--- a/core/jni/android_media_AudioRecord.cpp
+++ b/core/jni/android_media_AudioRecord.cpp
@@ -267,7 +267,7 @@
             (AudioRecord *)env->GetIntField(thiz, javaAudioRecordFields.nativeRecorderInJavaObj);
 
     if (lpRecorder) {
-        //LOGV("About to delete lpRecorder: %x\n", (int)lpRecorder);
+        LOGV("About to delete lpRecorder: %x\n", (int)lpRecorder);
         lpRecorder->stop();
         delete lpRecorder;
     }
@@ -449,6 +449,39 @@
 
 
 // ----------------------------------------------------------------------------
+// returns the minimum required size for the successful creation of an AudioRecord instance.
+// returns 0 if the parameter combination is not supported.
+// return -1 if there was an error querying the buffer size.
+static jint android_media_AudioRecord_get_min_buff_size(JNIEnv *env,  jobject thiz,
+    jint sampleRateInHertz, jint nbChannels, jint audioFormat) {
+    
+    size_t inputBuffSize = 0;
+    LOGV(">> android_media_AudioRecord_get_min_buff_size(%d, %d, %d)", sampleRateInHertz, nbChannels, audioFormat);
+    
+    status_t result = AudioSystem::getInputBufferSize(
+                        sampleRateInHertz, 
+                        (audioFormat == javaAudioRecordFields.PCM16 ? 
+                            AudioSystem::PCM_16_BIT : AudioSystem::PCM_8_BIT), 
+                        nbChannels, &inputBuffSize);
+    switch(result) {
+    case(NO_ERROR):
+        if(inputBuffSize == 0) {
+            LOGV("Recording parameters are not supported: %dHz, %d channel(s), (java) format %d",
+                sampleRateInHertz, nbChannels, audioFormat);
+            return 0;
+        } else {
+            // the minimum buffer size is twice the hardware input buffer size
+            return 2*inputBuffSize;
+        }
+        break;
+    case(PERMISSION_DENIED):
+    default:
+        return -1; 
+    }
+}
+
+
+// ----------------------------------------------------------------------------
 // ----------------------------------------------------------------------------
 static JNINativeMethod gMethods[] = {
     // name,               signature,  funcPtr
@@ -470,6 +503,8 @@
                              "(I)I",   (void *)android_media_AudioRecord_set_pos_update_period},
     {"native_get_pos_update_period",
                              "()I",    (void *)android_media_AudioRecord_get_pos_update_period},
+    {"native_get_min_buff_size",
+                             "(III)I",   (void *)android_media_AudioRecord_get_min_buff_size},
 };
 
 // field names found in android/media/AudioRecord.java
diff --git a/core/jni/android_media_AudioSystem.cpp b/core/jni/android_media_AudioSystem.cpp
index 6bd3655..692610e 100644
--- a/core/jni/android_media_AudioSystem.cpp
+++ b/core/jni/android_media_AudioSystem.cpp
@@ -53,13 +53,8 @@
 android_media_AudioSystem_setVolume(JNIEnv *env, jobject clazz, jint type, jint volume)
 {
     LOGV("setVolume(%d)", int(volume));
-    if (int(type) == AudioTrack::VOICE_CALL) {
-        return check_AudioSystem_Command(AudioSystem::setStreamVolume(type, float(volume) / 100.0));
-    } else if (int(type) == AudioTrack::BLUETOOTH_SCO) {
-        return check_AudioSystem_Command(AudioSystem::setStreamVolume(type, float(1.0)));
-    } else {
-        return check_AudioSystem_Command(AudioSystem::setStreamVolume(type, AudioSystem::linearToLog(volume)));
-    }
+    
+    return check_AudioSystem_Command(AudioSystem::setStreamVolume(type, AudioSystem::linearToLog(volume)));
 }
 
 static int
@@ -68,12 +63,7 @@
     float v;
     int v_int = -1;
     if (AudioSystem::getStreamVolume(int(type), &v) == NO_ERROR) {
-        // voice call volume is converted to log scale in the hardware
-        if (int(type) == AudioTrack::VOICE_CALL) {
-            v_int = lrint(v * 100.0);
-        } else {
-            v_int = AudioSystem::logToLinear(v);
-        }
+        v_int = AudioSystem::logToLinear(v);
     }
     return v_int;
 }
diff --git a/core/jni/android_media_AudioTrack.cpp b/core/jni/android_media_AudioTrack.cpp
index bbecc1b..6ca821d 100644
--- a/core/jni/android_media_AudioTrack.cpp
+++ b/core/jni/android_media_AudioTrack.cpp
@@ -72,6 +72,7 @@
         sp<MemoryHeapBase>         mMemHeap;
         sp<MemoryBase>             mMemBase;
         audiotrack_callback_cookie mCallbackData;
+        int                        mStreamType;
 
     AudioTrackJniStorage() {
     }
@@ -168,11 +169,11 @@
     int afSampleRate;
     int afFrameCount;
 
-    if (AudioSystem::getOutputFrameCount(&afFrameCount) != NO_ERROR) {
+    if (AudioSystem::getOutputFrameCount(&afFrameCount, streamType) != NO_ERROR) {
         LOGE("Error creating AudioTrack: Could not get AudioSystem frame count.");
         return AUDIOTRACK_ERROR_SETUP_AUDIOSYSTEM;
     }
-    if (AudioSystem::getOutputSamplingRate(&afSampleRate) != NO_ERROR) {
+    if (AudioSystem::getOutputSamplingRate(&afSampleRate, streamType) != NO_ERROR) {
         LOGE("Error creating AudioTrack: Could not get AudioSystem sampling rate.");
         return AUDIOTRACK_ERROR_SETUP_AUDIOSYSTEM;
     }
@@ -183,21 +184,21 @@
     }
     
     // check the stream type
-    AudioTrack::stream_type atStreamType;
+    AudioSystem::stream_type atStreamType;
     if (streamType == javaAudioTrackFields.STREAM_VOICE_CALL) {
-        atStreamType = AudioTrack::VOICE_CALL;
+        atStreamType = AudioSystem::VOICE_CALL;
     } else if (streamType == javaAudioTrackFields.STREAM_SYSTEM) {
-        atStreamType = AudioTrack::SYSTEM;
+        atStreamType = AudioSystem::SYSTEM;
     } else if (streamType == javaAudioTrackFields.STREAM_RING) {
-        atStreamType = AudioTrack::RING;
+        atStreamType = AudioSystem::RING;
     } else if (streamType == javaAudioTrackFields.STREAM_MUSIC) {
-        atStreamType = AudioTrack::MUSIC;
+        atStreamType = AudioSystem::MUSIC;
     } else if (streamType == javaAudioTrackFields.STREAM_ALARM) {
-        atStreamType = AudioTrack::ALARM;
+        atStreamType = AudioSystem::ALARM;
     } else if (streamType == javaAudioTrackFields.STREAM_NOTIFICATION) {
-        atStreamType = AudioTrack::NOTIFICATION;
+        atStreamType = AudioSystem::NOTIFICATION;
     } else if (streamType == javaAudioTrackFields.STREAM_BLUETOOTH_SCO) {
-        atStreamType = AudioTrack::BLUETOOTH_SCO;
+        atStreamType = AudioSystem::BLUETOOTH_SCO;
     } else {
         LOGE("Error creating AudioTrack: unknown stream type.");
         return AUDIOTRACK_ERROR_SETUP_INVALIDSTREAMTYPE;
@@ -238,6 +239,8 @@
     // we use a weak reference so the AudioTrack object can be garbage collected.
     lpJniStorage->mCallbackData.audioTrack_ref = env->NewGlobalRef(weak_this);
     
+    lpJniStorage->mStreamType = atStreamType;
+    
     // create the native AudioTrack object
     AudioTrack* lpTrack = new AudioTrack();
     if (lpTrack == NULL) {
@@ -656,8 +659,14 @@
 
 // ----------------------------------------------------------------------------
 static jint android_media_AudioTrack_get_output_sample_rate(JNIEnv *env,  jobject thiz) {
-    int afSamplingRate;
-    if (AudioSystem::getOutputSamplingRate(&afSamplingRate) != NO_ERROR) {
+    int afSamplingRate;    
+    AudioTrackJniStorage* lpJniStorage = (AudioTrackJniStorage *)env->GetIntField(
+        thiz, javaAudioTrackFields.jniData);
+    if (lpJniStorage == NULL) {
+        return DEFAULT_OUTPUT_SAMPLE_RATE;
+    }
+
+    if (AudioSystem::getOutputSamplingRate(&afSamplingRate, lpJniStorage->mStreamType) != NO_ERROR) {
         return DEFAULT_OUTPUT_SAMPLE_RATE;
     } else {
         return afSamplingRate;
diff --git a/core/jni/android_server_BluetoothEventLoop.cpp b/core/jni/android_server_BluetoothEventLoop.cpp
index 75a0fbee..e5ae2ea 100644
--- a/core/jni/android_server_BluetoothEventLoop.cpp
+++ b/core/jni/android_server_BluetoothEventLoop.cpp
@@ -751,6 +751,10 @@
             // Other device is not responding at all
             LOGV("... error = %s (%s)\n", err.name, err.message);
             result = BOND_RESULT_REMOTE_DEVICE_DOWN;
+        } else if (!strcmp(err.name, BLUEZ_DBUS_BASE_IFC ".Error.AlreadyExists")) {
+            // already bonded
+            LOGV("... error = %s (%s)\n", err.name, err.message);
+            result = BOND_RESULT_SUCCESS;
         } else {
             LOGE("%s: D-Bus error: %s (%s)\n", __FUNCTION__, err.name, err.message);
             result = BOND_RESULT_ERROR;
diff --git a/core/jni/android_util_EventLog.cpp b/core/jni/android_util_EventLog.cpp
index d0cac18..5e5103a 100644
--- a/core/jni/android_util_EventLog.cpp
+++ b/core/jni/android_util_EventLog.cpp
@@ -19,7 +19,7 @@
 #include "JNIHelp.h"
 #include "android_runtime/AndroidRuntime.h"
 #include "jni.h"
-#include "utils/logger.h"
+#include "cutils/logger.h"
 
 #define END_DELIMITER '\n'
 #define INT_BUFFER_SIZE (sizeof(jbyte)+sizeof(jint)+sizeof(END_DELIMITER))
diff --git a/core/res/res/drawable/presence_away.png b/core/res/res/drawable/presence_away.png
index a539ec7..f8120df 100644
--- a/core/res/res/drawable/presence_away.png
+++ b/core/res/res/drawable/presence_away.png
Binary files differ
diff --git a/core/res/res/drawable/presence_busy.png b/core/res/res/drawable/presence_busy.png
index 1e3f547b..9d7620b 100644
--- a/core/res/res/drawable/presence_busy.png
+++ b/core/res/res/drawable/presence_busy.png
Binary files differ
diff --git a/core/res/res/drawable/presence_invisible.png b/core/res/res/drawable/presence_invisible.png
index fb86cf1..21399a4 100644
--- a/core/res/res/drawable/presence_invisible.png
+++ b/core/res/res/drawable/presence_invisible.png
Binary files differ
diff --git a/core/res/res/drawable/presence_offline.png b/core/res/res/drawable/presence_offline.png
index da54fe7..3941b82 100644
--- a/core/res/res/drawable/presence_offline.png
+++ b/core/res/res/drawable/presence_offline.png
Binary files differ
diff --git a/core/res/res/drawable/presence_online.png b/core/res/res/drawable/presence_online.png
index 879a762..22d5683 100644
--- a/core/res/res/drawable/presence_online.png
+++ b/core/res/res/drawable/presence_online.png
Binary files differ
diff --git a/core/res/res/drawable/zoom_ring_trail.xml b/core/res/res/drawable/zoom_ring_trail.xml
new file mode 100644
index 0000000..08931ac
--- /dev/null
+++ b/core/res/res/drawable/zoom_ring_trail.xml
@@ -0,0 +1,37 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2009 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<rotate xmlns:android="http://schemas.android.com/apk/res/android"
+    android:pivotX="50%"
+    android:pivotY="50%"
+    android:fromDegrees="0"
+    android:toDegrees="360">
+
+    <shape
+        android:shape="ring"
+        android:innerRadius="60dip"
+        android:thickness="14dip"
+        android:useLevel="true">
+
+        <gradient
+            android:type="sweep"
+            android:useLevel="true"
+            android:startColor="#1000ceff"
+            android:endColor="#ffadd252" />
+
+    </shape>
+
+ </rotate>
diff --git a/core/res/res/layout/date_picker.xml b/core/res/res/layout/date_picker.xml
index a398bd0..0760cc0 100644
--- a/core/res/res/layout/date_picker.xml
+++ b/core/res/res/layout/date_picker.xml
@@ -24,6 +24,7 @@
 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
     android:id="@+id/parent"
     android:orientation="horizontal"
+    android:layout_gravity="center_horizontal"
     android:layout_width="wrap_content"
     android:layout_height="wrap_content">
 
diff --git a/core/res/res/layout/date_picker_dialog.xml b/core/res/res/layout/date_picker_dialog.xml
index 879f3398..949c8a3 100644
--- a/core/res/res/layout/date_picker_dialog.xml
+++ b/core/res/res/layout/date_picker_dialog.xml
@@ -17,11 +17,9 @@
 */
 -->
 
-<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
-        android:layout_width="wrap_content"
-        android:layout_height="wrap_content"
-        android:padding="5dip">
-    <DatePicker android:id="@+id/datePicker"
-            android:layout_width="fill_parent"
-            android:layout_height="fill_parent"/>
-</FrameLayout>
+<DatePicker xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/datePicker"
+    android:padding="5dip"
+    android:layout_gravity="center_horizontal"
+    android:layout_width="wrap_content"
+    android:layout_height="wrap_content"/>
diff --git a/core/res/res/layout/number_picker.xml b/core/res/res/layout/number_picker.xml
index 422733a..bbdb31c 100644
--- a/core/res/res/layout/number_picker.xml
+++ b/core/res/res/layout/number_picker.xml
@@ -22,23 +22,21 @@
     <com.android.internal.widget.NumberPickerButton android:id="@+id/increment"
         android:layout_width="fill_parent"
         android:layout_height="wrap_content"
-        android:background="@drawable/timepicker_up_btn"
-        />
-        
-		<EditText android:id="@+id/timepicker_input"
-		    android:layout_width="fill_parent"
-		    android:layout_height="wrap_content"
-		    android:gravity="center"
-		    android:singleLine="true"
-		    style="?android:attr/textAppearanceLargeInverse"
-		    android:textSize="30sp"
-		    android:background="@drawable/timepicker_input"
-		    />
-        
+        android:background="@drawable/timepicker_up_btn" />
+
+    <EditText android:id="@+id/timepicker_input"
+        android:layout_width="fill_parent"
+        android:layout_height="wrap_content"
+        android:gravity="center"
+        android:singleLine="true"
+        style="?android:attr/textAppearanceLargeInverse"
+        android:textColor="@android:color/primary_text_light"
+        android:textSize="30sp"
+        android:background="@drawable/timepicker_input" />
+
     <com.android.internal.widget.NumberPickerButton android:id="@+id/decrement"
         android:layout_width="fill_parent"
         android:layout_height="wrap_content"
-        android:background="@drawable/timepicker_down_btn"
-        />
-        
+        android:background="@drawable/timepicker_down_btn" />
+
 </merge>
diff --git a/core/res/res/layout/number_picker_edit.xml b/core/res/res/layout/number_picker_edit.xml
index 46f4845..f3af6e9 100644
--- a/core/res/res/layout/number_picker_edit.xml
+++ b/core/res/res/layout/number_picker_edit.xml
@@ -23,6 +23,7 @@
     android:gravity="center_horizontal"
     android:singleLine="true"
     style="?android:attr/textAppearanceLargeInverse"
+    android:textColor="@android:color/primary_text_light"
     android:textSize="30sp"
     android:background="@drawable/timepicker_input"
     />
diff --git a/core/res/res/layout/time_picker.xml b/core/res/res/layout/time_picker.xml
index bdfe490..c601e0e 100644
--- a/core/res/res/layout/time_picker.xml
+++ b/core/res/res/layout/time_picker.xml
@@ -21,6 +21,7 @@
 
 <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">
 
@@ -55,5 +56,6 @@
         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_dialog.xml b/core/res/res/layout/time_picker_dialog.xml
index 6dc1bf6..d5a6b5e 100644
--- a/core/res/res/layout/time_picker_dialog.xml
+++ b/core/res/res/layout/time_picker_dialog.xml
@@ -17,11 +17,9 @@
 */
 -->
 
-<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
-        android:layout_width="wrap_content"
-        android:layout_height="wrap_content"
-        android:padding="5dip">
-    <TimePicker android:id="@+id/timePicker"
-            android:layout_width="fill_parent"
-            android:layout_height="fill_parent"/>
-</FrameLayout>
+<TimePicker xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/timePicker"
+    android:layout_gravity="center_horizontal"
+    android:layout_width="wrap_content"
+    android:layout_height="wrap_content"
+    android:padding="5dip" />
diff --git a/core/res/res/layout/time_picker_text.xml b/core/res/res/layout/time_picker_text.xml
deleted file mode 100644
index bad980b..0000000
--- a/core/res/res/layout/time_picker_text.xml
+++ /dev/null
@@ -1,27 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-**
-** Copyright 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.
-*/
--->
-
-<!-- TextView of time picker-->
-
-<TextView xmlns:android="http://schemas.android.com/apk/res/android"
-    android:layout_width="fill_parent"
-    android:layout_height="fill_parent"
-    android:textAppearance="?attr/textAppearanceLargeInverse"
-    android:gravity="center"
-    />
diff --git a/core/res/res/values-cs-rCZ/strings.xml b/core/res/res/values-cs-rCZ/strings.xml
deleted file mode 100644
index e1eb3f4..0000000
--- a/core/res/res/values-cs-rCZ/strings.xml
+++ /dev/null
@@ -1,1112 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <!-- no translation found for byteShort (2850097084724465606) -->
-    <skip />
-    <!-- no translation found for kilobyteShort (5865542430193761682) -->
-    <skip />
-    <!-- no translation found for megabyteShort (112984851085937882) -->
-    <skip />
-    <!-- no translation found for gigabyteShort (8586075069559273847) -->
-    <skip />
-    <!-- no translation found for terabyteShort (5828502357595687794) -->
-    <skip />
-    <!-- no translation found for petabyteShort (7523248732657962413) -->
-    <skip />
-    <string name="untitled">"&lt;bez názvu&gt;"</string>
-    <string name="ellipsis">"…"</string>
-    <string name="emptyPhoneNumber">"(žádné telefonní číslo)"</string>
-    <string name="unknownName">"(neznámý)"</string>
-    <string name="defaultVoiceMailAlphaTag">"Hlasová schránka"</string>
-    <string name="defaultMsisdnAlphaTag">"Msisdn1"</string>
-    <string name="mmiError">"Chyba sítě nebo neplatný kód MMI."</string>
-    <string name="serviceEnabled">"Služba povolena"</string>
-    <string name="serviceEnabledFor">"Služba povolena pro:"</string>
-    <string name="serviceDisabled">"Služba zakázána"</string>
-    <string name="serviceRegistered">"Registrace úspěšná"</string>
-    <string name="serviceErased">"Odstranění úspěšné"</string>
-    <string name="passwordIncorrect">"Nesprávné heslo."</string>
-    <string name="mmiComplete">"MMI dokončeno"</string>
-    <!-- no translation found for badPin (5103184589972647739) -->
-    <skip />
-    <!-- no translation found for badPuk (2200634943393540609) -->
-    <skip />
-    <!-- no translation found for mismatchPin (5055729703806180857) -->
-    <skip />
-    <!-- no translation found for invalidPin (6201854814319326475) -->
-    <skip />
-    <!-- no translation found for needPuk (4788728144863892764) -->
-    <skip />
-    <!-- no translation found for needPuk2 (7056908944942451033) -->
-    <skip />
-    <!-- no translation found for ClipMmi (5649729434121615509) -->
-    <skip />
-    <!-- no translation found for ClirMmi (5220979296096544477) -->
-    <skip />
-    <!-- no translation found for CfMmi (4998483717856803914) -->
-    <skip />
-    <!-- no translation found for CwMmi (5678103638951836350) -->
-    <skip />
-    <!-- no translation found for BaMmi (6030555200442855833) -->
-    <skip />
-    <!-- no translation found for PwdMmi (2549941247959366670) -->
-    <skip />
-    <!-- no translation found for PinMmi (2463353963837922189) -->
-    <skip />
-    <string name="CLIRDefaultOnNextCallOn">"Výchozí nastavení omezení ID - omezení. Další hovor: omezení"</string>
-    <string name="CLIRDefaultOnNextCallOff">"Výchozí nastavení omezení ID - omezení. Další hovor: bez omezení"</string>
-    <string name="CLIRDefaultOffNextCallOn">"Výchozí nastavení omezení ID - bez omezení. Další hovor: omezení"</string>
-    <string name="CLIRDefaultOffNextCallOff">"Výchozí nastavení omezení ID - bez omezení. Další hovor: bez omezení"</string>
-    <string name="serviceNotProvisioned">"Služba není poskytována."</string>
-    <string name="CLIRPermanent">"Omezení ID v trvalém režimu."</string>
-    <string name="serviceClassVoice">"Hlasový záznam"</string>
-    <string name="serviceClassData">"Data"</string>
-    <string name="serviceClassFAX">"FAX"</string>
-    <string name="serviceClassSMS">"SMS"</string>
-    <string name="serviceClassDataAsync">"Asynchronní"</string>
-    <string name="serviceClassDataSync">"Synchronizace"</string>
-    <string name="serviceClassPacket">"Pakety"</string>
-    <string name="serviceClassPAD">"PAD"</string>
-    <string name="cfTemplateNotForwarded">"{0}: Nepřesměrováno"</string>
-    <string name="cfTemplateForwarded">"{0}: {1}"</string>
-    <string name="cfTemplateForwardedTime">"{0}: {1} po {2} sekundách"</string>
-    <string name="cfTemplateRegistered">"{0}: Nepřesměrováno ({1})"</string>
-    <string name="cfTemplateRegisteredTime">"{0}: Nepřesměrováno ({1} po {2} sekundách)"</string>
-    <string name="httpErrorOk">"OK"</string>
-    <string name="httpError">"Neznámá chyba"</string>
-    <string name="httpErrorLookup">"Neznámý hostitel"</string>
-    <string name="httpErrorUnsupportedAuthScheme">"Nepodporované schéma ověření. Ověření se nezdařilo."</string>
-    <string name="httpErrorAuth">"Ověřování se nezdařilo"</string>
-    <string name="httpErrorProxyAuth">"Ověření serverem proxy se nezdařilo"</string>
-    <string name="httpErrorConnect">"Připojení k serveru se nezdařilo"</string>
-    <string name="httpErrorIO">"Čtení nebo zápis na server se nezdařil"</string>
-    <string name="httpErrorTimeout">"Časový limit připojení k serveru vypršel"</string>
-    <string name="httpErrorRedirectLoop">"Příliš mnoho přesměrování serverů"</string>
-    <string name="httpErrorUnsupportedScheme">"Nepodporovaný protokol"</string>
-    <string name="httpErrorFailedSslHandshake">"Navázání spojení typu SSL handshake se nezdařilo"</string>
-    <string name="httpErrorBadUrl">"Nepodařilo se analyzovat URL"</string>
-    <string name="httpErrorFile">"File error"</string>
-    <string name="httpErrorFileNotFound">"File not found"</string>
-    <!-- no translation found for httpErrorTooManyRequests (3764334538393544875) -->
-    <skip />
-    <string name="contentServiceSync">"Synchronizace"</string>
-    <string name="contentServiceSyncNotificationTitle">"Synchronizace"</string>
-    <!-- no translation found for contentServiceTooManyDeletesNotificationDesc (8477597194404210723) -->
-    <skip />
-    <!-- no translation found for low_memory (4191592786596642367) -->
-    <skip />
-    <!-- no translation found for me (4616693653158602117) -->
-    <skip />
-    <string name="power_dialog">"Možnosti napájení"</string>
-    <string name="silent_mode">"Tichý režim"</string>
-    <string name="turn_on_radio">"Zapnout rádio"</string>
-    <string name="turn_off_radio">"Vypnout rádio"</string>
-    <!-- no translation found for screen_lock (1560333453597081877) -->
-    <skip />
-    <string name="power_off">"Vypnuto"</string>
-    <!-- no translation found for shutdown_progress (3735034517335251808) -->
-    <skip />
-    <!-- no translation found for shutdown_confirm (699224922526414097) -->
-    <skip />
-    <!-- no translation found for no_recent_tasks (1367712919998349373) -->
-    <skip />
-    <!-- no translation found for global_actions (8299888906525675157) -->
-    <skip />
-    <!-- no translation found for global_action_lock (5943677976245541105) -->
-    <skip />
-    <!-- no translation found for global_action_power_off (3143027278596694254) -->
-    <skip />
-    <!-- no translation found for global_action_toggle_silent_mode (5849335789367070450) -->
-    <skip />
-    <!-- no translation found for global_action_silent_mode_on_status (6053429980569202260) -->
-    <skip />
-    <!-- no translation found for global_action_silent_mode_off_status (1994514127029249081) -->
-    <skip />
-    <!-- no translation found for safeMode (3375134507868534320) -->
-    <skip />
-    <!-- no translation found for permgrouplab_costMoney (904087853776533085) -->
-    <skip />
-    <!-- no translation found for permgroupdesc_costMoney (4662370555643969515) -->
-    <skip />
-    <!-- no translation found for permgrouplab_messages (2984053976424233925) -->
-    <skip />
-    <!-- no translation found for permgroupdesc_messages (2129093134354989379) -->
-    <skip />
-    <!-- no translation found for permgrouplab_personalInfo (4548406335021507392) -->
-    <skip />
-    <!-- no translation found for permgroupdesc_personalInfo (8499310823817958034) -->
-    <skip />
-    <!-- no translation found for permgrouplab_location (8535677827151907069) -->
-    <skip />
-    <!-- no translation found for permgroupdesc_location (2341662219604651887) -->
-    <skip />
-    <!-- no translation found for permgrouplab_network (3597781730625751831) -->
-    <skip />
-    <!-- no translation found for permgroupdesc_network (8332572695347918340) -->
-    <skip />
-    <!-- no translation found for permgrouplab_accounts (8631201594657951893) -->
-    <skip />
-    <!-- no translation found for permgroupdesc_accounts (443982868906396781) -->
-    <skip />
-    <!-- no translation found for permgrouplab_hardwareControls (5074512938567152139) -->
-    <skip />
-    <!-- no translation found for permgroupdesc_hardwareControls (8772503144945278440) -->
-    <skip />
-    <!-- no translation found for permgrouplab_phoneCalls (7096448531266882376) -->
-    <skip />
-    <!-- no translation found for permgroupdesc_phoneCalls (6703873478653366233) -->
-    <skip />
-    <!-- no translation found for permgrouplab_systemTools (1840847965111633430) -->
-    <skip />
-    <!-- no translation found for permgroupdesc_systemTools (2810337951496685271) -->
-    <skip />
-    <!-- no translation found for permgrouplab_developmentTools (692844635256963358) -->
-    <skip />
-    <!-- no translation found for permgroupdesc_developmentTools (5253915519857796400) -->
-    <skip />
-    <!-- no translation found for permlab_statusBar (8789506912215455922) -->
-    <skip />
-    <!-- no translation found for permdesc_statusBar (5034247171231682403) -->
-    <skip />
-    <!-- no translation found for permlab_expandStatusBar (6382500803293284173) -->
-    <skip />
-    <!-- no translation found for permdesc_expandStatusBar (90953162060681436) -->
-    <skip />
-    <!-- no translation found for permlab_processOutgoingCalls (786316295241100144) -->
-    <skip />
-    <!-- no translation found for permdesc_processOutgoingCalls (1655242138991854396) -->
-    <skip />
-    <string name="permlab_receiveSms">"Příjem zpráv SMS"</string>
-    <string name="permdesc_receiveSms">"Umožňuje aplikacím přijímat a zpracovávat zprávy SMS. Škodlivé aplikace mohou sledovat vaše zprávy nebo je odstraňovat, aniž by se zobrazily."</string>
-    <string name="permlab_receiveMms">"Příjem zpráv MMS"</string>
-    <string name="permdesc_receiveMms">"Umožňuje aplikacím přijímat a zpracovávat zprávy MMS. Škodlivé aplikace mohou sledovat vaše zprávy nebo je odstraňovat, aniž by se zobrazily."</string>
-    <!-- no translation found for permlab_sendSms (4713837923748234081) -->
-    <skip />
-    <!-- no translation found for permdesc_sendSms (7126594387176704010) -->
-    <skip />
-    <!-- no translation found for permlab_readSms (4256004535185449429) -->
-    <skip />
-    <!-- no translation found for permdesc_readSms (4586480500886941902) -->
-    <skip />
-    <!-- no translation found for permlab_writeSms (8453452414726246828) -->
-    <skip />
-    <!-- no translation found for permdesc_writeSms (1036408118901361812) -->
-    <skip />
-    <string name="permlab_receiveWapPush">"Příjem zpráv WAP"</string>
-    <string name="permdesc_receiveWapPush">"Umožňuje aplikacím přijímat a zpracovávat zprávy WAP. Škodlivé aplikace mohou sledovat vaše zprávy nebo je odstraňovat, aniž by se zobrazily."</string>
-    <string name="permlab_getTasks">"Získat informace o úkolech"</string>
-    <string name="permdesc_getTasks">"Umožňuje aplikacím načítat informace o aktuálně a naposledy spuštěných úkolech. Umožňuje škodlivým aplikacím zjišťovat soukromé informace o jiných aplikacích."</string>
-    <!-- no translation found for permlab_reorderTasks (4758862288285224517) -->
-    <skip />
-    <!-- no translation found for permdesc_reorderTasks (7507060843941912021) -->
-    <skip />
-    <!-- no translation found for permlab_setDebugApp (2973363275929449444) -->
-    <skip />
-    <!-- no translation found for permdesc_setDebugApp (5720449860498265972) -->
-    <skip />
-    <!-- no translation found for permlab_changeConfiguration (8581093564179818627) -->
-    <skip />
-    <!-- no translation found for permdesc_changeConfiguration (4055366453803187171) -->
-    <skip />
-    <!-- no translation found for permlab_restartPackages (5836367540766044606) -->
-    <skip />
-    <!-- no translation found for permdesc_restartPackages (1764965996765573321) -->
-    <skip />
-    <!-- no translation found for permlab_setProcessForeground (4860990420780868638) -->
-    <skip />
-    <!-- no translation found for permdesc_setProcessForeground (3795477299954784360) -->
-    <skip />
-    <!-- no translation found for permlab_forceBack (4737517869935566733) -->
-    <skip />
-    <!-- no translation found for permdesc_forceBack (5579316297001154697) -->
-    <skip />
-    <string name="permlab_dump">"Výpis stavu systému"</string>
-    <string name="permdesc_dump">"Umožňuje aplikacím načítat vnitřní stav systému. Škodlivé aplikace mohou načítat široký rozsah soukromých a důvěrných informací, jež by obvykle neměly nikdy vyžadovat."</string>
-    <string name="permlab_addSystemService">"Přidat systémovou službu"</string>
-    <string name="permdesc_addSystemService">"Umožňuje aplikacím vydávat vlastní systémové služby nižší úrovně. Škodlivé aplikace mohou napadnout systém a vykrást nebo poškodit jeho data."</string>
-    <string name="permlab_runSetActivityWatcher">"Nastavení sledování činností"</string>
-    <string name="permdesc_runSetActivityWatcher">"Umožňuje aplikacím sledovat a řídit spouštění činností systému. Škodlivé aplikace mohou zcela zničit systém. Toto oprávnění je nutné pouze pro vývoj, nikdy pro normální používání zařízení."</string>
-    <string name="permlab_broadcastPackageRemoved">"Sada vysílání odebrána"</string>
-    <string name="permdesc_broadcastPackageRemoved">"Umožňuje aplikacím vysílat oznámení o odebrání sady aplikací. Škodlivé aplikace toho mohou využít k likvidaci jiné spuštěné aplikace."</string>
-    <!-- no translation found for permlab_broadcastSmsReceived (1994692154847312518) -->
-    <skip />
-    <!-- no translation found for permdesc_broadcastSmsReceived (6072362543164841432) -->
-    <skip />
-    <!-- no translation found for permlab_broadcastWapPush (3070023012636951639) -->
-    <skip />
-    <!-- no translation found for permdesc_broadcastWapPush (726912255218924336) -->
-    <skip />
-    <!-- no translation found for permlab_setProcessLimit (5190694306017260601) -->
-    <skip />
-    <!-- no translation found for permdesc_setProcessLimit (593938303319848578) -->
-    <skip />
-    <!-- no translation found for permlab_setAlwaysFinish (8745533365504920540) -->
-    <skip />
-    <!-- no translation found for permdesc_setAlwaysFinish (2437195869854312148) -->
-    <skip />
-    <string name="permlab_fotaUpdate">"Instalace aktualizace systému"</string>
-    <string name="permdesc_fotaUpdate">"Umožňuje aplikacím přijímat oznámení o aktualizacích systému čekajících na dokončení a spouštět jejich instalaci. Škodlivé aplikace toho mohou využít k poškození systému neautorizovanými aktualizacemi nebo obecně k zásahům do aktualizačního procesu."</string>
-    <!-- no translation found for permlab_batteryStats (1598947993704535568) -->
-    <skip />
-    <!-- no translation found for permdesc_batteryStats (6247598531831307989) -->
-    <skip />
-    <string name="permlab_internalSystemWindow">"Okno vnitřního systému"</string>
-    <string name="permdesc_internalSystemWindow">"Umožňuje vytváření oken určených k použití uživatelským rozhraním vnitřního systému . Není určeno k použití normálními aplikacemi."</string>
-    <string name="permlab_systemAlertWindow">"Okno systémových výstrah"</string>
-    <string name="permdesc_systemAlertWindow">"Umožňuje aplikacím zobrazovat okna systémových výstrah. Škodlivé aplikace mohou ovládnout celou obrazovku zařízení."</string>
-    <!-- no translation found for permlab_setAnimationScale (2419250686027992384) -->
-    <skip />
-    <!-- no translation found for permdesc_setAnimationScale (8518027785481727264) -->
-    <skip />
-    <!-- no translation found for permlab_manageAppTokens (1033424552444304594) -->
-    <skip />
-    <!-- no translation found for permdesc_manageAppTokens (7285840918912623550) -->
-    <skip />
-    <!-- no translation found for permlab_injectEvents (1383601196263145482) -->
-    <skip />
-    <!-- no translation found for permdesc_injectEvents (840097509341464737) -->
-    <skip />
-    <!-- no translation found for permlab_readInputState (2723668746963882102) -->
-    <skip />
-    <!-- no translation found for permdesc_readInputState (4651137638757852001) -->
-    <skip />
-    <!-- no translation found for permlab_setOrientation (1112555600323148680) -->
-    <skip />
-    <!-- no translation found for permdesc_setOrientation (1960269530378827858) -->
-    <skip />
-    <string name="permlab_signalPersistentProcesses">"Signálové trvalé procesy"</string>
-    <string name="permdesc_signalPersistentProcesses">"Umožňuje aplikacím vyžadovat, aby se přiváděný signál odesílal do všech trvalých procesů."</string>
-    <!-- no translation found for permlab_persistentActivity (8163108526929094627) -->
-    <skip />
-    <!-- no translation found for permdesc_persistentActivity (5258975883823299624) -->
-    <skip />
-    <string name="permlab_deletePackages">"Odstranit sady"</string>
-    <string name="permdesc_deletePackages">"Umožňuje aplikacím odstranit sady systému Android. Škodlivé aplikace toho mohou využít k odstranění důležitých aplikací."</string>
-    <!-- no translation found for permlab_clearAppUserData (3858185484601410171) -->
-    <skip />
-    <!-- no translation found for permdesc_clearAppUserData (7233537744753081136) -->
-    <skip />
-    <!-- no translation found for permlab_deleteCacheFiles (7362746182961997888) -->
-    <skip />
-    <!-- no translation found for permdesc_deleteCacheFiles (8293849509208181266) -->
-    <skip />
-    <!-- no translation found for permlab_getPackageSize (6743556676630447973) -->
-    <skip />
-    <!-- no translation found for permdesc_getPackageSize (2893996655828539776) -->
-    <skip />
-    <string name="permlab_installPackages">"Instalovat sady"</string>
-    <string name="permdesc_installPackages">"Umožňuje aplikacím instalovat nové nebo aktualizované sady systému Android. Škodlivé aplikace toho mohou využít k přidání nových aplikací s libovolně silnými oprávněními."</string>
-    <!-- no translation found for permlab_clearAppCache (7860214328511700776) -->
-    <skip />
-    <!-- no translation found for permdesc_clearAppCache (5203820862573167878) -->
-    <skip />
-    <!-- no translation found for permlab_readLogs (6653488552442991707) -->
-    <skip />
-    <!-- no translation found for permdesc_readLogs (356352685800884319) -->
-    <skip />
-    <!-- no translation found for permlab_diagnostic (2955142476313469329) -->
-    <skip />
-    <!-- no translation found for permdesc_diagnostic (1282409892215520166) -->
-    <skip />
-    <string name="permlab_changeComponentState">"Povolit nebo zakázat součásti aplikací"</string>
-    <string name="permdesc_changeComponentState">"Umožňuje změnu aplikace bez ohledu na to, zda je součást další aplikace povolená nebo zakázaná. Škodlivá aplikace toho může využít k zakázání důležitých funkcí zařízení. Je třeba nakládat s oprávněními opatrně, protože se mohou součásti aplikace dostat do stavu nepoužitelnosti, nekonzistence nebo nestability."</string>
-    <string name="permlab_setPreferredApplications">"Nastavení upřednostňovaných aplikací"</string>
-    <string name="permdesc_setPreferredApplications">"Umožňuje aplikacím upravovat oblíbené aplikace. Škodlivé aplikace tak mohou bez upozornění měnit spouštěné aplikace a klamně využívat stávající aplikace ke shromažďování vašich soukromých dat."</string>
-    <string name="permlab_writeSettings">"Nastavení systému pro zápis"</string>
-    <string name="permdesc_writeSettings">"Umožňuje aplikacím upravovat data nastavení systému. Škodlivé aplikace mohou narušit systémovou konfiguraci."</string>
-    <!-- no translation found for permlab_writeSecureSettings (4851801872124242319) -->
-    <skip />
-    <!-- no translation found for permdesc_writeSecureSettings (2080620249472761366) -->
-    <skip />
-    <!-- no translation found for permlab_writeGservices (296370685945777755) -->
-    <skip />
-    <!-- no translation found for permdesc_writeGservices (2496928471286495053) -->
-    <skip />
-    <string name="permlab_receiveBootCompleted">"Spustit při spouštění"</string>
-    <string name="permdesc_receiveBootCompleted">"Umožňuje aplikacím spouštět se po dokončení spuštění systému. Tím se může prodlužovat doba spouštění zařízení a aplikace může svým stálým spouštěním zpomalovat celé zařízení."</string>
-    <string name="permlab_broadcastSticky">"Vysílat lepivý obsah (sticky)"</string>
-    <string name="permdesc_broadcastSticky">"Umožňuje aplikacím odesílat tzv. lepivé (sticky) vysílání, které zůstává i po ukončení vysílání. Škodlivé aplikace mohou zpomalit zařízení nebo narušit jeho stabilitu vynucením využívání příliš velké části paměti."</string>
-    <string name="permlab_readContacts">"Čtení dat o kontaktech"</string>
-    <string name="permdesc_readContacts">"Umožňuje aplikacím číst všechna data o kontaktech (adresy) uložená v zařízení. Škodlivé aplikace toho mohou využívat k odesílání vašich dat jiným osobám."</string>
-    <string name="permlab_writeContacts">"Zápis dat o kontaktech"</string>
-    <string name="permdesc_writeContacts">"Umožňuje aplikacím upravovat data o kontaktech (adresy) uložená v zařízení. Škodlivé aplikace toho mohou využívat k vymazání nebo úpravě dat o kontaktech."</string>
-    <!-- no translation found for permlab_writeOwnerData (8036840529708535113) -->
-    <skip />
-    <!-- no translation found for permdesc_writeOwnerData (5873447528845878348) -->
-    <skip />
-    <!-- no translation found for permlab_readOwnerData (1847040178513733757) -->
-    <skip />
-    <!-- no translation found for permdesc_readOwnerData (7563299529149214764) -->
-    <skip />
-    <!-- no translation found for permlab_readCalendar (2111238731453410895) -->
-    <skip />
-    <!-- no translation found for permdesc_readCalendar (4408253940601239114) -->
-    <skip />
-    <!-- no translation found for permlab_writeCalendar (7518052789370653396) -->
-    <skip />
-    <!-- no translation found for permdesc_writeCalendar (8057304232140147596) -->
-    <skip />
-    <!-- no translation found for permlab_accessMockLocation (321094551062270213) -->
-    <skip />
-    <!-- no translation found for permdesc_accessMockLocation (3651565866471419739) -->
-    <skip />
-    <!-- no translation found for permlab_accessLocationExtraCommands (8291822077788811687) -->
-    <skip />
-    <!-- no translation found for permdesc_accessLocationExtraCommands (5135782633548630731) -->
-    <skip />
-    <string name="permlab_accessFineLocation">"Používat službu GPS"</string>
-    <string name="permdesc_accessFineLocation">"Technologii GPS v zařízení lze používat, pokud je k dispozici. Toto oprávnění vyžaduje oprávnění ACCESS_LOCATION. Škodlivé aplikace toho mohou využívat k určení vaší polohy a mohou spotřebovávat zbytečně energii baterie."</string>
-    <string name="permlab_accessCoarseLocation">"Používat službu Cell ID"</string>
-    <string name="permdesc_accessCoarseLocation">"Identifikátory pro technologii využívající polohu vysílačů mobilních sítí (je-li k dispozici) se používají k určení přibližné polohy zařízení. Toto oprávnění vyžaduje oprávnění ACCESS_LOCATION. Škodlivé aplikace toho mohou využívat k určení vaší přibližné polohy."</string>
-    <string name="permlab_accessSurfaceFlinger">"Používat službu SurfaceFlinger"</string>
-    <string name="permdesc_accessSurfaceFlinger">"Umožňuje aplikacím používat funkce nižší úrovně SurfaceFlinger."</string>
-    <string name="permlab_readFrameBuffer">"Čtení vyrovnávací paměti rámce"</string>
-    <string name="permdesc_readFrameBuffer">"Umožňuje aplikacím používat čtení obsahu vyrovnávací paměti rámce."</string>
-    <!-- no translation found for permlab_modifyAudioSettings (1587341813207960943) -->
-    <skip />
-    <!-- no translation found for permdesc_modifyAudioSettings (1447143004892708149) -->
-    <skip />
-    <!-- no translation found for permlab_recordAudio (4447848534036991667) -->
-    <skip />
-    <!-- no translation found for permdesc_recordAudio (6936874682400894820) -->
-    <skip />
-    <!-- no translation found for permlab_camera (1944473855727060380) -->
-    <skip />
-    <!-- no translation found for permdesc_camera (5978058582323766022) -->
-    <skip />
-    <!-- no translation found for permlab_brick (4749832243303289777) -->
-    <skip />
-    <!-- no translation found for permdesc_brick (7428524578693695766) -->
-    <skip />
-    <!-- no translation found for permlab_reboot (8844650672567077423) -->
-    <skip />
-    <!-- no translation found for permdesc_reboot (4704919552870918328) -->
-    <skip />
-    <!-- no translation found for permlab_mount_unmount_filesystems (1009574821038043781) -->
-    <skip />
-    <!-- no translation found for permdesc_mount_unmount_filesystems (100792065894811109) -->
-    <skip />
-    <!-- no translation found for permlab_vibrate (61984555644467146) -->
-    <skip />
-    <!-- no translation found for permdesc_vibrate (7831723100758509238) -->
-    <skip />
-    <!-- no translation found for permlab_flashlight (9097145977808182652) -->
-    <skip />
-    <!-- no translation found for permdesc_flashlight (7851502731988978358) -->
-    <skip />
-    <!-- no translation found for permlab_hardware_test (4103324677866524254) -->
-    <skip />
-    <!-- no translation found for permdesc_hardware_test (7315242723603994769) -->
-    <skip />
-    <string name="permlab_callPhone">"Volat telefonní čísla"</string>
-    <string name="permdesc_callPhone">"Umožňuje aplikacím volat telefonní čísla bez vašeho zásahu. Škodlivé aplikace mohou přinést na váš telefonní účet neočekávané hovory."</string>
-    <!-- no translation found for permlab_callPrivileged (2166923597287697159) -->
-    <skip />
-    <!-- no translation found for permdesc_callPrivileged (5109789447971735501) -->
-    <skip />
-    <!-- no translation found for permlab_locationUpdates (4216418293360456836) -->
-    <skip />
-    <!-- no translation found for permdesc_locationUpdates (7635814693478743648) -->
-    <skip />
-    <!-- no translation found for permlab_checkinProperties (2260796787386280708) -->
-    <skip />
-    <!-- no translation found for permdesc_checkinProperties (3508022022841741945) -->
-    <skip />
-    <!-- no translation found for permlab_modifyPhoneState (7791696535097912313) -->
-    <skip />
-    <!-- no translation found for permdesc_modifyPhoneState (6352405226410454770) -->
-    <skip />
-    <!-- no translation found for permlab_readPhoneState (7320082586621086653) -->
-    <skip />
-    <!-- no translation found for permdesc_readPhoneState (8004450067066407969) -->
-    <skip />
-    <!-- no translation found for permlab_wakeLock (1591164750935072136) -->
-    <skip />
-    <!-- no translation found for permdesc_wakeLock (160471538196734936) -->
-    <skip />
-    <!-- no translation found for permlab_devicePower (9214865067086065548) -->
-    <skip />
-    <!-- no translation found for permdesc_devicePower (5608364066480036402) -->
-    <skip />
-    <!-- no translation found for permlab_factoryTest (7786199300637896247) -->
-    <skip />
-    <!-- no translation found for permdesc_factoryTest (3466066005210542042) -->
-    <skip />
-    <!-- no translation found for permlab_setWallpaper (2256730637138641725) -->
-    <skip />
-    <!-- no translation found for permdesc_setWallpaper (3034653140208685093) -->
-    <skip />
-    <!-- no translation found for permlab_setWallpaperHints (4192438316932517807) -->
-    <skip />
-    <!-- no translation found for permdesc_setWallpaperHints (738757439960921674) -->
-    <skip />
-    <!-- no translation found for permlab_masterClear (6155403967270586906) -->
-    <skip />
-    <!-- no translation found for permdesc_masterClear (4213553172342689754) -->
-    <skip />
-    <!-- no translation found for permlab_setTimeZone (477196167239548690) -->
-    <skip />
-    <!-- no translation found for permdesc_setTimeZone (8564892020460841198) -->
-    <skip />
-    <!-- no translation found for permlab_getAccounts (2764070033402295170) -->
-    <skip />
-    <!-- no translation found for permdesc_getAccounts (1203491378748649898) -->
-    <skip />
-    <!-- no translation found for permlab_accessNetworkState (2032916924886010827) -->
-    <skip />
-    <!-- no translation found for permdesc_accessNetworkState (7081329402551195933) -->
-    <skip />
-    <!-- no translation found for permlab_createNetworkSockets (4706698319966917864) -->
-    <skip />
-    <!-- no translation found for permdesc_createNetworkSockets (2580337178778551792) -->
-    <skip />
-    <!-- no translation found for permlab_writeApnSettings (3190585220761979369) -->
-    <skip />
-    <!-- no translation found for permdesc_writeApnSettings (4093875220468761052) -->
-    <skip />
-    <!-- no translation found for permlab_changeNetworkState (2710779001260856872) -->
-    <skip />
-    <!-- no translation found for permdesc_changeNetworkState (8076109230787022270) -->
-    <skip />
-    <!-- no translation found for permlab_accessWifiState (3613679494230374297) -->
-    <skip />
-    <!-- no translation found for permdesc_accessWifiState (8226508433563326925) -->
-    <skip />
-    <!-- no translation found for permlab_changeWifiState (6043889338995432957) -->
-    <skip />
-    <!-- no translation found for permdesc_changeWifiState (7829372845909567994) -->
-    <skip />
-    <!-- no translation found for permlab_bluetoothAdmin (5513286736585647334) -->
-    <skip />
-    <!-- no translation found for permdesc_bluetoothAdmin (1838208497914347365) -->
-    <skip />
-    <!-- no translation found for permlab_bluetooth (6378797624765639115) -->
-    <skip />
-    <!-- no translation found for permdesc_bluetooth (8592386018922265273) -->
-    <skip />
-    <!-- no translation found for permlab_disableKeyguard (4574886811903233903) -->
-    <skip />
-    <!-- no translation found for permdesc_disableKeyguard (815972646344251271) -->
-    <skip />
-    <!-- no translation found for permlab_readSyncSettings (8818819977141505127) -->
-    <skip />
-    <!-- no translation found for permdesc_readSyncSettings (8454705401908767847) -->
-    <skip />
-    <!-- no translation found for permlab_writeSyncSettings (4514911143753152941) -->
-    <skip />
-    <!-- no translation found for permdesc_writeSyncSettings (7630627689635091836) -->
-    <skip />
-    <!-- no translation found for permlab_readSyncStats (5748337739678952863) -->
-    <skip />
-    <!-- no translation found for permdesc_readSyncStats (582551457321957183) -->
-    <skip />
-    <!-- no translation found for permlab_subscribedFeedsRead (2043206814904506589) -->
-    <skip />
-    <!-- no translation found for permdesc_subscribedFeedsRead (6977343942680042449) -->
-    <skip />
-    <!-- no translation found for permlab_subscribedFeedsWrite (2556727307229571556) -->
-    <skip />
-    <!-- no translation found for permdesc_subscribedFeedsWrite (4134783294590266220) -->
-    <skip />
-    <!-- no translation found for phoneTypes:7 (1326005699931077792) -->
-  <string-array name="emailAddressTypes">
-    <item>"Výchozí"</item>
-    <item>"Zaměstnání"</item>
-    <item>"Primární"</item>
-    <item>"Vlastní…"</item>
-  </string-array>
-  <string-array name="postalAddressTypes">
-    <item>"Poštovní"</item>
-    <item>"Výchozí"</item>
-    <item>"Zaměstnání"</item>
-    <item>"Vlastní…"</item>
-  </string-array>
-    <!-- no translation found for imAddressTypes:0 (7806620012096518833) -->
-    <!-- no translation found for imAddressTypes:1 (5748846799950672787) -->
-    <!-- no translation found for imAddressTypes:2 (6196536810275073680) -->
-    <!-- no translation found for imAddressTypes:3 (8519128375350623648) -->
-    <!-- no translation found for organizationTypes:0 (1299224825223821142) -->
-    <!-- no translation found for organizationTypes:1 (2455717447227299354) -->
-    <!-- no translation found for organizationTypes:2 (7027570839313438290) -->
-    <!-- no translation found for imProtocols:0 (3318725788774688043) -->
-    <!-- no translation found for imProtocols:1 (1787713387022932886) -->
-    <!-- no translation found for imProtocols:2 (6751174158442316516) -->
-    <!-- no translation found for imProtocols:3 (1151283347465052653) -->
-    <!-- no translation found for imProtocols:4 (2157980008878817934) -->
-    <!-- no translation found for imProtocols:5 (7836237460308230767) -->
-    <!-- no translation found for imProtocols:6 (1180789904462172516) -->
-    <!-- no translation found for imProtocols:7 (21955111672779862) -->
-    <!-- no translation found for keyguard_password_enter_pin_code (6779835451906812518) -->
-    <skip />
-    <!-- no translation found for keyguard_password_wrong_pin_code (230312338493035499) -->
-    <skip />
-    <string name="keyguard_label_text">"Telefon odemknete stisknutím tlačítka nabídky a poté 0."</string>
-    <!-- no translation found for emergency_call_dialog_number_for_display (6256361184251050511) -->
-    <skip />
-    <!-- no translation found for lockscreen_carrier_default (5222269885486229730) -->
-    <skip />
-    <!-- no translation found for lockscreen_screen_locked (1922273663462058967) -->
-    <skip />
-    <!-- no translation found for lockscreen_instructions_when_pattern_enabled (7535864145009679967) -->
-    <skip />
-    <!-- no translation found for lockscreen_instructions_when_pattern_disabled (6526504555912746785) -->
-    <skip />
-    <!-- no translation found for lockscreen_pattern_instructions (8984964506352089877) -->
-    <skip />
-    <!-- no translation found for lockscreen_emergency_call (422835617844547383) -->
-    <skip />
-    <!-- no translation found for lockscreen_pattern_correct (7104753084746383672) -->
-    <skip />
-    <!-- no translation found for lockscreen_pattern_wrong (7517004470797680361) -->
-    <skip />
-    <!-- no translation found for lockscreen_plugged_in (8806977650003537118) -->
-    <skip />
-    <!-- no translation found for lockscreen_low_battery (9002637795199621345) -->
-    <skip />
-    <!-- no translation found for lockscreen_missing_sim_message_short (5051192587315492957) -->
-    <skip />
-    <!-- no translation found for lockscreen_missing_sim_message (8912914495901434841) -->
-    <skip />
-    <!-- no translation found for lockscreen_missing_sim_instructions (8125847194365725429) -->
-    <skip />
-    <!-- no translation found for lockscreen_network_locked_message (323609607922245071) -->
-    <skip />
-    <!-- no translation found for lockscreen_sim_puk_locked_message (1005803622871256359) -->
-    <skip />
-    <!-- no translation found for lockscreen_sim_puk_locked_instructions (5033160098036646955) -->
-    <skip />
-    <!-- no translation found for lockscreen_sim_locked_message (7398401200962556379) -->
-    <skip />
-    <!-- no translation found for lockscreen_sim_unlock_progress_dialog_message (5939537246164692076) -->
-    <skip />
-    <!-- no translation found for lockscreen_too_many_failed_attempts_dialog_message (6709066241494622136) -->
-    <skip />
-    <!-- no translation found for lockscreen_failed_attempts_almost_glogin (1569017295989454551) -->
-    <skip />
-    <!-- no translation found for lockscreen_too_many_failed_attempts_countdown (8823588000022797566) -->
-    <skip />
-    <!-- no translation found for lockscreen_forgot_pattern_button_text (4219994639843985488) -->
-    <skip />
-    <!-- no translation found for lockscreen_glogin_too_many_attempts (7504679498838839295) -->
-    <skip />
-    <!-- no translation found for lockscreen_glogin_instructions (6542400673357252011) -->
-    <skip />
-    <!-- no translation found for lockscreen_glogin_username_hint (6378418320242015111) -->
-    <skip />
-    <!-- no translation found for lockscreen_glogin_password_hint (3224230234042131153) -->
-    <skip />
-    <!-- no translation found for lockscreen_glogin_submit_button (5562051040043760034) -->
-    <skip />
-    <!-- no translation found for lockscreen_glogin_invalid_input (4881057177478491580) -->
-    <skip />
-    <!-- no translation found for status_bar_time_format (2168573805413119180) -->
-    <skip />
-    <!-- no translation found for hour_minute_ampm (1850330605794978742) -->
-    <skip />
-    <!-- no translation found for hour_minute_cap_ampm (1122840227537374196) -->
-    <skip />
-    <!-- no translation found for hour_ampm (7665432130905376251) -->
-    <skip />
-    <!-- no translation found for hour_cap_ampm (3600295014648400268) -->
-    <skip />
-    <!-- no translation found for status_bar_clear_all_button (2202004591253243750) -->
-    <skip />
-    <!-- no translation found for status_bar_no_notifications_title (5123133188102094464) -->
-    <skip />
-    <!-- no translation found for status_bar_ongoing_events_title (799961521630569167) -->
-    <skip />
-    <!-- no translation found for status_bar_latest_events_title (5414094466807164279) -->
-    <skip />
-    <!-- no translation found for battery_status_text_percent_format (7391464609447031944) -->
-    <skip />
-    <!-- no translation found for battery_status_charging (5078780715755132756) -->
-    <skip />
-    <!-- no translation found for battery_low_title (3665400828395001695) -->
-    <skip />
-    <!-- no translation found for battery_low_subtitle (7537149915372180016) -->
-    <skip />
-    <!-- no translation found for battery_low_percent_format (8635359708781261154) -->
-    <skip />
-    <string name="factorytest_failed">"Výrobní test skončil chybou"</string>
-    <string name="factorytest_not_system">"Akce FACTORY_TEST je podporována pouze pro sady instalované v adresáři /system/app."</string>
-    <string name="factorytest_no_action">"Nebyla nalezena žádná sada, která zajišťuje akci FACTORY_TEST."</string>
-    <string name="factorytest_reboot">"Restartovat"</string>
-    <!-- no translation found for save_password_label (4129493019621348626) -->
-    <skip />
-    <!-- no translation found for save_password_message (7412617920202682045) -->
-    <skip />
-    <!-- no translation found for save_password_notnow (3887362423496820832) -->
-    <skip />
-    <!-- no translation found for save_password_remember (4319688896716308569) -->
-    <skip />
-    <!-- no translation found for save_password_never (1836981952883642377) -->
-    <skip />
-    <!-- no translation found for open_permission_deny (6408502671105717111) -->
-    <skip />
-    <!-- no translation found for text_copied (6106873823411904723) -->
-    <skip />
-    <string name="more_item_label">"Další"</string>
-    <string name="prepend_shortcut_label">"Menu+"</string>
-    <!-- no translation found for menu_space_shortcut_label (194586306440382711) -->
-    <skip />
-    <!-- no translation found for menu_enter_shortcut_label (7214761412193519345) -->
-    <skip />
-    <!-- no translation found for menu_delete_shortcut_label (2854936426194985313) -->
-    <skip />
-    <string name="search_go">"PŘEJÍT"</string>
-    <string name="today">"Dnes"</string>
-    <string name="yesterday">"Včera"</string>
-    <string name="tomorrow">"Zítra"</string>
-    <!-- no translation found for oneMonthDurationPast (3402179395240209557) -->
-    <skip />
-    <!-- no translation found for beforeOneMonthDurationPast (7578100953282866827) -->
-    <skip />
-    <!-- no translation found for num_seconds_ago:one (7416512229671810725) -->
-    <!-- no translation found for num_seconds_ago:other (8138756910300398447) -->
-    <!-- no translation found for num_minutes_ago:one (8620869479299420562) -->
-    <!-- no translation found for num_minutes_ago:other (5065488162050522741) -->
-    <!-- no translation found for num_hours_ago:one (853404611989669641) -->
-    <!-- no translation found for num_hours_ago:other (3558873784561756849) -->
-    <!-- no translation found for num_days_ago:one (4222479980812128212) -->
-    <!-- no translation found for num_days_ago:other (5445701370433601703) -->
-    <!-- no translation found for in_num_seconds:one (4253290037777327003) -->
-    <!-- no translation found for in_num_seconds:other (1280033870920841404) -->
-    <!-- no translation found for in_num_minutes:one (1487585791027953091) -->
-    <!-- no translation found for in_num_minutes:other (6274204576475209932) -->
-    <!-- no translation found for in_num_hours:one (6501470863235186391) -->
-    <!-- no translation found for in_num_hours:other (4415358752953289251) -->
-    <!-- no translation found for in_num_days:one (5608475533104443893) -->
-    <!-- no translation found for in_num_days:other (3827193006163842267) -->
-    <!-- no translation found for preposition_for_date (2689847983632851560) -->
-    <skip />
-    <!-- no translation found for preposition_for_time (2613388053493148013) -->
-    <skip />
-    <!-- no translation found for preposition_for_year (6968468294728152393) -->
-    <skip />
-    <string name="day">"den"</string>
-    <string name="days">"dnů"</string>
-    <string name="hour">"hodinu"</string>
-    <string name="hours">"hodin"</string>
-    <string name="minute">"minutu"</string>
-    <string name="minutes">"minut"</string>
-    <string name="second">"sekund"</string>
-    <string name="seconds">"sekund"</string>
-    <string name="week">"týden"</string>
-    <string name="weeks">"týdnů"</string>
-    <!-- no translation found for year (8024790425994085153) -->
-    <skip />
-    <!-- no translation found for years (8592090054773244417) -->
-    <skip />
-    <string name="sunday">"Neděle"</string>
-    <string name="monday">"Pondělí"</string>
-    <string name="tuesday">"Úterý"</string>
-    <string name="wednesday">"Středa"</string>
-    <string name="thursday">"Čtvrtek"</string>
-    <string name="friday">"Pátek"</string>
-    <string name="saturday">"Sobota"</string>
-    <string name="every_weekday">"Každý den v týdnu (Po–Pá)"</string>
-    <string name="daily">"Denně"</string>
-    <string name="weekly">"Týdně (%s)"</string>
-    <string name="monthly">"Měsíčně"</string>
-    <string name="yearly">"Ročně"</string>
-    <!-- no translation found for VideoView_error_title (1024334251681931859) -->
-    <skip />
-    <!-- no translation found for VideoView_error_text_unknown (3398417247398476771) -->
-    <skip />
-    <!-- no translation found for VideoView_error_button (3144127115413163445) -->
-    <skip />
-    <string name="am">"dop."</string>
-    <string name="pm">"odp."</string>
-    <!-- no translation found for numeric_date (5120078478872821100) -->
-    <skip />
-    <!-- no translation found for wday1_date1_time1_wday2_date2_time2 (7066878981949584861) -->
-    <skip />
-    <!-- no translation found for wday1_date1_wday2_date2 (8671068747172261907) -->
-    <skip />
-    <!-- no translation found for date1_time1_date2_time2 (3645498975775629615) -->
-    <skip />
-    <!-- no translation found for date1_date2 (377057563556488062) -->
-    <skip />
-    <!-- no translation found for time1_time2 (3173474242109288305) -->
-    <skip />
-    <!-- no translation found for time_wday_date (8928955562064570313) -->
-    <skip />
-    <!-- no translation found for wday_date (8794741400546136975) -->
-    <skip />
-    <!-- no translation found for time_date (1922644512833014496) -->
-    <skip />
-    <!-- no translation found for time_wday (1422050241301754712) -->
-    <skip />
-    <!-- no translation found for full_date_month_first (6011143962222283357) -->
-    <skip />
-    <!-- no translation found for full_date_day_first (8621594762705478189) -->
-    <skip />
-    <!-- no translation found for medium_date_month_first (48990963718825728) -->
-    <skip />
-    <!-- no translation found for medium_date_day_first (2898992016440387123) -->
-    <skip />
-    <!-- no translation found for twelve_hour_time_format (6015557937879492156) -->
-    <skip />
-    <!-- no translation found for twenty_four_hour_time_format (5176807998669709535) -->
-    <skip />
-    <!-- no translation found for noon (8390796001560682897) -->
-    <skip />
-    <!-- no translation found for Noon (7698941576181064429) -->
-    <skip />
-    <!-- no translation found for midnight (7773339795626486146) -->
-    <skip />
-    <!-- no translation found for Midnight (1260172107848123187) -->
-    <skip />
-    <!-- no translation found for month_day (3356633704511426364) -->
-    <skip />
-    <!-- no translation found for month (3017405760734206414) -->
-    <skip />
-    <!-- no translation found for month_day_year (2435948225709176752) -->
-    <skip />
-    <!-- no translation found for month_year (6228414124777343135) -->
-    <skip />
-    <!-- no translation found for time_of_day (8375993139317154157) -->
-    <skip />
-    <!-- no translation found for date_and_time (9197690194373107109) -->
-    <skip />
-    <!-- no translation found for same_year_md1_md2 (9199324363135981317) -->
-    <skip />
-    <!-- no translation found for same_year_wday1_md1_wday2_md2 (6006392413355305178) -->
-    <skip />
-    <!-- no translation found for same_year_mdy1_mdy2 (1576657593937827090) -->
-    <skip />
-    <!-- no translation found for same_year_wday1_mdy1_wday2_mdy2 (9135935796468891580) -->
-    <skip />
-    <!-- no translation found for same_year_md1_time1_md2_time2 (2172964106375558081) -->
-    <skip />
-    <!-- no translation found for same_year_wday1_md1_time1_wday2_md2_time2 (1702879534101786310) -->
-    <skip />
-    <!-- no translation found for same_year_mdy1_time1_mdy2_time2 (2476443311723358767) -->
-    <skip />
-    <!-- no translation found for same_year_wday1_mdy1_time1_wday2_mdy2_time2 (1564837340334069879) -->
-    <skip />
-    <!-- no translation found for numeric_md1_md2 (8908376522875100300) -->
-    <skip />
-    <!-- no translation found for numeric_wday1_md1_wday2_md2 (3239690882018292077) -->
-    <skip />
-    <!-- no translation found for numeric_mdy1_mdy2 (8883797176939233525) -->
-    <skip />
-    <!-- no translation found for numeric_wday1_mdy1_wday2_mdy2 (4150475769255828954) -->
-    <skip />
-    <!-- no translation found for numeric_md1_time1_md2_time2 (3624746590607741419) -->
-    <skip />
-    <!-- no translation found for numeric_wday1_md1_time1_wday2_md2_time2 (4258040955467298134) -->
-    <skip />
-    <!-- no translation found for numeric_mdy1_time1_mdy2_time2 (3598215409314517987) -->
-    <skip />
-    <!-- no translation found for numeric_wday1_mdy1_time1_wday2_mdy2_time2 (264076937155877259) -->
-    <skip />
-    <!-- no translation found for same_month_md1_md2 (2393563617438036111) -->
-    <skip />
-    <!-- no translation found for same_month_wday1_md1_wday2_md2 (1208946773794057819) -->
-    <skip />
-    <!-- no translation found for same_month_mdy1_mdy2 (3713236637869030492) -->
-    <skip />
-    <!-- no translation found for same_month_wday1_mdy1_wday2_mdy2 (389638922479870472) -->
-    <skip />
-    <!-- no translation found for same_month_md1_time1_md2_time2 (7477075526337542685) -->
-    <skip />
-    <!-- no translation found for same_month_wday1_md1_time1_wday2_md2_time2 (3516978303779391173) -->
-    <skip />
-    <!-- no translation found for same_month_mdy1_time1_mdy2_time2 (7320410992514057310) -->
-    <skip />
-    <!-- no translation found for same_month_wday1_mdy1_time1_wday2_mdy2_time2 (1332950588774239228) -->
-    <skip />
-    <!-- no translation found for abbrev_month_day_year (5767271534015320250) -->
-    <skip />
-    <!-- no translation found for abbrev_month_year (8058929633673942490) -->
-    <skip />
-    <!-- no translation found for abbrev_month_day (458867920693482757) -->
-    <skip />
-    <!-- no translation found for abbrev_month (1674509986330181349) -->
-    <skip />
-    <!-- no translation found for day_of_week_long_sunday (9057662850446501884) -->
-    <skip />
-    <!-- no translation found for day_of_week_long_monday (7358451993082888343) -->
-    <skip />
-    <!-- no translation found for day_of_week_long_tuesday (2282901451170509613) -->
-    <skip />
-    <!-- no translation found for day_of_week_long_wednesday (2100217950343286482) -->
-    <skip />
-    <!-- no translation found for day_of_week_long_thursday (5475158963242863176) -->
-    <skip />
-    <!-- no translation found for day_of_week_long_friday (4081018004819837155) -->
-    <skip />
-    <!-- no translation found for day_of_week_long_saturday (1929694088305891795) -->
-    <skip />
-    <!-- no translation found for day_of_week_medium_sunday (6462580883948669820) -->
-    <skip />
-    <!-- no translation found for day_of_week_medium_monday (6960587654241349502) -->
-    <skip />
-    <!-- no translation found for day_of_week_medium_tuesday (7004462235990108936) -->
-    <skip />
-    <!-- no translation found for day_of_week_medium_wednesday (5688564741951314696) -->
-    <skip />
-    <!-- no translation found for day_of_week_medium_thursday (1784339868453982400) -->
-    <skip />
-    <!-- no translation found for day_of_week_medium_friday (4314577583604069357) -->
-    <skip />
-    <!-- no translation found for day_of_week_medium_saturday (70321191398427845) -->
-    <skip />
-    <!-- no translation found for day_of_week_short_sunday (7403409454572591357) -->
-    <skip />
-    <!-- no translation found for day_of_week_short_monday (5278358100012478239) -->
-    <skip />
-    <!-- no translation found for day_of_week_short_tuesday (5121116040712487059) -->
-    <skip />
-    <!-- no translation found for day_of_week_short_wednesday (1601079579293330319) -->
-    <skip />
-    <!-- no translation found for day_of_week_short_thursday (5863422096017401812) -->
-    <skip />
-    <!-- no translation found for day_of_week_short_friday (2916686031099723960) -->
-    <skip />
-    <!-- no translation found for day_of_week_short_saturday (8521564973195542073) -->
-    <skip />
-    <!-- no translation found for day_of_week_shorter_sunday (1650484495176707638) -->
-    <skip />
-    <!-- no translation found for day_of_week_shorter_monday (9133193697786876074) -->
-    <skip />
-    <!-- no translation found for day_of_week_shorter_tuesday (4012095408481489663) -->
-    <skip />
-    <!-- no translation found for day_of_week_shorter_wednesday (6279056612496078470) -->
-    <skip />
-    <!-- no translation found for day_of_week_shorter_thursday (2748599403545071011) -->
-    <skip />
-    <!-- no translation found for day_of_week_shorter_friday (5037282109124849673) -->
-    <skip />
-    <!-- no translation found for day_of_week_shorter_saturday (3208167155877833783) -->
-    <skip />
-    <!-- no translation found for day_of_week_shortest_sunday (4683862964821549758) -->
-    <skip />
-    <!-- no translation found for day_of_week_shortest_monday (6701142261471667000) -->
-    <skip />
-    <!-- no translation found for day_of_week_shortest_tuesday (9098171980161292477) -->
-    <skip />
-    <!-- no translation found for day_of_week_shortest_wednesday (655049238289460956) -->
-    <skip />
-    <!-- no translation found for day_of_week_shortest_thursday (7816913627500884083) -->
-    <skip />
-    <!-- no translation found for day_of_week_shortest_friday (903301878650619398) -->
-    <skip />
-    <!-- no translation found for day_of_week_shortest_saturday (5359692489649817988) -->
-    <skip />
-    <!-- no translation found for month_long_january (7128497801440564337) -->
-    <skip />
-    <!-- no translation found for month_long_february (7808570514581190617) -->
-    <skip />
-    <!-- no translation found for month_long_march (2061328556983796034) -->
-    <skip />
-    <!-- no translation found for month_long_april (6575007959043269919) -->
-    <skip />
-    <!-- no translation found for month_long_may (8404051103463071121) -->
-    <skip />
-    <!-- no translation found for month_long_june (6255771619238859451) -->
-    <skip />
-    <!-- no translation found for month_long_july (4129177743136800884) -->
-    <skip />
-    <!-- no translation found for month_long_august (5494331003296804494) -->
-    <skip />
-    <!-- no translation found for month_long_september (2691137479752033087) -->
-    <skip />
-    <!-- no translation found for month_long_october (7501261567327243313) -->
-    <skip />
-    <!-- no translation found for month_long_november (8759690753068763664) -->
-    <skip />
-    <!-- no translation found for month_long_december (4505008719696569497) -->
-    <skip />
-    <!-- no translation found for month_medium_january (2315492772833932512) -->
-    <skip />
-    <!-- no translation found for month_medium_february (118412521324313430) -->
-    <skip />
-    <!-- no translation found for month_medium_march (5546835583839352358) -->
-    <skip />
-    <!-- no translation found for month_medium_april (7052559668687733702) -->
-    <skip />
-    <!-- no translation found for month_medium_may (2825303871720116018) -->
-    <skip />
-    <!-- no translation found for month_medium_june (829843667101495271) -->
-    <skip />
-    <!-- no translation found for month_medium_july (5029778226925324789) -->
-    <skip />
-    <!-- no translation found for month_medium_august (8851230594641162805) -->
-    <skip />
-    <!-- no translation found for month_medium_september (8420590486625304647) -->
-    <skip />
-    <!-- no translation found for month_medium_october (1787382806172930239) -->
-    <skip />
-    <!-- no translation found for month_medium_november (675513809622370603) -->
-    <skip />
-    <!-- no translation found for month_medium_december (2934948295928978783) -->
-    <skip />
-    <!-- no translation found for month_shortest_january (6070060405144675883) -->
-    <skip />
-    <!-- no translation found for month_shortest_february (5632605004902176653) -->
-    <skip />
-    <!-- no translation found for month_shortest_march (4304231552356086624) -->
-    <skip />
-    <!-- no translation found for month_shortest_april (1166434066469385532) -->
-    <skip />
-    <!-- no translation found for month_shortest_may (9131326028845529001) -->
-    <skip />
-    <!-- no translation found for month_shortest_june (1875723154506665289) -->
-    <skip />
-    <!-- no translation found for month_shortest_july (2003596275389810773) -->
-    <skip />
-    <!-- no translation found for month_shortest_august (9120245162625763214) -->
-    <skip />
-    <!-- no translation found for month_shortest_september (7980651111022693669) -->
-    <skip />
-    <!-- no translation found for month_shortest_october (3640405450427788312) -->
-    <skip />
-    <!-- no translation found for month_shortest_november (4002935318566146993) -->
-    <skip />
-    <!-- no translation found for month_shortest_december (6213739417171334040) -->
-    <skip />
-    <!-- no translation found for elapsed_time_short_format_mm_ss (1294409362352514646) -->
-    <skip />
-    <!-- no translation found for elapsed_time_short_format_h_mm_ss (2997059666628785039) -->
-    <skip />
-    <!-- no translation found for selectAll (691691810023908884) -->
-    <skip />
-    <!-- no translation found for cut (5845613239192595662) -->
-    <skip />
-    <!-- no translation found for cutAll (4474519683293791451) -->
-    <skip />
-    <!-- no translation found for copy (8603721575469529820) -->
-    <skip />
-    <!-- no translation found for copyAll (4777548804630476932) -->
-    <skip />
-    <!-- no translation found for paste (6458036735811828538) -->
-    <skip />
-    <!-- no translation found for copyUrl (5785708478767435812) -->
-    <skip />
-    <!-- no translation found for inputMethod (7911866729148111492) -->
-    <skip />
-    <!-- no translation found for editTextMenuTitle (3984253728638788023) -->
-    <skip />
-    <!-- no translation found for low_internal_storage_view_title (5997772070488639934) -->
-    <skip />
-    <!-- no translation found for low_internal_storage_view_text (2230118755295375293) -->
-    <skip />
-    <!-- no translation found for ok (4003878536083514869) -->
-    <skip />
-    <!-- no translation found for cancel (1527674037280267012) -->
-    <skip />
-    <!-- no translation found for yes (8185296114406773873) -->
-    <skip />
-    <!-- no translation found for no (2300685350903156262) -->
-    <skip />
-    <!-- no translation found for capital_on (8418242581217554942) -->
-    <skip />
-    <!-- no translation found for capital_off (8870368560477693851) -->
-    <skip />
-    <!-- no translation found for whichApplication (2828159696176255212) -->
-    <skip />
-    <!-- no translation found for alwaysUse (6433627451071144629) -->
-    <skip />
-    <!-- no translation found for clearDefaultHintMsg (5742432113023174321) -->
-    <skip />
-    <!-- no translation found for chooseActivity (7588691622928031978) -->
-    <skip />
-    <!-- no translation found for noApplications (4068560364116066745) -->
-    <skip />
-    <!-- no translation found for aerr_title (2654390351574026098) -->
-    <skip />
-    <!-- no translation found for aerr_application (4917288809565116720) -->
-    <skip />
-    <!-- no translation found for aerr_process (1273819861108073461) -->
-    <skip />
-    <!-- no translation found for anr_title (3305935690891435915) -->
-    <skip />
-    <!-- no translation found for anr_activity_application (1653036325679156678) -->
-    <skip />
-    <!-- no translation found for anr_activity_process (2674027618362070465) -->
-    <skip />
-    <!-- no translation found for anr_application_process (2163656674970221928) -->
-    <skip />
-    <!-- no translation found for anr_process (7747550780123472160) -->
-    <skip />
-    <!-- no translation found for force_close (9020954128872810669) -->
-    <skip />
-    <!-- no translation found for wait (7973775702304037058) -->
-    <skip />
-    <!-- no translation found for debug (857932504764728770) -->
-    <skip />
-    <!-- no translation found for sendText (6158329286172492543) -->
-    <skip />
-    <!-- no translation found for volume_ringtone (4121694816346562058) -->
-    <skip />
-    <!-- no translation found for volume_music (4869950240104717493) -->
-    <skip />
-    <!-- no translation found for volume_call (5723421277753250395) -->
-    <skip />
-    <!-- no translation found for volume_alarm (2752102730973081294) -->
-    <skip />
-    <!-- no translation found for volume_unknown (6908187627672375742) -->
-    <skip />
-    <!-- no translation found for ringtone_default (2873893375149093475) -->
-    <skip />
-    <!-- no translation found for ringtone_default_with_actual (5474076151665761913) -->
-    <skip />
-    <!-- no translation found for ringtone_silent (7477159279081654685) -->
-    <skip />
-    <!-- no translation found for ringtone_picker_title (7055241890764367884) -->
-    <skip />
-    <!-- no translation found for ringtone_unknown (6888219771401173795) -->
-    <skip />
-    <!-- no translation found for wifi_available:one (8168012881468888470) -->
-    <!-- no translation found for wifi_available:other (4666122955807117718) -->
-    <!-- no translation found for wifi_available_detailed:one (5107769161192143259) -->
-    <!-- no translation found for wifi_available_detailed:other (853347657960575809) -->
-    <!-- no translation found for select_character (3735110139249491726) -->
-    <skip />
-    <!-- no translation found for sms_control_default_app_name (7522184737840550841) -->
-    <skip />
-    <!-- no translation found for sms_control_title (2742400596989418394) -->
-    <skip />
-    <!-- no translation found for sms_control_message (3447126217666595989) -->
-    <skip />
-    <!-- no translation found for sms_control_yes (8839660939359273650) -->
-    <skip />
-    <!-- no translation found for sms_control_no (909756849988183801) -->
-    <skip />
-    <!-- no translation found for date_time_set (2495199891239480952) -->
-    <skip />
-    <!-- no translation found for default_permission_group (7742780381379652409) -->
-    <skip />
-    <!-- no translation found for no_permissions (85461124044682315) -->
-    <skip />
-    <!-- no translation found for perms_hide (4145325555929151849) -->
-    <skip />
-    <!-- no translation found for perms_show_all (6040194843455403173) -->
-    <skip />
-    <!-- no translation found for googlewebcontenthelper_loading (2140804350507245589) -->
-    <skip />
-    <!-- no translation found for usb_storage_title (8699631567051394409) -->
-    <skip />
-    <!-- no translation found for usb_storage_message (5344039189213308733) -->
-    <skip />
-    <!-- no translation found for usb_storage_button_mount (6700104384375121662) -->
-    <skip />
-    <!-- no translation found for usb_storage_button_unmount (465869657252626688) -->
-    <skip />
-    <!-- no translation found for usb_storage_error_message (3192564550748426087) -->
-    <skip />
-    <!-- no translation found for usb_storage_notification_title (6237028017872246940) -->
-    <skip />
-    <!-- no translation found for usb_storage_notification_message (7371717280517625905) -->
-    <skip />
-    <!-- no translation found for select_input_method (2658280517827502015) -->
-    <skip />
-    <!-- no translation found for fast_scroll_alphabet (1017432309285755759) -->
-    <skip />
-    <!-- no translation found for fast_scroll_numeric_alphabet (3092587363718901074) -->
-    <skip />
-    <!-- no translation found for candidates_style (7738463880139922176) -->
-    <skip />
-</resources>
diff --git a/core/res/res/values-cs/strings.xml b/core/res/res/values-cs/strings.xml
index 37632f8..e0c0a64 100644
--- a/core/res/res/values-cs/strings.xml
+++ b/core/res/res/values-cs/strings.xml
@@ -817,6 +817,5 @@
     <skip />
     <!-- no translation found for permdesc_pkgUsageStats (891553695716752835) -->
     <skip />
-    <!-- no translation found for tutorial_double_tap_to_zoom_message (9111326385548696308) -->
     <skip />
 </resources>
diff --git a/core/res/res/values-de/strings.xml b/core/res/res/values-de/strings.xml
index 3015957..d9c4174 100644
--- a/core/res/res/values-de/strings.xml
+++ b/core/res/res/values-de/strings.xml
@@ -818,6 +818,5 @@
     <skip />
     <!-- no translation found for permdesc_pkgUsageStats (891553695716752835) -->
     <skip />
-    <!-- no translation found for tutorial_double_tap_to_zoom_message (9111326385548696308) -->
     <skip />
 </resources>
diff --git a/core/res/res/values-en-rGB/strings.xml b/core/res/res/values-en-rGB/strings.xml
index 4cb3ee1..d9cf3d5 100644
--- a/core/res/res/values-en-rGB/strings.xml
+++ b/core/res/res/values-en-rGB/strings.xml
@@ -1,765 +1,5 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="byteShort">"B"</string>
-    <string name="kilobyteShort">"KB"</string>
-    <string name="megabyteShort">"MB"</string>
-    <string name="gigabyteShort">"GB"</string>
-    <string name="terabyteShort">"TB"</string>
-    <string name="petabyteShort">"PB"</string>
-    <string name="untitled">"&lt;untitled&gt;"</string>
-    <string name="ellipsis">"…"</string>
-    <string name="emptyPhoneNumber">"(No phone number)"</string>
-    <string name="unknownName">"(Unknown)"</string>
-    <string name="defaultVoiceMailAlphaTag">"Voicemail"</string>
-    <string name="defaultMsisdnAlphaTag">"MSISDN1"</string>
-    <string name="mmiError">"Connection problem or invalid MMI code."</string>
-    <string name="serviceEnabled">"Service was enabled."</string>
-    <string name="serviceEnabledFor">"Service was enabled for:"</string>
-    <string name="serviceDisabled">"Service has been disabled."</string>
-    <string name="serviceRegistered">"Registration was successful."</string>
-    <string name="serviceErased">"Erasure was successful."</string>
-    <string name="passwordIncorrect">"Incorrect password."</string>
-    <string name="mmiComplete">"MMI complete."</string>
-    <string name="badPin">"The old PIN you typed is not correct."</string>
-    <string name="badPuk">"The PUK you typed is not correct."</string>
-    <string name="mismatchPin">"The PINs you entered do not match."</string>
-    <string name="invalidPin">"Type a PIN that is 4 to 8 numbers."</string>
-    <!-- no translation found for needPuk (4788728144863892764) -->
-    <skip />
-    <string name="needPuk2">"Type PUK2 to unblock SIM card."</string>
-    <string name="ClipMmi">"Incoming Caller ID"</string>
-    <string name="ClirMmi">"Outgoing Caller ID"</string>
-    <string name="CfMmi">"Call forwarding"</string>
-    <string name="CwMmi">"Call waiting"</string>
-    <string name="BaMmi">"Call barring"</string>
-    <string name="PwdMmi">"Password change"</string>
-    <string name="PinMmi">"PIN change"</string>
-    <string name="CLIRDefaultOnNextCallOn">"Caller ID defaults to restricted. Next call: Restricted"</string>
-    <string name="CLIRDefaultOnNextCallOff">"Caller ID defaults to restricted. Next call: Not restricted"</string>
-    <string name="CLIRDefaultOffNextCallOn">"Caller ID defaults to not restricted. Next call: Restricted"</string>
-    <string name="CLIRDefaultOffNextCallOff">"Caller ID defaults to not restricted. Next call: Not restricted"</string>
-    <string name="serviceNotProvisioned">"Service not provisioned."</string>
-    <string name="CLIRPermanent">"The caller ID setting cannot be changed."</string>
-    <string name="serviceClassVoice">"Voice"</string>
-    <string name="serviceClassData">"Data"</string>
-    <string name="serviceClassFAX">"FAX"</string>
-    <string name="serviceClassSMS">"SMS"</string>
-    <string name="serviceClassDataAsync">"Async"</string>
-    <string name="serviceClassDataSync">"Sync"</string>
-    <string name="serviceClassPacket">"Packet"</string>
-    <string name="serviceClassPAD">"PAD"</string>
-    <string name="cfTemplateNotForwarded">"{0}: Not forwarded"</string>
-    <string name="cfTemplateForwarded">"{0}: {1}"</string>
-    <string name="cfTemplateForwardedTime">"{0}: {1} after {2} seconds"</string>
-    <string name="cfTemplateRegistered">"{0}: Not forwarded"</string>
-    <string name="cfTemplateRegisteredTime">"{0}: Not forwarded"</string>
-    <string name="httpErrorOk">"OK"</string>
-    <string name="httpError">"The Web page contains an error."</string>
-    <string name="httpErrorLookup">"The URL could not be found."</string>
-    <string name="httpErrorUnsupportedAuthScheme">"The site authentication scheme is not supported."</string>
-    <string name="httpErrorAuth">"Authentication was unsuccessful."</string>
-    <string name="httpErrorProxyAuth">"Authentication via the proxy server was unsuccessful."</string>
-    <string name="httpErrorConnect">"The connection to the server was unsuccessful."</string>
-    <string name="httpErrorIO">"The server failed to communicate. Try again later."</string>
-    <string name="httpErrorTimeout">"The connection to the server timed out."</string>
-    <string name="httpErrorRedirectLoop">"The page contains too many server redirects."</string>
-    <string name="httpErrorUnsupportedScheme">"The protocol is not supported."</string>
-    <string name="httpErrorFailedSslHandshake">"A secure connection could not be established."</string>
-    <string name="httpErrorBadUrl">"The page could not be opened because the URL is invalid."</string>
-    <string name="httpErrorFile">"The file could not be accessed."</string>
-    <string name="httpErrorFileNotFound">"The requested file was not found."</string>
-    <string name="httpErrorTooManyRequests">"Too many requests are being processed. Try again later."</string>
-    <string name="contentServiceSync">"Sync"</string>
-    <string name="contentServiceSyncNotificationTitle">"Sync"</string>
-    <string name="contentServiceTooManyDeletesNotificationDesc">"Too many %s deletes."</string>
-    <string name="low_memory">"Phone storage is full! Delete some files to free space."</string>
-    <string name="me">"Me"</string>
-    <string name="power_dialog">"Phone options"</string>
-    <string name="silent_mode">"Silent mode"</string>
-    <string name="turn_on_radio">"Turn on wireless"</string>
-    <string name="turn_off_radio">"Turn off wireless"</string>
-    <string name="screen_lock">"Screen lock"</string>
-    <string name="power_off">"Power off"</string>
-    <string name="shutdown_progress">"Shutting down…"</string>
-    <string name="shutdown_confirm">"Your phone will shut down."</string>
-    <string name="no_recent_tasks">"No recent applications."</string>
-    <string name="global_actions">"Phone options"</string>
-    <string name="global_action_lock">"Screen lock"</string>
-    <string name="global_action_power_off">"Power off"</string>
-    <string name="global_action_toggle_silent_mode">"Silent mode"</string>
-    <string name="global_action_silent_mode_on_status">"Sound is OFF"</string>
-    <string name="global_action_silent_mode_off_status">"Sound is ON"</string>
-    <string name="safeMode">"Safe mode"</string>
-    <string name="permgrouplab_costMoney">"Cost you money"</string>
-    <string name="permgroupdesc_costMoney">"Allow applications to do things that can cost you money."</string>
-    <string name="permgrouplab_messages">"Your messages"</string>
-    <string name="permgroupdesc_messages">"Read and write your SMS, e-mail, and other messages."</string>
-    <string name="permgrouplab_personalInfo">"Your personal information"</string>
-    <string name="permgroupdesc_personalInfo">"Direct access to your contacts and calendar stored on the phone."</string>
-    <string name="permgrouplab_location">"Your location"</string>
-    <string name="permgroupdesc_location">"Monitor your physical location"</string>
-    <string name="permgrouplab_network">"Network communication"</string>
-    <string name="permgroupdesc_network">"Allow applications to access various network features."</string>
-    <string name="permgrouplab_accounts">"Your Google accounts"</string>
-    <string name="permgroupdesc_accounts">"Access the available Google accounts."</string>
-    <string name="permgrouplab_hardwareControls">"Hardware controls"</string>
-    <string name="permgroupdesc_hardwareControls">"Direct access to hardware on the handset."</string>
-    <string name="permgrouplab_phoneCalls">"Phone calls"</string>
-    <string name="permgroupdesc_phoneCalls">"Monitor, record, and process phone calls."</string>
-    <string name="permgrouplab_systemTools">"System tools"</string>
-    <string name="permgroupdesc_systemTools">"Lower-level access and control of the system."</string>
-    <string name="permgrouplab_developmentTools">"Development tools"</string>
-    <string name="permgroupdesc_developmentTools">"Features only needed for application developers."</string>
-    <string name="permlab_statusBar">"disable or modify status bar"</string>
-    <string name="permdesc_statusBar">"Allows application to disable the status bar or add and remove system icons."</string>
-    <string name="permlab_expandStatusBar">"expand/collapse status bar"</string>
-    <string name="permdesc_expandStatusBar">"Allows application to expand or collapse the status bar."</string>
-    <string name="permlab_processOutgoingCalls">"intercept outgoing calls"</string>
-    <string name="permdesc_processOutgoingCalls">"Allows application to process outgoing calls and change the number to be dialed. Malicious applications may monitor, redirect, or prevent outgoing calls."</string>
-    <string name="permlab_receiveSms">"receive SMS"</string>
-    <string name="permdesc_receiveSms">"Allows application to receive and process SMS messages. Malicious applications may monitor your messages or delete them without showing them to you."</string>
-    <string name="permlab_receiveMms">"receive MMS"</string>
-    <string name="permdesc_receiveMms">"Allows application to receive and process MMS messages. Malicious applications may monitor your messages or delete them without showing them to you."</string>
-    <string name="permlab_sendSms">"send SMS messages"</string>
-    <string name="permdesc_sendSms">"Allows application to send SMS messages. Malicious applications may cost you money by sending messages without your confirmation."</string>
-    <string name="permlab_readSms">"read SMS or MMS"</string>
-    <string name="permdesc_readSms">"Allows application to read SMS messages stored on your phone or SIM card. Malicious applications may read your confidential messages."</string>
-    <string name="permlab_writeSms">"edit SMS or MMS"</string>
-    <string name="permdesc_writeSms">"Allows application to write to SMS messages stored on your phone or SIM card. Malicious applications may delete your messages."</string>
-    <string name="permlab_receiveWapPush">"receive WAP"</string>
-    <string name="permdesc_receiveWapPush">"Allows application to receive and process WAP messages. Malicious applications may monitor your messages or delete them without showing them to you."</string>
-    <string name="permlab_getTasks">"retrieve running applications"</string>
-    <string name="permdesc_getTasks">"Allows application to retrieve information about currently and recently running tasks. May allow malicious applications to discover private information about other applications."</string>
-    <string name="permlab_reorderTasks">"reorder running applications"</string>
-    <string name="permdesc_reorderTasks">"Allows an application to move tasks to the foreground and background. Malicious applications can force themselves to the front without your control."</string>
-    <string name="permlab_setDebugApp">"enable application debugging"</string>
-    <string name="permdesc_setDebugApp">"Allows an application to turn on debugging for another application. Malicious applications can use this to kill other applications."</string>
-    <string name="permlab_changeConfiguration">"change your UI settings"</string>
-    <string name="permdesc_changeConfiguration">"Allows an application to change the current configuration, such as the locale or overall font size."</string>
-    <string name="permlab_restartPackages">"restart other applications"</string>
-    <string name="permdesc_restartPackages">"Allows an application to forcibly restart other applications."</string>
-    <string name="permlab_setProcessForeground">"keep from being stopped"</string>
-    <!-- unknown placeholder BREAK in permdesc_setProcessForeground -->
-    <skip />
-    <string name="permlab_forceBack">"force application to close"</string>
-    <string name="permdesc_forceBack">"Allows an application to force any activity that is in the foreground to close and go back. Should never be needed for normal applications."</string>
-    <string name="permlab_dump">"retrieve system internal state"</string>
-    <string name="permdesc_dump">"Allows application to retrieve internal state of the system. Malicious applications may retrieve a wide variety of private and secure information that they should never normally need."</string>
-    <string name="permlab_addSystemService">"publish low-level services"</string>
-    <string name="permdesc_addSystemService">"Allows application to publish its own low-level system services. Malicious applications may hijack the system, and steal or corrupt any data on it."</string>
-    <string name="permlab_runSetActivityWatcher">"monitor and control all application launching"</string>
-    <string name="permdesc_runSetActivityWatcher">"Allows an application to monitor and control how the system launches activities. Malicious applications may completely compromise the system. This permission is only needed for development, never for normal phone usage."</string>
-    <string name="permlab_broadcastPackageRemoved">"send package removed broadcast"</string>
-    <string name="permdesc_broadcastPackageRemoved">"Allows an application to broadcast a notification that an application package has been removed. Malicious applications may use this to kill any other running application."</string>
-    <!-- no translation found for permlab_broadcastSmsReceived (1994692154847312518) -->
-    <skip />
-    <!-- no translation found for permdesc_broadcastSmsReceived (6072362543164841432) -->
-    <skip />
-    <!-- no translation found for permlab_broadcastWapPush (3070023012636951639) -->
-    <skip />
-    <!-- no translation found for permdesc_broadcastWapPush (726912255218924336) -->
-    <skip />
-    <string name="permlab_setProcessLimit">"limit number of running processes"</string>
-    <string name="permdesc_setProcessLimit">"Allows an application to control the maximum number of processes that will run. Never needed for normal applications."</string>
-    <string name="permlab_setAlwaysFinish">"make all background applications close"</string>
-    <string name="permdesc_setAlwaysFinish">"Allows an application to control whether activities are always finished as soon as they go to the background. Never needed for normal applications."</string>
-    <string name="permlab_fotaUpdate">"automatically install system updates"</string>
-    <string name="permdesc_fotaUpdate">"Allows an application to receive notifications about pending system updates and trigger their installation. Malicious applications may use this to corrupt the system with unauthorized updates, or generally interfere with the update process."</string>
-    <string name="permlab_batteryStats">"modify battery statistics"</string>
-    <string name="permdesc_batteryStats">"Allows the modification of collected battery statistics. Not for use by normal applications."</string>
-    <string name="permlab_internalSystemWindow">"display unauthorized windows"</string>
-    <string name="permdesc_internalSystemWindow">"Allows the creation of windows that are intended to be used by the internal system user interface. Not for use by normal applications."</string>
-    <string name="permlab_systemAlertWindow">"display system-level alerts"</string>
-    <string name="permdesc_systemAlertWindow">"Allows an application to show system alert windows. Malicious applications can take over the entire screen of the phone."</string>
-    <string name="permlab_setAnimationScale">"modify global animation speed"</string>
-    <string name="permdesc_setAnimationScale">"Allows an application to change the global animation speed (faster or slower animations) at any time."</string>
-    <string name="permlab_manageAppTokens">"manage application tokens"</string>
-    <string name="permdesc_manageAppTokens">"Allows applications to create and manage their own tokens, bypassing their normal Z-ordering. Should never be needed for normal applications."</string>
-    <string name="permlab_injectEvents">"press keys and control buttons"</string>
-    <string name="permdesc_injectEvents">"Allows an application to deliver its own input events (key presses, etc.) to other applications. Malicious applications can use this to take over the phone."</string>
-    <string name="permlab_readInputState">"record what you type and actions you take"</string>
-    <string name="permdesc_readInputState">"Allows applications to watch the keys you press even when interacting with another application (such as entering a password). Should never be needed for normal applications."</string>
-    <string name="permlab_setOrientation">"change screen orientation"</string>
-    <string name="permdesc_setOrientation">"Allows an application to change the rotation of the screen at any time. Should never be needed for normal applications."</string>
-    <string name="permlab_signalPersistentProcesses">"send Linux signals to applications"</string>
-    <string name="permdesc_signalPersistentProcesses">"Allows application to request that the supplied signal be sent to all persistent processes."</string>
-    <string name="permlab_persistentActivity">"make application always run"</string>
-    <!-- unknown placeholder BREAK in permdesc_persistentActivity -->
-    <skip />
-    <string name="permlab_deletePackages">"delete applications"</string>
-    <string name="permdesc_deletePackages">"Allows an application to delete Android packages. Malicious applications can use this to delete important applications."</string>
-    <string name="permlab_clearAppUserData">"delete other applications data"</string>
-    <string name="permdesc_clearAppUserData">"Allows an application to clear user data."</string>
-    <string name="permlab_deleteCacheFiles">"delete other applications cache"</string>
-    <string name="permdesc_deleteCacheFiles">"Allows an application to delete cache files."</string>
-    <string name="permlab_getPackageSize">"measure application storage space"</string>
-    <string name="permdesc_getPackageSize">"Allows an application to retrieve its code, data, and cache sizes"</string>
-    <string name="permlab_installPackages">"directly install applications"</string>
-    <string name="permdesc_installPackages">"Allows an application to install new or updated Android packages. Malicious applications can use this to add new applications with arbitrarily powerful permissions."</string>
-    <string name="permlab_clearAppCache">"delete all application cache data"</string>
-    <string name="permdesc_clearAppCache">"Allows an application to free phone storage by deleting files in application cache directory. Access is very restricted usually to system process."</string>
-    <string name="permlab_readLogs">"read system log files"</string>
-    <!-- unknown placeholder BREAK_0 in permdesc_readLogs -->
-    <skip />
-    <!-- no translation found for permlab_diagnostic (2955142476313469329) -->
-    <skip />
-    <!-- no translation found for permdesc_diagnostic (1282409892215520166) -->
-    <skip />
-    <string name="permlab_changeComponentState">"enable or disable application components"</string>
-    <string name="permdesc_changeComponentState">"Allows an application to change whether a component of another application is enabled or not. Malicious applications can use this to disable important phone capabilities. Care must be used with permission, as it is possible to get application components into an unusable, inconsistant, or unstable state."</string>
-    <string name="permlab_setPreferredApplications">"set preferred applications"</string>
-    <string name="permdesc_setPreferredApplications">"Allows an application to modify your preferred applications. This can allow malicious applications to silently change the applications that are run, spoofing your existing applications to collect private data from you."</string>
-    <string name="permlab_writeSettings">"modify global system settings"</string>
-    <string name="permdesc_writeSettings">"Allows an application to modify the systems settings data. Malicious applications can corrupt your systems configuration."</string>
-    <!-- no translation found for permlab_writeSecureSettings (4851801872124242319) -->
-    <skip />
-    <!-- no translation found for permdesc_writeSecureSettings (2080620249472761366) -->
-    <skip />
-    <!-- no translation found for permlab_writeGservices (296370685945777755) -->
-    <skip />
-    <!-- no translation found for permdesc_writeGservices (2496928471286495053) -->
-    <skip />
-    <string name="permlab_receiveBootCompleted">"automatically start at boot"</string>
-    <string name="permdesc_receiveBootCompleted">"Allows an application to have itself started as soon as the system has finished booting. This can make it take longer to start the phone and allow the application to slow down the overall phone by always running."</string>
-    <string name="permlab_broadcastSticky">"send sticky broadcast"</string>
-    <string name="permdesc_broadcastSticky">"Allows an application to send sticky broadcasts, which remain after the broadcast ends. Malicious applications can make the phone slow or unstable by causing it to use too much memory."</string>
-    <string name="permlab_readContacts">"read contact data"</string>
-    <string name="permdesc_readContacts">"Allows an application to read all of the contact (address) data stored on your phone. Malicious applications can use this to send your data to other people."</string>
-    <string name="permlab_writeContacts">"write contact data"</string>
-    <string name="permdesc_writeContacts">"Allows an application to modify the contact (address) data stored on your phone. Malicious applications can use this to erase or modify your contact data."</string>
-    <string name="permlab_writeOwnerData">"write owner data"</string>
-    <string name="permdesc_writeOwnerData">"Allows an application to modify the phone owner data stored on your phone. Malicious applications can use this to erase or modify owner data."</string>
-    <string name="permlab_readOwnerData">"read owner data"</string>
-    <string name="permdesc_readOwnerData">"Allows an application read the phone owner data stored on your phone. Malicious applications can use this to read phone owner data."</string>
-    <string name="permlab_readCalendar">"read calendar data"</string>
-    <string name="permdesc_readCalendar">"Allows an application to read all of the calendar events stored on your phone. Malicious applications can use this to send your calendar events to other people."</string>
-    <string name="permlab_writeCalendar">"write calendar data"</string>
-    <string name="permdesc_writeCalendar">"Allows an application to modify the calendar events stored on your phone. Malicious applications can use this to erase or modify your calendar data."</string>
-    <string name="permlab_accessMockLocation">"mock location sources for testing"</string>
-    <string name="permdesc_accessMockLocation">"Create mock location sources for testing. Malicious applications can use this to override the location and/or status returned by real location sources such as GPS or Network providers."</string>
-    <!-- no translation found for permlab_accessLocationExtraCommands (8291822077788811687) -->
-    <skip />
-    <!-- no translation found for permdesc_accessLocationExtraCommands (5135782633548630731) -->
-    <skip />
-    <string name="permlab_accessFineLocation">"fine (GPS) location"</string>
-    <string name="permdesc_accessFineLocation">"Access fine location sources such as the Global Positioning System on the phone, where available. Malicious applications can use this to determine where you are, and may consume additional battery power."</string>
-    <string name="permlab_accessCoarseLocation">"coarse (network-based) location"</string>
-    <string name="permdesc_accessCoarseLocation">"Access coarse location sources such as the cellular network database to determine an approximate phone location, where available. Malicious applications can use this to determine approximately where you are."</string>
-    <string name="permlab_accessSurfaceFlinger">"access SurfaceFlinger"</string>
-    <string name="permdesc_accessSurfaceFlinger">"Allows application to use SurfaceFlinger low-level features."</string>
-    <string name="permlab_readFrameBuffer">"read frame buffer"</string>
-    <string name="permdesc_readFrameBuffer">"Allows application to use read the content of the frame buffer."</string>
-    <string name="permlab_modifyAudioSettings">"change your audio settings"</string>
-    <string name="permdesc_modifyAudioSettings">"Allows application to modify global audio settings such as volume and routing."</string>
-    <string name="permlab_recordAudio">"record audio"</string>
-    <string name="permdesc_recordAudio">"Allows application to access the audio record path."</string>
-    <string name="permlab_camera">"take pictures"</string>
-    <string name="permdesc_camera">"Allows application to take pictures with the camera. This allows the application at any time to collect images the camera is seeing."</string>
-    <string name="permlab_brick">"permanently disable phone"</string>
-    <string name="permdesc_brick">"Allows the application to disable the entire phone permanently. This is very dangerous."</string>
-    <!-- no translation found for permlab_reboot (8844650672567077423) -->
-    <skip />
-    <!-- no translation found for permdesc_reboot (4704919552870918328) -->
-    <skip />
-    <string name="permlab_mount_unmount_filesystems">"mount and unmount filesystems"</string>
-    <string name="permdesc_mount_unmount_filesystems">"Allows the application to mount and unmount filesystems for removable storage."</string>
-    <string name="permlab_vibrate">"control vibrator"</string>
-    <string name="permdesc_vibrate">"Allows the application to control the vibrator."</string>
-    <string name="permlab_flashlight">"control flashlight"</string>
-    <string name="permdesc_flashlight">"Allows the application to control the flashlight."</string>
-    <string name="permlab_hardware_test">"test hardware"</string>
-    <string name="permdesc_hardware_test">"Allows the application to control various peripherals for the purpose of hardware testing."</string>
-    <string name="permlab_callPhone">"directly call phone numbers"</string>
-    <string name="permdesc_callPhone">"Allows the application to call phone numbers without your intervention. Malicious applications may cause unexpected calls on your phone bill. Note that this does not allow the application to call emergency numbers."</string>
-    <!-- no translation found for permlab_callPrivileged (2166923597287697159) -->
-    <skip />
-    <!-- no translation found for permdesc_callPrivileged (5109789447971735501) -->
-    <skip />
-    <!-- no translation found for permlab_locationUpdates (4216418293360456836) -->
-    <skip />
-    <!-- no translation found for permdesc_locationUpdates (7635814693478743648) -->
-    <skip />
-    <!-- no translation found for permlab_checkinProperties (2260796787386280708) -->
-    <skip />
-    <!-- no translation found for permdesc_checkinProperties (3508022022841741945) -->
-    <skip />
-    <string name="permlab_modifyPhoneState">"modify phone state"</string>
-    <string name="permdesc_modifyPhoneState">"Allows the application to control the phone features of the device. An application with this permission can switch networks, turn the phone radio on and off and the like without ever notifying you."</string>
-    <string name="permlab_readPhoneState">"read phone state"</string>
-    <string name="permdesc_readPhoneState">"Allows the application to access the phone features of the device. An application with this permission can determine the phone number of this phone, whether a call is active, the number that call is connected to and the like."</string>
-    <string name="permlab_wakeLock">"prevent phone from sleeping"</string>
-    <string name="permdesc_wakeLock">"Allows an application to prevent the phone from going to sleep."</string>
-    <string name="permlab_devicePower">"power phone on or off"</string>
-    <string name="permdesc_devicePower">"Allows the application to turn the phone on or off."</string>
-    <string name="permlab_factoryTest">"run in factory test mode"</string>
-    <string name="permdesc_factoryTest">"Run as a low-level manufacturer test, allowing complete access to the phone hardware. Only available when a phone is running in manufacturer test mode."</string>
-    <string name="permlab_setWallpaper">"set wallpaper"</string>
-    <string name="permdesc_setWallpaper">"Allows the application to set the system wallpaper."</string>
-    <string name="permlab_setWallpaperHints">"set wallpaper size hints"</string>
-    <string name="permdesc_setWallpaperHints">"Allows the application to set the system wallpaper size hints."</string>
-    <string name="permlab_masterClear">"reset system to factory defaults"</string>
-    <string name="permdesc_masterClear">"Allows an application to completely reset the system to its factory settings, erasing all data, configuration, and installed applications."</string>
-    <string name="permlab_setTimeZone">"set time zone"</string>
-    <string name="permdesc_setTimeZone">"Allows an application to change the phones time zone."</string>
-    <string name="permlab_getAccounts">"discover known accounts"</string>
-    <string name="permdesc_getAccounts">"Allows an application to get the list of accounts known by the phone."</string>
-    <string name="permlab_accessNetworkState">"view network state"</string>
-    <string name="permdesc_accessNetworkState">"Allows an application to view the state of all networks."</string>
-    <string name="permlab_createNetworkSockets">"full Internet access"</string>
-    <string name="permdesc_createNetworkSockets">"Allows an application to create network sockets."</string>
-    <!-- no translation found for permlab_writeApnSettings (3190585220761979369) -->
-    <skip />
-    <!-- no translation found for permdesc_writeApnSettings (4093875220468761052) -->
-    <skip />
-    <string name="permlab_changeNetworkState">"change network connectivity"</string>
-    <string name="permdesc_changeNetworkState">"Allows an application to change the state network connectivity."</string>
-    <string name="permlab_accessWifiState">"view Wi-Fi state"</string>
-    <string name="permdesc_accessWifiState">"Allows an application to view the information about the state of Wi-Fi."</string>
-    <string name="permlab_changeWifiState">"change Wi-Fi state"</string>
-    <string name="permdesc_changeWifiState">"Allows an application to connect to and disconnect from Wi-Fi access points, and to make changes to configured Wi-Fi networks."</string>
-    <string name="permlab_bluetoothAdmin">"bluetooth administration"</string>
-    <string name="permdesc_bluetoothAdmin">"Allows an application to configure the local Bluetooth phone, and to discover and pair with remote devices."</string>
-    <string name="permlab_bluetooth">"create Bluetooth connections"</string>
-    <string name="permdesc_bluetooth">"Allows an application to view configuration of the local Bluetooth phone, and to make and accept connections with paired devices."</string>
-    <string name="permlab_disableKeyguard">"disable keylock"</string>
-    <string name="permdesc_disableKeyguard">"Allows an application to disable the keylock and any associated password security. A legitimate example of this is the phone disabling the keylock when receiving an incoming phone call, then re-enabling the keylock when the call is finished."</string>
-    <string name="permlab_readSyncSettings">"read sync settings"</string>
-    <string name="permdesc_readSyncSettings">"Allows an application to read the sync settings, such as whether sync is enabled for Contacts."</string>
-    <string name="permlab_writeSyncSettings">"write sync settings"</string>
-    <string name="permdesc_writeSyncSettings">"Allows an application to modify the sync settings, such as whether sync is enabled for Contacts."</string>
-    <string name="permlab_readSyncStats">"read sync statistics"</string>
-    <string name="permdesc_readSyncStats">"Allows an application to reafocusd the sync stats; e.g., the history of syncs that have occurred."</string>
-    <!-- no translation found for permlab_subscribedFeedsRead (2043206814904506589) -->
-    <skip />
-    <!-- no translation found for permdesc_subscribedFeedsRead (6977343942680042449) -->
-    <skip />
-    <!-- no translation found for permlab_subscribedFeedsWrite (2556727307229571556) -->
-    <skip />
-    <!-- no translation found for permdesc_subscribedFeedsWrite (4134783294590266220) -->
-    <skip />
-    <!-- no translation found for phoneTypes:0 (6070018634209800981) -->
-    <!-- no translation found for phoneTypes:1 (1514509689885965711) -->
-    <!-- no translation found for phoneTypes:2 (497473201754095234) -->
-    <!-- no translation found for phoneTypes:3 (5554432614281047787) -->
-    <!-- no translation found for phoneTypes:4 (2222084401110150993) -->
-    <!-- no translation found for phoneTypes:5 (2290007103906353121) -->
-    <!-- no translation found for phoneTypes:6 (6930783706213719251) -->
-    <!-- no translation found for phoneTypes:7 (1326005699931077792) -->
-    <!-- no translation found for emailAddressTypes:0 (1540640638077615417) -->
-    <!-- no translation found for emailAddressTypes:1 (4252853367575831977) -->
-    <!-- no translation found for emailAddressTypes:2 (7158046581744435718) -->
-    <!-- no translation found for emailAddressTypes:3 (3625034471181268169) -->
-    <!-- no translation found for postalAddressTypes:0 (5732960259696659380) -->
-    <!-- no translation found for postalAddressTypes:1 (7132240704786130285) -->
-    <!-- no translation found for postalAddressTypes:2 (1317604357745852817) -->
-    <!-- no translation found for postalAddressTypes:3 (1582953598462826702) -->
-    <!-- no translation found for imAddressTypes:0 (7806620012096518833) -->
-    <!-- no translation found for imAddressTypes:1 (5748846799950672787) -->
-    <!-- no translation found for imAddressTypes:2 (6196536810275073680) -->
-    <!-- no translation found for imAddressTypes:3 (8519128375350623648) -->
-    <!-- no translation found for organizationTypes:0 (1299224825223821142) -->
-    <!-- no translation found for organizationTypes:1 (2455717447227299354) -->
-    <!-- no translation found for organizationTypes:2 (7027570839313438290) -->
-    <!-- no translation found for imProtocols:0 (3318725788774688043) -->
-    <!-- no translation found for imProtocols:1 (1787713387022932886) -->
-    <!-- no translation found for imProtocols:2 (6751174158442316516) -->
-    <!-- no translation found for imProtocols:3 (1151283347465052653) -->
-    <!-- no translation found for imProtocols:4 (2157980008878817934) -->
-    <!-- no translation found for imProtocols:5 (7836237460308230767) -->
-    <!-- no translation found for imProtocols:6 (1180789904462172516) -->
-    <!-- no translation found for imProtocols:7 (21955111672779862) -->
-    <string name="keyguard_password_enter_pin_code">"Enter PIN code:"</string>
-    <string name="keyguard_password_wrong_pin_code">"Incorrect PIN code!"</string>
-    <string name="keyguard_label_text">"To unlock, press Menu then 0."</string>
-    <string name="emergency_call_dialog_number_for_display">"Emergency number"</string>
-    <string name="lockscreen_carrier_default">"(No service)"</string>
-    <string name="lockscreen_screen_locked">"Screen locked"</string>
-    <string name="lockscreen_instructions_when_pattern_enabled">"Press Menu to unlock or place emergency call."</string>
-    <string name="lockscreen_instructions_when_pattern_disabled">"Press Menu to unlock."</string>
-    <string name="lockscreen_pattern_instructions">"Draw pattern to unlock:"</string>
-    <string name="lockscreen_emergency_call">"Emergency call"</string>
-    <string name="lockscreen_pattern_correct">"Correct!"</string>
-    <string name="lockscreen_pattern_wrong">"Sorry, try again:"</string>
-    <string name="lockscreen_plugged_in">"Charging (<xliff:g id="NUMBER">%d%%</xliff:g>)"</string>
-    <string name="lockscreen_low_battery">"Connect your charger."</string>
-    <string name="lockscreen_missing_sim_message_short">"No SIM card."</string>
-    <string name="lockscreen_missing_sim_message">"No SIM card in phone."</string>
-    <string name="lockscreen_missing_sim_instructions">"Please insert a SIM card."</string>
-    <!-- no translation found for lockscreen_network_locked_message (323609607922245071) -->
-    <skip />
-    <string name="lockscreen_sim_puk_locked_message">"SIM card is PUK-locked."</string>
-    <string name="lockscreen_sim_puk_locked_instructions">"Please contact Customer Care."</string>
-    <string name="lockscreen_sim_locked_message">"SIM card is locked."</string>
-    <string name="lockscreen_sim_unlock_progress_dialog_message">"Unlocking SIM card…"</string>
-    <string name="lockscreen_too_many_failed_attempts_dialog_message">"You have incorrectly drawn your unlock pattern <xliff:g id="NUMBER_0">%d</xliff:g> times. "\n\n"Please try again in <xliff:g id="NUMBER_1">%d</xliff:g> seconds."</string>
-    <string name="lockscreen_failed_attempts_almost_glogin">"You have incorrectly drawn your unlock pattern <xliff:g id="NUMBER_0">%d</xliff:g> times. After <xliff:g id="NUMBER_1">%d</xliff:g> more unsuccessful attempts, you will be asked to unlock your phone using your Google sign-in."\n\n" Please try again in <xliff:g id="NUMBER_2">%d</xliff:g> seconds."</string>
-    <string name="lockscreen_too_many_failed_attempts_countdown">"Try again in <xliff:g id="NUMBER">%d</xliff:g> seconds."</string>
-    <string name="lockscreen_forgot_pattern_button_text">"Forgot pattern?"</string>
-    <string name="lockscreen_glogin_too_many_attempts">"Too many pattern attempts!"</string>
-    <string name="lockscreen_glogin_instructions">"To unlock,"\n"sign in with your Google account:"</string>
-    <string name="lockscreen_glogin_username_hint">"Username (email)"</string>
-    <string name="lockscreen_glogin_password_hint">"Password"</string>
-    <string name="lockscreen_glogin_submit_button">"Sign in"</string>
-    <string name="lockscreen_glogin_invalid_input">"Invalid username or password."</string>
-    <!-- unknown placeholder FORMAT in status_bar_time_format -->
-    <skip />
-    <!-- no translation found for hour_minute_ampm (1850330605794978742) -->
-    <skip />
-    <!-- no translation found for hour_minute_cap_ampm (1122840227537374196) -->
-    <skip />
-    <!-- no translation found for hour_ampm (7665432130905376251) -->
-    <skip />
-    <!-- no translation found for hour_cap_ampm (3600295014648400268) -->
-    <skip />
-    <string name="status_bar_clear_all_button">"Clear notifications"</string>
-    <string name="status_bar_no_notifications_title">"No notifications"</string>
-    <string name="status_bar_ongoing_events_title">"Ongoing"</string>
-    <string name="status_bar_latest_events_title">"Notifications"</string>
-    <string name="battery_status_text_percent_format">"<xliff:g id="NUMBER">%d</xliff:g>"</string>
-    <string name="battery_status_charging">"Charging…"</string>
-    <string name="battery_low_title">"Please connect charger"</string>
-    <string name="battery_low_subtitle">"The battery is getting low:"</string>
-    <string name="battery_low_percent_format">"less than <xliff:g id="NUMBER">%d%%</xliff:g> remaining."</string>
-    <string name="factorytest_failed">"Factory test failed"</string>
-    <string name="factorytest_not_system">"The FACTORY_TEST action is only supported for packages installed in /system/app."</string>
-    <string name="factorytest_no_action">"No package was found that provides the FACTORY_TEST action."</string>
-    <string name="factorytest_reboot">"Reboot"</string>
-    <string name="save_password_label">"Confirm"</string>
-    <string name="save_password_message">"Do you want the browser to remember this password?"</string>
-    <string name="save_password_notnow">"Not now"</string>
-    <string name="save_password_remember">"Remember"</string>
-    <string name="save_password_never">"Never"</string>
-    <string name="open_permission_deny">"You do not have permission to open this page."</string>
-    <string name="text_copied">"Text copied to clipboard."</string>
-    <string name="more_item_label">"More"</string>
-    <string name="prepend_shortcut_label">"Menu+"</string>
-    <!-- no translation found for menu_space_shortcut_label (194586306440382711) -->
-    <skip />
-    <!-- no translation found for menu_enter_shortcut_label (7214761412193519345) -->
-    <skip />
-    <!-- no translation found for menu_delete_shortcut_label (2854936426194985313) -->
-    <skip />
-    <string name="search_go">"Search"</string>
-    <string name="today">"Today"</string>
-    <string name="yesterday">"Yesterday"</string>
-    <string name="tomorrow">"Tomorrow"</string>
-    <string name="oneMonthDurationPast">"1 month ago"</string>
-    <!-- no translation found for beforeOneMonthDurationPast (7578100953282866827) -->
-    <skip />
-    <!-- no translation found for num_seconds_ago:one (7416512229671810725) -->
-    <!-- no translation found for num_seconds_ago:other (8138756910300398447) -->
-    <!-- no translation found for num_minutes_ago:one (8620869479299420562) -->
-    <!-- no translation found for num_minutes_ago:other (5065488162050522741) -->
-    <!-- no translation found for num_hours_ago:one (853404611989669641) -->
-    <!-- no translation found for num_hours_ago:other (3558873784561756849) -->
-    <!-- no translation found for num_days_ago:one (4222479980812128212) -->
-    <!-- no translation found for num_days_ago:other (5445701370433601703) -->
-    <!-- no translation found for in_num_seconds:one (4253290037777327003) -->
-    <!-- no translation found for in_num_seconds:other (1280033870920841404) -->
-    <!-- no translation found for in_num_minutes:one (1487585791027953091) -->
-    <!-- no translation found for in_num_minutes:other (6274204576475209932) -->
-    <!-- no translation found for in_num_hours:one (6501470863235186391) -->
-    <!-- no translation found for in_num_hours:other (4415358752953289251) -->
-    <!-- no translation found for in_num_days:one (5608475533104443893) -->
-    <!-- no translation found for in_num_days:other (3827193006163842267) -->
-    <string name="preposition_for_date">"on %s"</string>
-    <string name="preposition_for_time">"at %s"</string>
-    <string name="preposition_for_year">"in %s"</string>
-    <string name="day">"day"</string>
-    <string name="days">"days"</string>
-    <string name="hour">"hour"</string>
-    <string name="hours">"hours"</string>
-    <string name="minute">"min"</string>
-    <string name="minutes">"mins"</string>
-    <string name="second">"sec"</string>
-    <string name="seconds">"secs"</string>
-    <string name="week">"week"</string>
-    <string name="weeks">"weeks"</string>
-    <string name="year">"year"</string>
-    <string name="years">"years"</string>
-    <string name="sunday">"Sunday"</string>
-    <string name="monday">"Monday"</string>
-    <string name="tuesday">"Tuesday"</string>
-    <string name="wednesday">"Wednesday"</string>
-    <string name="thursday">"Thursday"</string>
-    <string name="friday">"Friday"</string>
-    <string name="saturday">"Saturday"</string>
-    <string name="every_weekday">"Every weekday (Mon–Fri)"</string>
-    <string name="daily">"Daily"</string>
-    <string name="weekly">"Weekly on <xliff:g id="DAY">%s</xliff:g>"</string>
-    <string name="monthly">"Monthly"</string>
-    <string name="yearly">"Yearly"</string>
-    <string name="VideoView_error_title">"Cannot play video"</string>
-    <string name="VideoView_error_text_unknown">"Sorry, this video cannot be played."</string>
-    <string name="VideoView_error_button">"OK"</string>
-    <string name="am">"AM"</string>
-    <string name="pm">"PM"</string>
-    <!-- unknown placeholder FORMAT in numeric_date -->
-    <skip />
-    <!-- unknown placeholder FORMAT in wday1_date1_time1_wday2_date2_time2 -->
-    <skip />
-    <!-- unknown placeholder FORMAT in wday1_date1_wday2_date2 -->
-    <skip />
-    <!-- unknown placeholder FORMAT in date1_time1_date2_time2 -->
-    <skip />
-    <!-- unknown placeholder FORMAT in date1_date2 -->
-    <skip />
-    <!-- unknown placeholder FORMAT in time1_time2 -->
-    <skip />
-    <!-- unknown placeholder FORMAT in time_wday_date -->
-    <skip />
-    <!-- unknown placeholder FORMAT in wday_date -->
-    <skip />
-    <!-- unknown placeholder FORMAT in time_date -->
-    <skip />
-    <!-- unknown placeholder FORMAT in time_wday -->
-    <skip />
-    <!-- no translation found for full_date_month_first (6011143962222283357) -->
-    <skip />
-    <!-- no translation found for full_date_day_first (8621594762705478189) -->
-    <skip />
-    <!-- no translation found for medium_date_month_first (48990963718825728) -->
-    <skip />
-    <!-- no translation found for medium_date_day_first (2898992016440387123) -->
-    <skip />
-    <!-- no translation found for twelve_hour_time_format (6015557937879492156) -->
-    <skip />
-    <!-- no translation found for twenty_four_hour_time_format (5176807998669709535) -->
-    <skip />
-    <string name="noon">"noon"</string>
-    <string name="Noon">"Noon"</string>
-    <string name="midnight">"midnight"</string>
-    <string name="Midnight">"Midnight"</string>
-    <!-- unknown placeholder FORMAT in month_day -->
-    <skip />
-    <!-- unknown placeholder FORMAT in month -->
-    <skip />
-    <!-- unknown placeholder FORMAT in month_day_year -->
-    <skip />
-    <!-- unknown placeholder FORMAT in month_year -->
-    <skip />
-    <!-- no translation found for time_of_day (8375993139317154157) -->
-    <skip />
-    <!-- no translation found for date_and_time (9197690194373107109) -->
-    <skip />
-    <!-- unknown placeholder FORMAT in same_year_md1_md2 -->
-    <skip />
-    <!-- unknown placeholder FORMAT in same_year_wday1_md1_wday2_md2 -->
-    <skip />
-    <!-- unknown placeholder FORMAT in same_year_mdy1_mdy2 -->
-    <skip />
-    <!-- unknown placeholder FORMAT in same_year_wday1_mdy1_wday2_mdy2 -->
-    <skip />
-    <!-- unknown placeholder FORMAT in same_year_md1_time1_md2_time2 -->
-    <skip />
-    <!-- unknown placeholder FORMAT in same_year_wday1_md1_time1_wday2_md2_time2 -->
-    <skip />
-    <!-- unknown placeholder FORMAT in same_year_mdy1_time1_mdy2_time2 -->
-    <skip />
-    <!-- unknown placeholder FORMAT in same_year_wday1_mdy1_time1_wday2_mdy2_time2 -->
-    <skip />
-    <!-- unknown placeholder FORMAT in numeric_md1_md2 -->
-    <skip />
-    <!-- unknown placeholder FORMAT in numeric_wday1_md1_wday2_md2 -->
-    <skip />
-    <!-- unknown placeholder FORMAT in numeric_mdy1_mdy2 -->
-    <skip />
-    <!-- unknown placeholder FORMAT in numeric_wday1_mdy1_wday2_mdy2 -->
-    <skip />
-    <!-- unknown placeholder FORMAT in numeric_md1_time1_md2_time2 -->
-    <skip />
-    <!-- unknown placeholder FORMAT in numeric_wday1_md1_time1_wday2_md2_time2 -->
-    <skip />
-    <!-- unknown placeholder FORMAT in numeric_mdy1_time1_mdy2_time2 -->
-    <skip />
-    <!-- unknown placeholder FORMAT in numeric_wday1_mdy1_time1_wday2_mdy2_time2 -->
-    <skip />
-    <!-- unknown placeholder FORMAT in same_month_md1_md2 -->
-    <skip />
-    <!-- unknown placeholder FORMAT in same_month_wday1_md1_wday2_md2 -->
-    <skip />
-    <!-- unknown placeholder FORMAT in same_month_mdy1_mdy2 -->
-    <skip />
-    <!-- unknown placeholder FORMAT in same_month_wday1_mdy1_wday2_mdy2 -->
-    <skip />
-    <!-- unknown placeholder FORMAT in same_month_md1_time1_md2_time2 -->
-    <skip />
-    <!-- unknown placeholder FORMAT in same_month_wday1_md1_time1_wday2_md2_time2 -->
-    <skip />
-    <!-- unknown placeholder FORMAT in same_month_mdy1_time1_mdy2_time2 -->
-    <skip />
-    <!-- unknown placeholder FORMAT in same_month_wday1_mdy1_time1_wday2_mdy2_time2 -->
-    <skip />
-    <!-- unknown placeholder FORMAT in abbrev_month_day_year -->
-    <skip />
-    <!-- unknown placeholder FORMAT in abbrev_month_year -->
-    <skip />
-    <!-- unknown placeholder FORMAT in abbrev_month_day -->
-    <skip />
-    <!-- unknown placeholder FORMAT in abbrev_month -->
-    <skip />
-    <string name="day_of_week_long_sunday">"Sunday"</string>
-    <string name="day_of_week_long_monday">"Monday"</string>
-    <string name="day_of_week_long_tuesday">"Tuesday"</string>
-    <string name="day_of_week_long_wednesday">"Wednesday"</string>
-    <string name="day_of_week_long_thursday">"Thursday"</string>
-    <string name="day_of_week_long_friday">"Friday"</string>
-    <string name="day_of_week_long_saturday">"Saturday"</string>
-    <string name="day_of_week_medium_sunday">"Sun"</string>
-    <string name="day_of_week_medium_monday">"Mon"</string>
-    <string name="day_of_week_medium_tuesday">"Tue"</string>
-    <string name="day_of_week_medium_wednesday">"Wed"</string>
-    <string name="day_of_week_medium_thursday">"Thu"</string>
-    <string name="day_of_week_medium_friday">"Fri"</string>
-    <string name="day_of_week_medium_saturday">"Sat"</string>
-    <string name="day_of_week_short_sunday">"Su"</string>
-    <string name="day_of_week_short_monday">"Mo"</string>
-    <string name="day_of_week_short_tuesday">"Tu"</string>
-    <string name="day_of_week_short_wednesday">"We"</string>
-    <string name="day_of_week_short_thursday">"Th"</string>
-    <string name="day_of_week_short_friday">"Fr"</string>
-    <string name="day_of_week_short_saturday">"Sa"</string>
-    <string name="day_of_week_shorter_sunday">"Su"</string>
-    <string name="day_of_week_shorter_monday">"M"</string>
-    <string name="day_of_week_shorter_tuesday">"Tu"</string>
-    <string name="day_of_week_shorter_wednesday">"W"</string>
-    <string name="day_of_week_shorter_thursday">"Th"</string>
-    <string name="day_of_week_shorter_friday">"F"</string>
-    <string name="day_of_week_shorter_saturday">"Sa"</string>
-    <string name="day_of_week_shortest_sunday">"S"</string>
-    <string name="day_of_week_shortest_monday">"M"</string>
-    <string name="day_of_week_shortest_tuesday">"T"</string>
-    <string name="day_of_week_shortest_wednesday">"W"</string>
-    <string name="day_of_week_shortest_thursday">"T"</string>
-    <string name="day_of_week_shortest_friday">"F"</string>
-    <string name="day_of_week_shortest_saturday">"S"</string>
-    <string name="month_long_january">"January"</string>
-    <string name="month_long_february">"February"</string>
-    <string name="month_long_march">"March"</string>
-    <string name="month_long_april">"April"</string>
-    <string name="month_long_may">"May"</string>
-    <string name="month_long_june">"June"</string>
-    <string name="month_long_july">"July"</string>
-    <string name="month_long_august">"August"</string>
-    <string name="month_long_september">"September"</string>
-    <string name="month_long_october">"October"</string>
-    <string name="month_long_november">"November"</string>
-    <string name="month_long_december">"December"</string>
-    <string name="month_medium_january">"Jan"</string>
-    <string name="month_medium_february">"Feb"</string>
-    <string name="month_medium_march">"Mar"</string>
-    <string name="month_medium_april">"Apr"</string>
-    <string name="month_medium_may">"May"</string>
-    <string name="month_medium_june">"Jun"</string>
-    <string name="month_medium_july">"Jul"</string>
-    <string name="month_medium_august">"Aug"</string>
-    <string name="month_medium_september">"Sep"</string>
-    <string name="month_medium_october">"Oct"</string>
-    <string name="month_medium_november">"Nov"</string>
-    <string name="month_medium_december">"Dec"</string>
-    <string name="month_shortest_january">"J"</string>
-    <string name="month_shortest_february">"F"</string>
-    <string name="month_shortest_march">"M"</string>
-    <string name="month_shortest_april">"A"</string>
-    <string name="month_shortest_may">"M"</string>
-    <string name="month_shortest_june">"J"</string>
-    <string name="month_shortest_july">"J"</string>
-    <string name="month_shortest_august">"A"</string>
-    <string name="month_shortest_september">"S"</string>
-    <string name="month_shortest_october">"O"</string>
-    <string name="month_shortest_november">"N"</string>
-    <string name="month_shortest_december">"D"</string>
-    <!-- unknown placeholder FORMAT in elapsed_time_short_format_mm_ss -->
-    <skip />
-    <!-- unknown placeholder FORMAT in elapsed_time_short_format_h_mm_ss -->
-    <skip />
-    <string name="selectAll">"Select all"</string>
-    <string name="cut">"Cut"</string>
-    <string name="cutAll">"Cut all"</string>
-    <string name="copy">"Copy"</string>
-    <string name="copyAll">"Copy all"</string>
-    <string name="paste">"Paste"</string>
-    <string name="copyUrl">"Copy URL"</string>
-    <!-- no translation found for inputMethod (7911866729148111492) -->
-    <skip />
-    <!-- no translation found for editTextMenuTitle (3984253728638788023) -->
-    <skip />
-    <string name="low_internal_storage_view_title">"Low on space"</string>
-    <string name="low_internal_storage_view_text">"Your phone is running low on internal storage space."</string>
-    <string name="ok">"OK"</string>
-    <string name="cancel">"Cancel"</string>
-    <string name="yes">"OK"</string>
-    <string name="no">"Cancel"</string>
-    <string name="capital_on">"ON"</string>
-    <string name="capital_off">"OFF"</string>
-    <string name="whichApplication">"Complete action using"</string>
-    <string name="alwaysUse">"Use by default for this action."</string>
-    <string name="clearDefaultHintMsg">"Clear default in Home Settings &gt; Applications &gt; Manage applications."</string>
-    <string name="chooseActivity">"Select an action"</string>
-    <string name="noApplications">"No applications can perform this action."</string>
-    <string name="aerr_title">"Sorry!"</string>
-    <string name="aerr_application">"The application <xliff:g id="APPLICATION">%1$s</xliff:g> (process <xliff:g id="PROCESS">%2$s</xliff:g>) has stopped unexpectedly. Please try again."</string>
-    <string name="aerr_process">"The process <xliff:g id="PROCESS">%1$s</xliff:g> has stopped unexpectedly. Please try again."</string>
-    <string name="anr_title">"Application unresponsive"</string>
-    <string name="anr_activity_application">"Activity <xliff:g id="ACTIVITY">%1$s</xliff:g> (in application <xliff:g id="APPLICATION">%2$s</xliff:g>) is not responding."</string>
-    <string name="anr_activity_process">"Activity <xliff:g id="ACTIVITY">%1$s</xliff:g> (in process <xliff:g id="PROCESS">%2$s</xliff:g>) is not responding."</string>
-    <string name="anr_application_process">"Application <xliff:g id="APPLICATION">%1$s</xliff:g> (in process <xliff:g id="PROCESS">%2$s</xliff:g>) is not responding."</string>
-    <string name="anr_process">"Process <xliff:g id="PROCESS">%1$s</xliff:g> is not responding."</string>
-    <string name="force_close">"Force close"</string>
-    <string name="wait">"Wait"</string>
-    <string name="debug">"Debug"</string>
-    <string name="sendText">"Select an action for text"</string>
-    <string name="volume_ringtone">"Ringer volume"</string>
-    <string name="volume_music">"Music/video volume"</string>
-    <string name="volume_call">"In-call volume"</string>
-    <string name="volume_alarm">"Alarm volume"</string>
-    <string name="volume_unknown">"Volume"</string>
-    <string name="ringtone_default">"Default ringtone"</string>
-    <string name="ringtone_default_with_actual">"Default ringtone (<xliff:g id="ACTUAL_RINGTONE">%1$s</xliff:g>)"</string>
-    <string name="ringtone_silent">"Silent"</string>
-    <string name="ringtone_picker_title">"Select a ringtone"</string>
-    <string name="ringtone_unknown">"Unknown ringtone"</string>
-    <!-- no translation found for wifi_available:one (8168012881468888470) -->
-    <!-- no translation found for wifi_available:other (4666122955807117718) -->
-    <!-- no translation found for wifi_available_detailed:one (5107769161192143259) -->
-    <!-- no translation found for wifi_available_detailed:other (853347657960575809) -->
-    <string name="select_character">"Select character to insert"</string>
-    <!-- no translation found for sms_control_default_app_name (7522184737840550841) -->
-    <skip />
-    <string name="sms_control_title">"Sending SMS messages"</string>
-    <string name="sms_control_message">"A large number of SMS messages are being sent. Select \"OK\" to continue, or \"Cancel\" to stop sending."</string>
-    <string name="sms_control_yes">"OK"</string>
-    <string name="sms_control_no">"Cancel"</string>
-    <string name="date_time_set">"Set"</string>
-    <string name="default_permission_group">"Default"</string>
-    <string name="no_permissions">"No permissions required"</string>
-    <!-- no translation found for perms_hide (4145325555929151849) -->
-    <skip />
-    <!-- no translation found for perms_show_all (6040194843455403173) -->
-    <skip />
-    <!-- no translation found for googlewebcontenthelper_loading (2140804350507245589) -->
-    <skip />
-    <!-- no translation found for usb_storage_title (8699631567051394409) -->
-    <skip />
-    <!-- no translation found for usb_storage_message (5344039189213308733) -->
-    <skip />
-    <!-- no translation found for usb_storage_button_mount (6700104384375121662) -->
-    <skip />
-    <!-- no translation found for usb_storage_button_unmount (465869657252626688) -->
-    <skip />
-    <!-- no translation found for usb_storage_error_message (3192564550748426087) -->
-    <skip />
-    <!-- no translation found for usb_storage_notification_title (6237028017872246940) -->
-    <skip />
-    <!-- no translation found for usb_storage_notification_message (7371717280517625905) -->
-    <skip />
-    <!-- no translation found for select_input_method (2658280517827502015) -->
-    <skip />
-    <!-- no translation found for fast_scroll_alphabet (1017432309285755759) -->
-    <skip />
-    <!-- no translation found for fast_scroll_numeric_alphabet (3092587363718901074) -->
-    <skip />
-    <!-- no translation found for candidates_style (7738463880139922176) -->
-    <skip />
+    <string name="byteShort">B</string>
 </resources>
diff --git a/core/res/res/values-es/strings.xml b/core/res/res/values-es/strings.xml
index f8881b6f..dc17445 100644
--- a/core/res/res/values-es/strings.xml
+++ b/core/res/res/values-es/strings.xml
@@ -817,6 +817,5 @@
     <skip />
     <!-- no translation found for permdesc_pkgUsageStats (891553695716752835) -->
     <skip />
-    <!-- no translation found for tutorial_double_tap_to_zoom_message (9111326385548696308) -->
     <skip />
 </resources>
diff --git a/core/res/res/values-fr/strings.xml b/core/res/res/values-fr/strings.xml
index 47f1bf4..95e3052 100644
--- a/core/res/res/values-fr/strings.xml
+++ b/core/res/res/values-fr/strings.xml
@@ -817,6 +817,5 @@
     <skip />
     <!-- no translation found for permdesc_pkgUsageStats (891553695716752835) -->
     <skip />
-    <!-- no translation found for tutorial_double_tap_to_zoom_message (9111326385548696308) -->
     <skip />
 </resources>
diff --git a/core/res/res/values-it/strings.xml b/core/res/res/values-it/strings.xml
index 710c493..2cf7b43 100644
--- a/core/res/res/values-it/strings.xml
+++ b/core/res/res/values-it/strings.xml
@@ -817,6 +817,5 @@
     <skip />
     <!-- no translation found for permdesc_pkgUsageStats (891553695716752835) -->
     <skip />
-    <!-- no translation found for tutorial_double_tap_to_zoom_message (9111326385548696308) -->
     <skip />
 </resources>
diff --git a/core/res/res/values-ja/strings.xml b/core/res/res/values-ja/strings.xml
index 0eba7f5..24e3cb6 100644
--- a/core/res/res/values-ja/strings.xml
+++ b/core/res/res/values-ja/strings.xml
@@ -558,12 +558,12 @@
     <!-- no translation found for relative_time (1818557177829411417) -->
     <skip />
     <string name="time_wday">"<xliff:g id="WEEKDAY">%2$s</xliff:g>、<xliff:g id="TIME_RANGE">%1$s</xliff:g>"</string>
-    <string name="full_date_month_first">"<xliff:g id="YEAR">yyyy</xliff:g>\'年\'<xliff:g id="MONTH">MMMM</xliff:g><xliff:g id="DAY">d</xliff:g>\'日\'"</string>
-    <string name="full_date_day_first">"<xliff:g id="YEAR">yyyy</xliff:g>\'年\'<xliff:g id="MONTH">MMMM</xliff:g><xliff:g id="DAY">d</xliff:g>\'日\'"</string>
-    <string name="medium_date_month_first">"<xliff:g id="YEAR">yyyy</xliff:g>\'年\'<xliff:g id="MONTH">MMM</xliff:g><xliff:g id="DAY">d</xliff:g>\'日\'"</string>
-    <string name="medium_date_day_first">"<xliff:g id="YEAR">yyyy</xliff:g>\'年\'<xliff:g id="MONTH">MMM</xliff:g><xliff:g id="DAY">d</xliff:g>\'日\'"</string>
-    <string name="twelve_hour_time_format">"<xliff:g id="HOUR">h</xliff:g>:<xliff:g id="MINUTE">mm</xliff:g> <xliff:g id="AMPM">a</xliff:g>"</string>
-    <string name="twenty_four_hour_time_format">"<xliff:g id="HOUR">H</xliff:g>:<xliff:g id="MINUTE">mm</xliff:g>"</string>
+    <string name="full_date_month_first">"<xliff:g id="YEAR">yyyy</xliff:g>'\'\'年\'\''<xliff:g id="MONTH">MMMM</xliff:g><xliff:g id="DAY">d</xliff:g>'\'\'日\'\''"</string>
+    <string name="full_date_day_first">"<xliff:g id="YEAR">yyyy</xliff:g>'\'\'年\'\''<xliff:g id="MONTH">MMMM</xliff:g><xliff:g id="DAY">d</xliff:g>'\'\'日\'\''"</string>
+    <string name="medium_date_month_first">"<xliff:g id="YEAR">yyyy</xliff:g>'\'\'年\'\''<xliff:g id="MONTH">MMM</xliff:g><xliff:g id="DAY">d</xliff:g>'\'\'日\'\''"</string>
+    <string name="medium_date_day_first">"<xliff:g id="YEAR">yyyy</xliff:g>'\'\'年\'\''<xliff:g id="MONTH">MMM</xliff:g><xliff:g id="DAY">d</xliff:g>'\'\'日\'\''"</string>
+    <string name="twelve_hour_time_format">"<xliff:g id="HOUR">h</xliff:g>':'<xliff:g id="MINUTE">mm</xliff:g>' '<xliff:g id="AMPM">a</xliff:g>"</string>
+    <string name="twenty_four_hour_time_format">"<xliff:g id="HOUR">H</xliff:g>':'<xliff:g id="MINUTE">mm</xliff:g>"</string>
     <string name="noon">"正午"</string>
     <string name="Noon">"正午"</string>
     <string name="midnight">"午前0時"</string>
@@ -573,7 +573,8 @@
     <!-- no translation found for month (7026169712234774086) -->
     <skip />
     <string name="month_day_year">"<xliff:g id="YEAR">%Y</xliff:g>年<xliff:g id="MONTH">%B</xliff:g><xliff:g id="DAY">%-d</xliff:g>日"</string>
-    <string name="month_year">"<xliff:g id="YEAR">%Y</xliff:g>年 <xliff:g id="MONTH">%B</xliff:g>"</string>
+    <!-- no translation found for month_year (9219019380312413367) -->
+    <skip />
     <string name="time_of_day">"<xliff:g id="HOUR">%H</xliff:g>:<xliff:g id="MINUTE">%M</xliff:g>:<xliff:g id="SECOND">%S</xliff:g>"</string>
     <string name="date_and_time">"<xliff:g id="YEAR">%Y</xliff:g>年<xliff:g id="MONTH">%B</xliff:g><xliff:g id="DAY">%-d</xliff:g>日<xliff:g id="HOUR">%H</xliff:g>:<xliff:g id="MINUTE">%M</xliff:g>:<xliff:g id="SECOND">%S</xliff:g>"</string>
     <string name="same_year_md1_md2">"<xliff:g id="MONTH1">%2$s</xliff:g><xliff:g id="DAY1">%3$s</xliff:g>日~<xliff:g id="MONTH2">%7$s</xliff:g><xliff:g id="DAY2">%8$s</xliff:g>日"</string>
@@ -816,6 +817,5 @@
     <skip />
     <!-- no translation found for permdesc_pkgUsageStats (891553695716752835) -->
     <skip />
-    <!-- no translation found for tutorial_double_tap_to_zoom_message (9111326385548696308) -->
     <skip />
 </resources>
diff --git a/core/res/res/values-ko/strings.xml b/core/res/res/values-ko/strings.xml
index 4272684f..140f32f1 100644
--- a/core/res/res/values-ko/strings.xml
+++ b/core/res/res/values-ko/strings.xml
@@ -817,6 +817,5 @@
     <skip />
     <!-- no translation found for permdesc_pkgUsageStats (891553695716752835) -->
     <skip />
-    <!-- no translation found for tutorial_double_tap_to_zoom_message (9111326385548696308) -->
     <skip />
 </resources>
diff --git a/core/res/res/values-nb/strings.xml b/core/res/res/values-nb/strings.xml
index 9f49557..466f2b1 100644
--- a/core/res/res/values-nb/strings.xml
+++ b/core/res/res/values-nb/strings.xml
@@ -262,10 +262,8 @@
     <string name="permdesc_reboot">"Lar applikasjonen tvinge telefonen til å starte på nytt."</string>
     <string name="permlab_mount_unmount_filesystems">"montere og avmontere filsystemer"</string>
     <string name="permdesc_mount_unmount_filesystems">"Lar applikasjonen montere og avmontere filsystemer for uttagbar lagring."</string>
-    <!-- no translation found for permlab_mount_format_filesystems (5523285143576718981) -->
-    <skip />
-    <!-- no translation found for permdesc_mount_format_filesystems (574060044906047386) -->
-    <skip />
+    <string name="permlab_mount_format_filesystems">"formatere ekstern lagringsplass"</string>
+    <string name="permdesc_mount_format_filesystems">"Lar applikasjonen formatere ekstern lagringsplass."</string>
     <string name="permlab_vibrate">"kontrollere vibratoren"</string>
     <string name="permdesc_vibrate">"Lar applikasjonen kontrollere vibratoren."</string>
     <string name="permlab_flashlight">"kontrollere lommelykten"</string>
@@ -280,10 +278,8 @@
     <string name="permdesc_locationUpdates">"Lar applikasjonen slå av/på varsling om plasseringsendringer fra radioen. Ikke ment for vanlige applikasjoner."</string>
     <string name="permlab_checkinProperties">"få tilgang til egenskaper for innsjekking"</string>
     <string name="permdesc_checkinProperties">"Gir lese- og skrivetilgang til egenskaper lastet opp av innsjekkingstjenesten. Ikke ment for vanlige applikasjoner."</string>
-    <!-- no translation found for permlab_bindGadget (2519859363977647275) -->
-    <skip />
-    <!-- no translation found for permdesc_bindGadget (7865866514555126333) -->
-    <skip />
+    <string name="permlab_bindGadget">"velg gadgeter"</string>
+    <string name="permdesc_bindGadget">"Lar applikasjonen fortelle systemet hvilke gadgeter som kan brukes av hvilke applikasjoner. Med denne rettigheten kan applikasjoner andre applikasjoner tilgang til personlig data. Ikke ment for vanlige applikasjoner."</string>
     <string name="permlab_modifyPhoneState">"endre telefontilstand"</string>
     <string name="permdesc_modifyPhoneState">"Lar applikasjonen kontrollere telefonfunksjonaliteten i enheten. En applikasjon med denne rettigheten kan endre nettverk, slå telefonens radio av eller på og lignende uten noensinne å varsle brukeren."</string>
     <string name="permlab_readPhoneState">"lese telefontilstand"</string>
@@ -312,10 +308,8 @@
     <string name="permdesc_writeApnSettings">"Lar applikasjonen to endre APN-innstillinger slik som mellomtjener eller port for hvilket som helst aksesspunkt."</string>
     <string name="permlab_changeNetworkState">"endre nettverkskonnektivitet"</string>
     <string name="permdesc_changeNetworkState">"Lar applikasjonen endre tilstanden til nettverkskonnektivitet."</string>
-    <!-- no translation found for permlab_changeBackgroundDataSetting (1400666012671648741) -->
-    <skip />
-    <!-- no translation found for permdesc_changeBackgroundDataSetting (1001482853266638864) -->
-    <skip />
+    <string name="permlab_changeBackgroundDataSetting">"endre innstilling for bakgrunnsdata"</string>
+    <string name="permdesc_changeBackgroundDataSetting">"Lar applikasjonen endre innstillingen for bakgrunnsdata."</string>
     <string name="permlab_accessWifiState">"se tilstand for trådløse nettverk"</string>
     <string name="permdesc_accessWifiState">"Lar applikasjonen få se informasjon om tilstanden til de trådløse nettene."</string>
     <string name="permlab_changeWifiState">"endre tilstand for trådløse nettverk"</string>
@@ -336,14 +330,10 @@
     <string name="permdesc_subscribedFeedsRead">"Lar applikasjonen hente detaljer om hvilke nyhetskilder som synkroniseres."</string>
     <string name="permlab_subscribedFeedsWrite">"endre abonnement på nyhetskilder"</string>
     <string name="permdesc_subscribedFeedsWrite">"Lar applikasjonen redigere hvilke nyhetskilder som synkroniseres. Dette kan gi en ondsinnet applikasjon tilgang til å endre hvilke nyhetskilder som synkroniseres."</string>
-    <!-- no translation found for permlab_readDictionary (432535716804748781) -->
-    <skip />
-    <!-- no translation found for permdesc_readDictionary (1082972603576360690) -->
-    <skip />
-    <!-- no translation found for permlab_writeDictionary (6703109511836343341) -->
-    <skip />
-    <!-- no translation found for permdesc_writeDictionary (2241256206524082880) -->
-    <skip />
+    <string name="permlab_readDictionary">"lese brukerdefinert ordliste"</string>
+    <string name="permdesc_readDictionary">"Lar applikasjonen lese private ord, navn og uttrykk som brukeren har lagret i den brukerdefinerte ordlisten."</string>
+    <string name="permlab_writeDictionary">"skrive til brukerdefinert ordliste"</string>
+    <string name="permdesc_writeDictionary">"Lar applikasjonen skrive nye ord til den brukerdefinerte ordlisten."</string>
   <string-array name="phoneTypes">
     <item>"Hjemme"</item>
     <item>"Mobil"</item>
@@ -440,12 +430,9 @@
     <string name="factorytest_not_system">"The FACTORY_TEST action is only supported for packages installed in /system/app."</string>
     <string name="factorytest_no_action">"No package was found that provides the FACTORY_TEST action."</string>
     <string name="factorytest_reboot">"Reboot"</string>
-    <!-- no translation found for js_dialog_title (8143918455087008109) -->
-    <skip />
-    <!-- no translation found for js_dialog_title_default (6961903213729667573) -->
-    <skip />
-    <!-- no translation found for js_dialog_before_unload (1901675448179653089) -->
-    <skip />
+    <string name="js_dialog_title">"Siden \\\'<xliff:g id="TITLE">%s</xliff:g>\\\' sier:"</string>
+    <string name="js_dialog_title_default">"JavaScript"</string>
+    <string name="js_dialog_before_unload">"Naviger bort fra denne siden?"\n\n"<xliff:g id="MESSAGE">%s</xliff:g>"\n\n"Velg OK for å fortsette, eller Avbryt for å forbli på denne siden."</string>
     <string name="save_password_label">"Bekreft"</string>
     <string name="save_password_message">"Ønsker du at nettleseren skal huske dette passordet?"</string>
     <string name="save_password_notnow">"Ikke nå"</string>
@@ -569,17 +556,15 @@
     <string name="time_wday_date">"<xliff:g id="TIME_RANGE">%1$s</xliff:g>, <xliff:g id="WEEKDAY">%2$s</xliff:g> <xliff:g id="DATE">%3$s</xliff:g>"</string>
     <string name="wday_date">"<xliff:g id="WEEKDAY">%2$s</xliff:g> <xliff:g id="DATE">%3$s</xliff:g>"</string>
     <string name="time_date">"<xliff:g id="TIME_RANGE">%1$s</xliff:g>, <xliff:g id="DATE">%3$s</xliff:g>"</string>
-    <!-- no translation found for date_time (6104442718633642836) -->
-    <skip />
-    <!-- no translation found for relative_time (1818557177829411417) -->
-    <skip />
+    <string name="date_time">"<xliff:g id="DATE">%1$s</xliff:g>, <xliff:g id="TIME">%2$s</xliff:g>"</string>
+    <string name="relative_time">"<xliff:g id="DATE">%1$s</xliff:g>, <xliff:g id="TIME">%2$s</xliff:g>"</string>
     <string name="time_wday">"<xliff:g id="TIME_RANGE">%1$s</xliff:g>, <xliff:g id="WEEKDAY">%2$s</xliff:g>"</string>
-    <string name="full_date_month_first">"<xliff:g id="MONTH">MMMM</xliff:g>' '<xliff:g id="DAY">d</xliff:g>'., '<xliff:g id="YEAR">yyyy</xliff:g>"</string>
-    <string name="full_date_day_first">"<xliff:g id="DAY">d</xliff:g>'. '<xliff:g id="MONTH">MMMM</xliff:g>' '<xliff:g id="YEAR">yyyy</xliff:g>"</string>
-    <string name="medium_date_month_first">"<xliff:g id="MONTH">MMM</xliff:g>' '<xliff:g id="DAY">d</xliff:g>', '<xliff:g id="YEAR">yyyy</xliff:g>"</string>
-    <string name="medium_date_day_first">"<xliff:g id="DAY">d</xliff:g>'. '<xliff:g id="MONTH">MMM</xliff:g>' '<xliff:g id="YEAR">yyyy</xliff:g>"</string>
-    <string name="twelve_hour_time_format">"<xliff:g id="HOUR">h</xliff:g>':'<xliff:g id="MINUTE">mm</xliff:g>' '<xliff:g id="AMPM">a</xliff:g>"</string>
-    <string name="twenty_four_hour_time_format">"<xliff:g id="HOUR">H</xliff:g>':'<xliff:g id="MINUTE">mm</xliff:g>"</string>
+    <string name="full_date_month_first">"<xliff:g id="MONTH">MMMM</xliff:g>'\\\'\'\\\'\' \\\'\'\\\'\''<xliff:g id="DAY">d</xliff:g>'\\\'\'\\\'\'., \\\'\'\\\'\''<xliff:g id="YEAR">yyyy</xliff:g>"</string>
+    <string name="full_date_day_first">"<xliff:g id="DAY">d</xliff:g>'\\\'\'\\\'\'. \\\'\'\\\'\''<xliff:g id="MONTH">MMMM</xliff:g>'\\\'\'\\\'\' \\\'\'\\\'\''<xliff:g id="YEAR">yyyy</xliff:g>"</string>
+    <string name="medium_date_month_first">"<xliff:g id="MONTH">MMM</xliff:g>'\\\'\'\\\'\' \\\'\'\\\'\''<xliff:g id="DAY">d</xliff:g>'\\\'\'\\\'\', \\\'\'\\\'\''<xliff:g id="YEAR">yyyy</xliff:g>"</string>
+    <string name="medium_date_day_first">"<xliff:g id="DAY">d</xliff:g>'\\\'\'\\\'\'. \\\'\'\\\'\''<xliff:g id="MONTH">MMM</xliff:g>'\\\'\'\\\'\' \\\'\'\\\'\''<xliff:g id="YEAR">yyyy</xliff:g>"</string>
+    <string name="twelve_hour_time_format">"<xliff:g id="HOUR">h</xliff:g>'\\\'\'\\\'\':\\\'\'\\\'\''<xliff:g id="MINUTE">mm</xliff:g>'\\\'\'\\\'\' \\\'\'\\\'\''<xliff:g id="AMPM">a</xliff:g>"</string>
+    <string name="twenty_four_hour_time_format">"<xliff:g id="HOUR">H</xliff:g>'\\\'\'\\\'\':\\\'\'\\\'\''<xliff:g id="MINUTE">mm</xliff:g>"</string>
     <string name="noon">"middag"</string>
     <string name="Noon">"Middag"</string>
     <string name="midnight">"midnatt"</string>
@@ -596,18 +581,14 @@
     <string name="same_year_md1_md2">"<xliff:g id="MONTH1">%2$s</xliff:g> <xliff:g id="DAY1">%3$s</xliff:g> – <xliff:g id="MONTH2">%7$s</xliff:g> <xliff:g id="DAY2">%8$s</xliff:g>"</string>
     <string name="same_year_wday1_md1_wday2_md2">"<xliff:g id="WEEKDAY1">%1$s</xliff:g> <xliff:g id="DAY1_0">%3$s</xliff:g>. <xliff:g id="MONTH1">%2$s</xliff:g> – <xliff:g id="WEEKDAY2">%6$s</xliff:g> <xliff:g id="DAY2_1">%8$s</xliff:g>. <xliff:g id="MONTH2">%7$s</xliff:g>"</string>
     <string name="same_year_mdy1_mdy2">"<xliff:g id="DAY1">%3$s</xliff:g>. <xliff:g id="MONTH1">%2$s</xliff:g> – <xliff:g id="DAY2">%8$s</xliff:g>. <xliff:g id="MONTH2">%7$s</xliff:g> <xliff:g id="YEAR">%9$s</xliff:g>"</string>
-    <!-- no translation found for same_year_wday1_mdy1_wday2_mdy2 (1345612987720788874) -->
-    <skip />
+    <string name="same_year_wday1_mdy1_wday2_mdy2">"<xliff:g id="WEEKDAY1">%1$s</xliff:g> <xliff:g id="MONTH1">%2$s</xliff:g> <xliff:g id="DAY1_0">%3$s</xliff:g> – <xliff:g id="WEEKDAY2">%6$s</xliff:g> <xliff:g id="MONTH2">%7$s</xliff:g> <xliff:g id="DAY2_1">%8$s</xliff:g>, <xliff:g id="YEAR">%9$s</xliff:g>"</string>
     <string name="same_year_md1_time1_md2_time2">"<xliff:g id="DAY1">%3$s</xliff:g>. <xliff:g id="MONTH1">%2$s</xliff:g> <xliff:g id="TIME1">%5$s</xliff:g> – <xliff:g id="DAY2">%8$s</xliff:g>. <xliff:g id="MONTH2">%7$s</xliff:g> <xliff:g id="TIME2">%10$s</xliff:g>"</string>
     <string name="same_year_wday1_md1_time1_wday2_md2_time2">"<xliff:g id="WEEKDAY1">%1$s</xliff:g> <xliff:g id="DAY1_0">%3$s</xliff:g>. <xliff:g id="MONTH1">%2$s</xliff:g> <xliff:g id="TIME1">%5$s</xliff:g> – <xliff:g id="WEEKDAY2">%6$s</xliff:g> <xliff:g id="DAY2_1">%8$s</xliff:g>. <xliff:g id="MONTH2">%7$s</xliff:g> <xliff:g id="TIME2">%10$s</xliff:g>"</string>
-    <!-- no translation found for same_year_mdy1_time1_mdy2_time2 (2959466512848524124) -->
-    <skip />
-    <!-- no translation found for same_year_wday1_mdy1_time1_wday2_mdy2_time2 (5129735426508861428) -->
-    <skip />
+    <string name="same_year_mdy1_time1_mdy2_time2">"<xliff:g id="DAY1">%3$s</xliff:g>. <xliff:g id="MONTH1">%2$s</xliff:g> <xliff:g id="YEAR1">%4$s</xliff:g> <xliff:g id="TIME1">%5$s</xliff:g> – <xliff:g id="DAY2">%8$s</xliff:g>. <xliff:g id="MONTH2">%7$s</xliff:g> <xliff:g id="YEAR2">%9$s</xliff:g> <xliff:g id="TIME2">%10$s</xliff:g>"</string>
+    <string name="same_year_wday1_mdy1_time1_wday2_mdy2_time2">"<xliff:g id="WEEKDAY1">%1$s</xliff:g> <xliff:g id="DAY1_0">%3$s</xliff:g>. <xliff:g id="MONTH1">%2$s</xliff:g> <xliff:g id="YEAR1">%4$s</xliff:g> <xliff:g id="TIME1">%5$s</xliff:g> – <xliff:g id="WEEKDAY2">%6$s</xliff:g> <xliff:g id="DAY2_1">%8$s</xliff:g>. <xliff:g id="MONTH2">%7$s</xliff:g> <xliff:g id="YEAR2">%9$s</xliff:g> <xliff:g id="TIME2">%10$s</xliff:g>"</string>
     <string name="numeric_md1_md2">"<xliff:g id="DAY1">%3$s</xliff:g>.<xliff:g id="MONTH1">%2$s</xliff:g>. – <xliff:g id="DAY2">%8$s</xliff:g>.<xliff:g id="MONTH2">%7$s</xliff:g>."</string>
     <string name="numeric_wday1_md1_wday2_md2">"<xliff:g id="WEEKDAY1">%1$s</xliff:g> <xliff:g id="DAY1_0">%3$s</xliff:g>.<xliff:g id="MONTH1">%2$s</xliff:g>. – <xliff:g id="WEEKDAY2">%6$s</xliff:g> <xliff:g id="DAY2_1">%8$s</xliff:g>.<xliff:g id="MONTH2">%7$s</xliff:g>."</string>
-    <!-- no translation found for numeric_mdy1_mdy2 (3933951218078638018) -->
-    <skip />
+    <string name="numeric_mdy1_mdy2">"<xliff:g id="DAY1">%3$s</xliff:g>.<xliff:g id="MONTH1">%2$s</xliff:g>.<xliff:g id="YEAR1">%4$s</xliff:g> – <xliff:g id="DAY2">%8$s</xliff:g>.<xliff:g id="MONTH2">%7$s</xliff:g>.<xliff:g id="YEAR2">%9$s</xliff:g>"</string>
     <string name="numeric_wday1_mdy1_wday2_mdy2">"<xliff:g id="WEEKDAY1">%1$s</xliff:g> <xliff:g id="DAY1_0">%3$s</xliff:g>.<xliff:g id="MONTH1">%2$s</xliff:g>.<xliff:g id="YEAR1">%4$s</xliff:g> – <xliff:g id="WEEKDAY2">%6$s</xliff:g> <xliff:g id="DAY2_1">%8$s</xliff:g>.<xliff:g id="MONTH2">%7$s</xliff:g>.<xliff:g id="YEAR2">%9$s</xliff:g>"</string>
     <string name="numeric_md1_time1_md2_time2">"<xliff:g id="DAY1">%3$s</xliff:g>.<xliff:g id="MONTH1">%2$s</xliff:g>. <xliff:g id="TIME1">%5$s</xliff:g> – <xliff:g id="DAY2">%8$s</xliff:g>.<xliff:g id="MONTH2">%7$s</xliff:g>. <xliff:g id="TIME2">%10$s</xliff:g>"</string>
     <string name="numeric_wday1_md1_time1_wday2_md2_time2">"<xliff:g id="WEEKDAY1">%1$s</xliff:g> <xliff:g id="DAY1_0">%3$s</xliff:g>.<xliff:g id="MONTH1">%2$s</xliff:g>. <xliff:g id="TIME1">%5$s</xliff:g> – <xliff:g id="WEEKDAY2">%6$s</xliff:g> <xliff:g id="DAY2_1">%8$s</xliff:g>.<xliff:g id="MONTH2">%7$s</xliff:g>. <xliff:g id="TIME2">%10$s</xliff:g>"</string>
@@ -711,8 +692,7 @@
     <string name="paste">"Lim inn"</string>
     <string name="copyUrl">"Kopier URL"</string>
     <string name="inputMethod">"Inndatametode"</string>
-    <!-- no translation found for addToDictionary (726256909274177272) -->
-    <skip />
+    <string name="addToDictionary">"Legg \\\"%s\\\" til ordlisten"</string>
     <string name="editTextMenuTitle">"Rediger tekst"</string>
     <string name="low_internal_storage_view_title">"Lite plass"</string>
     <string name="low_internal_storage_view_text">"Det begynner å bli lite lagringsplass på telefonen."</string>
@@ -720,8 +700,7 @@
     <string name="cancel">"Avbryt"</string>
     <string name="yes">"OK"</string>
     <string name="no">"Avbryt"</string>
-    <!-- no translation found for dialog_alert_title (2049658708609043103) -->
-    <skip />
+    <string name="dialog_alert_title">"Merk"</string>
     <string name="capital_on">"På"</string>
     <string name="capital_off">"Av"</string>
     <string name="whichApplication">"Complete action using"</string>
@@ -745,8 +724,7 @@
     <string name="volume_music">"Medievolum"</string>
     <string name="volume_music_hint_playing_through_bluetooth">"Spiller over Bluetooth"</string>
     <string name="volume_call">"Samtalevolum"</string>
-    <!-- no translation found for volume_bluetooth_call (2002891926351151534) -->
-    <skip />
+    <string name="volume_bluetooth_call">"Bluetooth-samtalevolum"</string>
     <string name="volume_alarm">"Alarmvolum"</string>
     <string name="volume_notification">"Varslingsvolum"</string>
     <string name="volume_unknown">"Volum"</string>
@@ -766,7 +744,7 @@
     <string name="select_character">"Sett inn tegn"</string>
     <string name="sms_control_default_app_name">"Ukjent applikasjon"</string>
     <string name="sms_control_title">"Sending SMS messages"</string>
-    <string name="sms_control_message">"A large number of SMS messages are being sent. Select \\\"OK\\\" to continue, or \\\"Cancel\\\" to stop sending."</string>
+    <string name="sms_control_message">"A large number of SMS messages are being sent. Select \\\\\\\"OK\\\\\\\" to continue, or \\\\\\\"Cancel\\\\\\\" to stop sending."</string>
     <string name="sms_control_yes">"OK"</string>
     <string name="sms_control_no">"Avbryt"</string>
     <string name="date_time_set">"Lagre"</string>
@@ -776,67 +754,39 @@
     <string name="perms_show_all"><b>"Vis alle"</b></string>
     <string name="googlewebcontenthelper_loading">"Laster inn…"</string>
     <string name="usb_storage_title">"USB koblet til"</string>
-    <string name="usb_storage_message">"Du har koblet telefonen til en datamaskin via USB. Velg \\\"Monter\\\" dersom du ønsker å kopiere filer mellom datmaskinen og minnekortet i telefonen."</string>
+    <string name="usb_storage_message">"Du har koblet telefonen til en datamaskin via USB. Velg \\\\\\\"Monter\\\\\\\" dersom du ønsker å kopiere filer mellom datmaskinen og minnekortet i telefonen."</string>
     <string name="usb_storage_button_mount">"Monter"</string>
     <string name="usb_storage_button_unmount">"Ikke monter"</string>
     <string name="usb_storage_error_message">"Det oppsto et problem med å bruke minnekortet ditt for USB-lagring."</string>
     <string name="usb_storage_notification_title">"USB tilkoblet"</string>
     <string name="usb_storage_notification_message">"Velg om du ønsker å kopiere filer til/fra en datamaskin."</string>
-    <!-- no translation found for usb_storage_stop_notification_title (2336058396663516017) -->
-    <skip />
-    <!-- no translation found for usb_storage_stop_notification_message (2591813490269841539) -->
-    <skip />
-    <!-- no translation found for usb_storage_stop_title (6014127947456185321) -->
-    <skip />
-    <!-- no translation found for usb_storage_stop_message (2390958966725232848) -->
-    <skip />
-    <!-- no translation found for usb_storage_stop_button_mount (1181858854166273345) -->
-    <skip />
-    <!-- no translation found for usb_storage_stop_button_unmount (3774611918660582898) -->
-    <skip />
-    <!-- no translation found for usb_storage_stop_error_message (3917317248440072084) -->
-    <skip />
-    <!-- no translation found for extmedia_format_title (8663247929551095854) -->
-    <skip />
-    <!-- no translation found for extmedia_format_message (3621369962433523619) -->
-    <skip />
-    <!-- no translation found for extmedia_format_button_format (4131064560127478695) -->
-    <skip />
+    <string name="usb_storage_stop_notification_title">"Slå av USB-lagring"</string>
+    <string name="usb_storage_stop_notification_message">"Velg for å slå av USB-lagring."</string>
+    <string name="usb_storage_stop_title">"Slå av USB-lagring"</string>
+    <string name="usb_storage_stop_message">"Før du slår av USB-lagring, sjekk at du har avmontert enheten i USB-verten. Velg «slå av» for å slå av USB-lagring."</string>
+    <string name="usb_storage_stop_button_mount">"Slå av"</string>
+    <string name="usb_storage_stop_button_unmount">"Avbryt"</string>
+    <string name="usb_storage_stop_error_message">"Det oppsto et problem under avslutningen av USB-lagring. Sjekk at USB-verten har avmontert og prøv igjen."</string>
+    <string name="extmedia_format_title">"Formatere minnekort"</string>
+    <string name="extmedia_format_message">"Er du sikker på at du ønsker å formatere minnekortet? Alle data på kortet vil gå tapt."</string>
+    <string name="extmedia_format_button_format">"Format"</string>
     <string name="select_input_method">"Velg inndatametode"</string>
     <string name="fast_scroll_alphabet">"ABCDEFGHIJKLMNOPQRSTUVWXYZÆØÅ"</string>
     <string name="fast_scroll_numeric_alphabet">"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZÆØÅ"</string>
-    <!-- unknown quoting pattern: original -1, translation 1 -->
-    <string name="candidates_style">"TAG_FONT"<u>"kandidater"</u>"u&amp;gt;CLOSE_FONT"</string>
-    <!-- no translation found for ext_media_checking_notification_title (5457603418970994050) -->
-    <skip />
-    <!-- no translation found for ext_media_checking_notification_message (4747432538578886744) -->
-    <skip />
-    <!-- no translation found for ext_media_nofs_notification_title (780477838241212997) -->
-    <skip />
-    <!-- no translation found for ext_media_nofs_notification_message (1312266820092958014) -->
-    <skip />
-    <!-- no translation found for ext_media_unmountable_notification_title (6410723906019100189) -->
-    <skip />
-    <!-- no translation found for ext_media_unmountable_notification_message (2679412884290061775) -->
-    <skip />
-    <!-- no translation found for ext_media_badremoval_notification_title (6872152882604407837) -->
-    <skip />
-    <!-- no translation found for ext_media_badremoval_notification_message (7260183293747448241) -->
-    <skip />
-    <!-- no translation found for ext_media_safe_unmount_notification_title (6729801130790616200) -->
-    <skip />
-    <!-- no translation found for ext_media_safe_unmount_notification_message (7613960686747592770) -->
-    <skip />
-    <!-- no translation found for ext_media_nomedia_notification_title (8902518030404381318) -->
-    <skip />
-    <!-- no translation found for ext_media_nomedia_notification_message (4205117227342822275) -->
-    <skip />
-    <!-- no translation found for activity_list_empty (4168820609403385789) -->
-    <skip />
-    <!-- no translation found for permlab_pkgUsageStats (8787352074326748892) -->
-    <skip />
-    <!-- no translation found for permdesc_pkgUsageStats (891553695716752835) -->
-    <skip />
-    <!-- no translation found for tutorial_double_tap_to_zoom_message (9111326385548696308) -->
-    <skip />
+    <string name="candidates_style">"TAG_FONT"<u>"kandidater"</u>"CLOSE_FONT"</string>
+    <string name="ext_media_checking_notification_title">"Forbereder minnekort"</string>
+    <string name="ext_media_checking_notification_message">"Sjekker for feil"</string>
+    <string name="ext_media_nofs_notification_title">"Tomt minnekort"</string>
+    <string name="ext_media_nofs_notification_message">"Minnekortet er tomt eller bruker et ustøttet filsystem."</string>
+    <string name="ext_media_unmountable_notification_title">"Skadet minnekort"</string>
+    <string name="ext_media_unmountable_notification_message">"Minnekortet er skadet. Det kan være du må formatere kortet."</string>
+    <string name="ext_media_badremoval_notification_title">"Minnekortet ble tatt ut uventet"</string>
+    <string name="ext_media_badremoval_notification_message">"Avmonter minnekortet før det tas ut, for å unngå datatap."</string>
+    <string name="ext_media_safe_unmount_notification_title">"Trygt å ta ut minnekort"</string>
+    <string name="ext_media_safe_unmount_notification_message">"Minnekortet kan nå trygt tas ut."</string>
+    <string name="ext_media_nomedia_notification_title">"Minnekortet ble tatt ut"</string>
+    <string name="ext_media_nomedia_notification_message">"Minnekortet ble tatt ut. Sett inn et nytt minnekort for å øke lagringsplassen."</string>
+    <string name="activity_list_empty">"Fant ingen tilsvarende aktiviteter"</string>
+    <string name="permlab_pkgUsageStats">"oppdater statistikk over komponentbruk"</string>
+    <string name="permdesc_pkgUsageStats">"Tillater endring av innsamlet data om bruk av komponenter. Ikke ment for vanlige applikasjoner."</string>
 </resources>
diff --git a/core/res/res/values-nl/strings.xml b/core/res/res/values-nl/strings.xml
index 7ce4c66..a2810a1 100644
--- a/core/res/res/values-nl/strings.xml
+++ b/core/res/res/values-nl/strings.xml
@@ -817,6 +817,5 @@
     <skip />
     <!-- no translation found for permdesc_pkgUsageStats (891553695716752835) -->
     <skip />
-    <!-- no translation found for tutorial_double_tap_to_zoom_message (9111326385548696308) -->
     <skip />
 </resources>
diff --git a/core/res/res/values-pl/strings.xml b/core/res/res/values-pl/strings.xml
index 03c4f8b..12f1616 100644
--- a/core/res/res/values-pl/strings.xml
+++ b/core/res/res/values-pl/strings.xml
@@ -817,6 +817,5 @@
     <skip />
     <!-- no translation found for permdesc_pkgUsageStats (891553695716752835) -->
     <skip />
-    <!-- no translation found for tutorial_double_tap_to_zoom_message (9111326385548696308) -->
     <skip />
 </resources>
diff --git a/core/res/res/values-ru/strings.xml b/core/res/res/values-ru/strings.xml
index d25ab8d..76a358d 100644
--- a/core/res/res/values-ru/strings.xml
+++ b/core/res/res/values-ru/strings.xml
@@ -817,6 +817,5 @@
     <skip />
     <!-- no translation found for permdesc_pkgUsageStats (891553695716752835) -->
     <skip />
-    <!-- no translation found for tutorial_double_tap_to_zoom_message (9111326385548696308) -->
     <skip />
 </resources>
diff --git a/core/res/res/values-zh-rCN/strings.xml b/core/res/res/values-zh-rCN/strings.xml
index 447fccd..13d4e9c 100644
--- a/core/res/res/values-zh-rCN/strings.xml
+++ b/core/res/res/values-zh-rCN/strings.xml
@@ -817,6 +817,5 @@
     <skip />
     <!-- no translation found for permdesc_pkgUsageStats (891553695716752835) -->
     <skip />
-    <!-- no translation found for tutorial_double_tap_to_zoom_message (9111326385548696308) -->
     <skip />
 </resources>
diff --git a/core/res/res/values-zh-rTW/strings.xml b/core/res/res/values-zh-rTW/strings.xml
index e97c142..419e8c2 100644
--- a/core/res/res/values-zh-rTW/strings.xml
+++ b/core/res/res/values-zh-rTW/strings.xml
@@ -817,6 +817,5 @@
     <skip />
     <!-- no translation found for permdesc_pkgUsageStats (891553695716752835) -->
     <skip />
-    <!-- no translation found for tutorial_double_tap_to_zoom_message (9111326385548696308) -->
     <skip />
 </resources>
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index 3f21303..593d1ff 100644
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -1056,6 +1056,10 @@
              enabled for events such as clicking and touching. -->
         <attr name="soundEffectsEnabled" format="boolean" />
 
+        <!-- Boolean that controls whether a view should have haptic feedback
+             enabled for events such as long presses. -->
+        <attr name="hapticFeedbackEnabled" format="boolean" />
+
     </declare-styleable>
 
     <!-- Attributes that can be used with a {@link android.view.ViewGroup} or any
@@ -2035,8 +2039,18 @@
             <enum name="line" value="2" />
             <enum name="ring" value="3" />
         </attr>
+        <!-- Inner radius of the ring expressed as a ratio of the ring's width. For instance,
+             if innerRadiusRatio=9, then the inner radius equals the ring's width divided by 9.
+             This value is ignored if innerRadius is defined. Default value is 9. -->
         <attr name="innerRadiusRatio" format="float" />
+        <!-- Thickness of the ring expressed as a ratio of the ring's width. For instance,
+             if thicknessRatio=3, then the thickness equals the ring's width divided by 3.
+             This value is ignored if innerRadius is defined. Default value is 3. -->
         <attr name="thicknessRatio" format="float" />
+        <!-- Inner radius of the ring. When defined, innerRadiusRatio is ignored. -->
+        <attr name="innerRadius" format="dimension" />
+        <!-- Thickness of the ring. When defined, thicknessRatio is ignored. -->
+        <attr name="thickness" format="dimension" />
         <attr name="useLevel" />
     </declare-styleable>
     
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index 1031585..9175f31 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -1001,6 +1001,9 @@
   <public type="attr" name="content" id="0x0101025b" />
   <public type="attr" name="animateOnClick" id="0x0101025c" />
   <public type="attr" name="configure" id="0x0101025d" />
+  <public type="attr" name="hapticFeedbackEnabled" id="0x0101025e" />
+  <public type="attr" name="innerRadius" id="0x0101025f" />
+  <public type="attr" name="thickness" id="0x01010260" />
 
   <!-- The part of the UI shown by an
        {@link android.inputmethodservice.InputMethodService} that contains the
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 4700b93..1174996 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -2263,8 +2263,7 @@
     <string name="permdesc_pkgUsageStats">Allows the modification of collected component usage statistics. Not for use by normal applications.</string>
 
     <!-- Shown in the tutorial for double tap to zoom. -->
-    <string name="tutorial_double_tap_to_zoom_message">Congratulations on downloading the Android software update.  This update includes a number of great new features for you to enjoy.  One major improvement we've made is to how you zoom.  Now, when you want to zoom, just double tap on the screen.  This will bring up a zoom widget.  Drag the widget's handle clockwise to zoom in, and counter-clockwise to zoom out.</string>
-
+    <string name="tutorial_double_tap_to_zoom_message_short">Double tap to zoom</string>
 </resources>
 
 
diff --git a/graphics/java/android/graphics/drawable/GradientDrawable.java b/graphics/java/android/graphics/drawable/GradientDrawable.java
index 82cb795..3db45f0 100644
--- a/graphics/java/android/graphics/drawable/GradientDrawable.java
+++ b/graphics/java/android/graphics/drawable/GradientDrawable.java
@@ -47,7 +47,9 @@
  * @attr ref android.R.styleable#GradientDrawable_visible
  * @attr ref android.R.styleable#GradientDrawable_shape
  * @attr ref android.R.styleable#GradientDrawable_innerRadiusRatio
+ * @attr ref android.R.styleable#GradientDrawable_innerRadius
  * @attr ref android.R.styleable#GradientDrawable_thicknessRatio
+ * @attr ref android.R.styleable#GradientDrawable_thickness
  * @attr ref android.R.styleable#GradientDrawable_useLevel
  * @attr ref android.R.styleable#GradientDrawableSize_width
  * @attr ref android.R.styleable#GradientDrawableSize_height
@@ -121,6 +123,8 @@
     private Paint mLayerPaint;    // internal, used if we use saveLayer()
     private boolean mRectIsDirty;   // internal state
     private boolean mMutated;
+    private Path mRingPath;
+    private boolean mPathIsDirty;
 
     /**
      * Controls how the gradient is oriented relative to the drawable's bounds
@@ -213,6 +217,7 @@
     }
     
     public void setShape(int shape) {
+        mRingPath = null;
         mGradientState.setShape(shape);
     }
 
@@ -248,14 +253,12 @@
         // remember the alpha values, in case we temporarily overwrite them
         // when we modulate them with mAlpha
         final int prevFillAlpha = mFillPaint.getAlpha();
-        final int prevStrokeAlpha = mStrokePaint != null ?
-                                        mStrokePaint.getAlpha() : 0;
+        final int prevStrokeAlpha = mStrokePaint != null ? mStrokePaint.getAlpha() : 0;
         // compute the modulate alpha values
         final int currFillAlpha = modulateAlpha(prevFillAlpha);
         final int currStrokeAlpha = modulateAlpha(prevStrokeAlpha);
 
-        final boolean haveStroke = currStrokeAlpha > 0 &&
-                                   mStrokePaint.getStrokeWidth() > 0;
+        final boolean haveStroke = currStrokeAlpha > 0 && mStrokePaint.getStrokeWidth() > 0;
         final boolean haveFill = currFillAlpha > 0;
         final GradientState st = mGradientState;
         /*  we need a layer iff we're drawing both a fill and stroke, and the
@@ -264,7 +267,7 @@
             of the fill (if any) without worrying about blending artifacts.
          */
          final boolean useLayer = haveStroke && haveFill && st.mShape != LINE &&
-                                  currStrokeAlpha < 255;
+                 currStrokeAlpha < 255;
 
         /*  Drawing with a layer is slower than direct drawing, but it
             allows us to apply paint effects like alpha and colorfilter to
@@ -336,10 +339,10 @@
                 break;
             }
             case RING:
-                Path ring = buildRing(st);
-                canvas.drawPath(ring, mFillPaint);
+                Path path = buildRing(st);
+                canvas.drawPath(path, mFillPaint);
                 if (haveStroke) {
-                    canvas.drawPath(ring, mStrokePaint);
+                    canvas.drawPath(path, mStrokePaint);
                 }
                 break;
         }
@@ -355,6 +358,9 @@
     }
     
     private Path buildRing(GradientState st) {
+        if (mRingPath != null && (!st.mUseLevelForShape || !mPathIsDirty)) return mRingPath;
+        mPathIsDirty = false;
+
         float sweep = st.mUseLevelForShape ? (360.0f * getLevel() / 10000.0f) : 360f;
         
         RectF bounds = new RectF(mRect);
@@ -362,9 +368,11 @@
         float x = bounds.width() / 2.0f;
         float y = bounds.height() / 2.0f;
 
-        float thickness = bounds.width() / st.mThickness;
+        float thickness = st.mThickness != -1 ?
+                st.mThickness : bounds.width() / st.mThicknessRatio;
         // inner radius
-        float radius = bounds.width() / st.mInnerRadius;
+        float radius = st.mInnerRadius != -1 ?
+                st.mInnerRadius : bounds.width() / st.mInnerRadiusRatio;
 
         RectF innerBounds = new RectF(bounds);
         innerBounds.inset(x - radius, y - radius);
@@ -372,27 +380,33 @@
         bounds = new RectF(innerBounds);
         bounds.inset(-thickness, -thickness);
 
-        Path path = new Path();
+        if (mRingPath == null) {
+            mRingPath = new Path();
+        } else {
+            mRingPath.reset();            
+        }
+
+        final Path ringPath = mRingPath;
         // arcTo treats the sweep angle mod 360, so check for that, since we
         // think 360 means draw the entire oval
         if (sweep < 360 && sweep > -360) {
-            path.setFillType(Path.FillType.EVEN_ODD);
+            ringPath.setFillType(Path.FillType.EVEN_ODD);
             // inner top
-            path.moveTo(x + radius, y);
+            ringPath.moveTo(x + radius, y);
             // outer top
-            path.lineTo(x + radius + thickness, y);
+            ringPath.lineTo(x + radius + thickness, y);
             // outer arc
-            path.arcTo(bounds, 0.0f, sweep, false);
+            ringPath.arcTo(bounds, 0.0f, sweep, false);
             // inner arc
-            path.arcTo(innerBounds, sweep, -sweep, false);
-            path.close();
+            ringPath.arcTo(innerBounds, sweep, -sweep, false);
+            ringPath.close();
         } else {
             // add the entire ovals
-            path.addOval(bounds, Path.Direction.CW);
-            path.addOval(innerBounds, Path.Direction.CCW);
+            ringPath.addOval(bounds, Path.Direction.CW);
+            ringPath.addOval(innerBounds, Path.Direction.CCW);
         }
 
-        return path;
+        return ringPath;
     }
 
     public void setColor(int argb) {
@@ -430,6 +444,8 @@
     @Override
     protected void onBoundsChange(Rect r) {
         super.onBoundsChange(r);
+        mRingPath = null;
+        mPathIsDirty = true;
         mRectIsDirty = true;
     }
 
@@ -437,6 +453,7 @@
     protected boolean onLevelChange(int level) {
         super.onLevelChange(level);
         mRectIsDirty = true;
+        mPathIsDirty = true;
         invalidateSelf();
         return true;
     }
@@ -462,8 +479,9 @@
 
             mRect.set(bounds.left + inset, bounds.top + inset,
                       bounds.right - inset, bounds.bottom - inset);
-            
-            if (st.mColors != null) {
+
+            final int[] colors = st.mColors;
+            if (colors != null) {
                 RectF r = mRect;
                 float x0, x1, y0, y1;
 
@@ -505,8 +523,7 @@
                     }
 
                     mFillPaint.setShader(new LinearGradient(x0, y0, x1, y1,
-                                                            st.mColors, st.mPositions,
-                                                            Shader.TileMode.CLAMP));
+                            colors, st.mPositions, Shader.TileMode.CLAMP));
                 } else if (st.mGradient == RADIAL_GRADIENT) {
                     x0 = r.left + (r.right - r.left) * st.mCenterX;
                     y0 = r.top + (r.bottom - r.top) * st.mCenterY;
@@ -514,30 +531,38 @@
                     final float level = st.mUseLevel ? (float) getLevel() / 10000.0f : 1.0f;
 
                     mFillPaint.setShader(new RadialGradient(x0, y0,
-                            level * st.mGradientRadius, st.mColors, null,
+                            level * st.mGradientRadius, colors, null,
                             Shader.TileMode.CLAMP));
                 } else if (st.mGradient == SWEEP_GRADIENT) {
                     x0 = r.left + (r.right - r.left) * st.mCenterX;
                     y0 = r.top + (r.bottom - r.top) * st.mCenterY;
 
-                    float[] positions = null;
-                    int[] colors = st.mColors;
+                    int[] tempColors = colors;
+                    float[] tempPositions = null;
 
                     if (st.mUseLevel) {
-                        final int length = st.mColors.length;
-                        colors = new int[length + 1];
-                        System.arraycopy(st.mColors, 0, colors, 0, length);
-                        colors[length] = st.mColors[length - 1];
+                        tempColors = st.mTempColors;
+                        final int length = colors.length;
+                        if (tempColors == null || tempColors.length != length + 1) {
+                            tempColors = st.mTempColors = new int[length + 1];
+                        }
+                        System.arraycopy(colors, 0, tempColors, 0, length);
+                        tempColors[length] = colors[length - 1];
 
+                        tempPositions = st.mTempPositions;
                         final float fraction = 1.0f / (float) (length - 1);
-                        positions = new float[length + 1];
+                        if (tempPositions == null || tempPositions.length != length + 1) {
+                            tempPositions = st.mTempPositions = new float[length + 1];
+                        }
+
                         final float level = (float) getLevel() / 10000.0f;
                         for (int i = 0; i < length; i++) {
-                            positions[i] = i * fraction * level;
+                            tempPositions[i] = i * fraction * level;
                         }
-                        positions[length] = 1.0f;
+                        tempPositions[length] = 1.0f;
+
                     }
-                    mFillPaint.setShader(new SweepGradient(x0, y0, colors, positions));
+                    mFillPaint.setShader(new SweepGradient(x0, y0, tempColors, tempPositions));
                 }
             }
         }
@@ -561,10 +586,18 @@
                 com.android.internal.R.styleable.GradientDrawable_shape, RECTANGLE);
         
         if (shapeType == RING) {
-            st.mInnerRadius = a.getFloat(
-                    com.android.internal.R.styleable.GradientDrawable_innerRadiusRatio, 3.0f);
-            st.mThickness = a.getFloat(
-                    com.android.internal.R.styleable.GradientDrawable_thicknessRatio, 9.0f);
+            st.mInnerRadius = a.getDimensionPixelSize(
+                    com.android.internal.R.styleable.GradientDrawable_innerRadius, -1);
+            if (st.mInnerRadius == -1) {
+                st.mInnerRadiusRatio = a.getFloat(
+                        com.android.internal.R.styleable.GradientDrawable_innerRadiusRatio, 3.0f);
+            }
+            st.mThickness = a.getDimensionPixelSize(
+                    com.android.internal.R.styleable.GradientDrawable_thickness, -1);
+            if (st.mThickness == -1) {
+                st.mThicknessRatio = a.getFloat(
+                        com.android.internal.R.styleable.GradientDrawable_thicknessRatio, 9.0f);
+            }
             st.mUseLevelForShape = a.getBoolean(
                     com.android.internal.R.styleable.GradientDrawable_useLevel, true);
         }
@@ -808,6 +841,8 @@
         public int mGradient = LINEAR_GRADIENT;
         public Orientation mOrientation;
         public int[] mColors;
+        public int[] mTempColors; // no need to copy
+        public float[] mTempPositions; // no need to copy
         public float[] mPositions;
         public boolean mHasSolidColor;
         public int mSolidColor;
@@ -820,8 +855,10 @@
         public Rect mPadding;
         public int mWidth = -1;
         public int mHeight = -1;
-        public float mInnerRadius;
-        public float mThickness;
+        public float mInnerRadiusRatio;
+        public float mThicknessRatio;
+        public int mInnerRadius;
+        public int mThickness;
         private float mCenterX = 0.5f;
         private float mCenterY = 0.5f;
         private float mGradientRadius = 0.5f;
@@ -844,17 +881,25 @@
             mGradient = state.mGradient;
             mOrientation = state.mOrientation;
             mColors = state.mColors.clone();
-            mPositions = state.mPositions.clone();
+            if (state.mPositions != null) {
+                mPositions = state.mPositions.clone();
+            }
             mHasSolidColor = state.mHasSolidColor;
             mStrokeWidth = state.mStrokeWidth;
             mStrokeColor = state.mStrokeColor;
             mStrokeDashWidth = state.mStrokeDashWidth;
             mStrokeDashGap = state.mStrokeDashGap;
             mRadius = state.mRadius;
-            mRadiusArray = state.mRadiusArray.clone();
-            mPadding = new Rect(state.mPadding);
+            if (state.mRadiusArray != null) {
+                mRadiusArray = state.mRadiusArray.clone();
+            }
+            if (state.mPadding != null) {
+                mPadding = new Rect(state.mPadding);
+            }
             mWidth = state.mWidth;
             mHeight = state.mHeight;
+            mInnerRadiusRatio = state.mInnerRadiusRatio;
+            mThicknessRatio = state.mThicknessRatio;
             mInnerRadius = state.mInnerRadius;
             mThickness = state.mThickness;
             mCenterX = state.mCenterX;
diff --git a/graphics/java/android/graphics/drawable/RotateDrawable.java b/graphics/java/android/graphics/drawable/RotateDrawable.java
index e4b821a..cb16cb7 100644
--- a/graphics/java/android/graphics/drawable/RotateDrawable.java
+++ b/graphics/java/android/graphics/drawable/RotateDrawable.java
@@ -88,6 +88,13 @@
         canvas.restoreToCount(saveCount);
     }
 
+    /**
+     * Returns the drawable rotated by this RotateDrawable.
+     */
+    public Drawable getDrawable() {
+        return mState.mDrawable;
+    }
+
     @Override
     public int getChangingConfigurations() {
         return super.getChangingConfigurations()
diff --git a/graphics/java/android/graphics/drawable/ScaleDrawable.java b/graphics/java/android/graphics/drawable/ScaleDrawable.java
index b3322c9..7125ab1 100644
--- a/graphics/java/android/graphics/drawable/ScaleDrawable.java
+++ b/graphics/java/android/graphics/drawable/ScaleDrawable.java
@@ -63,6 +63,13 @@
         }
     }
 
+    /**
+     * Returns the drawable scaled by this ScaleDrawable.
+     */
+    public Drawable getDrawable() {
+        return mScaleState.mDrawable;
+    }
+
     private static float getPercent(TypedArray a, int name) {
         String s = a.getString(name);
         if (s != null) {
diff --git a/include/media/AudioSystem.h b/include/media/AudioSystem.h
index 6bd54ba..7437f65 100644
--- a/include/media/AudioSystem.h
+++ b/include/media/AudioSystem.h
@@ -29,8 +29,27 @@
 {
 public:
 
+    enum stream_type {
+        DEFAULT         =-1,
+        VOICE_CALL      = 0,
+        SYSTEM          = 1,
+        RING            = 2,
+        MUSIC           = 3,
+        ALARM           = 4,
+        NOTIFICATION    = 5,
+        BLUETOOTH_SCO   = 6,
+        NUM_STREAM_TYPES
+    };
+
+    enum audio_output_type {
+        AUDIO_OUTPUT_DEFAULT      =-1,
+        AUDIO_OUTPUT_HARDWARE     = 0,
+        AUDIO_OUTPUT_A2DP         = 1,
+        NUM_AUDIO_OUTPUT_TYPES
+    };
+
     enum audio_format {
-        DEFAULT = 0,
+        FORMAT_DEFAULT = 0,
         PCM_16_BIT,
         PCM_8_BIT,
         INVALID_FORMAT
@@ -96,9 +115,11 @@
     static float linearToLog(int volume);
     static int logToLinear(float volume);
 
-    static status_t getOutputSamplingRate(int* samplingRate);
-    static status_t getOutputFrameCount(int* frameCount);
-    static status_t getOutputLatency(uint32_t* latency);
+    static status_t getOutputSamplingRate(int* samplingRate, int stream = DEFAULT);
+    static status_t getOutputFrameCount(int* frameCount, int stream = DEFAULT);
+    static status_t getOutputLatency(uint32_t* latency, int stream = DEFAULT);
+
+    static bool routedToA2dpOutput(int streamType);
     
     static status_t getInputBufferSize(uint32_t sampleRate, int format, int channelCount, 
         size_t* buffSize);
@@ -117,9 +138,10 @@
         virtual void binderDied(const wp<IBinder>& who);
         
         // IAudioFlingerClient
-        virtual void audioOutputChanged(uint32_t frameCount, uint32_t samplingRate, uint32_t latency);
+        virtual void a2dpEnabledChanged(bool enabled);
         
     };
+    static int getOutput(int streamType);
 
     static sp<AudioFlingerClient> gAudioFlingerClient;
 
@@ -128,9 +150,10 @@
     static Mutex gLock;
     static sp<IAudioFlinger> gAudioFlinger;
     static audio_error_callback gAudioErrorCallback;
-    static int gOutSamplingRate;
-    static int gOutFrameCount;
-    static uint32_t gOutLatency;
+    static int gOutSamplingRate[NUM_AUDIO_OUTPUT_TYPES];
+    static int gOutFrameCount[NUM_AUDIO_OUTPUT_TYPES];
+    static uint32_t gOutLatency[NUM_AUDIO_OUTPUT_TYPES];
+    static bool gA2dpEnabled;
     
     static size_t gInBuffSize;
     // previous parameters for recording buffer size queries
diff --git a/include/media/AudioTrack.h b/include/media/AudioTrack.h
index 5b2bab9..659f5f8 100644
--- a/include/media/AudioTrack.h
+++ b/include/media/AudioTrack.h
@@ -42,19 +42,6 @@
 class AudioTrack
 {
 public:
-
-    enum stream_type {
-        DEFAULT         =-1,
-        VOICE_CALL      = 0,
-        SYSTEM          = 1,
-        RING            = 2,
-        MUSIC           = 3,
-        ALARM           = 4,
-        NOTIFICATION    = 5,
-        BLUETOOTH_SCO   = 6,
-        NUM_STREAM_TYPES
-    };
-
     enum channel_index {
         MONO   = 0,
         LEFT   = 0,
@@ -128,7 +115,7 @@
      * Parameters:
      *
      * streamType:         Select the type of audio stream this track is attached to
-     *                     (e.g. AudioTrack::MUSIC).
+     *                     (e.g. AudioSystem::MUSIC).
      * sampleRate:         Track sampling rate in Hz.
      * format:             PCM sample format (e.g AudioSystem::PCM_16_BIT for signed
      *                     16 bits per sample).
diff --git a/include/media/IAudioFlinger.h b/include/media/IAudioFlinger.h
index df601d7..6f13fe0 100644
--- a/include/media/IAudioFlinger.h
+++ b/include/media/IAudioFlinger.h
@@ -65,11 +65,11 @@
     /* query the audio hardware state. This state never changes,
      * and therefore can be cached.
      */
-    virtual     uint32_t    sampleRate() const = 0;
-    virtual     int         channelCount() const = 0;
-    virtual     int         format() const = 0;
-    virtual     size_t      frameCount() const = 0;
-    virtual     uint32_t    latency() const = 0;
+    virtual     uint32_t    sampleRate(int output) const = 0;
+    virtual     int         channelCount(int output) const = 0;
+    virtual     int         format(int output) const = 0;
+    virtual     size_t      frameCount(int output) const = 0;
+    virtual     uint32_t    latency(int output) const = 0;
 
     /* set/get the audio hardware state. This will probably be used by
      * the preference panel, mostly.
@@ -117,6 +117,9 @@
     
     // force AudioFlinger thread out of standby
     virtual     void        wakeUp() = 0;
+
+    // is A2DP output enabled
+    virtual     bool        isA2dpEnabled() const = 0;
 };
 
 
diff --git a/include/media/IAudioFlingerClient.h b/include/media/IAudioFlingerClient.h
index 10c3e0f..c3deb0b 100644
--- a/include/media/IAudioFlingerClient.h
+++ b/include/media/IAudioFlingerClient.h
@@ -32,7 +32,7 @@
     DECLARE_META_INTERFACE(AudioFlingerClient);
 
     // Notifies a change of audio output from/to hardware to/from A2DP.
-    virtual void audioOutputChanged(uint32_t frameCount, uint32_t samplingRate, uint32_t latency) = 0;
+    virtual void a2dpEnabledChanged(bool enabled) = 0;
 
 };
 
diff --git a/include/media/IMediaRecorder.h b/include/media/IMediaRecorder.h
index 49e45d1..0dff84e 100644
--- a/include/media/IMediaRecorder.h
+++ b/include/media/IMediaRecorder.h
@@ -38,6 +38,7 @@
     virtual	status_t		setVideoEncoder(int ve) = 0;
     virtual	status_t		setAudioEncoder(int ae) = 0;
     virtual	status_t		setOutputFile(const char* path) = 0;
+    virtual	status_t		setOutputFile(int fd, int64_t offset, int64_t length) = 0;
     virtual	status_t		setVideoSize(int width, int height) = 0;
     virtual	status_t		setVideoFrameRate(int frames_per_second) = 0;
     virtual	status_t		prepare() = 0;
diff --git a/include/media/PVMediaRecorder.h b/include/media/PVMediaRecorder.h
index 5fee0d6..f795d04 100644
--- a/include/media/PVMediaRecorder.h
+++ b/include/media/PVMediaRecorder.h
@@ -43,6 +43,7 @@
     status_t setCamera(const sp<ICamera>& camera);
     status_t setPreviewSurface(const sp<ISurface>& surface);
     status_t setOutputFile(const char *path);
+    status_t setOutputFile(int fd, int64_t offset, int64_t length);
     status_t prepare();
     status_t start();
     status_t stop();
diff --git a/include/media/mediarecorder.h b/include/media/mediarecorder.h
index a901d32..436e8f1 100644
--- a/include/media/mediarecorder.h
+++ b/include/media/mediarecorder.h
@@ -102,6 +102,7 @@
     status_t    setVideoEncoder(int ve);
     status_t    setAudioEncoder(int ae);
     status_t    setOutputFile(const char* path);
+    status_t    setOutputFile(int fd, int64_t offset, int64_t length);
     status_t    setVideoSize(int width, int height);
     status_t    setVideoFrameRate(int frames_per_second);
     status_t    prepare();
diff --git a/include/ui/ISurface.h b/include/ui/ISurface.h
index 1c8043d..87b320f 100644
--- a/include/ui/ISurface.h
+++ b/include/ui/ISurface.h
@@ -25,6 +25,8 @@
 #include <utils/RefBase.h>
 #include <ui/PixelFormat.h>
 
+#include <hardware/hardware.h>
+
 namespace android {
 
 typedef int32_t    SurfaceID;
@@ -49,16 +51,8 @@
     class BufferHeap {
     public:
         enum {
-            /* flip source image horizontally */
-            FLIP_H    = 0x01,
-            /* flip source image vertically */
-            FLIP_V    = 0x02,
             /* rotate source image 90 degrees */
-            ROT_90    = 0x04,
-            /* rotate source image 180 degrees */
-            ROT_180   = 0x03,
-            /* rotate source image 270 degrees */
-            ROT_270   = 0x07,
+            ROT_90    = HAL_TRANSFORM_ROT_90,
         };
         BufferHeap();
         
diff --git a/include/utils/logger.h b/include/utils/logger.h
deleted file mode 100644
index 3a08019..0000000
--- a/include/utils/logger.h
+++ /dev/null
@@ -1,46 +0,0 @@
-/* utils/logger.h
-** 
-** Copyright 2007, The Android Open Source Project
-**
-** This file is dual licensed.  It may be redistributed and/or modified
-** under the terms of the Apache 2.0 License OR version 2 of the GNU
-** General Public License.
-*/
-
-#ifndef _UTILS_LOGGER_H
-#define _UTILS_LOGGER_H
-
-#include <stdint.h>
-
-struct logger_entry {
-    uint16_t    len;    /* length of the payload */
-    uint16_t    __pad;  /* no matter what, we get 2 bytes of padding */
-    int32_t     pid;    /* generating process's pid */
-    int32_t     tid;    /* generating process's tid */
-    int32_t     sec;    /* seconds since Epoch */
-    int32_t     nsec;   /* nanoseconds */
-    char        msg[0]; /* the entry's payload */
-};
-
-#define LOGGER_LOG_MAIN		"log/main"
-#define LOGGER_LOG_RADIO	"log/radio"
-#define LOGGER_LOG_EVENTS	"log/events"
-
-#define LOGGER_ENTRY_MAX_LEN		(4*1024)
-#define LOGGER_ENTRY_MAX_PAYLOAD	\
-	(LOGGER_ENTRY_MAX_LEN - sizeof(struct logger_entry))
-
-#ifdef HAVE_IOCTL
-
-#include <sys/ioctl.h>
-
-#define __LOGGERIO	0xAE
-
-#define LOGGER_GET_LOG_BUF_SIZE		_IO(__LOGGERIO, 1) /* size of log */
-#define LOGGER_GET_LOG_LEN		_IO(__LOGGERIO, 2) /* used log len */
-#define LOGGER_GET_NEXT_ENTRY_LEN	_IO(__LOGGERIO, 3) /* next entry len */
-#define LOGGER_FLUSH_LOG		_IO(__LOGGERIO, 4) /* flush log */
-
-#endif // HAVE_IOCTL
-
-#endif /* _UTILS_LOGGER_H */
diff --git a/libs/audioflinger/AudioFlinger.cpp b/libs/audioflinger/AudioFlinger.cpp
index 017a298..d347f14 100644
--- a/libs/audioflinger/AudioFlinger.cpp
+++ b/libs/audioflinger/AudioFlinger.cpp
@@ -47,6 +47,15 @@
 #include "A2dpAudioInterface.h"
 #endif
 
+// ----------------------------------------------------------------------------
+// the sim build doesn't have gettid
+
+#ifndef HAVE_GETTID
+# define gettid getpid
+#endif
+
+// ----------------------------------------------------------------------------
+
 namespace android {
 
 //static const nsecs_t kStandbyTimeInNsecs = seconds(3);
@@ -59,6 +68,13 @@
 static const int8_t kMaxTrackRetries = 50;
 static const int8_t kMaxTrackStartupRetries = 50;
 
+static const int kStartSleepTime = 30000;
+static const int kStopSleepTime = 30000;
+
+// Maximum number of pending buffers allocated by OutputTrack::write()
+static const uint8_t kMaxOutputTrackBuffers = 5;
+
+
 #define AUDIOFLINGER_SECURITY_ENABLED 1
 
 // ----------------------------------------------------------------------------
@@ -98,13 +114,10 @@
 // ----------------------------------------------------------------------------
 
 AudioFlinger::AudioFlinger()
-    : BnAudioFlinger(), Thread(false),
-        mMasterVolume(0), mMasterMute(true), mHardwareAudioMixer(0), mA2dpAudioMixer(0),
-        mAudioMixer(0), mAudioHardware(0), mA2dpAudioInterface(0), mHardwareOutput(0),
-        mA2dpOutput(0), mOutput(0), mRequestedOutput(0), mAudioRecordThread(0),
-        mSampleRate(0), mFrameCount(0), mChannelCount(0), mFormat(0), mMixBuffer(0),
-        mLastWriteTime(0), mNumWrites(0), mNumDelayedWrites(0), mStandby(false),
-        mInWrite(false), mA2dpDisableCount(0), mA2dpSuppressed(false)
+    : BnAudioFlinger(),
+        mAudioHardware(0), mA2dpAudioInterface(0),
+        mA2dpEnabled(false), mA2dpEnabledReq(false),
+        mForcedSpeakerCount(0), mForcedRoute(0), mRouteRestoreTime(0), mMusicMuteSaved(false)
 {
     mHardwareStatus = AUDIO_HW_IDLE;
     mAudioHardware = AudioHardwareInterface::create();
@@ -113,42 +126,43 @@
         // open 16-bit output stream for s/w mixer
         mHardwareStatus = AUDIO_HW_OUTPUT_OPEN;
         status_t status;
-        mHardwareOutput = mAudioHardware->openOutputStream(AudioSystem::PCM_16_BIT, 0, 0, &status);
+        AudioStreamOut *hwOutput = mAudioHardware->openOutputStream(AudioSystem::PCM_16_BIT, 0, 0, &status);
         mHardwareStatus = AUDIO_HW_IDLE;
-        if (mHardwareOutput) {
-            mHardwareAudioMixer = new AudioMixer(getOutputFrameCount(mHardwareOutput), mHardwareOutput->sampleRate());
-            mRequestedOutput = mHardwareOutput;
-            doSetOutput(mHardwareOutput);
-
-            // FIXME - this should come from settings
-            setMasterVolume(1.0f);
-            setRouting(AudioSystem::MODE_NORMAL, AudioSystem::ROUTE_SPEAKER, AudioSystem::ROUTE_ALL);
-            setRouting(AudioSystem::MODE_RINGTONE, AudioSystem::ROUTE_SPEAKER, AudioSystem::ROUTE_ALL);
-            setRouting(AudioSystem::MODE_IN_CALL, AudioSystem::ROUTE_EARPIECE, AudioSystem::ROUTE_ALL);
-            setMode(AudioSystem::MODE_NORMAL);
-            mMasterMute = false;
+        if (hwOutput) {
+            mHardwareMixerThread = new MixerThread(this, hwOutput, AudioSystem::AUDIO_OUTPUT_HARDWARE);
         } else {
-            LOGE("Failed to initialize output stream, status: %d", status);
+            LOGE("Failed to initialize hardware output stream, status: %d", status);
         }
         
 #ifdef WITH_A2DP
         // Create A2DP interface
         mA2dpAudioInterface = new A2dpAudioInterface();
-        mA2dpOutput = mA2dpAudioInterface->openOutputStream(AudioSystem::PCM_16_BIT, 0, 0, &status);       
-        mA2dpAudioMixer = new AudioMixer(getOutputFrameCount(mA2dpOutput), mA2dpOutput->sampleRate());
-
-        // create a buffer big enough for both hardware and A2DP audio output.
-        size_t hwFrameCount = getOutputFrameCount(mHardwareOutput);
-        size_t a2dpFrameCount = getOutputFrameCount(mA2dpOutput);
-        size_t frameCount = (hwFrameCount > a2dpFrameCount ? hwFrameCount : a2dpFrameCount);
-#else
-        size_t frameCount = getOutputFrameCount(mHardwareOutput);
+        AudioStreamOut *a2dpOutput = mA2dpAudioInterface->openOutputStream(AudioSystem::PCM_16_BIT, 0, 0, &status);
+        if (a2dpOutput) {
+            mA2dpMixerThread = new MixerThread(this, a2dpOutput, AudioSystem::AUDIO_OUTPUT_A2DP);
+            if (hwOutput) {  
+                uint32_t frameCount = ((a2dpOutput->bufferSize()/a2dpOutput->frameSize()) * hwOutput->sampleRate()) / a2dpOutput->sampleRate();
+                MixerThread::OutputTrack *a2dpOutTrack = new MixerThread::OutputTrack(mA2dpMixerThread,
+                                                            hwOutput->sampleRate(),
+                                                            AudioSystem::PCM_16_BIT,
+                                                            hwOutput->channelCount(),
+                                                            frameCount);
+                mHardwareMixerThread->setOuputTrack(a2dpOutTrack);                
+            }
+        } else {
+            LOGE("Failed to initialize A2DP output stream, status: %d", status);
+        }
 #endif
-        // FIXME - Current mixer implementation only supports stereo output: Always
-        // Allocate a stereo buffer even if HW output is mono.
-        mMixBuffer = new int16_t[frameCount * 2];
-        memset(mMixBuffer, 0, frameCount * 2 * sizeof(int16_t));
-        
+ 
+        // FIXME - this should come from settings
+        setRouting(AudioSystem::MODE_NORMAL, AudioSystem::ROUTE_SPEAKER, AudioSystem::ROUTE_ALL);
+        setRouting(AudioSystem::MODE_RINGTONE, AudioSystem::ROUTE_SPEAKER, AudioSystem::ROUTE_ALL);
+        setRouting(AudioSystem::MODE_IN_CALL, AudioSystem::ROUTE_EARPIECE, AudioSystem::ROUTE_ALL);
+        setMode(AudioSystem::MODE_NORMAL);
+
+        setMasterVolume(1.0f);
+        setMasterMute(false);
+
         // Start record thread
         mAudioRecordThread = new AudioRecordThread(mAudioHardware);
         if (mAudioRecordThread != 0) {
@@ -162,7 +176,7 @@
     property_get("ro.audio.silent", value, "0");
     if (atoi(value)) {
         LOGD("Silence is golden");
-        mMasterMute = true;
+        setMasterMute(true);
     }
 }
 
@@ -172,64 +186,36 @@
         mAudioRecordThread->exit();
         mAudioRecordThread.clear();        
     }
+    mHardwareMixerThread.clear();
     delete mAudioHardware;
     // deleting mA2dpAudioInterface also deletes mA2dpOutput;
+#ifdef WITH_A2DP
+    mA2dpMixerThread.clear();
     delete mA2dpAudioInterface;
-    delete [] mMixBuffer;
-    delete mHardwareAudioMixer;
-    delete mA2dpAudioMixer;
-}
- 
-void AudioFlinger::setOutput(AudioStreamOut* output)
-{
-    mRequestedOutput = output;
-    mWaitWorkCV.broadcast();
+#endif
 }
 
-void AudioFlinger::doSetOutput(AudioStreamOut* output)
-{
-    mSampleRate = output->sampleRate();
-    mChannelCount = output->channelCount();
-
-    // FIXME - Current mixer implementation only supports stereo output
-    if (mChannelCount == 1) {
-        LOGE("Invalid audio hardware channel count");
-    }
-    mFormat = output->format();
-    mFrameCount = getOutputFrameCount(output);
-    mAudioMixer = (output == mA2dpOutput ? mA2dpAudioMixer : mHardwareAudioMixer);
-    mOutput = output;
-    notifyOutputChange_l();
-}
-
-size_t AudioFlinger::getOutputFrameCount(AudioStreamOut* output) 
-{
-    return output->bufferSize() / output->channelCount() / sizeof(int16_t);
-}
 
 #ifdef WITH_A2DP
-bool AudioFlinger::streamDisablesA2dp(int streamType)
-{
-    return (streamType == AudioTrack::SYSTEM ||
-            streamType == AudioTrack::RING ||
-            streamType == AudioTrack::ALARM ||
-            streamType == AudioTrack::VOICE_CALL ||
-            streamType == AudioTrack::BLUETOOTH_SCO ||
-            streamType == AudioTrack::NOTIFICATION);
-}
-
 void AudioFlinger::setA2dpEnabled(bool enable)
 {
-    if (enable) {
-        LOGD("set output to A2DP\n");
-        setOutput(mA2dpOutput);
-    } else {
-        LOGD("set output to hardware audio\n");
-        setOutput(mHardwareOutput);
-    }
+    LOGV_IF(enable, "set output to A2DP\n");
+    LOGV_IF(!enable, "set output to hardware audio\n");
+
+    mA2dpEnabledReq = enable;
+    mA2dpMixerThread->wakeUp();
 }
 #endif // WITH_A2DP
 
+bool AudioFlinger::streamForcedToSpeaker(int streamType)
+{
+    // NOTE that streams listed here must not be routed to A2DP by default:
+    // AudioSystem::routedToA2dpOutput(streamType) == false
+    return (streamType == AudioSystem::RING ||
+            streamType == AudioSystem::ALARM ||
+            streamType == AudioSystem::NOTIFICATION);
+}
+
 status_t AudioFlinger::dumpClients(int fd, const Vector<String16>& args)
 {
     const size_t SIZE = 256;
@@ -251,40 +237,6 @@
     return NO_ERROR;
 }
 
-status_t AudioFlinger::dumpTracks(int fd, const Vector<String16>& args)
-{
-    const size_t SIZE = 256;
-    char buffer[SIZE];
-    String8 result;
-
-    result.append("Tracks:\n");
-    result.append("   Name Clien Typ Fmt Chn Buf S M F SRate LeftV RighV Serv User\n");
-    for (size_t i = 0; i < mTracks.size(); ++i) {
-        wp<Track> wTrack = mTracks[i];
-        if (wTrack != 0) {
-            sp<Track> track = wTrack.promote();
-            if (track != 0) {
-                track->dump(buffer, SIZE);
-                result.append(buffer);
-            }
-        }
-    }
-
-    result.append("Active Tracks:\n");
-    result.append("   Name Clien Typ Fmt Chn Buf S M F SRate LeftV RighV Serv User\n");
-    for (size_t i = 0; i < mActiveTracks.size(); ++i) {
-        wp<Track> wTrack = mTracks[i];
-        if (wTrack != 0) {
-            sp<Track> track = wTrack.promote();
-            if (track != 0) {
-                track->dump(buffer, SIZE);
-                result.append(buffer);
-            }
-        }
-    }
-    write(fd, result.string(), result.size());
-    return NO_ERROR;
-}
 
 status_t AudioFlinger::dumpInternals(int fd, const Vector<String16>& args)
 {
@@ -292,18 +244,6 @@
     char buffer[SIZE];
     String8 result;
 
-    snprintf(buffer, SIZE, "AudioMixer tracks: %08x\n", audioMixer()->trackNames());
-    result.append(buffer);
-    snprintf(buffer, SIZE, "last write occurred (msecs): %llu\n", ns2ms(systemTime() - mLastWriteTime));
-    result.append(buffer);
-    snprintf(buffer, SIZE, "total writes: %d\n", mNumWrites);
-    result.append(buffer);
-    snprintf(buffer, SIZE, "delayed writes: %d\n", mNumDelayedWrites);
-    result.append(buffer);
-    snprintf(buffer, SIZE, "blocked in write: %d\n", mInWrite);
-    result.append(buffer);
-    snprintf(buffer, SIZE, "standby: %d\n", mStandby);
-    result.append(buffer);
     snprintf(buffer, SIZE, "Hardware status: %d\n", mHardwareStatus);
     result.append(buffer);
     write(fd, result.string(), result.size());
@@ -332,8 +272,12 @@
         AutoMutex lock(&mLock);
 
         dumpClients(fd, args);
-        dumpTracks(fd, args);
         dumpInternals(fd, args);
+        mHardwareMixerThread->dump(fd, args);
+#ifdef WITH_A2DP
+        mA2dpMixerThread->dump(fd, args);
+#endif
+
         if (mAudioHardware) {
             mAudioHardware->dumpState(fd, args);
         }
@@ -341,226 +285,9 @@
     return NO_ERROR;
 }
 
-// Thread virtuals
-bool AudioFlinger::threadLoop()
-{
-    unsigned long sleepTime = kBufferRecoveryInUsecs;
-    int16_t* curBuf = mMixBuffer;
-    Vector< sp<Track> > tracksToRemove;
-    size_t enabledTracks = 0;
-    nsecs_t standbyTime = systemTime();    
-    nsecs_t outputSwitchStandbyTime = 0;
-
-    do {
-        enabledTracks = 0;
-        { // scope for the mLock
-        
-            Mutex::Autolock _l(mLock);
-            const SortedVector< wp<Track> >& activeTracks = mActiveTracks;
-
-            // put audio hardware into standby after short delay
-            if UNLIKELY(!activeTracks.size() && systemTime() > standbyTime) {
-                // wait until we have something to do...
-                LOGV("Audio hardware entering standby\n");
-                mHardwareStatus = AUDIO_HW_STANDBY;
-                if (!mStandby) {
-                    mOutput->standby();
-                    mStandby = true;
-                }
-                if (outputSwitchStandbyTime) {
-                    AudioStreamOut *output = (mOutput == mHardwareOutput) ? mA2dpOutput : mHardwareOutput;
-                    output->standby();
-                    outputSwitchStandbyTime = 0;
-                }
-                mHardwareStatus = AUDIO_HW_IDLE;
-                // we're about to wait, flush the binder command buffer
-                IPCThreadState::self()->flushCommands();
-                mWaitWorkCV.wait(mLock);
-                LOGV("Audio hardware exiting standby\n");
-                standbyTime = systemTime() + kStandbyTimeInNsecs;
-                continue;
-            }
-
-            // check for change in output
-            if (mRequestedOutput != mOutput) {
-
-                // put current output into standby mode
-                if (mOutput) {
-                    outputSwitchStandbyTime = systemTime() + milliseconds(mOutput->latency());
-                }
-
-                // change output
-                doSetOutput(mRequestedOutput);
-            }
-            if (outputSwitchStandbyTime && systemTime() > outputSwitchStandbyTime) {
-                AudioStreamOut *output = (mOutput == mHardwareOutput) ? mA2dpOutput : mHardwareOutput;
-                output->standby();
-                outputSwitchStandbyTime = 0;
-            }
-
-            // find out which tracks need to be processed
-            size_t count = activeTracks.size();
-            for (size_t i=0 ; i<count ; i++) {
-                sp<Track> t = activeTracks[i].promote();
-                if (t == 0) continue;
-
-                Track* const track = t.get();
-                audio_track_cblk_t* cblk = track->cblk();
-
-                // The first time a track is added we wait
-                // for all its buffers to be filled before processing it
-                mAudioMixer->setActiveTrack(track->name());
-                if (cblk->framesReady() && (track->isReady() || track->isStopped()) &&
-                        !track->isPaused())
-                {
-                    //LOGD("u=%08x, s=%08x [OK]", u, s);
-
-                    // compute volume for this track
-                    int16_t left, right;
-                    if (track->isMuted() || mMasterMute || track->isPausing()) {
-                        left = right = 0;
-                        if (track->isPausing()) {
-                            LOGV("paused(%d)", track->name());
-                            track->setPaused();
-                        }
-                    } else {
-                        float typeVolume = mStreamTypes[track->type()].volume;
-                        float v = mMasterVolume * typeVolume;
-                        float v_clamped = v * cblk->volume[0];
-                        if (v_clamped > MAX_GAIN) v_clamped = MAX_GAIN;
-                        left = int16_t(v_clamped);
-                        v_clamped = v * cblk->volume[1];
-                        if (v_clamped > MAX_GAIN) v_clamped = MAX_GAIN;
-                        right = int16_t(v_clamped);
-                    }
-
-                    // XXX: these things DON'T need to be done each time
-                    mAudioMixer->setBufferProvider(track);
-                    mAudioMixer->enable(AudioMixer::MIXING);
-
-                    int param;
-                    if ( track->mFillingUpStatus == Track::FS_FILLED) {
-                        // no ramp for the first volume setting
-                        track->mFillingUpStatus = Track::FS_ACTIVE;
-                        if (track->mState == TrackBase::RESUMING) {
-                            track->mState = TrackBase::ACTIVE;
-                            param = AudioMixer::RAMP_VOLUME;
-                        } else {
-                            param = AudioMixer::VOLUME;
-                        }
-                    } else {
-                        param = AudioMixer::RAMP_VOLUME;
-                    }
-                    mAudioMixer->setParameter(param, AudioMixer::VOLUME0, left);
-                    mAudioMixer->setParameter(param, AudioMixer::VOLUME1, right);
-                    mAudioMixer->setParameter(
-                        AudioMixer::TRACK,
-                        AudioMixer::FORMAT, track->format());
-                    mAudioMixer->setParameter(
-                        AudioMixer::TRACK,
-                        AudioMixer::CHANNEL_COUNT, track->channelCount());
-                    mAudioMixer->setParameter(
-                        AudioMixer::RESAMPLE,
-                        AudioMixer::SAMPLE_RATE,
-                        int(cblk->sampleRate));
-
-                    // reset retry count
-                    track->mRetryCount = kMaxTrackRetries;
-                    enabledTracks++;
-                } else {
-                    //LOGD("u=%08x, s=%08x [NOT READY]", u, s);
-                    if (track->isStopped()) {
-                        track->reset();
-                    }
-                    if (track->isTerminated() || track->isStopped() || track->isPaused()) {
-                        // We have consumed all the buffers of this track.
-                        // Remove it from the list of active tracks.
-                        LOGV("remove(%d) from active list", track->name());
-                        tracksToRemove.add(track);
-                    } else {
-                        // No buffers for this track. Give it a few chances to
-                        // fill a buffer, then remove it from active list.
-                        if (--(track->mRetryCount) <= 0) {
-                            LOGV("BUFFER TIMEOUT: remove(%d) from active list", track->name());
-                            tracksToRemove.add(track);
-                        }
-                    }
-                    // LOGV("disable(%d)", track->name());
-                    mAudioMixer->disable(AudioMixer::MIXING);
-                }
-            }
-
-            // remove all the tracks that need to be...
-            count = tracksToRemove.size();
-            if (UNLIKELY(count)) {
-                for (size_t i=0 ; i<count ; i++) {
-                    const sp<Track>& track = tracksToRemove[i];
-                    removeActiveTrack(track);
-                    if (track->isTerminated()) {
-                        mTracks.remove(track);
-                        deleteTrackName(track->mName);
-                    }
-                }
-            }  
-       }
-        if (LIKELY(enabledTracks)) {
-            // mix buffers...
-            mAudioMixer->process(curBuf);
-
-            // output audio to hardware
-            mLastWriteTime = systemTime();
-            mInWrite = true;
-            size_t mixBufferSize = mFrameCount*mChannelCount*sizeof(int16_t);
-            mOutput->write(curBuf, mixBufferSize);
-            mNumWrites++;
-            mInWrite = false;
-            mStandby = false;
-            nsecs_t temp = systemTime();
-            standbyTime = temp + kStandbyTimeInNsecs;
-            nsecs_t delta = temp - mLastWriteTime;
-            nsecs_t maxPeriod = seconds(mFrameCount) / mSampleRate * 2;
-            if (delta > maxPeriod) {
-                LOGW("write blocked for %llu msecs", ns2ms(delta));
-                mNumDelayedWrites++;
-            }
-            sleepTime = kBufferRecoveryInUsecs;
-        } else {
-            // There was nothing to mix this round, which means all
-            // active tracks were late. Sleep a little bit to give
-            // them another chance. If we're too late, the audio
-            // hardware will zero-fill for us.
-//            LOGV("no buffers - usleep(%lu)", sleepTime);
-            usleep(sleepTime);
-            if (sleepTime < kMaxBufferRecoveryInUsecs) {
-                sleepTime += kBufferRecoveryInUsecs;
-            }
-        }
-
-        // finally let go of all our tracks, without the lock held
-        // since we can't guarantee the destructors won't acquire that
-        // same lock.
-        tracksToRemove.clear();
-    } while (true);
-
-    return false;
-}
-
-status_t AudioFlinger::readyToRun()
-{
-    if (mSampleRate == 0) {
-        LOGE("No working audio driver found.");
-        return NO_INIT;
-    }
-    LOGI("AudioFlinger's main thread ready to run.");
-    return NO_ERROR;
-}
-
-void AudioFlinger::onFirstRef()
-{
-    run("AudioFlinger", ANDROID_PRIORITY_URGENT_AUDIO);
-}
-
 // IAudioFlinger interface
+
+
 sp<IAudioTrack> AudioFlinger::createTrack(
         pid_t pid,
         int streamType,
@@ -572,34 +299,21 @@
         const sp<IMemory>& sharedBuffer,
         status_t *status)
 {
-    sp<Track> track;
+    sp<MixerThread::Track> track;
     sp<TrackHandle> trackHandle;
     sp<Client> client;
     wp<Client> wclient;
     status_t lStatus;
 
-    if (streamType >= AudioTrack::NUM_STREAM_TYPES) {
+    if (streamType >= AudioSystem::NUM_STREAM_TYPES) {
         LOGE("invalid stream type");
         lStatus = BAD_VALUE;
         goto Exit;
     }
 
-    // Resampler implementation limits input sampling rate to 2 x output sampling rate.
-    if (sampleRate > MAX_SAMPLE_RATE || sampleRate > mSampleRate*2) {
-        LOGE("Sample rate out of range: %d", sampleRate);
-        lStatus = BAD_VALUE;
-        goto Exit;
-    }
-
     {
         Mutex::Autolock _l(mLock);
 
-        if (mSampleRate == 0) {
-            LOGE("Audio driver not initialized.");
-            lStatus = NO_INIT;
-            goto Exit;
-        }
-
         wclient = mClients.valueFor(pid);
 
         if (wclient != NULL) {
@@ -608,13 +322,20 @@
             client = new Client(this, pid);
             mClients.add(pid, client);
         }
-
-        track = new Track(this, client, streamType, sampleRate, format,
-                channelCount, frameCount, sharedBuffer);
-        mTracks.add(track);
-        trackHandle = new TrackHandle(track);
-
-        lStatus = NO_ERROR;
+#ifdef WITH_A2DP
+        if (isA2dpEnabled() && AudioSystem::routedToA2dpOutput(streamType)) {
+            track = mA2dpMixerThread->createTrack(client, streamType, sampleRate, format,
+                    channelCount, frameCount, sharedBuffer, &lStatus);            
+        } else 
+#endif
+        {
+            track = mHardwareMixerThread->createTrack(client, streamType, sampleRate, format,
+                    channelCount, frameCount, sharedBuffer, &lStatus);            
+        }
+        if (track != NULL) {
+            trackHandle = new TrackHandle(track);
+            lStatus = NO_ERROR;            
+        }
     }
 
 Exit:
@@ -624,34 +345,54 @@
     return trackHandle;
 }
 
-uint32_t AudioFlinger::sampleRate() const
+uint32_t AudioFlinger::sampleRate(int output) const
 {
-    return mSampleRate;
+#ifdef WITH_A2DP
+     if (output == AudioSystem::AUDIO_OUTPUT_A2DP) {
+         return mA2dpMixerThread->sampleRate();
+     }
+#endif
+     return mHardwareMixerThread->sampleRate();
 }
 
-int AudioFlinger::channelCount() const
+int AudioFlinger::channelCount(int output) const
 {
-    return mChannelCount;
+#ifdef WITH_A2DP
+     if (output == AudioSystem::AUDIO_OUTPUT_A2DP) {
+         return mA2dpMixerThread->channelCount();
+     }
+#endif
+     return mHardwareMixerThread->channelCount();
 }
 
-int AudioFlinger::format() const
+int AudioFlinger::format(int output) const
 {
-    return mFormat;
+#ifdef WITH_A2DP
+     if (output == AudioSystem::AUDIO_OUTPUT_A2DP) {
+         return mA2dpMixerThread->format();
+     }
+#endif
+     return mHardwareMixerThread->format();
 }
 
-size_t AudioFlinger::frameCount() const
+size_t AudioFlinger::frameCount(int output) const
 {
-    return mFrameCount;
+#ifdef WITH_A2DP
+     if (output == AudioSystem::AUDIO_OUTPUT_A2DP) {
+         return mA2dpMixerThread->frameCount();
+     }
+#endif
+     return mHardwareMixerThread->frameCount();
 }
 
-uint32_t AudioFlinger::latency() const
+uint32_t AudioFlinger::latency(int output) const
 {
-    if (mOutput) {
-        return mOutput->latency();
-    }
-    else {
-        return 0;
-    }
+#ifdef WITH_A2DP
+     if (output == AudioSystem::AUDIO_OUTPUT_A2DP) {
+         return mA2dpMixerThread->latency();
+     }
+#endif
+     return mHardwareMixerThread->latency();
 }
 
 status_t AudioFlinger::setMasterVolume(float value)
@@ -665,12 +406,14 @@
     AutoMutex lock(mHardwareLock);
     mHardwareStatus = AUDIO_HW_SET_MASTER_VOLUME;
     if (mAudioHardware->setMasterVolume(value) == NO_ERROR) {
-        mMasterVolume = 1.0f;
-    }
-    else {
-        mMasterVolume = value;
+        value = 1.0f;
     }
     mHardwareStatus = AUDIO_HW_IDLE;
+    mHardwareMixerThread->setMasterVolume(value);
+#ifdef WITH_A2DP
+    mA2dpMixerThread->setMasterVolume(value);
+#endif
+    
     return NO_ERROR;
 }
 
@@ -688,20 +431,17 @@
     }
 
 #ifdef WITH_A2DP
-    LOGD("setRouting %d %d %d\n", mode, routes, mask);
+    LOGD("setRouting %d %d %d, tid %d, calling tid %d\n", mode, routes, mask, gettid(), IPCThreadState::self()->getCallingPid());
     if (mode == AudioSystem::MODE_NORMAL && 
             (mask & AudioSystem::ROUTE_BLUETOOTH_A2DP)) {
         AutoMutex lock(&mLock);
 
         bool enableA2dp = false;
         if (routes & AudioSystem::ROUTE_BLUETOOTH_A2DP) {
-            if (mA2dpDisableCount > 0)
-                mA2dpSuppressed = true;
-            else
-                enableA2dp = true;
+            enableA2dp = true;
         }
         setA2dpEnabled(enableA2dp);
-        LOGD("setOutput done\n");
+        LOGV("setOutput done\n");
     }
 #endif
 
@@ -714,6 +454,12 @@
         err = mAudioHardware->getRouting(mode, &r);
         if (err == NO_ERROR) {
             r = (r & ~mask) | (routes & mask);
+            if (mode == AudioSystem::MODE_NORMAL || 
+                (mode == AudioSystem::MODE_CURRENT && getMode() == AudioSystem::MODE_NORMAL)) {
+                mSavedRoute = r;
+                r |= mForcedRoute;
+                LOGV("setRouting mSavedRoute %08x mForcedRoute %08x\n", mSavedRoute, mForcedRoute);
+            }
             mHardwareStatus = AUDIO_HW_SET_ROUTING;
             err = mAudioHardware->setRouting(mode, r);
         }
@@ -726,9 +472,14 @@
 {
     uint32_t routes = 0;
     if ((mode >= AudioSystem::MODE_CURRENT) && (mode < AudioSystem::NUM_MODES)) {
-        mHardwareStatus = AUDIO_HW_GET_ROUTING;
-        mAudioHardware->getRouting(mode, &routes);
-        mHardwareStatus = AUDIO_HW_IDLE;
+        if (mode == AudioSystem::MODE_NORMAL || 
+            (mode == AudioSystem::MODE_CURRENT && getMode() == AudioSystem::MODE_NORMAL)) {
+            routes = mSavedRoute;                
+        } else {
+            mHardwareStatus = AUDIO_HW_GET_ROUTING;
+            mAudioHardware->getRouting(mode, &routes);
+            mHardwareStatus = AUDIO_HW_IDLE;
+        }
     } else {
         LOGW("Illegal value: getRouting(%d)", mode);
     }
@@ -791,19 +542,21 @@
     if (!settingsAllowed()) {
         return PERMISSION_DENIED;
     }
-
-    mMasterMute = muted;
+    mHardwareMixerThread->setMasterMute(muted);
+#ifdef WITH_A2DP
+    mA2dpMixerThread->setMasterMute(muted);
+#endif
     return NO_ERROR;
 }
 
 float AudioFlinger::masterVolume() const
 {
-    return mMasterVolume;
+    return mHardwareMixerThread->masterVolume();
 }
 
 bool AudioFlinger::masterMute() const
 {
-    return mMasterMute;
+    return mHardwareMixerThread->masterMute();
 }
 
 status_t AudioFlinger::setStreamVolume(int stream, float value)
@@ -813,14 +566,25 @@
         return PERMISSION_DENIED;
     }
 
-    if (uint32_t(stream) >= AudioTrack::NUM_STREAM_TYPES) {
+    if (uint32_t(stream) >= AudioSystem::NUM_STREAM_TYPES) {
         return BAD_VALUE;
     }
 
-    mStreamTypes[stream].volume = value;
+    mHardwareMixerThread->setStreamVolume(stream, value);
+#ifdef WITH_A2DP
+    mA2dpMixerThread->setStreamVolume(stream, value);
+#endif
+
     status_t ret = NO_ERROR;
-    if (stream == AudioTrack::VOICE_CALL ||
-        stream == AudioTrack::BLUETOOTH_SCO) {
+    if (stream == AudioSystem::VOICE_CALL ||
+        stream == AudioSystem::BLUETOOTH_SCO) {
+        
+        if (stream == AudioSystem::VOICE_CALL) {
+            value = (float)AudioSystem::logToLinear(value)/100.0f;
+        } else { // (type == AudioSystem::BLUETOOTH_SCO)
+            value = 1.0f;
+        }
+
         AutoMutex lock(mHardwareLock);
         mHardwareStatus = AUDIO_SET_VOICE_VOLUME;
         ret = mAudioHardware->setVoiceVolume(value);
@@ -837,59 +601,58 @@
         return PERMISSION_DENIED;
     }
 
-    if (uint32_t(stream) >= AudioTrack::NUM_STREAM_TYPES) {
+    if (uint32_t(stream) >= AudioSystem::NUM_STREAM_TYPES) {
         return BAD_VALUE;
     }
+    
 #ifdef WITH_A2DP
-    if (stream == AudioTrack::MUSIC) 
+    mA2dpMixerThread->setStreamMute(stream, muted);
+#endif
+    if (stream == AudioSystem::MUSIC) 
     {
-        AutoMutex lock(&mLock);
-        if (mA2dpDisableCount > 0)
+        AutoMutex lock(&mHardwareLock);
+        if (mForcedRoute != 0)
             mMusicMuteSaved = muted;
         else
-            mStreamTypes[stream].mute = muted;
+            mHardwareMixerThread->setStreamMute(stream, muted);
     } else {
-        mStreamTypes[stream].mute = muted;
+        mHardwareMixerThread->setStreamMute(stream, muted);
     }
-#else
-    mStreamTypes[stream].mute = muted;
-#endif
+
+    
+
     return NO_ERROR;
 }
 
 float AudioFlinger::streamVolume(int stream) const
 {
-    if (uint32_t(stream) >= AudioTrack::NUM_STREAM_TYPES) {
+    if (uint32_t(stream) >= AudioSystem::NUM_STREAM_TYPES) {
         return 0.0f;
     }
-    return mStreamTypes[stream].volume;
+    return mHardwareMixerThread->streamVolume(stream);
 }
 
 bool AudioFlinger::streamMute(int stream) const
 {
-    if (uint32_t(stream) >= AudioTrack::NUM_STREAM_TYPES) {
+    if (uint32_t(stream) >= AudioSystem::NUM_STREAM_TYPES) {
         return true;
     }
-#ifdef WITH_A2DP
-    if (stream == AudioTrack::MUSIC && mA2dpDisableCount > 0) 
+    
+    if (stream == AudioSystem::MUSIC && mForcedRoute != 0) 
     {
         return mMusicMuteSaved;
     }
-#endif
-    return mStreamTypes[stream].mute;
+    return mHardwareMixerThread->streamMute(stream);
 }
 
 bool AudioFlinger::isMusicActive() const
 {
-    size_t count = mActiveTracks.size();
-    for (size_t i = 0 ; i < count ; ++i) {
-        sp<Track> t = mActiveTracks[i].promote();
-        if (t == 0) continue;
-        Track* const track = t.get();
-        if (t->mStreamType == AudioTrack::MUSIC)
-            return true;
-    }
-    return false;
+ #ifdef WITH_A2DP
+     if (isA2dpEnabled()) {
+         return mA2dpMixerThread->isMusicActive();
+     }
+ #endif
+    return mHardwareMixerThread->isMusicActive();
 }
 
 status_t AudioFlinger::setParameter(const char* key, const char* value)
@@ -897,6 +660,8 @@
     status_t result, result2;
     AutoMutex lock(mHardwareLock);
     mHardwareStatus = AUDIO_SET_PARAMETER;
+    
+    LOGV("setParameter() key %s, value %s, tid %d, calling tid %d", key, value, gettid(), IPCThreadState::self()->getCallingPid());
     result = mAudioHardware->setParameter(key, value);
     if (mA2dpAudioInterface) {
         result2 = mA2dpAudioInterface->setParameter(key, value);
@@ -907,9 +672,15 @@
     return result;
 }
 
+size_t AudioFlinger::getInputBufferSize(uint32_t sampleRate, int format, int channelCount)
+{
+    return mAudioHardware->getInputBufferSize(sampleRate, format, channelCount);
+}
 
 void AudioFlinger::registerClient(const sp<IAudioFlingerClient>& client)
 {
+    
+    LOGV("registerClient() %p, tid %d, calling tid %d", client.get(), gettid(), IPCThreadState::self()->getCallingPid());
     Mutex::Autolock _l(mLock);
 
     sp<IBinder> binder = client->asBinder();
@@ -917,21 +688,13 @@
         LOGV("Adding notification client %p", binder.get());
         binder->linkToDeath(this);
         mNotificationClients.add(binder);
+        client->a2dpEnabledChanged(isA2dpEnabled());
     }
 }
 
-
-size_t AudioFlinger::getInputBufferSize(uint32_t sampleRate, int format, int channelCount)
-{
-    return mAudioHardware->getInputBufferSize(sampleRate, format, channelCount);
-}
-
-void AudioFlinger::wakeUp()
-{
-    mWaitWorkCV.broadcast();
-}
-
 void AudioFlinger::binderDied(const wp<IBinder>& who) {
+    
+    LOGV("binderDied() %p, tid %d, calling tid %d", who.unsafe_get(), gettid(), IPCThreadState::self()->getCallingPid());
     Mutex::Autolock _l(mLock);
 
     IBinder *binder = who.unsafe_get();
@@ -945,29 +708,680 @@
     }
 }
 
-// must be called with mLock held
-void AudioFlinger::notifyOutputChange_l()
+void AudioFlinger::handleOutputSwitch()
 {
-    size_t size = mNotificationClients.size();
-    uint32_t latency = mOutput->latency();
-    for (size_t i = 0; i < size; i++) {
-        sp<IBinder> binder = mNotificationClients.itemAt(i).promote();
-        if (binder != NULL) {
-            LOGV("Notifying output change to client %p", binder.get());
-            sp<IAudioFlingerClient> client = interface_cast<IAudioFlingerClient> (binder);
-            client->audioOutputChanged(mFrameCount, mSampleRate, latency);
+    if (mA2dpEnabled != mA2dpEnabledReq)
+    {
+        Mutex::Autolock _l(mLock);
+
+        if (mA2dpEnabled != mA2dpEnabledReq)
+        {
+            mA2dpEnabled = mA2dpEnabledReq;
+            SortedVector < sp<MixerThread::Track> > tracks;
+            SortedVector < wp<MixerThread::Track> > activeTracks;
+            
+            // We hold mA2dpMixerThread mLock already 
+            Mutex::Autolock _l(mHardwareMixerThread->mLock);
+            
+            // Transfer tracks playing on MUSIC stream from one mixer to the other
+            if (mA2dpEnabled) {
+                mHardwareMixerThread->getTracks(tracks, activeTracks);
+                mA2dpMixerThread->putTracks(tracks, activeTracks);
+            } else {
+                mA2dpMixerThread->getTracks(tracks, activeTracks);
+                mHardwareMixerThread->putTracks(tracks, activeTracks);
+            }            
+            
+            // Notify AudioSystem of the A2DP activation/deactivation
+            size_t size = mNotificationClients.size();
+            for (size_t i = 0; i < size; i++) {
+                sp<IBinder> binder = mNotificationClients.itemAt(i).promote();
+                if (binder != NULL) {
+                    LOGV("Notifying output change to client %p", binder.get());
+                    sp<IAudioFlingerClient> client = interface_cast<IAudioFlingerClient> (binder);
+                    client->a2dpEnabledChanged(mA2dpEnabled);
+                }
+            }
+
+            mHardwareMixerThread->wakeUp();
         }
     }
 }
 
 void AudioFlinger::removeClient(pid_t pid)
 {
+    LOGV("removeClient() pid %d, tid %d, calling tid %d", pid, gettid(), IPCThreadState::self()->getCallingPid());
     Mutex::Autolock _l(mLock);
     mClients.removeItem(pid);
 }
 
-status_t AudioFlinger::addTrack(const sp<Track>& track)
+void AudioFlinger::wakeUp()
 {
+    mHardwareMixerThread->wakeUp();
+#ifdef WITH_A2DP
+    mA2dpMixerThread->wakeUp();
+#endif // WITH_A2DP
+}
+
+bool AudioFlinger::isA2dpEnabled() const
+{
+    return mA2dpEnabledReq;
+}
+
+void AudioFlinger::handleForcedSpeakerRoute(int command)
+{
+    switch(command) {
+    case ACTIVE_TRACK_ADDED:
+        {
+            AutoMutex lock(mHardwareLock);
+            if (mForcedSpeakerCount++ == 0) {
+                mRouteRestoreTime = 0;
+                mMusicMuteSaved = mHardwareMixerThread->streamMute(AudioSystem::MUSIC);
+                if (mForcedRoute == 0 && !(mSavedRoute & AudioSystem::ROUTE_SPEAKER)) {
+                    LOGV("Route forced to Speaker ON %08x", mSavedRoute | AudioSystem::ROUTE_SPEAKER);
+                    mHardwareMixerThread->setStreamMute(AudioSystem::MUSIC, true);
+                    mHardwareStatus = AUDIO_HW_SET_MASTER_VOLUME;
+                    mAudioHardware->setMasterVolume(0);
+                    usleep(mHardwareMixerThread->latency()*1000);
+                    mHardwareStatus = AUDIO_HW_SET_ROUTING;
+                    mAudioHardware->setRouting(AudioSystem::MODE_NORMAL, mSavedRoute | AudioSystem::ROUTE_SPEAKER);
+                    mHardwareStatus = AUDIO_HW_IDLE;
+                    // delay track start so that audio hardware has time to siwtch routes
+                    usleep(kStartSleepTime);
+                    mHardwareStatus = AUDIO_HW_SET_MASTER_VOLUME;
+                    mAudioHardware->setMasterVolume(mHardwareMixerThread->masterVolume());
+                    mHardwareStatus = AUDIO_HW_IDLE;
+                }
+                mForcedRoute = AudioSystem::ROUTE_SPEAKER;
+            }
+            LOGV("mForcedSpeakerCount incremented to %d", mForcedSpeakerCount);
+        }
+        break;
+    case ACTIVE_TRACK_REMOVED:
+        {
+            AutoMutex lock(mHardwareLock);
+            if (mForcedSpeakerCount > 0){
+                if (--mForcedSpeakerCount == 0) {
+                    mRouteRestoreTime = systemTime() + milliseconds(kStopSleepTime/1000);
+                }
+                LOGV("mForcedSpeakerCount decremented to %d", mForcedSpeakerCount);            
+            } else {
+                LOGE("mForcedSpeakerCount is already zero");            
+            }            
+        }
+        break;
+    case CHECK_ROUTE_RESTORE_TIME:
+    case FORCE_ROUTE_RESTORE:
+        if (mRouteRestoreTime) {
+            AutoMutex lock(mHardwareLock);
+            if (mRouteRestoreTime && 
+               (systemTime() > mRouteRestoreTime || command == FORCE_ROUTE_RESTORE)) {
+                mHardwareMixerThread->setStreamMute(AudioSystem::MUSIC, mMusicMuteSaved);
+                mForcedRoute = 0;
+                if (!(mSavedRoute & AudioSystem::ROUTE_SPEAKER)) {
+                    mHardwareStatus = AUDIO_HW_SET_ROUTING;
+                    mAudioHardware->setRouting(AudioSystem::MODE_NORMAL, mSavedRoute);
+                    mHardwareStatus = AUDIO_HW_IDLE;
+                    LOGV("Route forced to Speaker OFF %08x", mSavedRoute);
+                }
+                mRouteRestoreTime = 0;
+            }
+        }
+        break;
+    }
+}
+
+
+// ----------------------------------------------------------------------------
+
+AudioFlinger::MixerThread::MixerThread(const sp<AudioFlinger>& audioFlinger, AudioStreamOut* output, int outputType)
+    :   Thread(false),
+        mAudioFlinger(audioFlinger), mAudioMixer(0), mOutput(output), mOutputType(outputType), 
+        mSampleRate(0), mFrameCount(0), mChannelCount(0), mFormat(0), mMixBuffer(0),
+        mLastWriteTime(0), mNumWrites(0), mNumDelayedWrites(0), mStandby(false),
+        mInWrite(false)
+{
+    mSampleRate = output->sampleRate();
+    mChannelCount = output->channelCount();
+
+    // FIXME - Current mixer implementation only supports stereo output
+    if (mChannelCount == 1) {
+        LOGE("Invalid audio hardware channel count");
+    }
+
+    mFormat = output->format();
+    mFrameCount = output->bufferSize() / output->channelCount() / sizeof(int16_t);
+    mAudioMixer = new AudioMixer(mFrameCount, output->sampleRate());
+
+    // FIXME - Current mixer implementation only supports stereo output: Always
+    // Allocate a stereo buffer even if HW output is mono.
+    mMixBuffer = new int16_t[mFrameCount * 2];
+    memset(mMixBuffer, 0, mFrameCount * 2 * sizeof(int16_t));
+}
+
+AudioFlinger::MixerThread::~MixerThread()
+{
+    delete [] mMixBuffer;
+    delete mAudioMixer;
+}
+
+status_t AudioFlinger::MixerThread::dump(int fd, const Vector<String16>& args)
+{
+    dumpInternals(fd, args);
+    dumpTracks(fd, args);
+    return NO_ERROR;
+}
+
+status_t AudioFlinger::MixerThread::dumpTracks(int fd, const Vector<String16>& args)
+{
+    const size_t SIZE = 256;
+    char buffer[SIZE];
+    String8 result;
+
+    snprintf(buffer, SIZE, "Output %d mixer thread tracks\n", mOutputType);
+    result.append(buffer);
+    result.append("   Name Clien Typ Fmt Chn Buf S M F SRate LeftV RighV Serv User\n");
+    for (size_t i = 0; i < mTracks.size(); ++i) {
+        wp<Track> wTrack = mTracks[i];
+        if (wTrack != 0) {
+            sp<Track> track = wTrack.promote();
+            if (track != 0) {
+                track->dump(buffer, SIZE);
+                result.append(buffer);
+            }
+        }
+    }
+
+    snprintf(buffer, SIZE, "Output %d mixer thread active tracks\n", mOutputType);
+    result.append(buffer);
+    result.append("   Name Clien Typ Fmt Chn Buf S M F SRate LeftV RighV Serv User\n");
+    for (size_t i = 0; i < mActiveTracks.size(); ++i) {
+        wp<Track> wTrack = mTracks[i];
+        if (wTrack != 0) {
+            sp<Track> track = wTrack.promote();
+            if (track != 0) {
+                track->dump(buffer, SIZE);
+                result.append(buffer);
+            }
+        }
+    }
+    write(fd, result.string(), result.size());
+    return NO_ERROR;
+}
+
+status_t AudioFlinger::MixerThread::dumpInternals(int fd, const Vector<String16>& args)
+{
+    const size_t SIZE = 256;
+    char buffer[SIZE];
+    String8 result;
+
+    snprintf(buffer, SIZE, "Output %d mixer thread internals\n", mOutputType);
+    result.append(buffer);
+    snprintf(buffer, SIZE, "AudioMixer tracks: %08x\n", mAudioMixer->trackNames());
+    result.append(buffer);
+    snprintf(buffer, SIZE, "last write occurred (msecs): %llu\n", ns2ms(systemTime() - mLastWriteTime));
+    result.append(buffer);
+    snprintf(buffer, SIZE, "total writes: %d\n", mNumWrites);
+    result.append(buffer);
+    snprintf(buffer, SIZE, "delayed writes: %d\n", mNumDelayedWrites);
+    result.append(buffer);
+    snprintf(buffer, SIZE, "blocked in write: %d\n", mInWrite);
+    result.append(buffer);
+    snprintf(buffer, SIZE, "standby: %d\n", mStandby);
+    result.append(buffer);
+    write(fd, result.string(), result.size());
+    return NO_ERROR;
+}
+
+// Thread virtuals
+bool AudioFlinger::MixerThread::threadLoop()
+{
+    unsigned long sleepTime = kBufferRecoveryInUsecs;
+    int16_t* curBuf = mMixBuffer;
+    Vector< sp<Track> > tracksToRemove;
+    size_t enabledTracks = 0;
+    nsecs_t standbyTime = systemTime();   
+    size_t mixBufferSize = mFrameCount*mChannelCount*sizeof(int16_t);
+    nsecs_t maxPeriod = seconds(mFrameCount) / mSampleRate * 2;
+
+#ifdef WITH_A2DP
+    bool outputTrackActive = false;
+#endif
+
+    do {
+        enabledTracks = 0;
+        { // scope for the mLock
+        
+            Mutex::Autolock _l(mLock);
+
+#ifdef WITH_A2DP
+            if (mOutputType == AudioSystem::AUDIO_OUTPUT_A2DP) {
+                mAudioFlinger->handleOutputSwitch();
+            }
+            if (mOutputTrack != NULL && !mAudioFlinger->isA2dpEnabled()) {
+                if (outputTrackActive) {
+                    mOutputTrack->stop();
+                    outputTrackActive = false;
+                }
+            }
+#endif
+
+            const SortedVector< wp<Track> >& activeTracks = mActiveTracks;
+
+            // put audio hardware into standby after short delay
+            if UNLIKELY(!activeTracks.size() && systemTime() > standbyTime) {
+                // wait until we have something to do...
+                LOGV("Audio hardware entering standby, output %d\n", mOutputType);
+//                mAudioFlinger->mHardwareStatus = AUDIO_HW_STANDBY;
+                if (!mStandby) {
+                    mOutput->standby();
+                    mStandby = true;
+                }
+                
+#ifdef WITH_A2DP
+                if (outputTrackActive) {
+                    mOutputTrack->stop();
+                    outputTrackActive = false;
+                }
+#endif
+                if (mOutputType == AudioSystem::AUDIO_OUTPUT_HARDWARE) {
+                    mAudioFlinger->handleForcedSpeakerRoute(FORCE_ROUTE_RESTORE);
+                }                
+//                mHardwareStatus = AUDIO_HW_IDLE;
+                // we're about to wait, flush the binder command buffer
+                IPCThreadState::self()->flushCommands();
+                mWaitWorkCV.wait(mLock);
+                LOGV("Audio hardware exiting standby, output %d\n", mOutputType);
+                standbyTime = systemTime() + kStandbyTimeInNsecs;
+                continue;
+            }
+
+            // Forced route to speaker is handled by hardware mixer thread
+            if (mOutputType == AudioSystem::AUDIO_OUTPUT_HARDWARE) {
+                mAudioFlinger->handleForcedSpeakerRoute(CHECK_ROUTE_RESTORE_TIME);
+            }
+
+            // find out which tracks need to be processed
+            size_t count = activeTracks.size();
+            for (size_t i=0 ; i<count ; i++) {
+                sp<Track> t = activeTracks[i].promote();
+                if (t == 0) continue;
+
+                Track* const track = t.get();
+                audio_track_cblk_t* cblk = track->cblk();
+
+                // The first time a track is added we wait
+                // for all its buffers to be filled before processing it
+                mAudioMixer->setActiveTrack(track->name());
+                if (cblk->framesReady() && (track->isReady() || track->isStopped()) &&
+                        !track->isPaused())
+                {
+                    //LOGV("track %d u=%08x, s=%08x [OK]", track->name(), cblk->user, cblk->server);
+
+                    // compute volume for this track
+                    int16_t left, right;
+                    if (track->isMuted() || mMasterMute || track->isPausing()) {
+                        left = right = 0;
+                        if (track->isPausing()) {
+                            LOGV("paused(%d)", track->name());
+                            track->setPaused();
+                        }
+                    } else {
+                        float typeVolume = mStreamTypes[track->type()].volume;
+                        float v = mMasterVolume * typeVolume;
+                        float v_clamped = v * cblk->volume[0];
+                        if (v_clamped > MAX_GAIN) v_clamped = MAX_GAIN;
+                        left = int16_t(v_clamped);
+                        v_clamped = v * cblk->volume[1];
+                        if (v_clamped > MAX_GAIN) v_clamped = MAX_GAIN;
+                        right = int16_t(v_clamped);
+                    }
+
+                    // XXX: these things DON'T need to be done each time
+                    mAudioMixer->setBufferProvider(track);
+                    mAudioMixer->enable(AudioMixer::MIXING);
+
+                    int param;
+                    if ( track->mFillingUpStatus == Track::FS_FILLED) {
+                        // no ramp for the first volume setting
+                        track->mFillingUpStatus = Track::FS_ACTIVE;
+                        if (track->mState == TrackBase::RESUMING) {
+                            track->mState = TrackBase::ACTIVE;
+                            param = AudioMixer::RAMP_VOLUME;
+                        } else {
+                            param = AudioMixer::VOLUME;
+                        }
+                    } else {
+                        param = AudioMixer::RAMP_VOLUME;
+                    }
+                    mAudioMixer->setParameter(param, AudioMixer::VOLUME0, left);
+                    mAudioMixer->setParameter(param, AudioMixer::VOLUME1, right);
+                    mAudioMixer->setParameter(
+                        AudioMixer::TRACK,
+                        AudioMixer::FORMAT, track->format());
+                    mAudioMixer->setParameter(
+                        AudioMixer::TRACK,
+                        AudioMixer::CHANNEL_COUNT, track->channelCount());
+                    mAudioMixer->setParameter(
+                        AudioMixer::RESAMPLE,
+                        AudioMixer::SAMPLE_RATE,
+                        int(cblk->sampleRate));
+
+                    // reset retry count
+                    track->mRetryCount = kMaxTrackRetries;
+                    enabledTracks++;
+                } else {
+                    //LOGV("track %d u=%08x, s=%08x [NOT READY]", track->name(), cblk->user, cblk->server);
+                    if (track->isStopped()) {
+                        track->reset();
+                    }
+                    if (track->isTerminated() || track->isStopped() || track->isPaused()) {
+                        // We have consumed all the buffers of this track.
+                        // Remove it from the list of active tracks.
+                        LOGV("remove(%d) from active list", track->name());
+                        tracksToRemove.add(track);
+                    } else {
+                        // No buffers for this track. Give it a few chances to
+                        // fill a buffer, then remove it from active list.
+                        if (--(track->mRetryCount) <= 0) {
+                            LOGV("BUFFER TIMEOUT: remove(%d) from active list", track->name());
+                            tracksToRemove.add(track);
+                        }
+                    }
+                    // LOGV("disable(%d)", track->name());
+                    mAudioMixer->disable(AudioMixer::MIXING);
+                }
+            }
+
+            // remove all the tracks that need to be...
+            count = tracksToRemove.size();
+            if (UNLIKELY(count)) {
+                for (size_t i=0 ; i<count ; i++) {
+                    const sp<Track>& track = tracksToRemove[i];
+                    removeActiveTrack(track);
+                    if (track->isTerminated()) {
+                        mTracks.remove(track);
+                        deleteTrackName(track->mName);
+                    }
+                }
+            }  
+       }
+        
+        if (LIKELY(enabledTracks)) {
+            // mix buffers...
+            mAudioMixer->process(curBuf);
+
+#ifdef WITH_A2DP
+            if (mOutputTrack != NULL && mAudioFlinger->isA2dpEnabled()) {
+                if (!outputTrackActive) {
+                    LOGV("starting output track in mixer for output %d", mOutputType);
+                    mOutputTrack->start();
+                    outputTrackActive = true;
+                }
+                mOutputTrack->write(curBuf, mFrameCount);
+            }
+#endif
+
+            // output audio to hardware
+            mLastWriteTime = systemTime();
+            mInWrite = true;
+            mOutput->write(curBuf, mixBufferSize);
+            mNumWrites++;
+            mInWrite = false;
+            mStandby = false;
+            nsecs_t temp = systemTime();
+            standbyTime = temp + kStandbyTimeInNsecs;
+            nsecs_t delta = temp - mLastWriteTime;
+            if (delta > maxPeriod) {
+                LOGW("write blocked for %llu msecs", ns2ms(delta));
+                mNumDelayedWrites++;
+            }
+            sleepTime = kBufferRecoveryInUsecs;
+        } else {         
+#ifdef WITH_A2DP
+            if (mOutputTrack != NULL && mAudioFlinger->isA2dpEnabled()) {
+                if (outputTrackActive) {
+                    mOutputTrack->write(curBuf, 0);
+                    if (mOutputTrack->bufferQueueEmpty()) {
+                        mOutputTrack->stop();
+                        outputTrackActive = false;
+                    } else {
+                        standbyTime = systemTime() + kStandbyTimeInNsecs;
+                    }
+                }
+            }
+#endif
+            // There was nothing to mix this round, which means all
+            // active tracks were late. Sleep a little bit to give
+            // them another chance. If we're too late, the audio
+            // hardware will zero-fill for us.
+//            LOGV("no buffers - usleep(%lu)", sleepTime);
+            usleep(sleepTime);
+            if (sleepTime < kMaxBufferRecoveryInUsecs) {
+                sleepTime += kBufferRecoveryInUsecs;
+            }
+        }
+
+        // finally let go of all our tracks, without the lock held
+        // since we can't guarantee the destructors won't acquire that
+        // same lock.
+        tracksToRemove.clear();
+    } while (true);
+
+    return false;
+}
+
+status_t AudioFlinger::MixerThread::readyToRun()
+{
+    if (mSampleRate == 0) {
+        LOGE("No working audio driver found.");
+        return NO_INIT;
+    }
+    LOGI("AudioFlinger's thread ready to run for output %d", mOutputType);
+    return NO_ERROR;
+}
+
+void AudioFlinger::MixerThread::onFirstRef()
+{
+    const size_t SIZE = 256;
+    char buffer[SIZE];
+
+    snprintf(buffer, SIZE, "Mixer Thread for output %d", mOutputType);
+
+    run(buffer, ANDROID_PRIORITY_URGENT_AUDIO);
+}
+
+
+sp<AudioFlinger::MixerThread::Track>  AudioFlinger::MixerThread::createTrack(
+        const sp<AudioFlinger::Client>& client,
+        int streamType,
+        uint32_t sampleRate,
+        int format,
+        int channelCount,
+        int frameCount,
+        const sp<IMemory>& sharedBuffer,
+        status_t *status)
+{
+    sp<Track> track;
+    status_t lStatus;
+    
+    // Resampler implementation limits input sampling rate to 2 x output sampling rate.
+    if (sampleRate > MAX_SAMPLE_RATE || sampleRate > mSampleRate*2) {
+        LOGE("Sample rate out of range: %d mSampleRate %d", sampleRate, mSampleRate);
+        lStatus = BAD_VALUE;
+        goto Exit;
+    }
+
+    {
+        Mutex::Autolock _l(mLock);
+
+        if (mSampleRate == 0) {
+            LOGE("Audio driver not initialized.");
+            lStatus = NO_INIT;
+            goto Exit;
+        }
+
+        track = new Track(this, client, streamType, sampleRate, format,
+                channelCount, frameCount, sharedBuffer);
+        mTracks.add(track);
+        lStatus = NO_ERROR;
+    }
+
+Exit:
+    if(status) {
+        *status = lStatus;
+    }
+    return track;
+}
+
+void AudioFlinger::MixerThread::getTracks(
+        SortedVector < sp<Track> >& tracks,
+        SortedVector < wp<Track> >& activeTracks)
+{
+    size_t size = mTracks.size();
+    LOGV ("MixerThread::getTracks() for output %d, mTracks.size %d, mActiveTracks.size %d", mOutputType,  mTracks.size(), mActiveTracks.size());
+    for (size_t i = 0; i < size; i++) {
+        sp<Track> t = mTracks[i];
+        if (AudioSystem::routedToA2dpOutput(t->mStreamType)) {
+            tracks.add(t);
+            int j = mActiveTracks.indexOf(t);
+            if (j >= 0) {
+                t = mActiveTracks[j].promote();
+                if (t != NULL) {
+                    activeTracks.add(t);                                    
+                }                            
+            }
+        }
+    }
+
+    size = activeTracks.size();
+    for (size_t i = 0; i < size; i++) {
+        removeActiveTrack(activeTracks[i]);
+    }
+    
+    size = tracks.size();
+    for (size_t i = 0; i < size; i++) {
+        sp<Track> t = tracks[i];
+        mTracks.remove(t);
+        deleteTrackName(t->name());
+    }
+}
+
+void AudioFlinger::MixerThread::putTracks(
+        SortedVector < sp<Track> >& tracks,
+        SortedVector < wp<Track> >& activeTracks)
+{
+
+    LOGV ("MixerThread::putTracks() for output %d, tracks.size %d, activeTracks.size %d", mOutputType,  tracks.size(), activeTracks.size());
+
+    size_t size = tracks.size();
+    for (size_t i = 0; i < size ; i++) {
+        sp<Track> t = tracks[i];
+        int name = getTrackName();
+
+        if (name < 0) return;
+        
+        t->mName = name;
+        t->mMixerThread = this;
+        mTracks.add(t);
+
+        int j = activeTracks.indexOf(t);
+        if (j >= 0) {
+            addActiveTrack(t);
+        }            
+    }
+}
+
+uint32_t AudioFlinger::MixerThread::sampleRate() const
+{
+    return mSampleRate;
+}
+
+int AudioFlinger::MixerThread::channelCount() const
+{
+    return mChannelCount;
+}
+
+int AudioFlinger::MixerThread::format() const
+{
+    return mFormat;
+}
+
+size_t AudioFlinger::MixerThread::frameCount() const
+{
+    return mFrameCount;
+}
+
+uint32_t AudioFlinger::MixerThread::latency() const
+{
+    if (mOutput) {
+        return mOutput->latency();
+    }
+    else {
+        return 0;
+    }
+}
+
+status_t AudioFlinger::MixerThread::setMasterVolume(float value)
+{
+    mMasterVolume = value;
+    return NO_ERROR;
+}
+
+status_t AudioFlinger::MixerThread::setMasterMute(bool muted)
+{
+    mMasterMute = muted;
+    return NO_ERROR;
+}
+
+float AudioFlinger::MixerThread::masterVolume() const
+{
+    return mMasterVolume;
+}
+
+bool AudioFlinger::MixerThread::masterMute() const
+{
+    return mMasterMute;
+}
+
+status_t AudioFlinger::MixerThread::setStreamVolume(int stream, float value)
+{
+    mStreamTypes[stream].volume = value;
+    return NO_ERROR;
+}
+
+status_t AudioFlinger::MixerThread::setStreamMute(int stream, bool muted)
+{
+    mStreamTypes[stream].mute = muted;
+    return NO_ERROR;
+}
+
+float AudioFlinger::MixerThread::streamVolume(int stream) const
+{
+    return mStreamTypes[stream].volume;
+}
+
+bool AudioFlinger::MixerThread::streamMute(int stream) const
+{
+    return mStreamTypes[stream].mute;
+}
+
+bool AudioFlinger::MixerThread::isMusicActive() const
+{
+    size_t count = mActiveTracks.size();
+    for (size_t i = 0 ; i < count ; ++i) {
+        sp<Track> t = mActiveTracks[i].promote();
+        if (t == 0) continue;
+        Track* const track = t.get();
+        if (t->mStreamType == AudioSystem::MUSIC)
+            return true;
+    }
+    return false;
+}
+
+status_t AudioFlinger::MixerThread::addTrack(const sp<Track>& track)
+{
+    status_t status = ALREADY_EXISTS;
     Mutex::Autolock _l(mLock);
 
     // here the track could be either new, or restarted
@@ -981,9 +1395,6 @@
     }
     // set retry count for buffer fill
     track->mRetryCount = kMaxTrackStartupRetries;
-    LOGV("mWaitWorkCV.broadcast");
-    mWaitWorkCV.broadcast();
-
     if (mActiveTracks.indexOf(track) < 0) {
         // the track is newly added, make sure it fills up all its
         // buffers before playing. This is to ensure the client will
@@ -991,12 +1402,16 @@
         track->mFillingUpStatus = Track::FS_FILLING;
         track->mResetDone = false;
         addActiveTrack(track);
-        return NO_ERROR;
+        status = NO_ERROR;
     }
-    return ALREADY_EXISTS;
+    
+    LOGV("mWaitWorkCV.broadcast");
+    mWaitWorkCV.broadcast();
+
+    return status;
 }
 
-void AudioFlinger::removeTrack(wp<Track> track, int name)
+void AudioFlinger::MixerThread::removeTrack(wp<Track> track, int name)
 {
     Mutex::Autolock _l(mLock);
     sp<Track> t = track.promote();
@@ -1005,7 +1420,7 @@
     }
 }
 
-void AudioFlinger::remove_track_l(wp<Track> track, int name)
+void AudioFlinger::MixerThread::remove_track_l(wp<Track> track, int name)
 {
     sp<Track> t = track.promote();
     if (t!=NULL) {
@@ -1016,7 +1431,7 @@
     mWaitWorkCV.broadcast();
 }
 
-void AudioFlinger::destroyTrack(const sp<Track>& track)
+void AudioFlinger::MixerThread::destroyTrack(const sp<Track>& track)
 {
     // NOTE: We're acquiring a strong reference on the track before
     // acquiring the lock, this is to make sure removing it from
@@ -1033,99 +1448,58 @@
     }
 }
 
-void AudioFlinger::addActiveTrack(const wp<Track>& t)
+
+void AudioFlinger::MixerThread::addActiveTrack(const wp<Track>& t)
 {
     mActiveTracks.add(t);
 
-#ifdef WITH_A2DP
-    // disable A2DP for certain stream types
-    sp<Track> track = t.promote();
-    if (streamDisablesA2dp(track->type())) {
-        if (mA2dpDisableCount++ == 0 && isA2dpEnabled()) {
-            setA2dpEnabled(false);
-            mA2dpSuppressed = true;
-            mMusicMuteSaved = mStreamTypes[AudioTrack::MUSIC].mute;
-            mStreamTypes[AudioTrack::MUSIC].mute = true;
-            LOGV("mA2dpSuppressed = true, track %d\n", track->name());
-        }
-        LOGV("mA2dpDisableCount incremented to %d, track %d\n", mA2dpDisableCount, track->name());
+    // Force routing to speaker for certain stream types
+    // The forced routing to speaker is managed by hardware mixer
+    if (mOutputType == AudioSystem::AUDIO_OUTPUT_HARDWARE) {
+        sp<Track> track = t.promote();
+        if (track == NULL) return;
+   
+        if (streamForcedToSpeaker(track->type())) {
+            mAudioFlinger->handleForcedSpeakerRoute(ACTIVE_TRACK_ADDED);
+        }        
     }
-#endif
 }
 
-void AudioFlinger::removeActiveTrack(const wp<Track>& t)
+void AudioFlinger::MixerThread::removeActiveTrack(const wp<Track>& t)
 {
     mActiveTracks.remove(t);
-#ifdef WITH_A2DP
-    // disable A2DP for certain stream types
-    sp<Track> track = t.promote();
-    if (streamDisablesA2dp(track->type())) {
-        if (mA2dpDisableCount > 0) {
-            mA2dpDisableCount--;
-            LOGV("mA2dpDisableCount decremented to %d, track %d\n", mA2dpDisableCount, track->name());
-            if (mA2dpDisableCount == 0 && mA2dpSuppressed) {
-                setA2dpEnabled(true);
-                mA2dpSuppressed = false;
-                mStreamTypes[AudioTrack::MUSIC].mute = mMusicMuteSaved;
-                LOGV("mA2dpSuppressed = false, track %d\n", track->name());
-            }   
-        } else
-            LOGE("mA2dpDisableCount is already zero");
+
+    // Force routing to speaker for certain stream types
+    // The forced routing to speaker is managed by hardware mixer
+    if (mOutputType == AudioSystem::AUDIO_OUTPUT_HARDWARE) {
+        sp<Track> track = t.promote();
+        if (track == NULL) return;
+
+        if (streamForcedToSpeaker(track->type())) {
+            mAudioFlinger->handleForcedSpeakerRoute(ACTIVE_TRACK_REMOVED);
+        }
     }
-#endif
 }
 
-int AudioFlinger::getTrackName()
+int AudioFlinger::MixerThread::getTrackName()
 {
-    // Both mixers must have the same set of track used to avoid mismatches when
-    // switching from A2DP output to hardware output
-    int a2DpName;
-    int hwName;
-#ifdef WITH_A2DP
-    a2DpName = mA2dpAudioMixer->getTrackName();
-#endif
-    hwName = mHardwareAudioMixer->getTrackName();
-    
-    LOGW_IF((a2DpName != hwName), "getTrackName track name mismatch! A2DP %d, HW %d", a2DpName, hwName);
-    
-    return hwName;
+    return mAudioMixer->getTrackName();
 }
 
-void AudioFlinger::deleteTrackName(int name)
+void AudioFlinger::MixerThread::deleteTrackName(int name)
 {
-    // Both mixers must have the same set of track used to avoid mismatches when
-    // switching from A2DP output to hardware output
-    mHardwareAudioMixer->deleteTrackName(name);
-#ifdef WITH_A2DP
-    mA2dpAudioMixer->deleteTrackName(name);
-#endif
+    mAudioMixer->deleteTrackName(name);
+}
+
+size_t AudioFlinger::MixerThread::getOutputFrameCount() 
+{
+    return mOutput->bufferSize() / mOutput->channelCount() / sizeof(int16_t);
 }
 
 // ----------------------------------------------------------------------------
 
-AudioFlinger::Client::Client(const sp<AudioFlinger>& audioFlinger, pid_t pid)
-    :   RefBase(),
-        mAudioFlinger(audioFlinger),
-        mMemoryDealer(new MemoryDealer(1024*1024)),
-        mPid(pid)
-{
-    // 1 MB of address space is good for 32 tracks, 8 buffers each, 4 KB/buffer
-}
-
-AudioFlinger::Client::~Client()
-{
-    mAudioFlinger->removeClient(mPid);
-}
-
-const sp<MemoryDealer>& AudioFlinger::Client::heap() const
-{
-    return mMemoryDealer;
-}
-
-// ----------------------------------------------------------------------------
-
-AudioFlinger::TrackBase::TrackBase(
-            const sp<AudioFlinger>& audioFlinger,
+AudioFlinger::MixerThread::TrackBase::TrackBase(
+            const sp<MixerThread>& mixerThread,
             const sp<Client>& client,
             int streamType,
             uint32_t sampleRate,
@@ -1134,7 +1508,7 @@
             int frameCount,
             const sp<IMemory>& sharedBuffer)
     :   RefBase(),
-        mAudioFlinger(audioFlinger),
+        mMixerThread(mixerThread),
         mClient(client),
         mStreamType(streamType),
         mFrameCount(0),
@@ -1143,7 +1517,7 @@
         mFormat(format),
         mFlags(0)
 {
-    mName = audioFlinger->getTrackName();
+    mName = mixerThread->getTrackName();
     LOGV("TrackBase contructor name %d, calling thread %d", mName, IPCThreadState::self()->getCallingPid());
     if (mName < 0) {
         LOGE("no more track names availlable");
@@ -1160,41 +1534,60 @@
        size += bufferSize;
    }
 
-    mCblkMemory = client->heap()->allocate(size);
-    if (mCblkMemory != 0) {
-        mCblk = static_cast<audio_track_cblk_t *>(mCblkMemory->pointer());
-        if (mCblk) { // construct the shared structure in-place.
-            new(mCblk) audio_track_cblk_t();
-            // clear all buffers
-            mCblk->frameCount = frameCount;
-            mCblk->sampleRate = sampleRate;
-            mCblk->channels = channelCount;
-            if (sharedBuffer == 0) {
-                mBuffer = (char*)mCblk + sizeof(audio_track_cblk_t);
-                memset(mBuffer, 0, frameCount*channelCount*sizeof(int16_t));
-                // Force underrun condition to avoid false underrun callback until first data is
-                // written to buffer
-                mCblk->flowControlFlag = 1;
-            } else {
-                mBuffer = sharedBuffer->pointer();
+   if (client != NULL) {
+        mCblkMemory = client->heap()->allocate(size);
+        if (mCblkMemory != 0) {
+            mCblk = static_cast<audio_track_cblk_t *>(mCblkMemory->pointer());
+            if (mCblk) { // construct the shared structure in-place.
+                new(mCblk) audio_track_cblk_t();
+                // clear all buffers
+                mCblk->frameCount = frameCount;
+                mCblk->sampleRate = sampleRate;
+                mCblk->channels = channelCount;
+                if (sharedBuffer == 0) {
+                    mBuffer = (char*)mCblk + sizeof(audio_track_cblk_t);
+                    memset(mBuffer, 0, frameCount*channelCount*sizeof(int16_t));
+                    // Force underrun condition to avoid false underrun callback until first data is
+                    // written to buffer
+                    mCblk->flowControlFlag = 1;
+                } else {
+                    mBuffer = sharedBuffer->pointer();
+                }
+                mBufferEnd = (uint8_t *)mBuffer + bufferSize;
             }
-            mBufferEnd = (uint8_t *)mBuffer + bufferSize;
+        } else {
+            LOGE("not enough memory for AudioTrack size=%u", size);
+            client->heap()->dump("AudioTrack");
+            return;
         }
-    } else {
-        LOGE("not enough memory for AudioTrack size=%u", size);
-        client->heap()->dump("AudioTrack");
-        return;
-    }
+   } else {
+       mCblk = (audio_track_cblk_t *)(new uint8_t[size]);
+       if (mCblk) { // construct the shared structure in-place.
+           new(mCblk) audio_track_cblk_t();
+           // clear all buffers
+           mCblk->frameCount = frameCount;
+           mCblk->sampleRate = sampleRate;
+           mCblk->channels = channelCount;
+           mBuffer = (char*)mCblk + sizeof(audio_track_cblk_t);
+           memset(mBuffer, 0, frameCount*channelCount*sizeof(int16_t));
+           // Force underrun condition to avoid false underrun callback until first data is
+           // written to buffer
+           mCblk->flowControlFlag = 1;
+           mBufferEnd = (uint8_t *)mBuffer + bufferSize;
+       }
+   }
 }
 
-AudioFlinger::TrackBase::~TrackBase()
+AudioFlinger::MixerThread::TrackBase::~TrackBase()
 {
-    mCblk->~audio_track_cblk_t();   // destroy our shared-structure.
+    if (mCblk) {
+        mCblk->~audio_track_cblk_t();   // destroy our shared-structure.        
+    }
     mCblkMemory.clear();            // and free the shared memory
     mClient.clear();
 }
 
-void AudioFlinger::TrackBase::releaseBuffer(AudioBufferProvider::Buffer* buffer)
+void AudioFlinger::MixerThread::TrackBase::releaseBuffer(AudioBufferProvider::Buffer* buffer)
 {
     buffer->raw = 0;
     mFrameCount = buffer->frameCount;
@@ -1202,7 +1595,7 @@
     buffer->frameCount = 0;
 }
 
-bool AudioFlinger::TrackBase::step() {
+bool AudioFlinger::MixerThread::TrackBase::step() {
     bool result;
     audio_track_cblk_t* cblk = this->cblk();
 
@@ -1214,7 +1607,7 @@
     return result;
 }
 
-void AudioFlinger::TrackBase::reset() {
+void AudioFlinger::MixerThread::TrackBase::reset() {
     audio_track_cblk_t* cblk = this->cblk();
 
     cblk->user = 0;
@@ -1225,20 +1618,20 @@
     LOGV("TrackBase::reset");
 }
 
-sp<IMemory> AudioFlinger::TrackBase::getCblk() const
+sp<IMemory> AudioFlinger::MixerThread::TrackBase::getCblk() const
 {
     return mCblkMemory;
 }
 
-int AudioFlinger::TrackBase::sampleRate() const {
+int AudioFlinger::MixerThread::TrackBase::sampleRate() const {
     return mCblk->sampleRate;
 }
 
-int AudioFlinger::TrackBase::channelCount() const {
+int AudioFlinger::MixerThread::TrackBase::channelCount() const {
     return mCblk->channels;
 }
 
-void* AudioFlinger::TrackBase::getBuffer(uint32_t offset, uint32_t frames) const {
+void* AudioFlinger::MixerThread::TrackBase::getBuffer(uint32_t offset, uint32_t frames) const {
     audio_track_cblk_t* cblk = this->cblk();
     int16_t *bufferStart = (int16_t *)mBuffer + (offset-cblk->serverBase)*cblk->channels;
     int16_t *bufferEnd = bufferStart + frames * cblk->channels;
@@ -1257,8 +1650,8 @@
 
 // ----------------------------------------------------------------------------
 
-AudioFlinger::Track::Track(
-            const sp<AudioFlinger>& audioFlinger,
+AudioFlinger::MixerThread::Track::Track(
+            const sp<MixerThread>& mixerThread,
             const sp<Client>& client,
             int streamType,
             uint32_t sampleRate,
@@ -1266,7 +1659,7 @@
             int channelCount,
             int frameCount,
             const sp<IMemory>& sharedBuffer)
-    :   TrackBase(audioFlinger, client, streamType, sampleRate, format, channelCount, frameCount, sharedBuffer)
+    :   TrackBase(mixerThread, client, streamType, sampleRate, format, channelCount, frameCount, sharedBuffer)
 {
     mVolume[0] = 1.0f;
     mVolume[1] = 1.0f;
@@ -1274,23 +1667,23 @@
     mSharedBuffer = sharedBuffer;
 }
 
-AudioFlinger::Track::~Track()
+AudioFlinger::MixerThread::Track::~Track()
 {
     wp<Track> weak(this); // never create a strong ref from the dtor
     mState = TERMINATED;
-    mAudioFlinger->removeTrack(weak, mName);
+    mMixerThread->removeTrack(weak, mName);
 }
 
-void AudioFlinger::Track::destroy()
+void AudioFlinger::MixerThread::Track::destroy()
 {
-    mAudioFlinger->destroyTrack(this);
+    mMixerThread->destroyTrack(this);
 }
 
-void AudioFlinger::Track::dump(char* buffer, size_t size)
+void AudioFlinger::MixerThread::Track::dump(char* buffer, size_t size)
 {
     snprintf(buffer, size, "  %5d %5d %3u %3u %3u %3u %1d %1d %1d %5u %5u %5u %04x %04x\n",
             mName - AudioMixer::TRACK0,
-            mClient->pid(),
+            (mClient == NULL) ? getpid() : mClient->pid(),
             mStreamType,
             mFormat,
             mCblk->channels,
@@ -1305,7 +1698,7 @@
             mCblk->user);
 }
 
-status_t AudioFlinger::Track::getNextBuffer(AudioBufferProvider::Buffer* buffer)
+status_t AudioFlinger::MixerThread::Track::getNextBuffer(AudioBufferProvider::Buffer* buffer)
 {
      audio_track_cblk_t* cblk = this->cblk();
      uint32_t framesReady;
@@ -1345,53 +1738,54 @@
      return NOT_ENOUGH_DATA;
 }
 
-bool AudioFlinger::Track::isReady() const {
+bool AudioFlinger::MixerThread::Track::isReady() const {
     if (mFillingUpStatus != FS_FILLING) return true;
 
     if (mCblk->framesReady() >= mCblk->frameCount ||
         mCblk->forceReady) {
         mFillingUpStatus = FS_FILLED;
         mCblk->forceReady = 0;
+        LOGV("Track::isReady() track %d for output %d", mName, mMixerThread->mOutputType);
         return true;
     }
     return false;
 }
 
-status_t AudioFlinger::Track::start()
+status_t AudioFlinger::MixerThread::Track::start()
 {
-    LOGV("start(%d), calling thread %d", mName, IPCThreadState::self()->getCallingPid());
-    mAudioFlinger->addTrack(this);
+    LOGV("start(%d), calling thread %d for output %d", mName, IPCThreadState::self()->getCallingPid(), mMixerThread->mOutputType);
+    mMixerThread->addTrack(this);
     return NO_ERROR;
 }
 
-void AudioFlinger::Track::stop()
+void AudioFlinger::MixerThread::Track::stop()
 {
-    LOGV("stop(%d), calling thread %d", mName, IPCThreadState::self()->getCallingPid());
-    Mutex::Autolock _l(mAudioFlinger->mLock);
+    LOGV("stop(%d), calling thread %d for output %d", mName, IPCThreadState::self()->getCallingPid(), mMixerThread->mOutputType);
+    Mutex::Autolock _l(mMixerThread->mLock);
     if (mState > STOPPED) {
         mState = STOPPED;
         // If the track is not active (PAUSED and buffers full), flush buffers
-        if (mAudioFlinger->mActiveTracks.indexOf(this) < 0) {
+        if (mMixerThread->mActiveTracks.indexOf(this) < 0) {
             reset();
         }
         LOGV("(> STOPPED) => STOPPED (%d)", mName);
     }
 }
 
-void AudioFlinger::Track::pause()
+void AudioFlinger::MixerThread::Track::pause()
 {
     LOGV("pause(%d), calling thread %d", mName, IPCThreadState::self()->getCallingPid());
-    Mutex::Autolock _l(mAudioFlinger->mLock);
+    Mutex::Autolock _l(mMixerThread->mLock);
     if (mState == ACTIVE || mState == RESUMING) {
         mState = PAUSING;
         LOGV("ACTIVE/RESUMING => PAUSING (%d)", mName);
     }
 }
 
-void AudioFlinger::Track::flush()
+void AudioFlinger::MixerThread::Track::flush()
 {
     LOGV("flush(%d)", mName);
-    Mutex::Autolock _l(mAudioFlinger->mLock);
+    Mutex::Autolock _l(mMixerThread->mLock);
     if (mState != STOPPED && mState != PAUSED && mState != PAUSING) {
         return;
     }
@@ -1407,7 +1801,7 @@
     reset();
 }
 
-void AudioFlinger::Track::reset()
+void AudioFlinger::MixerThread::Track::reset()
 {
     // Do not reset twice to avoid discarding data written just after a flush and before
     // the audioflinger thread detects the track is stopped.
@@ -1422,12 +1816,12 @@
     }
 }
 
-void AudioFlinger::Track::mute(bool muted)
+void AudioFlinger::MixerThread::Track::mute(bool muted)
 {
     mMute = muted;
 }
 
-void AudioFlinger::Track::setVolume(float left, float right)
+void AudioFlinger::MixerThread::Track::setVolume(float left, float right)
 {
     mVolume[0] = left;
     mVolume[1] = right;
@@ -1435,7 +1829,289 @@
 
 // ----------------------------------------------------------------------------
 
-AudioFlinger::TrackHandle::TrackHandle(const sp<AudioFlinger::Track>& track)
+AudioFlinger::MixerThread::RecordTrack::RecordTrack(
+            const sp<MixerThread>& mixerThread,
+            const sp<Client>& client,
+            int streamType,
+            uint32_t sampleRate,
+            int format,
+            int channelCount,
+            int frameCount)
+    :   TrackBase(mixerThread, client, streamType, sampleRate, format,
+            channelCount, frameCount, 0),
+            mOverflow(false)
+{
+}
+
+AudioFlinger::MixerThread::RecordTrack::~RecordTrack()
+{
+    mMixerThread->deleteTrackName(mName);
+}
+
+status_t AudioFlinger::MixerThread::RecordTrack::getNextBuffer(AudioBufferProvider::Buffer* buffer)
+{
+    audio_track_cblk_t* cblk = this->cblk();
+    uint32_t framesAvail;
+    uint32_t framesReq = buffer->frameCount;
+
+     // Check if last stepServer failed, try to step now
+    if (mFlags & TrackBase::STEPSERVER_FAILED) {
+        if (!step()) goto getNextBuffer_exit;
+        LOGV("stepServer recovered");
+        mFlags &= ~TrackBase::STEPSERVER_FAILED;
+    }
+
+    framesAvail = cblk->framesAvailable_l();
+
+    if (LIKELY(framesAvail)) {
+        uint32_t s = cblk->server;
+        uint32_t bufferEnd = cblk->serverBase + cblk->frameCount;
+
+        if (framesReq > framesAvail) {
+            framesReq = framesAvail;
+        }
+        if (s + framesReq > bufferEnd) {
+            framesReq = bufferEnd - s;
+        }
+
+        buffer->raw = getBuffer(s, framesReq);
+        if (buffer->raw == 0) goto getNextBuffer_exit;
+
+        buffer->frameCount = framesReq;
+        return NO_ERROR;
+    }
+
+getNextBuffer_exit:
+    buffer->raw = 0;
+    buffer->frameCount = 0;
+    return NOT_ENOUGH_DATA;
+}
+
+status_t AudioFlinger::MixerThread::RecordTrack::start()
+{
+    return mMixerThread->mAudioFlinger->startRecord(this);
+}
+
+void AudioFlinger::MixerThread::RecordTrack::stop()
+{
+    mMixerThread->mAudioFlinger->stopRecord(this);
+    TrackBase::reset();
+    // Force overerrun condition to avoid false overrun callback until first data is
+    // read from buffer
+    mCblk->flowControlFlag = 1;
+}
+
+
+// ----------------------------------------------------------------------------
+
+AudioFlinger::MixerThread::OutputTrack::OutputTrack(
+            const sp<MixerThread>& mixerThread,
+            uint32_t sampleRate,
+            int format,
+            int channelCount,
+            int frameCount)
+    :   Track(mixerThread, NULL, AudioSystem::SYSTEM, sampleRate, format, channelCount, frameCount, NULL),
+    mOutputMixerThread(mixerThread)
+{
+                
+    mCblk->out = 1;
+    mCblk->buffers = (char*)mCblk + sizeof(audio_track_cblk_t);
+    mCblk->volume[0] = mCblk->volume[1] = 0x1000;
+    mOutBuffer.frameCount = 0;
+    mCblk->bufferTimeoutMs = 10;
+    
+    LOGV("OutputTrack constructor mCblk %p, mBuffer %p, mCblk->buffers %p, mCblk->frameCount %d, mCblk->sampleRate %d, mCblk->channels %d mBufferEnd %p", 
+            mCblk, mBuffer, mCblk->buffers, mCblk->frameCount, mCblk->sampleRate, mCblk->channels, mBufferEnd);
+    
+}
+
+AudioFlinger::MixerThread::OutputTrack::~OutputTrack()
+{
+    stop();
+}
+
+status_t AudioFlinger::MixerThread::OutputTrack::start()
+{
+    status_t status = Track::start();
+    
+    mRetryCount = 127;
+    return status;
+}
+
+void AudioFlinger::MixerThread::OutputTrack::stop()
+{
+    Track::stop();
+    clearBufferQueue();
+    mOutBuffer.frameCount = 0;
+}
+
+void AudioFlinger::MixerThread::OutputTrack::write(int16_t* data, uint32_t frames)
+{
+    Buffer *pInBuffer;
+    Buffer inBuffer;
+    uint32_t channels = mCblk->channels;
+        
+    inBuffer.frameCount = frames;
+    inBuffer.i16 = data;
+    
+    if (mCblk->user == 0) {
+        if (mOutputMixerThread->isMusicActive()) {
+            mCblk->forceReady = 1;
+            LOGV("OutputTrack::start() force ready");
+        } else if (mCblk->frameCount > frames){
+            if (mBufferQueue.size() < kMaxOutputTrackBuffers) {
+                uint32_t startFrames = (mCblk->frameCount - frames);
+                LOGV("OutputTrack::start() write %d frames", startFrames);
+                pInBuffer = new Buffer;
+                pInBuffer->mBuffer = new int16_t[startFrames * channels];
+                pInBuffer->frameCount = startFrames;
+                pInBuffer->i16 = pInBuffer->mBuffer;
+                memset(pInBuffer->raw, 0, startFrames * channels * sizeof(int16_t));
+                mBufferQueue.add(pInBuffer);                
+            } else {
+                LOGW ("OutputTrack::write() no more buffers");
+            }
+        }        
+    }
+
+    while (1) { 
+        // First write pending buffers, then new data
+        if (mBufferQueue.size()) {
+            pInBuffer = mBufferQueue.itemAt(0);
+        } else {
+            pInBuffer = &inBuffer;
+        }
+ 
+        if (pInBuffer->frameCount == 0) {
+            break;
+        }
+        
+        if (mOutBuffer.frameCount == 0) {
+            mOutBuffer.frameCount = pInBuffer->frameCount;
+            if (obtainBuffer(&mOutBuffer) == (status_t)AudioTrack::NO_MORE_BUFFERS) {
+                break;
+            }
+        }
+            
+        uint32_t outFrames = pInBuffer->frameCount > mOutBuffer.frameCount ? mOutBuffer.frameCount : pInBuffer->frameCount;
+        memcpy(mOutBuffer.raw, pInBuffer->raw, outFrames * channels * sizeof(int16_t));
+        mCblk->stepUser(outFrames);
+        pInBuffer->frameCount -= outFrames;
+        pInBuffer->i16 += outFrames * channels;
+        mOutBuffer.frameCount -= outFrames;
+        mOutBuffer.i16 += outFrames * channels;            
+        
+        if (pInBuffer->frameCount == 0) {
+            if (mBufferQueue.size()) {
+                mBufferQueue.removeAt(0);
+                delete [] pInBuffer->mBuffer;
+                delete pInBuffer;
+            } else {
+                break;
+            }
+        }
+    }
+ 
+    // If we could not write all frames, allocate a buffer and queue it for next time.
+    if (inBuffer.frameCount) {
+        if (mBufferQueue.size() < kMaxOutputTrackBuffers) {
+            pInBuffer = new Buffer;
+            pInBuffer->mBuffer = new int16_t[inBuffer.frameCount * channels];
+            pInBuffer->frameCount = inBuffer.frameCount;
+            pInBuffer->i16 = pInBuffer->mBuffer;
+            memcpy(pInBuffer->raw, inBuffer.raw, inBuffer.frameCount * channels * sizeof(int16_t));
+            mBufferQueue.add(pInBuffer);
+        } else {
+            LOGW("OutputTrack::write() no more buffers");
+        }
+    }
+    
+    // Calling write() with a 0 length buffer, means that no more data will be written:
+    // If no more buffers are pending, fill output track buffer to make sure it is started 
+    // by output mixer.
+    if (frames == 0 && mBufferQueue.size() == 0 && mCblk->user < mCblk->frameCount) {
+        frames = mCblk->frameCount - mCblk->user;
+        pInBuffer = new Buffer;
+        pInBuffer->mBuffer = new int16_t[frames * channels];
+        pInBuffer->frameCount = frames;
+        pInBuffer->i16 = pInBuffer->mBuffer;
+        memset(pInBuffer->raw, 0, frames * channels * sizeof(int16_t));
+        mBufferQueue.add(pInBuffer);
+    }
+
+}
+
+status_t AudioFlinger::MixerThread::OutputTrack::obtainBuffer(AudioBufferProvider::Buffer* buffer)
+{
+    int active;
+    int timeout = 0;
+    status_t result;
+    audio_track_cblk_t* cblk = mCblk;
+    uint32_t framesReq = buffer->frameCount;
+
+    LOGV("OutputTrack::obtainBuffer user %d, server %d", cblk->user, cblk->server);
+    buffer->frameCount  = 0;
+    
+    uint32_t framesAvail = cblk->framesAvailable();
+
+    if (framesAvail == 0) {
+        return AudioTrack::NO_MORE_BUFFERS;
+    }
+
+    if (framesReq > framesAvail) {
+        framesReq = framesAvail;
+    }
+
+    uint32_t u = cblk->user;
+    uint32_t bufferEnd = cblk->userBase + cblk->frameCount;
+
+    if (u + framesReq > bufferEnd) {
+        framesReq = bufferEnd - u;
+    }
+
+    buffer->frameCount  = framesReq;
+    buffer->raw         = (void *)cblk->buffer(u);
+    return NO_ERROR;
+}
+
+
+void AudioFlinger::MixerThread::OutputTrack::clearBufferQueue()
+{
+    size_t size = mBufferQueue.size();
+    Buffer *pBuffer;
+    
+    for (size_t i = 0; i < size; i++) {
+        pBuffer = mBufferQueue.itemAt(i);
+        delete [] pBuffer->mBuffer;
+        delete pBuffer;
+    }
+    mBufferQueue.clear();
+}
+
+// ----------------------------------------------------------------------------
+
+AudioFlinger::Client::Client(const sp<AudioFlinger>& audioFlinger, pid_t pid)
+    :   RefBase(),
+        mAudioFlinger(audioFlinger),
+        mMemoryDealer(new MemoryDealer(1024*1024)),
+        mPid(pid)
+{
+    // 1 MB of address space is good for 32 tracks, 8 buffers each, 4 KB/buffer
+}
+
+AudioFlinger::Client::~Client()
+{
+    mAudioFlinger->removeClient(mPid);
+}
+
+const sp<MemoryDealer>& AudioFlinger::Client::heap() const
+{
+    return mMemoryDealer;
+}
+
+// ----------------------------------------------------------------------------
+
+AudioFlinger::TrackHandle::TrackHandle(const sp<AudioFlinger::MixerThread::Track>& track)
     : BnAudioTrack(),
       mTrack(track)
 {
@@ -1496,7 +2172,7 @@
         status_t *status)
 {
     sp<AudioRecordThread> thread;
-    sp<RecordTrack> recordTrack;
+    sp<MixerThread::RecordTrack> recordTrack;
     sp<RecordHandle> recordHandle;
     sp<Client> client;
     wp<Client> wclient;
@@ -1523,12 +2199,6 @@
         goto Exit;
     }
 
-    if (mSampleRate == 0) {
-        LOGE("Audio driver not initialized");
-        lStatus = NO_INIT;
-        goto Exit;
-    }
-
     if (mAudioRecordThread == 0) {
         LOGE("Audio record thread not started");
         lStatus = NO_INIT;
@@ -1561,7 +2231,7 @@
     frameCount = ((frameCount - 1)/inFrameCount + 1) * inFrameCount;
 
     // create new record track and pass to record thread
-    recordTrack = new RecordTrack(this, client, streamType, sampleRate,
+    recordTrack = new MixerThread::RecordTrack(mHardwareMixerThread, client, streamType, sampleRate,
             format, channelCount, frameCount);
 
     // return to handle to client
@@ -1575,97 +2245,22 @@
     return recordHandle;
 }
 
-status_t AudioFlinger::startRecord(RecordTrack* recordTrack) {
+status_t AudioFlinger::startRecord(MixerThread::RecordTrack* recordTrack) {
     if (mAudioRecordThread != 0) {
         return mAudioRecordThread->start(recordTrack);        
     }
     return NO_INIT;
 }
 
-void AudioFlinger::stopRecord(RecordTrack* recordTrack) {
+void AudioFlinger::stopRecord(MixerThread::RecordTrack* recordTrack) {
     if (mAudioRecordThread != 0) {
         mAudioRecordThread->stop(recordTrack);
     }
 }
 
-
 // ----------------------------------------------------------------------------
 
-AudioFlinger::RecordTrack::RecordTrack(
-            const sp<AudioFlinger>& audioFlinger,
-            const sp<Client>& client,
-            int streamType,
-            uint32_t sampleRate,
-            int format,
-            int channelCount,
-            int frameCount)
-    :   TrackBase(audioFlinger, client, streamType, sampleRate, format,
-            channelCount, frameCount, 0),
-            mOverflow(false)
-{
-}
-
-AudioFlinger::RecordTrack::~RecordTrack()
-{
-    mAudioFlinger->deleteTrackName(mName);
-}
-
-status_t AudioFlinger::RecordTrack::getNextBuffer(AudioBufferProvider::Buffer* buffer)
-{
-    audio_track_cblk_t* cblk = this->cblk();
-    uint32_t framesAvail;
-    uint32_t framesReq = buffer->frameCount;
-
-     // Check if last stepServer failed, try to step now
-    if (mFlags & TrackBase::STEPSERVER_FAILED) {
-        if (!step()) goto getNextBuffer_exit;
-        LOGV("stepServer recovered");
-        mFlags &= ~TrackBase::STEPSERVER_FAILED;
-    }
-
-    framesAvail = cblk->framesAvailable_l();
-
-    if (LIKELY(framesAvail)) {
-        uint32_t s = cblk->server;
-        uint32_t bufferEnd = cblk->serverBase + cblk->frameCount;
-
-        if (framesReq > framesAvail) {
-            framesReq = framesAvail;
-        }
-        if (s + framesReq > bufferEnd) {
-            framesReq = bufferEnd - s;
-        }
-
-        buffer->raw = getBuffer(s, framesReq);
-        if (buffer->raw == 0) goto getNextBuffer_exit;
-
-        buffer->frameCount = framesReq;
-        return NO_ERROR;
-    }
-
-getNextBuffer_exit:
-    buffer->raw = 0;
-    buffer->frameCount = 0;
-    return NOT_ENOUGH_DATA;
-}
-
-status_t AudioFlinger::RecordTrack::start()
-{
-    return mAudioFlinger->startRecord(this);
-}
-
-void AudioFlinger::RecordTrack::stop()
-{
-    mAudioFlinger->stopRecord(this);
-    TrackBase::reset();
-    // Force overerrun condition to avoid false overrun callback until first data is
-    // read from buffer
-    mCblk->flowControlFlag = 1;
-}
-
-// ----------------------------------------------------------------------------
-
-AudioFlinger::RecordHandle::RecordHandle(const sp<AudioFlinger::RecordTrack>& recordTrack)
+AudioFlinger::RecordHandle::RecordHandle(const sp<AudioFlinger::MixerThread::RecordTrack>& recordTrack)
     : BnAudioRecord(),
     mRecordTrack(recordTrack)
 {
@@ -1786,7 +2381,7 @@
     return false;
 }
 
-status_t AudioFlinger::AudioRecordThread::start(RecordTrack* recordTrack)
+status_t AudioFlinger::AudioRecordThread::start(MixerThread::RecordTrack* recordTrack)
 {
     LOGV("AudioRecordThread::start");
     AutoMutex lock(&mLock);
@@ -1807,7 +2402,7 @@
     return mStartStatus;
 }
 
-void AudioFlinger::AudioRecordThread::stop(RecordTrack* recordTrack) {
+void AudioFlinger::AudioRecordThread::stop(MixerThread::RecordTrack* recordTrack) {
     LOGV("AudioRecordThread::stop");
     AutoMutex lock(&mLock);
     if (mActive && (recordTrack == mRecordTrack.get())) {
diff --git a/libs/audioflinger/AudioFlinger.h b/libs/audioflinger/AudioFlinger.h
index 38fa001..3b5932d 100644
--- a/libs/audioflinger/AudioFlinger.h
+++ b/libs/audioflinger/AudioFlinger.h
@@ -33,6 +33,7 @@
 #include <utils/MemoryDealer.h>
 #include <utils/KeyedVector.h>
 #include <utils/SortedVector.h>
+#include <utils/Vector.h>
 
 #include <hardware_legacy/AudioHardwareInterface.h>
 
@@ -55,18 +56,13 @@
 
 static const nsecs_t kStandbyTimeInNsecs = seconds(3);
 
-class AudioFlinger : public BnAudioFlinger, protected Thread, public IBinder::DeathRecipient 
+class AudioFlinger : public BnAudioFlinger, public IBinder::DeathRecipient 
 {
 public:
     static void instantiate();
 
     virtual     status_t    dump(int fd, const Vector<String16>& args);
 
-    // Thread virtuals
-    virtual     bool        threadLoop();
-    virtual     status_t    readyToRun();
-    virtual     void        onFirstRef();
-
     // IAudioFlinger interface
     virtual sp<IAudioTrack> createTrack(
                                 pid_t pid,
@@ -79,11 +75,11 @@
                                 const sp<IMemory>& sharedBuffer,
                                 status_t *status);
 
-    virtual     uint32_t    sampleRate() const;
-    virtual     int         channelCount() const;
-    virtual     int         format() const;
-    virtual     size_t      frameCount() const;
-    virtual     size_t      latency() const;
+    virtual     uint32_t    sampleRate(int output) const;
+    virtual     int         channelCount(int output) const;
+    virtual     int         format(int output) const;
+    virtual     size_t      frameCount(int output) const;
+    virtual     uint32_t    latency(int output) const;
 
     virtual     status_t    setMasterVolume(float value);
     virtual     status_t    setMasterMute(bool muted);
@@ -108,6 +104,8 @@
 
     virtual     bool        isMusicActive() const;
 
+    virtual     bool        isA2dpEnabled() const;
+
     virtual     status_t    setParameter(const char* key, const char* value);
 
     virtual     void        registerClient(const sp<IAudioFlingerClient>& client);
@@ -159,23 +157,26 @@
                             AudioFlinger();
     virtual                 ~AudioFlinger();
     
-    void                    setOutput(AudioStreamOut* output);
-    void                    doSetOutput(AudioStreamOut* output);
-    size_t                  getOutputFrameCount(AudioStreamOut* output);
+    void                    setOutput(int outputType);
+    void                    doSetOutput(int outputType);
 
 #ifdef WITH_A2DP
-    static bool             streamDisablesA2dp(int streamType);
-    inline bool             isA2dpEnabled() const {
-                                return (mRequestedOutput == mA2dpOutput ||
-                                        (mOutput && mOutput == mA2dpOutput));
-                            }
     void                    setA2dpEnabled(bool enable);
 #endif
+    static bool             streamForcedToSpeaker(int streamType);
+    
+    // Management of forced route to speaker for certain track types.
+    enum force_speaker_command {
+        ACTIVE_TRACK_ADDED = 0,
+        ACTIVE_TRACK_REMOVED,
+        CHECK_ROUTE_RESTORE_TIME,
+        FORCE_ROUTE_RESTORE
+    };
+    void                    handleForcedSpeakerRoute(int command);
 
     // Internal dump utilites.
     status_t dumpPermissionDenial(int fd, const Vector<String16>& args);
     status_t dumpClients(int fd, const Vector<String16>& args);
-    status_t dumpTracks(int fd, const Vector<String16>& args);
     status_t dumpInternals(int fd, const Vector<String16>& args);
 
     // --- Client ---
@@ -194,168 +195,348 @@
     };
 
 
-    // --- Track ---
     class TrackHandle;
     class RecordHandle;
     class AudioRecordThread;
 
-    // base for record and playback
-    class TrackBase : public AudioBufferProvider, public RefBase {
-
+    
+    // --- MixerThread ---
+    class MixerThread : public Thread {
     public:
-        enum track_state {
-            IDLE,
-            TERMINATED,
-            STOPPED,
-            RESUMING,
-            ACTIVE,
-            PAUSING,
-            PAUSED
+        
+        // --- Track ---
+
+        // base for record and playback
+        class TrackBase : public AudioBufferProvider, public RefBase {
+
+        public:
+            enum track_state {
+                IDLE,
+                TERMINATED,
+                STOPPED,
+                RESUMING,
+                ACTIVE,
+                PAUSING,
+                PAUSED
+            };
+
+            enum track_flags {
+                STEPSERVER_FAILED = 0x01   //  StepServer could not acquire cblk->lock mutex
+            };
+
+                                TrackBase(  const sp<MixerThread>& mixerThread,
+                                        const sp<Client>& client,
+                                        int streamType,
+                                        uint32_t sampleRate,
+                                        int format,
+                                        int channelCount,
+                                        int frameCount,
+                                        const sp<IMemory>& sharedBuffer);
+                                ~TrackBase();
+
+            virtual status_t    start() = 0;
+            virtual void        stop() = 0;
+                    sp<IMemory> getCblk() const;
+
+        protected:
+            friend class MixerThread;
+            friend class RecordHandle;
+            friend class AudioRecordThread;
+
+                                TrackBase(const TrackBase&);
+                                TrackBase& operator = (const TrackBase&);
+
+            virtual status_t getNextBuffer(AudioBufferProvider::Buffer* buffer) = 0;
+            virtual void releaseBuffer(AudioBufferProvider::Buffer* buffer);
+
+            audio_track_cblk_t* cblk() const {
+                return mCblk;
+            }
+
+            int type() const {
+                return mStreamType;
+            }
+
+            int format() const {
+                return mFormat;
+            }
+
+            int channelCount() const ;
+
+            int sampleRate() const;
+
+            void* getBuffer(uint32_t offset, uint32_t frames) const;
+
+            int name() const {
+                return mName;
+            }
+
+            bool isStopped() const {
+                return mState == STOPPED;
+            }
+
+            bool isTerminated() const {
+                return mState == TERMINATED;
+            }
+
+            bool step();
+            void reset();
+
+            sp<MixerThread>     mMixerThread;
+            sp<Client>          mClient;
+            sp<IMemory>         mCblkMemory;
+            audio_track_cblk_t* mCblk;
+            int                 mStreamType;
+            void*               mBuffer;
+            void*               mBufferEnd;
+            uint32_t            mFrameCount;
+            int                 mName;
+            // we don't really need a lock for these
+            int                 mState;
+            int                 mClientTid;
+            uint8_t             mFormat;
+            uint8_t             mFlags;
         };
 
-        enum track_flags {
-            STEPSERVER_FAILED = 0x01   //  StepServer could not acquire cblk->lock mutex
+        // playback track
+        class Track : public TrackBase {
+        public:
+                                Track(  const sp<MixerThread>& mixerThread,
+                                        const sp<Client>& client,
+                                        int streamType,
+                                        uint32_t sampleRate,
+                                        int format,
+                                        int channelCount,
+                                        int frameCount,
+                                        const sp<IMemory>& sharedBuffer);
+                                ~Track();
+
+                    void        dump(char* buffer, size_t size);
+            virtual status_t    start();
+            virtual void        stop();
+                    void        pause();
+
+                    void        flush();
+                    void        destroy();
+                    void        mute(bool);
+                    void        setVolume(float left, float right);
+
+        protected:
+            friend class MixerThread;
+            friend class AudioFlinger;
+            friend class AudioFlinger::TrackHandle;
+
+                                Track(const Track&);
+                                Track& operator = (const Track&);
+
+            virtual status_t getNextBuffer(AudioBufferProvider::Buffer* buffer);
+
+            bool isMuted() const {
+                return (mMute || mMixerThread->mStreamTypes[mStreamType].mute);
+            }
+
+            bool isPausing() const {
+                return mState == PAUSING;
+            }
+
+            bool isPaused() const {
+                return mState == PAUSED;
+            }
+
+            bool isReady() const;
+
+            void setPaused() { mState = PAUSED; }
+            void reset();
+
+            // we don't really need a lock for these
+            float               mVolume[2];
+            volatile bool       mMute;
+            // FILLED state is used for suppressing volume ramp at begin of playing
+            enum {FS_FILLING, FS_FILLED, FS_ACTIVE};
+            mutable uint8_t     mFillingUpStatus;
+            int8_t              mRetryCount;
+            sp<IMemory>         mSharedBuffer;
+            bool                mResetDone;
+        };  // end of Track
+
+        // record track
+        class RecordTrack : public TrackBase {
+        public:
+                                RecordTrack(  const sp<MixerThread>& mixerThread,
+                                        const sp<Client>& client,
+                                        int streamType,
+                                        uint32_t sampleRate,
+                                        int format,
+                                        int channelCount,
+                                        int frameCount);
+                                ~RecordTrack();
+
+            virtual status_t    start();
+            virtual void        stop();
+
+                    bool        overflow() { bool tmp = mOverflow; mOverflow = false; return tmp; }
+                    bool        setOverflow() { bool tmp = mOverflow; mOverflow = true; return tmp; }
+
+        private:
+            friend class AudioFlinger;
+            friend class AudioFlinger::RecordHandle;
+            friend class AudioFlinger::AudioRecordThread;
+            friend class MixerThread;
+
+                                RecordTrack(const Track&);
+                                RecordTrack& operator = (const Track&);
+
+            virtual status_t getNextBuffer(AudioBufferProvider::Buffer* buffer);
+
+            bool                mOverflow;
         };
 
-                            TrackBase(  const sp<AudioFlinger>& audioFlinger,
-                                    const sp<Client>& client,
+        // playback track
+        class OutputTrack : public Track {
+        public:
+            
+            class Buffer: public AudioBufferProvider::Buffer {
+            public:
+                int16_t *mBuffer;
+            };
+            
+                                OutputTrack(  const sp<MixerThread>& mixerThread,
+                                        uint32_t sampleRate,
+                                        int format,
+                                        int channelCount,
+                                        int frameCount);
+                                ~OutputTrack();
+
+            virtual status_t    start();
+            virtual void        stop();
+                    void        write(int16_t* data, uint32_t frames);
+                    bool        bufferQueueEmpty() { return (mBufferQueue.size() == 0) ? true : false; }
+
+        private:
+
+            status_t            obtainBuffer(AudioBufferProvider::Buffer* buffer);
+            void                clearBufferQueue();
+            
+            sp<MixerThread>             mOutputMixerThread;
+            Vector < Buffer* >          mBufferQueue;
+            AudioBufferProvider::Buffer mOutBuffer;
+            uint32_t                    mFramesWritten;
+            
+         };  // end of OutputTrack
+
+        MixerThread (const sp<AudioFlinger>& audioFlinger, AudioStreamOut* output, int outputType);
+        virtual             ~MixerThread();
+
+        virtual     status_t    dump(int fd, const Vector<String16>& args);
+
+        // Thread virtuals
+        virtual     bool        threadLoop();
+        virtual     status_t    readyToRun();
+        virtual     void        onFirstRef();
+
+        virtual     uint32_t    sampleRate() const;
+        virtual     int         channelCount() const;
+        virtual     int         format() const;
+        virtual     size_t      frameCount() const;
+        virtual     uint32_t    latency() const;
+
+        virtual     status_t    setMasterVolume(float value);
+        virtual     status_t    setMasterMute(bool muted);
+
+        virtual     float       masterVolume() const;
+        virtual     bool        masterMute() const;
+
+        virtual     status_t    setStreamVolume(int stream, float value);
+        virtual     status_t    setStreamMute(int stream, bool muted);
+
+        virtual     float       streamVolume(int stream) const;
+        virtual     bool        streamMute(int stream) const;
+
+                    bool        isMusicActive() const;
+        
+                    
+        sp<Track> createTrack(
+                                    const sp<AudioFlinger::Client>& client,
                                     int streamType,
                                     uint32_t sampleRate,
                                     int format,
                                     int channelCount,
                                     int frameCount,
-                                    const sp<IMemory>& sharedBuffer);
-                            ~TrackBase();
+                                    const sp<IMemory>& sharedBuffer,
+                                    status_t *status);
 
-        virtual status_t    start() = 0;
-        virtual void        stop() = 0;
-                sp<IMemory> getCblk() const;
-
-    protected:
-        friend class AudioFlinger;
-        friend class RecordHandle;
-        friend class AudioRecordThread;
-
-                            TrackBase(const TrackBase&);
-                            TrackBase& operator = (const TrackBase&);
-
-        virtual status_t getNextBuffer(AudioBufferProvider::Buffer* buffer) = 0;
-        virtual void releaseBuffer(AudioBufferProvider::Buffer* buffer);
-
-        audio_track_cblk_t* cblk() const {
-            return mCblk;
-        }
-
-        int type() const {
-            return mStreamType;
-        }
-
-        int format() const {
-            return mFormat;
-        }
-
-        int channelCount() const ;
-
-        int sampleRate() const;
-
-        void* getBuffer(uint32_t offset, uint32_t frames) const;
-
-        int name() const {
-            return mName;
-        }
-
-        bool isStopped() const {
-            return mState == STOPPED;
-        }
-
-        bool isTerminated() const {
-            return mState == TERMINATED;
-        }
-
-        bool step();
-        void reset();
-
-        sp<AudioFlinger>    mAudioFlinger;
-        sp<Client>          mClient;
-        sp<IMemory>         mCblkMemory;
-        audio_track_cblk_t* mCblk;
-        int                 mStreamType;
-        void*               mBuffer;
-        void*               mBufferEnd;
-        uint32_t            mFrameCount;
-        int                 mName;
-        // we don't really need a lock for these
-        int                 mState;
-        int                 mClientTid;
-        uint8_t             mFormat;
-        uint8_t             mFlags;
-    };
-
-    // playback track
-    class Track : public TrackBase {
-    public:
-                            Track(  const sp<AudioFlinger>& audioFlinger,
-                                    const sp<Client>& client,
-                                    int streamType,
-                                    uint32_t sampleRate,
-                                    int format,
-                                    int channelCount,
-                                    int frameCount,
-                                    const sp<IMemory>& sharedBuffer);
-                            ~Track();
-
-                void        dump(char* buffer, size_t size);
-        virtual status_t    start();
-        virtual void        stop();
-                void        pause();
-
-                void        flush();
-                void        destroy();
-                void        mute(bool);
-                void        setVolume(float left, float right);
+                    void        wakeUp() { mWaitWorkCV.broadcast(); }
+                    
+                    void        getTracks(SortedVector < sp<Track> >& tracks,
+                                          SortedVector < wp<Track> >& activeTracks);
+                    void        putTracks(SortedVector < sp<Track> >& tracks,
+                                          SortedVector < wp<Track> >& activeTracks);
+                    void        setOuputTrack(OutputTrack *track) { mOutputTrack = track; }
+                    
+        struct  stream_type_t {
+            stream_type_t()
+                :   volume(1.0f),
+                    mute(false)
+            {
+            }
+            float       volume;
+            bool        mute;
+        };
 
     private:
+
+
         friend class AudioFlinger;
-        friend class TrackHandle;
+        friend class Track;
+        friend class TrackBase;
+        friend class RecordTrack;
+        
+        MixerThread(const Client&);
+        MixerThread& operator = (const MixerThread&);
+  
+        status_t    addTrack(const sp<Track>& track);
+        void        removeTrack(wp<Track> track, int name);
+        void        remove_track_l(wp<Track> track, int name);
+        void        destroyTrack(const sp<Track>& track);
+        int         getTrackName();
+        void        deleteTrackName(int name);
+        void        addActiveTrack(const wp<Track>& t);
+        void        removeActiveTrack(const wp<Track>& t);
+        size_t      getOutputFrameCount();
 
-                            Track(const Track&);
-                            Track& operator = (const Track&);
+        status_t    dumpInternals(int fd, const Vector<String16>& args);
+        status_t    dumpTracks(int fd, const Vector<String16>& args);
+        
+        sp<AudioFlinger>                mAudioFlinger;       
+        mutable     Mutex               mLock;
+        mutable     Condition           mWaitWorkCV;
+        SortedVector< wp<Track> >       mActiveTracks;
+        SortedVector< sp<Track> >       mTracks;
+        stream_type_t                   mStreamTypes[AudioSystem::NUM_STREAM_TYPES];
+        AudioMixer*                     mAudioMixer;
+        AudioStreamOut*                 mOutput;
+        int                             mOutputType;
+        uint32_t                        mSampleRate;
+        size_t                          mFrameCount;
+        int                             mChannelCount;
+        int                             mFormat;
+        int16_t*                        mMixBuffer;
+        float                           mMasterVolume;
+        bool                            mMasterMute;
+        nsecs_t                         mLastWriteTime;
+        int                             mNumWrites;
+        int                             mNumDelayedWrites;
+        bool                            mStandby;
+        bool                            mInWrite;
+        sp <OutputTrack>                mOutputTrack;
+    };
 
-        virtual status_t getNextBuffer(AudioBufferProvider::Buffer* buffer);
-
-        bool isMuted() const {
-            return (mMute || mAudioFlinger->mStreamTypes[mStreamType].mute);
-        }
-
-        bool isPausing() const {
-            return mState == PAUSING;
-        }
-
-        bool isPaused() const {
-            return mState == PAUSED;
-        }
-
-        bool isReady() const;
-
-        void setPaused() { mState = PAUSED; }
-        void reset();
-
-        // we don't really need a lock for these
-        float               mVolume[2];
-        volatile bool       mMute;
-        // FILLED state is used for suppressing volume ramp at begin of playing
-        enum {FS_FILLING, FS_FILLED, FS_ACTIVE};
-        mutable uint8_t     mFillingUpStatus;
-        int8_t              mRetryCount;
-        sp<IMemory>         mSharedBuffer;
-        bool                mResetDone;
-    };  // end of Track
-
+    
     friend class AudioBuffer;
 
     class TrackHandle : public android::BnAudioTrack {
     public:
-                            TrackHandle(const sp<Track>& track);
+                            TrackHandle(const sp<MixerThread::Track>& track);
         virtual             ~TrackHandle();
         virtual status_t    start();
         virtual void        stop();
@@ -367,72 +548,20 @@
         virtual status_t onTransact(
             uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags);
     private:
-        sp<Track> mTrack;
-    };
-
-    struct  stream_type_t {
-        stream_type_t()
-            :   volume(1.0f),
-                mute(false)
-        {
-        }
-        float       volume;
-        bool        mute;
+        sp<MixerThread::Track> mTrack;
     };
 
     friend class Client;
-    friend class Track;
+    friend class MixerThread::Track;
 
 
                 void        removeClient(pid_t pid);
 
-                status_t    addTrack(const sp<Track>& track);
-                void        removeTrack(wp<Track> track, int name);
-                void        remove_track_l(wp<Track> track, int name);
-                void        destroyTrack(const sp<Track>& track);
-                void        addActiveTrack(const wp<Track>& track);
-                void        removeActiveTrack(const wp<Track>& track);
-                int         getTrackName();
-                void        deleteTrackName(int name);
 
-                AudioMixer* audioMixer() {
-                    return mAudioMixer;
-                }
-
-    // record track
-    class RecordTrack : public TrackBase {
-    public:
-                            RecordTrack(  const sp<AudioFlinger>& audioFlinger,
-                                    const sp<Client>& client,
-                                    int streamType,
-                                    uint32_t sampleRate,
-                                    int format,
-                                    int channelCount,
-                                    int frameCount);
-                            ~RecordTrack();
-
-        virtual status_t    start();
-        virtual void        stop();
-
-                bool        overflow() { bool tmp = mOverflow; mOverflow = false; return tmp; }
-                bool        setOverflow() { bool tmp = mOverflow; mOverflow = true; return tmp; }
-
-    private:
-        friend class AudioFlinger;
-        friend class RecordHandle;
-        friend class AudioRecordThread;
-
-                            RecordTrack(const Track&);
-                            RecordTrack& operator = (const Track&);
-
-        virtual status_t getNextBuffer(AudioBufferProvider::Buffer* buffer);
-
-        bool                mOverflow;
-    };
 
     class RecordHandle : public android::BnAudioRecord {
     public:
-        RecordHandle(const sp<RecordTrack>& recordTrack);
+        RecordHandle(const sp<MixerThread::RecordTrack>& recordTrack);
         virtual             ~RecordHandle();
         virtual status_t    start();
         virtual void        stop();
@@ -440,7 +569,7 @@
         virtual status_t onTransact(
             uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags);
     private:
-        sp<RecordTrack> mRecordTrack;
+        sp<MixerThread::RecordTrack> mRecordTrack;
     };
 
     // record thread
@@ -453,14 +582,14 @@
         virtual status_t    readyToRun() { return NO_ERROR; }
         virtual void        onFirstRef() {}
 
-                status_t    start(RecordTrack* recordTrack);
-                void        stop(RecordTrack* recordTrack);
+                status_t    start(MixerThread::RecordTrack* recordTrack);
+                void        stop(MixerThread::RecordTrack* recordTrack);
                 void        exit();
 
     private:
                 AudioRecordThread();
                 AudioHardwareInterface              *mAudioHardware;
-                sp<RecordTrack>                     mRecordTrack;
+                sp<MixerThread::RecordTrack>        mRecordTrack;
                 Mutex                               mLock;
                 Condition                           mWaitWorkCV;
                 volatile bool                       mActive;
@@ -468,48 +597,31 @@
     };
 
     friend class AudioRecordThread;
+    friend class MixerThread;
 
-                status_t    startRecord(RecordTrack* recordTrack);
-                void        stopRecord(RecordTrack* recordTrack);
-
-                void notifyOutputChange_l();
+                status_t    startRecord(MixerThread::RecordTrack* recordTrack);
+                void        stopRecord(MixerThread::RecordTrack* recordTrack);
+                
+                void        handleOutputSwitch();
 
     mutable     Mutex                                       mHardwareLock;
     mutable     Mutex                                       mLock;
-    mutable     Condition                                   mWaitWorkCV;
                 DefaultKeyedVector< pid_t, wp<Client> >     mClients;
-                SortedVector< wp<Track> >                   mActiveTracks;
-                SortedVector< sp<Track> >                   mTracks;
-                float                               mMasterVolume;
-                uint32_t                            mMasterRouting;
-                bool                                mMasterMute;
-                stream_type_t                       mStreamTypes[AudioTrack::NUM_STREAM_TYPES];
 
-                AudioMixer*                         mHardwareAudioMixer;
-                AudioMixer*                         mA2dpAudioMixer;
-                AudioMixer*                         mAudioMixer;
+                sp<MixerThread>                     mA2dpMixerThread;
+                sp<MixerThread>                     mHardwareMixerThread;
                 AudioHardwareInterface*             mAudioHardware;
                 AudioHardwareInterface*             mA2dpAudioInterface;
-                AudioStreamOut*                     mHardwareOutput;
-                AudioStreamOut*                     mA2dpOutput;
-                AudioStreamOut*                     mOutput;
-                AudioStreamOut*                     mRequestedOutput;
                 sp<AudioRecordThread>               mAudioRecordThread;
-                uint32_t                            mSampleRate;
-                size_t                              mFrameCount;
-                int                                 mChannelCount;
-                int                                 mFormat;
-                int16_t*                            mMixBuffer;
+                bool                                mA2dpEnabled;
+                bool                                mA2dpEnabledReq;
     mutable     int                                 mHardwareStatus;
-                nsecs_t                             mLastWriteTime;
-                int                                 mNumWrites;
-                int                                 mNumDelayedWrites;
-                bool                                mStandby;
-                bool                                mInWrite;
-                int                                 mA2dpDisableCount;
-                bool                                mA2dpSuppressed;
-                bool                                mMusicMuteSaved;
                 SortedVector< wp<IBinder> >         mNotificationClients;
+                int                                 mForcedSpeakerCount;
+                uint32_t                            mSavedRoute;
+                uint32_t                            mForcedRoute;
+                nsecs_t                             mRouteRestoreTime;
+                bool                                mMusicMuteSaved;
 };
 
 // ----------------------------------------------------------------------------
diff --git a/libs/surfaceflinger/Android.mk b/libs/surfaceflinger/Android.mk
index 53ba3bc..496e271 100644
--- a/libs/surfaceflinger/Android.mk
+++ b/libs/surfaceflinger/Android.mk
@@ -16,9 +16,7 @@
     LayerBitmap.cpp \
     LayerDim.cpp \
     LayerOrientationAnim.cpp \
-    LayerScreenshot.cpp \
     OrientationAnimation.cpp \
-    RFBServer.cpp \
     SurfaceFlinger.cpp \
     Tokenizer.cpp \
     Transform.cpp \
diff --git a/libs/surfaceflinger/Layer.cpp b/libs/surfaceflinger/Layer.cpp
index 31e63ef..f65d669 100644
--- a/libs/surfaceflinger/Layer.cpp
+++ b/libs/surfaceflinger/Layer.cpp
@@ -186,7 +186,9 @@
         copybit_device_t* copybit = mFlinger->getBlitEngine();
         copybit->set_parameter(copybit, COPYBIT_TRANSFORM, getOrientation());
         copybit->set_parameter(copybit, COPYBIT_PLANE_ALPHA, s.alpha);
-        copybit->set_parameter(copybit, COPYBIT_DITHER, COPYBIT_ENABLE);
+        copybit->set_parameter(copybit, COPYBIT_DITHER,
+                s.flags & ISurfaceComposer::eLayerDither ?
+                        COPYBIT_ENABLE : COPYBIT_DISABLE);
 
         region_iterator it(clip);
         err = copybit->stretch(copybit, &dst, &src, &drect, &srect, &it);
diff --git a/libs/surfaceflinger/LayerBase.cpp b/libs/surfaceflinger/LayerBase.cpp
index 9277a64..0cf53f7 100644
--- a/libs/surfaceflinger/LayerBase.cpp
+++ b/libs/surfaceflinger/LayerBase.cpp
@@ -26,6 +26,8 @@
 #include <GLES/gl.h>
 #include <GLES/glext.h>
 
+#include <hardware/hardware.h>
+
 #include "clz.h"
 #include "LayerBase.h"
 #include "LayerBlur.h"
@@ -229,15 +231,10 @@
     return Point(front.w, front.h);
 }
 
-Transform LayerBase::getDrawingStateTransform() const
-{
-    return drawingState().transform;
-}
-
 void LayerBase::validateVisibility(const Transform& planeTransform)
 {
     const Layer::State& s(drawingState());
-    const Transform tr(planeTransform * getDrawingStateTransform());
+    const Transform tr(planeTransform * s.transform);
     const bool transformed = tr.transformed();
    
     const Point size(getPhysicalSize());
@@ -420,7 +417,7 @@
 }
 
 void LayerBase::drawWithOpenGL(const Region& clip,
-        GLint textureName, const GGLSurface& t) const
+        GLint textureName, const GGLSurface& t, int transform) const
 {
     const DisplayHardware& hw(graphicPlane(0).displayHardware());
     const uint32_t fbHeight = hw.getHeight();
@@ -492,6 +489,12 @@
 
             glMatrixMode(GL_TEXTURE);
             glLoadIdentity();
+            
+            if (transform == HAL_TRANSFORM_ROT_90) {
+                glTranslatef(0, 1, 0);
+                glRotatef(-90, 0, 0, 1);
+            }
+
             if (!(mFlags & DisplayHardware::NPOT_EXTENSION)) {
                 // find the smallest power-of-two that will accommodate our surface
                 GLuint tw = 1 << (31 - clz(t.width));
diff --git a/libs/surfaceflinger/LayerBase.h b/libs/surfaceflinger/LayerBase.h
index 2377a14..a020f44 100644
--- a/libs/surfaceflinger/LayerBase.h
+++ b/libs/surfaceflinger/LayerBase.h
@@ -169,13 +169,6 @@
     virtual void validateVisibility(const Transform& globalTransform);
 
     /**
-     * getDrawingStateTransform - returns the drawing state's transform.
-     * This is used in validateVisibility() and can be use to override or
-     * modify the transform (if so make sure to trigger a transaction).
-     */
-    virtual Transform getDrawingStateTransform() const;
-
-    /**
      * lockPageFlip - called each time the screen is redrawn and returns whether
      * the visible regions need to be recomputed (this is a fairly heavy
      * operation, so this should be set only if needed). Typically this is used
@@ -200,10 +193,15 @@
      * needsBlending - true if this surface needs blending
      */
     virtual bool needsBlending() const  { return false; }
-    
+
     /**
-     * isSecure - true if this surface is secure, that is if it prevents a
-     * screenshot to be taken,
+     * transformed -- true is this surface needs a to be transformed
+     */
+    virtual bool transformed() const    { return mTransformed; }
+
+    /**
+     * isSecure - true if this surface is secure, that is if it prevents
+     * screenshots or vns servers.
      */
     virtual bool isSecure() const       { return false; }
 
@@ -222,7 +220,6 @@
     }
 
     int32_t  getOrientation() const { return mOrientation; }
-    bool transformed() const    { return mTransformed; }
     int  tx() const             { return mLeft; }
     int  ty() const             { return mTop; }
     
@@ -233,7 +230,9 @@
           GLuint createTexture() const;
     
           void drawWithOpenGL(const Region& clip,
-                  GLint textureName, const GGLSurface& surface) const;
+                  GLint textureName,
+                  const GGLSurface& surface,
+                  int transform = 0) const;
 
           void clearWithOpenGL(const Region& clip) const;
 
diff --git a/libs/surfaceflinger/LayerBuffer.cpp b/libs/surfaceflinger/LayerBuffer.cpp
index fc0a603..00fab70 100644
--- a/libs/surfaceflinger/LayerBuffer.cpp
+++ b/libs/surfaceflinger/LayerBuffer.cpp
@@ -103,15 +103,6 @@
         source->unregisterBuffers();
 }
 
-Transform LayerBuffer::getDrawingStateTransform() const
-{
-    Transform tr(LayerBaseClient::getDrawingStateTransform());
-    sp<Source> source(getSource());
-    if (source != 0)
-        source->updateTransform(&tr);
-    return tr;
-}
-
 uint32_t LayerBuffer::doTransaction(uint32_t flags)
 {
     sp<Source> source(getSource());
@@ -141,6 +132,14 @@
     }
 }
 
+bool LayerBuffer::transformed() const
+{
+    sp<Source> source(getSource());
+    if (LIKELY(source != 0))
+        return source->transformed();
+    return false;
+}
+
 /**
  * This creates a "buffer" source for this surface
  */
@@ -316,7 +315,8 @@
 }
 void LayerBuffer::Source::unregisterBuffers() {
 }
-void LayerBuffer::Source::updateTransform(Transform* tr) const {
+bool LayerBuffer::Source::transformed() const {
+    return mLayer.mTransformed; 
 }
 
 // ---------------------------------------------------------------------------
@@ -363,6 +363,7 @@
     mLayer.setNeedsBlending((info.h_alpha - info.l_alpha) > 0);    
     mBufferSize = info.getScanlineSize(buffers.hor_stride)*buffers.ver_stride;
     mLayer.forceVisibilityTransaction();
+    
 }
 
 LayerBuffer::BufferSource::~BufferSource()
@@ -419,15 +420,9 @@
     mBuffer = buffer;
 }
 
-void LayerBuffer::BufferSource::updateTransform(Transform* tr) const
+bool LayerBuffer::BufferSource::transformed() const
 {
-    uint32_t bufTransform = mBufferHeap.transform;
-    // TODO: handle all transforms
-    if (bufTransform == ISurface::BufferHeap::ROT_90) {
-        Transform rot90;
-        rot90.set(0, -1, 1, 0);
-        *tr = (*tr) * rot90;
-    }
+    return mBufferHeap.transform ? true : Source::transformed(); 
 }
 
 void LayerBuffer::BufferSource::onDraw(const Region& clip) const 
@@ -476,7 +471,7 @@
             if (UNLIKELY(mTemporaryDealer == 0)) {
                 // allocate a memory-dealer for this the first time
                 mTemporaryDealer = mLayer.mFlinger->getSurfaceHeapManager()
-                ->createHeap(ISurfaceComposer::eHardware);
+                    ->createHeap(ISurfaceComposer::eHardware);
                 mTempBitmap.init(mTemporaryDealer);
             }
 
@@ -506,10 +501,23 @@
         copybit_image_t dst;
         hw.getDisplaySurface(&dst);
         const copybit_rect_t& drect
-        = reinterpret_cast<const copybit_rect_t&>(transformedBounds);
+            = reinterpret_cast<const copybit_rect_t&>(transformedBounds);
         const State& s(mLayer.drawingState());
         region_iterator it(clip);
-        copybit->set_parameter(copybit, COPYBIT_TRANSFORM, mLayer.getOrientation());
+        
+        // pick the right orientation for this buffer
+        int orientation = mLayer.getOrientation();
+        if (UNLIKELY(mBufferHeap.transform)) {
+            Transform rot90;
+            GraphicPlane::orientationToTransfrom(
+                    ISurfaceComposer::eOrientation90, 0, 0, &rot90);
+            const Transform& planeTransform(mLayer.graphicPlane(0).transform());
+            const Layer::State& s(mLayer.drawingState());
+            Transform tr(planeTransform * s.transform * rot90);
+            orientation = tr.getOrientation();
+        }
+        
+        copybit->set_parameter(copybit, COPYBIT_TRANSFORM, orientation);
         copybit->set_parameter(copybit, COPYBIT_PLANE_ALPHA, s.alpha);
         copybit->set_parameter(copybit, COPYBIT_DITHER, COPYBIT_ENABLE);
 
@@ -536,10 +544,11 @@
         t.data = (GGLubyte*)(intptr_t(src.img.base) + src.img.offset);
         const Region dirty(Rect(t.width, t.height));
         mLayer.loadTexture(dirty, mTextureName, t, w, h);
-        mLayer.drawWithOpenGL(clip, mTextureName, t);
+        mLayer.drawWithOpenGL(clip, mTextureName, t, mBufferHeap.transform);
     }
 }
 
+
 // ---------------------------------------------------------------------------
 
 LayerBuffer::OverlaySource::OverlaySource(LayerBuffer& layer,
diff --git a/libs/surfaceflinger/LayerBuffer.h b/libs/surfaceflinger/LayerBuffer.h
index 5532532..2dc77f1 100644
--- a/libs/surfaceflinger/LayerBuffer.h
+++ b/libs/surfaceflinger/LayerBuffer.h
@@ -46,7 +46,7 @@
         virtual void onVisibilityResolved(const Transform& planeTransform);
         virtual void postBuffer(ssize_t offset);
         virtual void unregisterBuffers();
-        virtual void updateTransform(Transform* tr) const;
+        virtual bool transformed() const;
     protected:
         LayerBuffer& mLayer;
     };
@@ -68,7 +68,7 @@
     virtual void onDraw(const Region& clip) const;
     virtual uint32_t doTransaction(uint32_t flags);
     virtual void unlockPageFlip(const Transform& planeTransform, Region& outDirtyRegion);
-    virtual Transform getDrawingStateTransform() const;
+    virtual bool transformed() const;
 
     status_t registerBuffers(const ISurface::BufferHeap& buffers);
     void postBuffer(ssize_t offset);
@@ -116,10 +116,10 @@
         sp<Buffer> getBuffer() const;
         void setBuffer(const sp<Buffer>& buffer);
 
-        virtual void updateTransform(Transform* tr) const; 
         virtual void onDraw(const Region& clip) const;
         virtual void postBuffer(ssize_t offset);
         virtual void unregisterBuffers();
+        virtual bool transformed() const;
     private:
         mutable Mutex   mLock;
         sp<Buffer>      mBuffer;
diff --git a/libs/surfaceflinger/LayerOrientationAnim.cpp b/libs/surfaceflinger/LayerOrientationAnim.cpp
index 46b3b19..2b72d7c 100644
--- a/libs/surfaceflinger/LayerOrientationAnim.cpp
+++ b/libs/surfaceflinger/LayerOrientationAnim.cpp
@@ -84,7 +84,7 @@
 void LayerOrientationAnim::validateVisibility(const Transform&)
 {
     const Layer::State& s(drawingState());
-    const Transform tr(getDrawingStateTransform());
+    const Transform tr(s.transform);
     const Point size(getPhysicalSize());
     uint32_t w = size.x;
     uint32_t h = size.y;
diff --git a/libs/surfaceflinger/LayerScreenshot.cpp b/libs/surfaceflinger/LayerScreenshot.cpp
deleted file mode 100644
index 40c47b0..0000000
--- a/libs/surfaceflinger/LayerScreenshot.cpp
+++ /dev/null
@@ -1,110 +0,0 @@
-/*
- * Copyright (C) 2007 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#define LOG_TAG "SurfaceFlinger"
-
-#include <stdlib.h>
-#include <stdint.h>
-#include <sys/types.h>
-
-#include <utils/Errors.h>
-#include <utils/Log.h>
-
-#include <core/SkBitmap.h>
-
-#include <ui/EGLDisplaySurface.h>
-
-#include "LayerBase.h"
-#include "LayerScreenshot.h"
-#include "SurfaceFlinger.h"
-#include "DisplayHardware/DisplayHardware.h"
-
-namespace android {
-// ---------------------------------------------------------------------------
-
-const uint32_t LayerScreenshot::typeInfo = LayerBase::typeInfo | 0x40;
-const char* const LayerScreenshot::typeID = "LayerScreenshot";
-
-// ---------------------------------------------------------------------------
-
-LayerScreenshot::LayerScreenshot(SurfaceFlinger* flinger, DisplayID display)
-    : LayerBase(flinger, display), mReply(0)
-{
-}
-
-LayerScreenshot::~LayerScreenshot()
-{
-}
-
-void LayerScreenshot::onDraw(const Region& clip) const
-{
-    const DisplayHardware& hw(graphicPlane(0).displayHardware());
-    copybit_image_t dst;
-    hw.getDisplaySurface(&dst);
-    if (dst.base != 0) {
-        uint8_t const* src = (uint8_t const*)(intptr_t(dst.base) + dst.offset); 
-        const int fbWidth = dst.w;
-        const int fbHeight = dst.h;
-        const int fbFormat = dst.format;
-
-        int x = mTransformedBounds.left;
-        int y = mTransformedBounds.top;
-        int w = mTransformedBounds.width();
-        int h = mTransformedBounds.height();
-        Parcel* const reply = mReply;
-        if (reply) {
-            const size_t Bpp = bytesPerPixel(fbFormat);
-            const size_t size = w * h * Bpp;
-            int32_t cfg = SkBitmap::kNo_Config;
-            switch (fbFormat) {
-                case PIXEL_FORMAT_RGBA_4444: cfg = SkBitmap::kARGB_4444_Config;
-                case PIXEL_FORMAT_RGBA_8888: cfg = SkBitmap::kARGB_8888_Config;
-                case PIXEL_FORMAT_RGB_565:   cfg = SkBitmap::kRGB_565_Config;
-                case PIXEL_FORMAT_A_8:       cfg = SkBitmap::kA8_Config;
-            }
-            reply->writeInt32(0);
-            reply->writeInt32(cfg);
-            reply->writeInt32(w);
-            reply->writeInt32(h);
-            reply->writeInt32(w * Bpp);
-            void* data = reply->writeInplace(size);
-            if (data) {
-                uint8_t* d = (uint8_t*)data;
-                uint8_t const* s = src + (x + y*fbWidth) * Bpp;
-                if (w == fbWidth) {
-                    memcpy(d, s, w*h*Bpp);   
-                } else {
-                    for (int y=0 ; y<h ; y++) {
-                        memcpy(d, s, w*Bpp);
-                        d += w*Bpp;
-                        s += fbWidth*Bpp;
-                    }
-                }
-            }
-        }
-    }
-    mCV.broadcast();
-}
-
-void LayerScreenshot::takeScreenshot(Mutex& lock, Parcel* reply)
-{
-    mReply = reply;
-    mCV.wait(lock);
-}
-
-// ---------------------------------------------------------------------------
-
-}; // namespace android
diff --git a/libs/surfaceflinger/LayerScreenshot.h b/libs/surfaceflinger/LayerScreenshot.h
deleted file mode 100644
index 2d9a8ec..0000000
--- a/libs/surfaceflinger/LayerScreenshot.h
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- * Copyright (C) 2007 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef ANDROID_LAYER_SCREENSHOT_H
-#define ANDROID_LAYER_SCREENSHOT_H
-
-#include <stdint.h>
-#include <sys/types.h>
-#include <utils/threads.h>
-#include <utils/Parcel.h>
-
-#include "LayerBase.h"
-
-namespace android {
-
-// ---------------------------------------------------------------------------
-
-class LayerScreenshot : public LayerBase
-{
-public:    
-    static const uint32_t typeInfo;
-    static const char* const typeID;
-    virtual char const* getTypeID() const { return typeID; }
-    virtual uint32_t getTypeInfo() const { return typeInfo; }
-    
-                LayerScreenshot(SurfaceFlinger* flinger, DisplayID display);
-        virtual ~LayerScreenshot();
-
-    virtual void onDraw(const Region& clip) const;
-    virtual bool needsBlending() const  { return true; }
-    virtual bool isSecure() const       { return false; }
-
-    void takeScreenshot(Mutex& lock, Parcel* reply);
-    
-private:
-    mutable Condition   mCV;
-    Parcel*             mReply;
-};
-
-// ---------------------------------------------------------------------------
-
-}; // namespace android
-
-#endif // ANDROID_LAYER_SCREENSHOT_H
diff --git a/libs/surfaceflinger/RFBServer.cpp b/libs/surfaceflinger/RFBServer.cpp
deleted file mode 100644
index c2c1989..0000000
--- a/libs/surfaceflinger/RFBServer.cpp
+++ /dev/null
@@ -1,722 +0,0 @@
-/*
- * Copyright (C) 2007 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#define LOG_TAG "RFBServer"
-
-#include <stdlib.h>
-#include <stdio.h>
-#include <stdint.h>
-#include <errno.h>
-#include <fcntl.h>
-
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <sys/ioctl.h>
-
-#include <netinet/in.h>
-
-#include <cutils/sockets.h>
-
-#include <utils/Log.h>
-#include <ui/Rect.h>
-
-#ifdef HAVE_ANDROID_OS
-#include <linux/input.h>
-#endif
-
-#include "RFBServer.h"
-#include "SurfaceFlinger.h"
-
-/* BUG=773511: this is a temporary hack required while developing the new
-   set of "clean kernel headers" for the Bionic C library. */
-#ifndef KEY_STAR
-#define KEY_STAR    227
-#endif
-#ifndef KEY_SHARP
-#define KEY_SHARP   228
-#endif
-#ifndef KEY_SOFT1
-#define KEY_SOFT1   229
-#endif
-#ifndef KEY_SOFT2
-#define KEY_SOFT2   230
-#endif
-#ifndef KEY_CENTER
-#define KEY_CENTER  232
-#endif
-
-// ----------------------------------------------------------------------------
-
-#define DEBUG_MSG   0
-
-// ----------------------------------------------------------------------------
-
-namespace android {
-
-const int VNC_PORT = 5900;
-
-RFBServer::RFBServer(uint32_t w, uint32_t h, android::PixelFormat format)
-    : Thread(false), mFD(-1), mStatus(NO_INIT), mIoVec(0)
-{
-    mFrameBuffer.version = sizeof(mFrameBuffer);
-    mFrameBuffer.width = w;
-    mFrameBuffer.height = h;
-    mFrameBuffer.stride = w;
-    mFrameBuffer.format = format;
-    mFrameBuffer.data = 0;
-}
-
-RFBServer::~RFBServer()
-{
-    if (mRobinThread != 0) {
-        // ask the thread to exit first
-        mRobinThread->exitAndWait();
-    }
-
-    free(mFrameBuffer.data);
-
-    delete [] mIoVec;
-}
-
-void RFBServer::onFirstRef()
-{
-    run("Batman");
-}
-
-status_t RFBServer::readyToRun()
-{
-    LOGI("RFB server ready to run");
-    return NO_ERROR;
-}
-
-bool RFBServer::threadLoop()
-{
-    struct sockaddr addr;
-    socklen_t alen;
-    int serverfd = -1;
-    int port = VNC_PORT;
-
-    do {
-        retry:
-        if (serverfd < 0) {
-            serverfd = socket_loopback_server(port, SOCK_STREAM);
-            if (serverfd < 0) {
-                if ((errno == EADDRINUSE) && (port < (VNC_PORT+10))) {
-                    LOGW("port %d already in use, trying %d", port, port+1);
-                    port++;
-                    goto retry;
-                }
-                LOGE("couldn't create socket, port=%d, error %d (%s)",
-                        port, errno, strerror(errno));
-                sleep(1);
-                break;
-            }
-            fcntl(serverfd, F_SETFD, FD_CLOEXEC);
-        }
-
-        alen = sizeof(addr);
-        mFD = accept(serverfd, &addr, &alen);
-
-        if (mFD < 0) {
-            LOGE("couldn't accept(), error %d (%s)", errno, strerror(errno));
-            // we could have run out of file descriptors, wait a bit and
-            // try again.
-            sleep(1);
-            goto retry;
-        }
-        fcntl(mFD, F_SETFD, FD_CLOEXEC);
-
-        // send protocol version and Authentication method
-        mStatus = NO_ERROR;
-        handshake(3, 3, Authentication::None);
-
-        if (alive()) {
-            // create the thread we use to send data to the client
-            mRobinThread = new ServerThread(this);
-        }
-
-        while( alive() ) {
-            // client message must be destroyed at each iteration
-            // (most of the time this is a no-op)
-            ClientMessage msg;
-            waitForClientMessage(msg);
-            if (alive()) {
-                handleClientMessage(msg);
-            }
-        }
-
-    } while( alive() );
-
-    // free-up some resources
-    if (mRobinThread != 0) {
-        mRobinThread->exitAndWait();
-        mRobinThread.clear();
-    }
-
-    free(mFrameBuffer.data);
-    mFrameBuffer.data = 0;
-
-    close(mFD);
-    close(serverfd);
-    mFD = -1;
-
-    // we'll try again
-    return true;
-}
-
-// ----------------------------------------------------------------------------
-
-RFBServer::ServerThread::ServerThread(const sp<RFBServer>& receiver)
-            : Thread(false), mReceiver(receiver)
-{
-    LOGD("RFB Server Thread created");
-}
-
-RFBServer::ServerThread::~ServerThread()
-{
-    LOGD("RFB Server Thread destroyed");
-}
-
-void RFBServer::ServerThread::onFirstRef()
-{
-    mUpdateBarrier.close();
-    run("Robin");
-}
-
-status_t RFBServer::ServerThread::readyToRun()
-{
-    return NO_ERROR;
-}
-
-void RFBServer::ServerThread::wake()
-{
-    mUpdateBarrier.open();
-}
-
-void RFBServer::ServerThread::exitAndWait()
-{
-    requestExit();
-    mUpdateBarrier.open();
-    requestExitAndWait();
-}
-
-bool RFBServer::ServerThread::threadLoop()
-{
-    sp<RFBServer> receiver(mReceiver.promote());
-    if (receiver == 0)
-        return false;
-
-    // wait for something to do
-    mUpdateBarrier.wait();
-
-    // we're asked to quit, abort everything
-    if (exitPending())
-        return false;
-
-    mUpdateBarrier.close();
-
-    // process updates
-    receiver->sendFrameBufferUpdates();
-    return !exitPending();
-}
-
-// ----------------------------------------------------------------------------
-
-void RFBServer::handshake(uint8_t major, uint8_t minor, uint32_t auth)
-{
-    ProtocolVersion protocolVersion(major, minor);
-    if( !write(protocolVersion) )
-        return;
-
-    if ( !read(protocolVersion) )
-        return;
-
-    int maj, min;
-    if ( protocolVersion.decode(maj, min) != NO_ERROR ) {
-        mStatus = -1;
-        return;
-    }
-
-#if DEBUG_MSG
-    LOGD("client protocol string: <%s>", (char*)protocolVersion.payload());
-    LOGD("client wants protocol version %d.%d\n", maj, min);
-#endif
-
-    Authentication authentication(auth);
-    if( !write(authentication) )
-        return;
-
-    ClientInitialization clientInit;
-    if ( !read(clientInit) )
-        return;
-
-#if DEBUG_MSG
-    LOGD("client initialization: sharedFlags = %d\n", clientInit.sharedFlags());
-#endif
-
-    ServerInitialization serverInit("Android RFB");
-    ServerInitialization::Payload& message(serverInit.message());
-        message.framebufferWidth = htons(mFrameBuffer.width);
-        message.framebufferHeight = htons(mFrameBuffer.height);
-        message.serverPixelFormat.bitsPerPixel = 16;
-        message.serverPixelFormat.depth = 16;
-        message.serverPixelFormat.bigEndianFlag = 0;
-        message.serverPixelFormat.trueColorFlag = 1;
-        message.serverPixelFormat.redMax   = htons((1<<5)-1);
-        message.serverPixelFormat.greenMax = htons((1<<6)-1);
-        message.serverPixelFormat.blueMax  = htons((1<<5)-1);
-        message.serverPixelFormat.redShift     = 11;
-        message.serverPixelFormat.greenShift   = 5;
-        message.serverPixelFormat.blueShift    = 0;
-
-    mIoVec = new iovec[mFrameBuffer.height];
-
-    write(serverInit);
-}
-
-void RFBServer::handleClientMessage(const ClientMessage& msg)
-{
-    switch(msg.type()) {
-    case SET_PIXEL_FORMAT:
-        handleSetPixelFormat(msg.messages().setPixelFormat);
-        break;
-    case SET_ENCODINGS:
-        handleSetEncodings(msg.messages().setEncodings);
-        break;
-    case FRAME_BUFFER_UPDATE_REQ:
-        handleFrameBufferUpdateReq(msg.messages().frameBufferUpdateRequest);
-        break;
-    case KEY_EVENT:
-        handleKeyEvent(msg.messages().keyEvent);
-        break;
-    }
-}
-
-void RFBServer::handleSetPixelFormat(const SetPixelFormat& msg)
-{
-    if (!validatePixelFormat(msg.pixelFormat)) {
-        LOGE("The builtin VNC server only supports the RGB 565 pixel format");
-        LOGD("requested pixel format:");
-        LOGD("bitsPerPixel:     %d", msg.pixelFormat.bitsPerPixel);
-        LOGD("depth:            %d", msg.pixelFormat.depth);
-        LOGD("bigEndianFlag:    %d", msg.pixelFormat.bigEndianFlag);
-        LOGD("trueColorFlag:    %d", msg.pixelFormat.trueColorFlag);
-        LOGD("redmax:           %d", ntohs(msg.pixelFormat.redMax));
-        LOGD("bluemax:          %d", ntohs(msg.pixelFormat.greenMax));
-        LOGD("greenmax:         %d", ntohs(msg.pixelFormat.blueMax));
-        LOGD("redshift:         %d", msg.pixelFormat.redShift);
-        LOGD("greenshift:       %d", msg.pixelFormat.greenShift);
-        LOGD("blueshift:        %d", msg.pixelFormat.blueShift);
-        mStatus = -1;
-    }
-}
-
-bool RFBServer::validatePixelFormat(const PixelFormat& pf)
-{
-    if ((pf.bitsPerPixel != 16) || (pf.depth != 16))
-        return false;
-
-    if (pf.bigEndianFlag || !pf.trueColorFlag)
-        return false;
-
-    if (ntohs(pf.redMax)!=0x1F ||
-        ntohs(pf.greenMax)!=0x3F ||
-        ntohs(pf.blueMax)!=0x1F) {
-        return false;
-    }
-
-    if (pf.redShift!=11 || pf.greenShift!=5 || pf.blueShift!=0)
-        return false;
-
-    return true;
-}
-
-void RFBServer::handleSetEncodings(const SetEncodings& msg)
-{
-    /* From the RFB specification:
-        Sets the encoding types in which pixel data can be sent by the server.
-        The order of the encoding types given in this message is a hint by the
-        client as to its preference (the first encoding specified being most
-        preferred). The server may or may not choose to make use of this hint.
-        Pixel data may always be sent in raw encoding even if not specified
-        explicitly here.
-    */
-
-    LOGW("SetEncodings received. Only RAW is supported.");
-}
-
-void RFBServer::handleFrameBufferUpdateReq(const FrameBufferUpdateRequest& msg)
-{
-#if DEBUG_MSG
-    LOGD("handle FrameBufferUpdateRequest");
-#endif
-
-    Rect r;
-    r.left = ntohs(msg.x);
-    r.top = ntohs(msg.y);
-    r.right = r.left + ntohs(msg.width);
-    r.bottom = r.top + ntohs(msg.height);
-
-    Mutex::Autolock _l(mRegionLock);
-    mClientRegionRequest.set(r);
-    if (!msg.incremental)
-        mDirtyRegion.orSelf(r);
-
-    mRobinThread->wake();
-}
-
-void RFBServer::handleKeyEvent(const KeyEvent& msg)
-{
-#ifdef HAVE_ANDROID_OS
-
-    int scancode = 0;
-    int code = ntohl(msg.key);
-
-    if (code>='0' && code<='9') {
-        scancode = (code & 0xF) - 1;
-        if (scancode<0) scancode += 10;
-        scancode += KEY_1;
-    } else if (code>=0xFF50 && code<=0xFF58) {
-        static const uint16_t map[] =
-             {  KEY_HOME, KEY_LEFT, KEY_UP, KEY_RIGHT, KEY_DOWN,
-                KEY_SOFT1, KEY_SOFT2, KEY_END, 0 };
-        scancode = map[code & 0xF];
-    } else if (code>=0xFFE1 && code<=0xFFEE) {
-        static const uint16_t map[] =
-             {  KEY_LEFTSHIFT, KEY_LEFTSHIFT,
-                KEY_COMPOSE, KEY_COMPOSE,
-                KEY_LEFTSHIFT, KEY_LEFTSHIFT,
-                0,0,
-                KEY_LEFTALT, KEY_RIGHTALT,
-                0, 0, 0, 0 };
-        scancode = map[code & 0xF];
-    } else if ((code>='A' && code<='Z') || (code>='a' && code<='z')) {
-        static const uint16_t map[] = {
-                KEY_A, KEY_B, KEY_C, KEY_D, KEY_E,
-                KEY_F, KEY_G, KEY_H, KEY_I, KEY_J,
-                KEY_K, KEY_L, KEY_M, KEY_N, KEY_O,
-                KEY_P, KEY_Q, KEY_R, KEY_S, KEY_T,
-                KEY_U, KEY_V, KEY_W, KEY_X, KEY_Y, KEY_Z };
-        scancode = map[(code & 0x5F) - 'A'];
-    } else {
-        switch (code) {
-            case 0x0003:    scancode = KEY_CENTER;      break;
-            case 0x0020:    scancode = KEY_SPACE;       break;
-            case 0x0023:    scancode = KEY_SHARP;       break;
-            case 0x0033:    scancode = KEY_SHARP;       break;
-            case 0x002C:    scancode = KEY_COMMA;       break;
-            case 0x003C:    scancode = KEY_COMMA;       break;
-            case 0x002E:    scancode = KEY_DOT;         break;
-            case 0x003E:    scancode = KEY_DOT;         break;
-            case 0x002F:    scancode = KEY_SLASH;       break;
-            case 0x003F:    scancode = KEY_SLASH;       break;
-            case 0x0032:    scancode = KEY_EMAIL;       break;
-            case 0x0040:    scancode = KEY_EMAIL;       break;
-            case 0xFF08:    scancode = KEY_BACKSPACE;   break;
-            case 0xFF1B:    scancode = KEY_BACK;        break;
-            case 0xFF09:    scancode = KEY_TAB;         break;
-            case 0xFF0D:    scancode = KEY_ENTER;       break;
-            case 0x002A:    scancode = KEY_STAR;        break;
-            case 0xFFBE:    scancode = KEY_SEND;        break; // F1
-            case 0xFFBF:    scancode = KEY_END;         break; // F2
-            case 0xFFC0:    scancode = KEY_HOME;        break; // F3
-            case 0xFFC5:    scancode = KEY_POWER;       break; // F8
-        }
-    }
-
-#if DEBUG_MSG
-   LOGD("handle KeyEvent 0x%08x, %d, scancode=%d\n", code, msg.downFlag, scancode);
-#endif
-
-    if (scancode) {
-        mEventInjector.injectKey(uint16_t(scancode),
-             msg.downFlag ? EventInjector::DOWN : EventInjector::UP);
-    }
-#endif
-}
-
-void RFBServer::waitForClientMessage(ClientMessage& msg)
-{
-    if ( !read(msg.payload(), 1) )
-        return;
-
-    switch(msg.type()) {
-
-    case SET_PIXEL_FORMAT:
-        read(msg.payload(1), sizeof(SetPixelFormat)-1);
-        break;
-
-    case FIX_COLOUR_MAP_ENTRIES:
-        mStatus = UNKNOWN_ERROR;
-        return;
-
-    case SET_ENCODINGS:
-    {
-        if ( !read(msg.payload(1), sizeof(SetEncodings)-1) )
-            return;
-
-        size_t size = ntohs( msg.messages().setEncodings.numberOfEncodings ) * 4;
-        if (msg.resize(sizeof(SetEncodings) + size) != NO_ERROR) {
-            mStatus = NO_MEMORY;
-            return;
-        }
-
-        if ( !read(msg.payload(sizeof(SetEncodings)), size) )
-            return;
-
-        break;
-    }
-
-    case FRAME_BUFFER_UPDATE_REQ:
-        read(msg.payload(1), sizeof(FrameBufferUpdateRequest)-1);
-        break;
-
-    case KEY_EVENT:
-        read(msg.payload(1), sizeof(KeyEvent)-1);
-        break;
-
-    case POINTER_EVENT:
-        read(msg.payload(1), sizeof(PointerEvent)-1);
-        break;
-
-    case CLIENT_CUT_TEXT:
-    {
-        if ( !read(msg.payload(1), sizeof(ClientCutText)-1) )
-            return;
-
-        size_t size = ntohl( msg.messages().clientCutText.length );
-        if (msg.resize(sizeof(ClientCutText) + size) != NO_ERROR) {
-            mStatus = NO_MEMORY;
-            return;
-        }
-
-        if ( !read(msg.payload(sizeof(SetEncodings)), size) )
-            return;
-
-        break;
-    }
-
-    default:
-        LOGE("Unknown Message %d", msg.type());
-        mStatus = UNKNOWN_ERROR;
-        return;
-    }
-}
-
-// ----------------------------------------------------------------------------
-
-bool RFBServer::write(const Message& msg)
-{
-    write(msg.payload(), msg.size());
-    return alive();
-}
-
-bool RFBServer::read(Message& msg)
-{
-    read(msg.payload(), msg.size());
-    return alive();
-}
-
-bool RFBServer::write(const void* buffer, int size)
-{
-    int wr = ::write(mFD, buffer, size);
-    if (wr != size) {
-        //LOGE("write(%d) error %d (%s)", size, wr, strerror(errno));
-        mStatus = (wr == -1) ? errno : -1;
-    }
-    return alive();
-}
-
-bool RFBServer::read(void* buffer, int size)
-{
-    int rd = ::read(mFD, buffer, size);
-    if (rd != size) {
-        //LOGE("read(%d) error %d (%s)", size, rd, strerror(errno));
-        mStatus = (rd == -1) ? errno : -1;
-    }
-    return alive();
-}
-
-bool RFBServer::alive() const
-{
-    return  mStatus == 0;
-}
-
-bool RFBServer::isConnected() const
-{
-    return alive();
-}
-
-// ----------------------------------------------------------------------------
-
-void RFBServer::frameBufferUpdated(const GGLSurface& front, const Region& reg)
-{
-    Mutex::Autolock _l(mRegionLock);
-
-    // update dirty region
-    mDirtyRegion.orSelf(reg);
-
-    // remember the front-buffer
-    mFrontBuffer = front;
-
-    // The client has not requested anything, don't do anything more
-    if (mClientRegionRequest.isEmpty())
-        return;
-
-    // wake the sending thread up
-    mRobinThread->wake();
-}
-
-void RFBServer::sendFrameBufferUpdates()
-{
-    Vector<Rect> rects;
-    size_t countRects;
-    GGLSurface fb;
-
-    { // Scope for the lock
-        Mutex::Autolock _l(mRegionLock);
-        if (mFrontBuffer.data == 0)
-            return;
-
-        const Region reg( mDirtyRegion.intersect(mClientRegionRequest) );
-        if (reg.isEmpty())
-            return;
-
-        mDirtyRegion.subtractSelf(reg);
-        countRects = reg.rects(rects);
-
-        // copy the frame-buffer so we can stay responsive
-        size_t bytesPerPix = bytesPerPixel(mFrameBuffer.format);
-        size_t bpr = mFrameBuffer.stride * bytesPerPix;
-        if (mFrameBuffer.data == 0) {
-            mFrameBuffer.data = (GGLubyte*)malloc(bpr * mFrameBuffer.height);
-            if (mFrameBuffer.data == 0)
-            	return;
-        }
-
-        memcpy(mFrameBuffer.data, mFrontBuffer.data, bpr*mFrameBuffer.height);
-        fb = mFrameBuffer;
-    }
-
-    FrameBufferUpdate msgHeader;
-    msgHeader.type = 0;
-    msgHeader.numberOfRectangles = htons(countRects);
-    write(&msgHeader, sizeof(msgHeader));
-
-    Rectangle rectangle;
-    for (size_t i=0 ; i<countRects ; i++) {
-        const Rect& r = rects[i];
-        rectangle.x = htons( r.left );
-        rectangle.y = htons( r.top );
-        rectangle.w = htons( r.width() );
-        rectangle.h = htons( r.height() );
-        rectangle.encoding = htons( SetEncodings::Raw );
-        write(&rectangle, sizeof(rectangle));
-        size_t h = r.height();
-        size_t w = r.width();
-        size_t bytesPerPix = bytesPerPixel(fb.format);
-        size_t bpr = fb.stride * bytesPerPix;
-        size_t bytes = w * bytesPerPix;
-        size_t offset = (r.top * bpr) + (r.left * bytesPerPix);
-        uint8_t* src = static_cast<uint8_t*>(fb.data) + offset;
-        iovec* iov = mIoVec;
-        while (h--) {
-            iov->iov_base = src;
-            iov->iov_len = bytes;
-            src += bpr;
-            iov++;
-        }
-        size_t iovcnt = iov - mIoVec;
-        int wr = ::writev(mFD, mIoVec, iovcnt);
-        if (wr < 0) {
-            //LOGE("write(%d) error %d (%s)", size, wr, strerror(errno));
-            mStatus =  errno;
-        }
-    }
-}
-
-// ----------------------------------------------------------------------------
-
-RFBServer::Message::Message(size_t size)
-    : mSize(size), mAllocatedSize(size)
-{
-    mPayload = malloc(size);
-}
-
-RFBServer::Message::Message(void* payload, size_t size)
-    : mPayload(payload), mSize(size), mAllocatedSize(0)
-{
-}
-
-RFBServer::Message::~Message()
-{
-    if (mAllocatedSize)
-        free(mPayload);
-}
-
-status_t RFBServer::Message::resize(size_t size)
-{
-    if (size > mAllocatedSize) {
-        void* newp;
-        if (mAllocatedSize) {
-            newp = realloc(mPayload, size);
-            if (!newp) return NO_MEMORY;
-        } else {
-            newp = malloc(size);
-            if (!newp) return NO_MEMORY;
-            memcpy(newp, mPayload, mSize);
-            mAllocatedSize = size;
-        }
-        mPayload = newp;
-    }
-    mSize = size;
-    return NO_ERROR;
-}
-
-// ----------------------------------------------------------------------------
-
-RFBServer::EventInjector::EventInjector()
-    : mFD(-1)
-{
-}
-
-RFBServer::EventInjector::~EventInjector()
-{
-}
-
-void RFBServer::EventInjector::injectKey(uint16_t code, uint16_t value)
-{
-#ifdef HAVE_ANDROID_OS
-    // XXX: we need to open the right event device
-    int version;
-    mFD = open("/dev/input/event0", O_RDWR);
-    ioctl(mFD, EVIOCGVERSION, &version);
-
-    input_event ev;
-    memset(&ev, 0, sizeof(ev));
-    ev.type = EV_KEY;
-    ev.code = code;
-    ev.value = value;
-    ::write(mFD, &ev, sizeof(ev));
-
-    close(mFD);
-    mFD = -1;
-#endif
-}
-
-
-}; // namespace android
-
diff --git a/libs/surfaceflinger/RFBServer.h b/libs/surfaceflinger/RFBServer.h
deleted file mode 100644
index 420912e..0000000
--- a/libs/surfaceflinger/RFBServer.h
+++ /dev/null
@@ -1,316 +0,0 @@
-/*
- * Copyright (C) 2007 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef ANDROID_RFB_SERVER_H
-#define ANDROID_RFB_SERVER_H
-
-#include <stdint.h>
-#include <sys/types.h>
-#include <sys/uio.h>
-#include <unistd.h>
-#include <arpa/inet.h>
-
-#include <utils/Errors.h>
-#include <utils/threads.h>
-#include <ui/Region.h>
-#include <ui/PixelFormat.h>
-
-#include <pixelflinger/pixelflinger.h>
-
-#include "Barrier.h"
-
-namespace android {
-
-class SurfaceFlinger;
-
-class RFBServer : public Thread
-{
-public:
-                        RFBServer(uint32_t w, uint32_t h, android::PixelFormat format);
-    virtual             ~RFBServer();
-
-    void    frameBufferUpdated(const GGLSurface& front, const Region& reg);
-    bool    isConnected() const;
-
-private:
-            typedef uint8_t     card8;
-            typedef uint16_t    card16;
-            typedef uint32_t    card32;
-
-            struct Message {
-                                Message(size_t size);
-                virtual         ~Message();
-                void*           payload(int offset=0) {
-                    return static_cast<char*>(mPayload)+offset;
-                }
-                void const *    payload(int offset=0) const {
-                    return static_cast<char const *>(mPayload)+offset;
-                }
-                size_t          size() const { return mSize; }
-            protected:
-                                Message(void* payload, size_t size);
-                status_t        resize(size_t size);
-            private:
-                void*       mPayload;
-                size_t      mSize;
-                size_t      mAllocatedSize;
-            };
-
-            struct ProtocolVersion : public Message {
-                ProtocolVersion(uint8_t major, uint8_t minor)
-                    : Message(&messageData, 12) {
-                    char* p = static_cast<char*>(payload());
-                    snprintf(p, 13, "RFB %03u.%03u%c", major, minor, 0xA);
-                }
-                status_t decode(int& maj, int& min) {
-                    char* p = static_cast<char*>(payload());
-                    int n = sscanf(p, "RFB %03u.%03u", &maj, &min);
-                    return (n == 2) ? NO_ERROR : NOT_ENOUGH_DATA;
-                }
-            private:
-                char messageData[12+1];
-            };
-            
-            struct Authentication : public Message {
-                enum { Failed=0, None=1, Vnc=2 };
-                Authentication(int auth) : Message(&messageData, 4) {
-                    *static_cast<card32*>(payload()) = htonl(auth);
-                }
-            private:
-                card32 messageData;
-            };
-            
-            struct ClientInitialization : public Message {
-                ClientInitialization() : Message(&messageData, 1) { }
-                int sharedFlags() {
-                    return messageData;
-                }
-            private:
-                card8 messageData;
-            };
-
-            struct PixelFormat {
-                card8   bitsPerPixel;
-                card8   depth;
-                card8   bigEndianFlag;
-                card8   trueColorFlag;
-                card16  redMax;
-                card16  greenMax;
-                card16  blueMax;
-                card8   redShift;
-                card8   greenShift;
-                card8   blueShift;
-                uint8_t padding[3];
-            } __attribute__((packed));
-            
-            struct ServerInitialization : public Message {
-                ServerInitialization(char const * name)
-                    : Message(sizeof(Payload) + strlen(name))
-                {
-                    const size_t nameLength = size() - sizeof(Payload);
-                    message().nameLength = htonl(nameLength); 
-                    memcpy((char*)message().nameString, name,nameLength);
-                }
-                struct Payload {
-                    card16      framebufferWidth;
-                    card16      framebufferHeight;
-                    PixelFormat serverPixelFormat;
-                    card32      nameLength;
-                    card8       nameString[0];
-                } __attribute__((packed));
-                Payload& message() {
-                    return *static_cast<Payload*>(payload());
-                }
-            };
-
-            // client messages...
-            
-            struct SetPixelFormat {
-                card8           type;
-                uint8_t         padding[3];
-                PixelFormat     pixelFormat;
-            } __attribute__((packed));
-
-            struct SetEncodings {
-                enum { Raw=0, CoR=1, RRE=2, CoRRE=4, Hextile=5 };
-                card8           type;
-                uint8_t         padding;
-                card16          numberOfEncodings;
-                card32          encodings[0];
-            } __attribute__((packed));
-
-            struct FrameBufferUpdateRequest {
-                card8           type;
-                card8           incremental;
-                card16          x;
-                card16          y;
-                card16          width;
-                card16          height;
-            } __attribute__((packed));
-            
-            struct KeyEvent {
-                card8           type;
-                card8           downFlag;
-                uint8_t         padding[2];
-                card32          key;
-            } __attribute__((packed));
-
-            struct PointerEvent {
-                card8           type;
-                card8           buttonMask;
-                card16          x;
-                card16          y;
-            } __attribute__((packed));
-
-            struct ClientCutText {
-                card8           type;
-                uint8_t         padding[3];
-                card32          length;
-                card8           text[0];
-            } __attribute__((packed));
-            
-            union ClientMessages {
-                card8                       type;
-                SetPixelFormat              setPixelFormat;
-                SetEncodings                setEncodings;
-                FrameBufferUpdateRequest    frameBufferUpdateRequest;
-                KeyEvent                    keyEvent;
-                PointerEvent                pointerEvent;
-                ClientCutText               clientCutText;
-            };
-
-            struct Rectangle {
-                card16      x;
-                card16      y;
-                card16      w;
-                card16      h;
-                card32      encoding;
-            } __attribute__((packed));
-
-            struct FrameBufferUpdate {
-                card8       type;
-                uint8_t     padding;
-                card16      numberOfRectangles;
-                Rectangle   rectangles[0];            
-            } __attribute__((packed));
-
-            enum {
-                SET_PIXEL_FORMAT        = 0,
-                FIX_COLOUR_MAP_ENTRIES  = 1,
-                SET_ENCODINGS           = 2,
-                FRAME_BUFFER_UPDATE_REQ = 3,
-                KEY_EVENT               = 4,
-                POINTER_EVENT           = 5,
-                CLIENT_CUT_TEXT         = 6,
-            };
-
-            struct ClientMessage : public Message {
-                ClientMessage()
-                    : Message(&messageData, sizeof(messageData)) {
-                }
-                const ClientMessages& messages() const {
-                    return *static_cast<ClientMessages const *>(payload());
-                }
-                const int type() const {
-                    return messages().type;
-                }
-                status_t resize(size_t size) {
-                    return Message::resize(size);
-                }
-
-                ClientMessages messageData;
-            };
-
-            
-            class ServerThread : public Thread
-            {
-                friend class RFBServer;
-            public:
-                        ServerThread(const sp<RFBServer>& receiver);
-                virtual ~ServerThread();
-                void wake();
-                void exitAndWait();
-            private:
-                virtual bool threadLoop();
-                virtual status_t readyToRun();
-                virtual void onFirstRef();
-                wp<RFBServer> mReceiver;
-                bool (RFBServer::*mAction)();
-                Barrier mUpdateBarrier;
-            };
-            
-            class EventInjector {
-            public:
-                enum { UP=0, DOWN=1 };
-                EventInjector();
-                ~EventInjector();
-                void injectKey(uint16_t code, uint16_t value);
-            private:
-                struct input_event {
-                    struct timeval time;
-                    uint16_t type;
-                    uint16_t code;
-                    uint32_t value;
-                };
-                int mFD;
-            };
-            
-            void        handshake(uint8_t major, uint8_t minor, uint32_t auth);
-            void        waitForClientMessage(ClientMessage& msg);
-            void        handleClientMessage(const ClientMessage& msg);
-            void        handleSetPixelFormat(const SetPixelFormat& msg);
-            void        handleSetEncodings(const SetEncodings& msg);
-            void        handleFrameBufferUpdateReq(const FrameBufferUpdateRequest& msg);
-            void        handleKeyEvent(const KeyEvent& msg);
-            void        sendFrameBufferUpdates();
-
-            bool        validatePixelFormat(const PixelFormat& pf);
-            bool        alive() const;
-            bool        write(const Message& msg);
-            bool        read(Message& msg);
-
-            bool        write(const void* buffer, int size);
-            bool        read(void* buffer, int size);
-
-    virtual bool        threadLoop();
-    virtual status_t    readyToRun();
-    virtual void        onFirstRef();
-
-            sp<ServerThread>    mRobinThread;
-
-            int         mFD;
-            int         mStatus;
-            iovec*      mIoVec;
-    
-            EventInjector   mEventInjector;
-
-            Mutex       mRegionLock;
-            // This is the region requested by the client since the last
-            // time we updated it
-            Region      mClientRegionRequest;
-            // This is the region of the screen that needs to be sent to the
-            // client since the last time we updated it.
-            // Typically this is the dirty region, but not necessarily, for
-            // instance if the client asked for a non incremental update.
-            Region      mDirtyRegion;
-            
-            GGLSurface  mFrameBuffer;
-            GGLSurface  mFrontBuffer;
-};
-
-}; // namespace android
-
-#endif // ANDROID_RFB_SERVER_H
diff --git a/libs/surfaceflinger/SurfaceFlinger.cpp b/libs/surfaceflinger/SurfaceFlinger.cpp
index 4e457c9..900282a 100644
--- a/libs/surfaceflinger/SurfaceFlinger.cpp
+++ b/libs/surfaceflinger/SurfaceFlinger.cpp
@@ -53,21 +53,14 @@
 #include "LayerDim.h"
 #include "LayerBitmap.h"
 #include "LayerOrientationAnim.h"
-#include "LayerScreenshot.h"
 #include "OrientationAnimation.h"
 #include "SurfaceFlinger.h"
-#include "RFBServer.h"
 #include "VRamHeap.h"
 
 #include "DisplayHardware/DisplayHardware.h"
 #include "GPUHardware/GPUHardware.h"
 
 
-// the VNC server even on local ports presents a significant
-// thread as it can allow an application to control and "see" other
-// applications, de-facto bypassing security permissions.
-#define ENABLE_VNC_SERVER   0
-
 #define DISPLAY_COUNT       1
 
 namespace android {
@@ -460,9 +453,6 @@
     if (mDebugNoBootAnimation == false)
         mBootAnimation = new BootAnimation(this);
 
-    if (ENABLE_VNC_SERVER)
-        mRFBServer = new RFBServer(w, h, f);
-
     return NO_ERROR;
 }
 
@@ -572,18 +562,6 @@
             debugShowFPS();
         }
 
-        if (UNLIKELY(ENABLE_VNC_SERVER &&
-                mRFBServer!=0 && mRFBServer->isConnected())) {
-            if (!mSecureFrameBuffer) {
-                GGLSurface fb;
-                // backbufer, is going to become the front buffer really soon
-                hw.getDisplaySurface(&fb);
-                if (LIKELY(fb.data != 0)) {
-                    mRFBServer->frameBufferUpdated(fb, mInvalidRegion);
-                }
-            }
-        }
-
         hw.flip(mInvalidRegion);
 
         mInvalidRegion.clear();
@@ -1571,55 +1549,17 @@
 
     status_t err = BnSurfaceComposer::onTransact(code, data, reply, flags);
     if (err == UNKNOWN_TRANSACTION || err == PERMISSION_DENIED) {
-        if (code == 1012) {
-            // take screen-shot of the front buffer
-            if (UNLIKELY(checkCallingPermission(
-                    String16("android.permission.READ_FRAME_BUFFER")) == false))
-            { // not allowed
-                LOGE("Permission Denial: "
-                        "can't take screenshots from pid=%d, uid=%d\n",
-                        IPCThreadState::self()->getCallingPid(),
-                        IPCThreadState::self()->getCallingUid());
-                return PERMISSION_DENIED;
-            }
-
-            if (UNLIKELY(mSecureFrameBuffer)) {
-                LOGE("A secure window is on screen: "
-                        "can't take screenshots from pid=%d, uid=%d\n",
-                        IPCThreadState::self()->getCallingPid(),
-                        IPCThreadState::self()->getCallingUid());
-                return PERMISSION_DENIED;
-            }
-
-            LOGI("Taking a screenshot...");
-
-            LayerScreenshot* l = new LayerScreenshot(this, 0);
-
-            Mutex::Autolock _l(mStateLock);
-            const DisplayHardware& hw(graphicPlane(0).displayHardware());
-            l->initStates(hw.getWidth(), hw.getHeight(), 0);
-            l->setLayer(INT_MAX);
-
-            addLayer_l(l);
-            setTransactionFlags(eTransactionNeeded|eTraversalNeeded);
-
-            l->takeScreenshot(mStateLock, reply);
-
-            removeLayer_l(l);
-            setTransactionFlags(eTransactionNeeded);
-            return NO_ERROR;
-        } else {
-            // HARDWARE_TEST stuff...
-            if (UNLIKELY(checkCallingPermission(
-                    String16("android.permission.HARDWARE_TEST")) == false))
-            { // not allowed
-                LOGE("Permission Denial: pid=%d, uid=%d\n",
-                        IPCThreadState::self()->getCallingPid(),
-                        IPCThreadState::self()->getCallingUid());
-                return PERMISSION_DENIED;
-            }
-            int n;
-            switch (code) {
+        // HARDWARE_TEST stuff...
+        if (UNLIKELY(checkCallingPermission(
+                String16("android.permission.HARDWARE_TEST")) == false))
+        { // not allowed
+            LOGE("Permission Denial: pid=%d, uid=%d\n",
+                    IPCThreadState::self()->getCallingPid(),
+                    IPCThreadState::self()->getCallingUid());
+            return PERMISSION_DENIED;
+        }
+        int n;
+        switch (code) {
             case 1000: // SHOW_CPU
                 n = data.readInt32();
                 mDebugCpu = n ? 1 : 0;
@@ -1652,8 +1592,8 @@
                 const DisplayHardware& hw(graphicPlane(0).displayHardware());
                 mDirtyRegion.set(hw.bounds()); // careful that's not thread-safe
                 signalEvent();
-                }
-                return NO_ERROR;
+            }
+            return NO_ERROR;
             case 1005: // ask GPU revoke
                 mGPU->friendlyRevoke();
                 return NO_ERROR;
@@ -1669,13 +1609,12 @@
                 reply->writeInt32(mDebugRegion);
                 reply->writeInt32(mDebugBackground);
                 return NO_ERROR;
-            case 1013: { // screenshot
+            case 1013: {
                 Mutex::Autolock _l(mStateLock);
                 const DisplayHardware& hw(graphicPlane(0).displayHardware());
                 reply->writeInt32(hw.getPageFlipCount());
             }
             return NO_ERROR;
-            }
         }
     }
     return err;
@@ -1829,10 +1768,33 @@
     mGlobalTransform = mOrientationTransform * mTransform;
 }
 
+status_t GraphicPlane::orientationToTransfrom(
+        int orientation, int w, int h, Transform* tr)
+{    
+    float a, b, c, d, x, y;
+    switch (orientation) {
+    case ISurfaceComposer::eOrientationDefault:
+        a=1; b=0; c=0; d=1; x=0; y=0;
+        break;
+    case ISurfaceComposer::eOrientation90:
+        a=0; b=-1; c=1; d=0; x=w; y=0;
+        break;
+    case ISurfaceComposer::eOrientation180:
+        a=-1; b=0; c=0; d=-1; x=w; y=h;
+        break;
+    case ISurfaceComposer::eOrientation270:
+        a=0; b=1; c=-1; d=0; x=0; y=h;
+        break;
+    default:
+        return BAD_VALUE;
+    }
+    tr->set(a, b, c, d);
+    tr->set(x, y);
+    return NO_ERROR;
+}
+
 status_t GraphicPlane::setOrientation(int orientation)
 {
-    float a, b, c, d, x, y;
-
     const DisplayHardware& hw(displayHardware());
     const float w = hw.getWidth();
     const float h = hw.getHeight();
@@ -1846,30 +1808,21 @@
 
     // If the rotation can be handled in hardware, this is where
     // the magic should happen.
-
-    switch (orientation) {
-    case ISurfaceComposer::eOrientation90:
-        a=0; b=-1; c=1; d=0; x=w; y=0;
-        break;
-    case ISurfaceComposer::eOrientation180:
-        a=-1; b=0; c=0; d=-1; x=w; y=h;
-        break;
-    case ISurfaceComposer::eOrientation270:
-        a=0; b=1; c=-1; d=0; x=0; y=h;
-        break;
-    case 42: {
+    if (UNLIKELY(orientation == 42)) {
+        float a, b, c, d, x, y;
         const float r = (3.14159265f / 180.0f) * 42.0f;
         const float si = sinf(r);
         const float co = cosf(r);
         a=co; b=-si; c=si; d=co;
         x = si*(h*0.5f) + (1-co)*(w*0.5f);
         y =-si*(w*0.5f) + (1-co)*(h*0.5f);
-    } break;
-    default:
-        return BAD_VALUE;
+        mOrientationTransform.set(a, b, c, d);
+        mOrientationTransform.set(x, y);
+    } else {
+        GraphicPlane::orientationToTransfrom(orientation, w, h,
+                &mOrientationTransform);
     }
-    mOrientationTransform.set(a, b, c, d);
-    mOrientationTransform.set(x, y);
+    
     mGlobalTransform = mOrientationTransform * mTransform;
     return NO_ERROR;
 }
diff --git a/libs/surfaceflinger/SurfaceFlinger.h b/libs/surfaceflinger/SurfaceFlinger.h
index 8e5fd88..f7d7764 100644
--- a/libs/surfaceflinger/SurfaceFlinger.h
+++ b/libs/surfaceflinger/SurfaceFlinger.h
@@ -58,7 +58,6 @@
 class LayerBuffer;
 class LayerOrientationAnim;
 class OrientationAnimation;
-class RFBServer;
 class SurfaceHeapManager;
 
 typedef int32_t ClientID;
@@ -112,6 +111,8 @@
 class GraphicPlane
 {
 public:
+    static status_t orientationToTransfrom(int orientation, int w, int h,
+            Transform* tr);
 
                                 GraphicPlane();
                                 ~GraphicPlane();
@@ -344,7 +345,6 @@
                 sp<GPUHardwareInterface>    mGPU;
                 GLuint                      mWormholeTexName;
                 sp<BootAnimation>           mBootAnimation;
-                sp<RFBServer>               mRFBServer;
                 nsecs_t                     mBootTime;
                 
                 // Can only accessed from the main thread, these members
diff --git a/libs/ui/ISurface.cpp b/libs/ui/ISurface.cpp
index abd3634..d5e9f81 100644
--- a/libs/ui/ISurface.cpp
+++ b/libs/ui/ISurface.cpp
@@ -37,7 +37,7 @@
         int32_t hor_stride, int32_t ver_stride,
         PixelFormat format, const sp<IMemoryHeap>& heap)
     : w(w), h(h), hor_stride(hor_stride), ver_stride(ver_stride),
-      format(format), heap(heap) 
+      format(format), transform(0), flags(0), heap(heap) 
 {
 }
 
diff --git a/location/java/com/android/internal/location/INetworkLocationManager.java b/location/java/com/android/internal/location/INetworkLocationManager.java
index 83bbe1f..6b632fd 100644
--- a/location/java/com/android/internal/location/INetworkLocationManager.java
+++ b/location/java/com/android/internal/location/INetworkLocationManager.java
@@ -16,6 +16,8 @@
 
 package com.android.internal.location;
 
+import android.content.Context;
+
 /**
  * Used to register network location and collection services 
  * with the Location Manager Service.
@@ -23,6 +25,13 @@
  * {@hide}
  */
 public interface INetworkLocationManager {
+
+    /* callback to allow installation to occur in Location Manager's thread */
+    public interface InstallCallback {
+        void installNetworkLocationProvider(Context context, INetworkLocationManager manager);
+    }
+    
+    void setInstallCallback(InstallCallback callback);
     void setNetworkLocationProvider(INetworkLocationProvider provider);
     void setLocationCollector(ILocationCollector collector);
 }
\ No newline at end of file
diff --git a/media/java/android/media/AudioManager.java b/media/java/android/media/AudioManager.java
index 2978774..4d2e725 100644
--- a/media/java/android/media/AudioManager.java
+++ b/media/java/android/media/AudioManager.java
@@ -135,7 +135,7 @@
     public static final int STREAM_VOICE_CALL = AudioSystem.STREAM_VOICE_CALL;
     /** The audio stream for system sounds */
     public static final int STREAM_SYSTEM = AudioSystem.STREAM_SYSTEM;
-    /** The audio stream for the phone ring and message alerts */
+    /** The audio stream for the phone ring */
     public static final int STREAM_RING = AudioSystem.STREAM_RING;
     /** The audio stream for music playback */
     public static final int STREAM_MUSIC = AudioSystem.STREAM_MUSIC;
@@ -214,14 +214,13 @@
     /**
      * Whether to include ringer modes as possible options when changing volume.
      * For example, if true and volume level is 0 and the volume is adjusted
-     * with {@link #ADJUST_LOWER}, then the ringer mode may switch the silent
-     * or vibrate mode.
+     * with {@link #ADJUST_LOWER}, then the ringer mode may switch the silent or
+     * vibrate mode.
      * <p>
-     * By default this is on for stream types that are affected by the ringer
-     * mode (for example, the ring stream type). If this flag is included, this
-     * behavior will be present regardless of the stream type being affected by
-     * the ringer mode.
-     *
+     * By default this is on for the ring stream. If this flag is included,
+     * this behavior will be present regardless of the stream type being
+     * affected by the ringer mode.
+     * 
      * @see #adjustVolume(int, int)
      * @see #adjustStreamVolume(int, int, int)
      */
diff --git a/media/java/android/media/AudioRecord.java b/media/java/android/media/AudioRecord.java
index 1314ba1..fd990fe 100644
--- a/media/java/android/media/AudioRecord.java
+++ b/media/java/android/media/AudioRecord.java
@@ -339,7 +339,11 @@
      * Releases the native AudioRecord resources.
      */
     public void release() {
-        stop();
+        try {
+            stop();
+        } catch(IllegalStateException ise) { 
+            // don't raise an exception, we're releasing the resources.
+        }
         native_release();
         mState = STATE_UNINITIALIZED;
     }
@@ -427,6 +431,56 @@
     public int getPositionNotificationPeriod() {
         return native_get_pos_update_period();
     }
+    
+    /**
+     * {@hide}
+     * Returns the minimum buffer size required for the successful creation of an AudioRecord
+     * object.
+     * @param sampleRateInHz the sample rate expressed in Hertz.
+     * @param channelConfig describes the configuration of the audio channels. 
+     *   See {@link AudioFormat#CHANNEL_CONFIGURATION_MONO} and
+     *   {@link AudioFormat#CHANNEL_CONFIGURATION_STEREO}
+     * @param audioFormat the format in which the audio data is represented. 
+     *   See {@link AudioFormat#ENCODING_PCM_16BIT}.
+     * @return {@link #ERROR_BAD_VALUE} if the recording parameters are not supported by the 
+     *  hardware, or an invalid parameter was passed,
+     *  or {@link #ERROR} if the implementation was unable to query the hardware for its 
+     *  output properties, 
+     *   or the minimum buffer size expressed in of bytes.
+     */
+    static public int getMinBufferSize(int sampleRateInHz, int channelConfig, int audioFormat) {
+        int channelCount = 0;
+        switch(channelConfig) {
+        case AudioFormat.CHANNEL_CONFIGURATION_DEFAULT:
+        case AudioFormat.CHANNEL_CONFIGURATION_MONO:
+            channelCount = 1;
+            break;
+        case AudioFormat.CHANNEL_CONFIGURATION_STEREO:
+            channelCount = 2;
+            break;
+        case AudioFormat.CHANNEL_CONFIGURATION_INVALID:
+        default:
+            loge("getMinBufferSize(): Invalid channel configuration.");
+            return AudioRecord.ERROR_BAD_VALUE;
+        }
+        
+        // PCM_8BIT is not supported at the moment
+        if (audioFormat != AudioFormat.ENCODING_PCM_16BIT) {
+            loge("getMinBufferSize(): Invalid audio format.");
+            return AudioRecord.ERROR_BAD_VALUE;
+        }
+        
+        int size = native_get_min_buff_size(sampleRateInHz, channelCount, audioFormat);
+        if (size == 0) {
+            return AudioRecord.ERROR_BAD_VALUE;
+        } 
+        else if (size == -1) {
+            return AudioRecord.ERROR;
+        }
+        else {
+            return size;
+        }
+    }
 
 
     //---------------------------------------------------------
@@ -699,6 +753,9 @@
     
     private native final int native_set_pos_update_period(int updatePeriod);
     private native final int native_get_pos_update_period();
+    
+    static private native final int native_get_min_buff_size(
+            int sampleRateInHz, int channelCount, int audioFormat);
 
     
     //---------------------------------------------------------
diff --git a/media/java/android/media/AudioService.java b/media/java/android/media/AudioService.java
index f3d8957..bdabda7 100644
--- a/media/java/android/media/AudioService.java
+++ b/media/java/android/media/AudioService.java
@@ -349,9 +349,9 @@
         // If either the client forces allowing ringer modes for this adjustment,
         // or the stream type is one that is affected by ringer modes
         if ((flags & AudioManager.FLAG_ALLOW_RINGER_MODES) != 0
-                || isStreamAffectedByRingerMode(streamType)) {
+                || streamType == AudioManager.STREAM_RING) {
             // Check if the ringer mode changes with this volume adjustment. If
-            // it does, it will handle adjusting the volome, so we won't below
+            // it does, it will handle adjusting the volume, so we won't below
             adjustVolume = checkForRingerModeChange(oldIndex, direction);
         }
 
diff --git a/media/java/android/media/AudioTrack.java b/media/java/android/media/AudioTrack.java
index 9bb1df9..74ffc1a 100644
--- a/media/java/android/media/AudioTrack.java
+++ b/media/java/android/media/AudioTrack.java
@@ -395,7 +395,11 @@
     public void release() {
         // even though native_release() stops the native AudioTrack, we need to stop
         // AudioTrack subclasses too.
-        stop();
+        try {
+            stop();
+        } catch(IllegalStateException ise) { 
+            // don't raise an exception, we're releasing the resources.
+        }
         native_release();
         mState = STATE_UNINITIALIZED;
     }
@@ -1007,4 +1011,4 @@
         Log.e(TAG, "[ android.media.AudioTrack ] " + msg);
     }
 
-}
\ No newline at end of file
+}
diff --git a/media/java/android/media/MediaRecorder.java b/media/java/android/media/MediaRecorder.java
index 4a30114..3609826 100644
--- a/media/java/android/media/MediaRecorder.java
+++ b/media/java/android/media/MediaRecorder.java
@@ -19,6 +19,10 @@
 import android.view.Surface;
 import android.hardware.Camera;
 import java.io.IOException;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.FileDescriptor;
+import android.util.Log;
 
 /**
  * Used to record audio and video. The recording control is based on a
@@ -50,6 +54,7 @@
     static {
         System.loadLibrary("media_jni");
     }
+    private final static String TAG = "MediaRecorder";
     
     // The two fields below are accessed by native methods
     @SuppressWarnings("unused")
@@ -57,7 +62,10 @@
     
     @SuppressWarnings("unused")
     private Surface mSurface;
-    
+
+    private String mPath;
+    private FileDescriptor mFd;
+
     /**
      * Default constructor.
      */
@@ -71,8 +79,6 @@
      * the camera object. Must call before prepare().
      * 
      * @param c the Camera to use for recording
-     * FIXME: Temporarily hidden until API approval
-     * @hide
      */
     public native void setCamera(Camera c);
 
@@ -104,7 +110,6 @@
     /**
      * Defines the video source. These constants are used with 
      * {@link MediaRecorder#setVideoSource(int)}.
-     * @hide
      */
     public final class VideoSource {
       /* Do not change these values without updating their counterparts
@@ -152,7 +157,6 @@
     /**
      * Defines the video encoding. These constants are used with 
      * {@link MediaRecorder#setVideoEncoder(int)}.
-     * @hide
      */
     public final class VideoEncoder {
       /* Do not change these values without updating their counterparts
@@ -187,7 +191,6 @@
      * @param video_source the video source to use
      * @throws IllegalStateException if it is called after setOutputFormat()
      * @see android.media.MediaRecorder.VideoSource
-     * @hide
      */ 
     public native void setVideoSource(int video_source)
             throws IllegalStateException;
@@ -214,7 +217,6 @@
      * @param height the height of the video to be captured
      * @throws IllegalStateException if it is called after 
      * prepare() or before setOutputFormat()
-     * @hide
      */
     public native void setVideoSize(int width, int height)
             throws IllegalStateException;
@@ -227,7 +229,10 @@
      * @param rate the number of frames per second of video to capture
      * @throws IllegalStateException if it is called after 
      * prepare() or before setOutputFormat().
-     * @hide
+     *
+     * NOTE: On some devices that have auto-frame rate, this sets the
+     * maximum frame rate, not a constant frame rate. Actual frame rate
+     * will vary according to lighting conditions.
      */
     public native void setVideoFrameRate(int rate) throws IllegalStateException;
 
@@ -253,22 +258,44 @@
      * @throws IllegalStateException if it is called before
      * setOutputFormat() or after prepare()
      * @see android.media.MediaRecorder.VideoEncoder
-     * @hide
      */ 
     public native void setVideoEncoder(int video_encoder)
             throws IllegalStateException;
 
     /**
-     * Sets the path of the output file to be produced. Call this after
+     * Pass in the file descriptor of the file to be written. Call this after
      * setOutputFormat() but before prepare().
      * 
-     * @param path The pathname to use()
+     * @param fd an open file descriptor to be written into.
      * @throws IllegalStateException if it is called before
      * setOutputFormat() or after prepare()
      */ 
-    public native void setOutputFile(String path) throws IllegalStateException;
+    public void setOutputFile(FileDescriptor fd) throws IllegalStateException
+    {
+        mPath = null;
+        mFd = fd;
+    }
   
     /**
+     * Sets the path of the output file to be produced. Call this after
+     * setOutputFormat() but before prepare().
+     * 
+     * @param path The pathname to use.
+     * @throws IllegalStateException if it is called before
+     * setOutputFormat() or after prepare()
+     */ 
+    public void setOutputFile(String path) throws IllegalStateException
+    {
+        mFd = null;
+        mPath = path;
+    }
+  
+    // native implementation
+    private native void _setOutputFile(FileDescriptor fd, long offset, long length)
+        throws IllegalStateException, IOException;
+    private native void _prepare() throws IllegalStateException, IOException;
+
+    /**
      * Prepares the recorder to begin capturing and encoding data. This method
      * must be called after setting up the desired audio and video sources,
      * encoders, file format, etc., but before start().
@@ -277,7 +304,18 @@
      * start() or before setOutputFormat().
      * @throws IOException if prepare fails otherwise.
      */
-    public native void prepare() throws IllegalStateException, IOException;
+    public void prepare() throws IllegalStateException, IOException
+    {
+        if (mPath != null) {
+            FileOutputStream f = new FileOutputStream(mPath);
+            _setOutputFile(f.getFD(), 0, 0);
+        } else if (mFd != null) {
+            _setOutputFile(mFd, 0, 0);
+        } else {
+            throw new IOException("No valid output file");
+        }
+        _prepare();
+    }
 
     /**
      * Begins capturing and encoding data to the file specified with 
diff --git a/media/jni/android_media_MediaRecorder.cpp b/media/jni/android_media_MediaRecorder.cpp
index 8eb638e..095749b 100644
--- a/media/jni/android_media_MediaRecorder.cpp
+++ b/media/jni/android_media_MediaRecorder.cpp
@@ -143,25 +143,17 @@
 }
 
 static void
-android_media_MediaRecorder_setOutputFile(JNIEnv *env, jobject thiz, jstring path)
+android_media_MediaRecorder_setOutputFileFD(JNIEnv *env, jobject thiz, jobject fileDescriptor, jlong offset, jlong length)
 {
     LOGV("setOutputFile");
+    if (fileDescriptor == NULL) {
+        jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
+        return;
+    }
+    int fd = getParcelFileDescriptorFD(env, fileDescriptor);
     MediaRecorder *mr = (MediaRecorder *)env->GetIntField(thiz, fields.context);
-
-    if (path == NULL) {
-        jniThrowException(env, "java/lang/IllegalArgumentException", "Path is a NULL pointer");
-        return;
-    }
-    const char *pathStr = env->GetStringUTFChars(path, NULL);
-    if (pathStr == NULL) {  // Out of memory
-        jniThrowException(env, "java/lang/RuntimeException", "Out of memory");
-        return;
-    }
-    status_t opStatus = mr->setOutputFile(pathStr);
-
-    // Make sure that local ref is released before a potential exception
-    env->ReleaseStringUTFChars(path, pathStr);
-    process_media_recorder_call(env, opStatus, "java/lang/RuntimeException", "setOutputFile failed.");
+    status_t opStatus = mr->setOutputFile(fd, offset, length);
+    process_media_recorder_call(env, opStatus, "java/io/IOException", "setOutputFile failed.");
 }
 
 static void
@@ -273,23 +265,23 @@
 // ----------------------------------------------------------------------------
 
 static JNINativeMethod gMethods[] = {
-    {"setCamera",            "(Landroid/hardware/Camera;)V",(void *)android_media_MediaRecorder_setCamera},
-    {"setVideoSource",       "(I)V",                    (void *)android_media_MediaRecorder_setVideoSource},
-    {"setAudioSource",       "(I)V",                    (void *)android_media_MediaRecorder_setAudioSource},
-    {"setOutputFormat",      "(I)V",                    (void *)android_media_MediaRecorder_setOutputFormat},
-    {"setVideoEncoder",      "(I)V",                    (void *)android_media_MediaRecorder_setVideoEncoder},
-    {"setAudioEncoder",      "(I)V",                    (void *)android_media_MediaRecorder_setAudioEncoder},
-    {"setOutputFile",        "(Ljava/lang/String;)V",   (void *)android_media_MediaRecorder_setOutputFile},
-    {"setVideoSize",         "(II)V",                   (void *)android_media_MediaRecorder_setVideoSize},
-    {"setVideoFrameRate",    "(I)V",                    (void *)android_media_MediaRecorder_setVideoFrameRate},
-    {"prepare",              "()V",                     (void *)android_media_MediaRecorder_prepare},
-    {"getMaxAmplitude",      "()I",                     (void *)android_media_MediaRecorder_native_getMaxAmplitude},
-    {"start",                "()V",                     (void *)android_media_MediaRecorder_start},
-    {"stop",                 "()V",                     (void *)android_media_MediaRecorder_stop},
-    {"reset",                "()V",                     (void *)android_media_MediaRecorder_reset},
-    {"release",              "()V",                     (void *)android_media_MediaRecorder_release},
-    {"native_setup",         "()V",                     (void *)android_media_MediaRecorder_native_setup},
-    {"native_finalize",      "()V",                     (void *)android_media_MediaRecorder_native_finalize},
+    {"setCamera",            "(Landroid/hardware/Camera;)V",    (void *)android_media_MediaRecorder_setCamera},
+    {"setVideoSource",       "(I)V",                            (void *)android_media_MediaRecorder_setVideoSource},
+    {"setAudioSource",       "(I)V",                            (void *)android_media_MediaRecorder_setAudioSource},
+    {"setOutputFormat",      "(I)V",                            (void *)android_media_MediaRecorder_setOutputFormat},
+    {"setVideoEncoder",      "(I)V",                            (void *)android_media_MediaRecorder_setVideoEncoder},
+    {"setAudioEncoder",      "(I)V",                            (void *)android_media_MediaRecorder_setAudioEncoder},
+    {"_setOutputFile",       "(Ljava/io/FileDescriptor;JJ)V",   (void *)android_media_MediaRecorder_setOutputFileFD},
+    {"setVideoSize",         "(II)V",                           (void *)android_media_MediaRecorder_setVideoSize},
+    {"setVideoFrameRate",    "(I)V",                            (void *)android_media_MediaRecorder_setVideoFrameRate},
+    {"_prepare",             "()V",                             (void *)android_media_MediaRecorder_prepare},
+    {"getMaxAmplitude",      "()I",                             (void *)android_media_MediaRecorder_native_getMaxAmplitude},
+    {"start",                "()V",                             (void *)android_media_MediaRecorder_start},
+    {"stop",                 "()V",                             (void *)android_media_MediaRecorder_stop},
+    {"reset",                "()V",                             (void *)android_media_MediaRecorder_reset},
+    {"release",              "()V",                             (void *)android_media_MediaRecorder_release},
+    {"native_setup",         "()V",                             (void *)android_media_MediaRecorder_native_setup},
+    {"native_finalize",      "()V",                             (void *)android_media_MediaRecorder_native_finalize},
 };
 
 static const char* const kClassPathName = "android/media/MediaRecorder";
diff --git a/media/jni/soundpool/SoundPool.cpp b/media/jni/soundpool/SoundPool.cpp
index 559f9d5..02731825 100644
--- a/media/jni/soundpool/SoundPool.cpp
+++ b/media/jni/soundpool/SoundPool.cpp
@@ -491,10 +491,11 @@
     // initialize track
     int afFrameCount;
     int afSampleRate;
-    if (AudioSystem::getOutputFrameCount(&afFrameCount) != NO_ERROR) {
+    int streamType = mSoundPool->streamType();
+    if (AudioSystem::getOutputFrameCount(&afFrameCount, streamType) != NO_ERROR) {
         afFrameCount = kDefaultFrameCount;
     }
-    if (AudioSystem::getOutputSamplingRate(&afSampleRate) != NO_ERROR) {
+    if (AudioSystem::getOutputSamplingRate(&afSampleRate, streamType) != NO_ERROR) {
         afSampleRate = kDefaultSampleRate;
     }
     int numChannels = sample->numChannels();
@@ -522,10 +523,10 @@
     void *userData = (void *)((unsigned long)this | toggle);
     
 #ifdef USE_SHARED_MEM_BUFFER
-    newTrack = new AudioTrack(mSoundPool->streamType(), sampleRate, sample->format(),
+    newTrack = new AudioTrack(streamType, sampleRate, sample->format(),
             numChannels, sample->getIMemory(), 0, callback, userData);
 #else
-    newTrack = new AudioTrack(mSoundPool->streamType(), sampleRate, sample->format(),
+    newTrack = new AudioTrack(streamType, sampleRate, sample->format(),
             numChannels, frameCount, 0, callback, userData, bufferFrames);
 #endif
     if (newTrack->initCheck() != NO_ERROR) {
diff --git a/media/libmedia/AudioRecord.cpp b/media/libmedia/AudioRecord.cpp
index a987b92..3d39181 100644
--- a/media/libmedia/AudioRecord.cpp
+++ b/media/libmedia/AudioRecord.cpp
@@ -128,22 +128,8 @@
         return BAD_VALUE;
     }
 
-    size_t inputBuffSizeInBytes = -1;
-    if (AudioSystem::getInputBufferSize(sampleRate, format, channelCount, &inputBuffSizeInBytes)
-        != NO_ERROR) {
-            LOGE("AudioSystem could not query the input buffer size.");
-            return NO_INIT;
-    }
-    if (inputBuffSizeInBytes == 0) {
-        LOGE("Recording parameters are not supported: sampleRate %d, channelCount %d, format %d",
-            sampleRate, channelCount, format);
-        return BAD_VALUE;
-    }
-    int frameSizeInBytes = channelCount * (format == AudioSystem::PCM_16_BIT ? 2 : 1);
-    
-    // We use 2* size of input buffer for ping pong use of record buffer.
-    int minFrameCount = 2 * inputBuffSizeInBytes / frameSizeInBytes;
-    LOGV("AudioRecord::set() minFrameCount = %d", minFrameCount);
+    // TODO: Get input frame count from hardware.
+    int minFrameCount = 1024*2;
 
     if (frameCount == 0) {
         frameCount = minFrameCount;
diff --git a/media/libmedia/AudioSystem.cpp b/media/libmedia/AudioSystem.cpp
index cf91105..63dfc3b 100644
--- a/media/libmedia/AudioSystem.cpp
+++ b/media/libmedia/AudioSystem.cpp
@@ -20,7 +20,6 @@
 #include <utils/Log.h>
 #include <utils/IServiceManager.h>
 #include <media/AudioSystem.h>
-#include <media/AudioTrack.h>
 #include <math.h>
 
 namespace android {
@@ -31,9 +30,10 @@
 sp<AudioSystem::AudioFlingerClient> AudioSystem::gAudioFlingerClient;
 audio_error_callback AudioSystem::gAudioErrorCallback = NULL;
 // Cached values
-int AudioSystem::gOutSamplingRate = 0;
-int AudioSystem::gOutFrameCount = 0;
-uint32_t AudioSystem::gOutLatency = 0;
+int AudioSystem::gOutSamplingRate[NUM_AUDIO_OUTPUT_TYPES];
+int AudioSystem::gOutFrameCount[NUM_AUDIO_OUTPUT_TYPES];
+uint32_t AudioSystem::gOutLatency[NUM_AUDIO_OUTPUT_TYPES];
+bool AudioSystem::gA2dpEnabled;
 // Cached values for recording queries
 uint32_t AudioSystem::gPrevInSamplingRate = 16000;
 int AudioSystem::gPrevInFormat = AudioSystem::PCM_16_BIT;
@@ -66,9 +66,12 @@
         gAudioFlinger = interface_cast<IAudioFlinger>(binder);
         gAudioFlinger->registerClient(gAudioFlingerClient);
         // Cache frequently accessed parameters 
-        gOutFrameCount = (int)gAudioFlinger->frameCount();
-        gOutSamplingRate = (int)gAudioFlinger->sampleRate();
-        gOutLatency = gAudioFlinger->latency();
+        for (int output = 0; output < NUM_AUDIO_OUTPUT_TYPES; output++) {
+            gOutFrameCount[output] = (int)gAudioFlinger->frameCount(output);
+            gOutSamplingRate[output] = (int)gAudioFlinger->sampleRate(output);
+            gOutLatency[output] = gAudioFlinger->latency(output);
+        }
+        gA2dpEnabled = gAudioFlinger->isA2dpEnabled();
     }
     LOGE_IF(gAudioFlinger==0, "no AudioFlinger!?");
     return gAudioFlinger;
@@ -147,7 +150,7 @@
 
 status_t AudioSystem::setStreamVolume(int stream, float value)
 {
-    if (uint32_t(stream) >= AudioTrack::NUM_STREAM_TYPES) return BAD_VALUE;
+    if (uint32_t(stream) >= NUM_STREAM_TYPES) return BAD_VALUE;
     const sp<IAudioFlinger>& af = AudioSystem::get_audio_flinger();
     if (af == 0) return PERMISSION_DENIED;
     af->setStreamVolume(stream, value);
@@ -156,7 +159,7 @@
 
 status_t AudioSystem::setStreamMute(int stream, bool mute)
 {
-    if (uint32_t(stream) >= AudioTrack::NUM_STREAM_TYPES) return BAD_VALUE;
+    if (uint32_t(stream) >= NUM_STREAM_TYPES) return BAD_VALUE;
     const sp<IAudioFlinger>& af = AudioSystem::get_audio_flinger();
     if (af == 0) return PERMISSION_DENIED;
     af->setStreamMute(stream, mute);
@@ -165,7 +168,7 @@
 
 status_t AudioSystem::getStreamVolume(int stream, float* volume)
 {
-    if (uint32_t(stream) >= AudioTrack::NUM_STREAM_TYPES) return BAD_VALUE;
+    if (uint32_t(stream) >= NUM_STREAM_TYPES) return BAD_VALUE;
     const sp<IAudioFlinger>& af = AudioSystem::get_audio_flinger();
     if (af == 0) return PERMISSION_DENIED;
     *volume = af->streamVolume(stream);
@@ -174,7 +177,7 @@
 
 status_t AudioSystem::getStreamMute(int stream, bool* mute)
 {
-    if (uint32_t(stream) >= AudioTrack::NUM_STREAM_TYPES) return BAD_VALUE;
+    if (uint32_t(stream) >= NUM_STREAM_TYPES) return BAD_VALUE;
     const sp<IAudioFlinger>& af = AudioSystem::get_audio_flinger();
     if (af == 0) return PERMISSION_DENIED;
     *mute = af->streamMute(stream);
@@ -252,37 +255,48 @@
     return volume ? 100 - int(dBConvertInverse * log(volume) + 0.5) : 0;
 }
 
-status_t AudioSystem::getOutputSamplingRate(int* samplingRate)
+status_t AudioSystem::getOutputSamplingRate(int* samplingRate, int streamType)
 {
-    if (gOutSamplingRate == 0) {
+    int output = getOutput(streamType);
+
+    if (gOutSamplingRate[output] == 0) {
         const sp<IAudioFlinger>& af = AudioSystem::get_audio_flinger();
         if (af == 0) return PERMISSION_DENIED;
         // gOutSamplingRate is updated by get_audio_flinger()
     }
-    *samplingRate = gOutSamplingRate;
+    LOGV("getOutputSamplingRate() streamType %d, output %d, sampling rate %d", streamType, output, gOutSamplingRate[output]);
+    *samplingRate = gOutSamplingRate[output];
     
     return NO_ERROR;
 }
 
-status_t AudioSystem::getOutputFrameCount(int* frameCount)
+status_t AudioSystem::getOutputFrameCount(int* frameCount, int streamType)
 {
-    if (gOutFrameCount == 0) {
+    int output = getOutput(streamType);
+
+    if (gOutFrameCount[output] == 0) {
         const sp<IAudioFlinger>& af = AudioSystem::get_audio_flinger();
         if (af == 0) return PERMISSION_DENIED;
         // gOutFrameCount is updated by get_audio_flinger()
     }
-    *frameCount = gOutFrameCount;
+    LOGV("getOutputFrameCount() streamType %d, output %d, frame count %d", streamType, output, gOutFrameCount[output]);
+
+    *frameCount = gOutFrameCount[output];
     return NO_ERROR;
 }
 
-status_t AudioSystem::getOutputLatency(uint32_t* latency)
+status_t AudioSystem::getOutputLatency(uint32_t* latency, int streamType)
 {
-    if (gOutLatency == 0) {
+    int output = getOutput(streamType);
+
+    if (gOutLatency[output] == 0) {
         const sp<IAudioFlinger>& af = AudioSystem::get_audio_flinger();
         if (af == 0) return PERMISSION_DENIED;
         // gOutLatency is updated by get_audio_flinger()
-    }    
-    *latency = gOutLatency;
+    }
+    LOGV("getOutputLatency() streamType %d, output %d, latency %d", streamType, output, gOutLatency[output]);
+
+    *latency = gOutLatency[output];
     
     return NO_ERROR;
 }
@@ -315,24 +329,23 @@
 void AudioSystem::AudioFlingerClient::binderDied(const wp<IBinder>& who) {   
     Mutex::Autolock _l(AudioSystem::gLock);
     AudioSystem::gAudioFlinger.clear();
-    AudioSystem::gOutSamplingRate = 0;
-    AudioSystem::gOutFrameCount = 0;
-    AudioSystem::gOutLatency = 0;
+
+    for (int output = 0; output < NUM_AUDIO_OUTPUT_TYPES; output++) {
+        gOutFrameCount[output] = 0;
+        gOutSamplingRate[output] = 0;
+        gOutLatency[output] = 0;
+    }
     AudioSystem::gInBuffSize = 0;
-    
+
     if (gAudioErrorCallback) {
         gAudioErrorCallback(DEAD_OBJECT);
     }
     LOGW("AudioFlinger server died!");
 }
 
-void AudioSystem::AudioFlingerClient::audioOutputChanged(uint32_t frameCount, uint32_t samplingRate, uint32_t latency) {
-
-    AudioSystem::gOutFrameCount = frameCount;
-    AudioSystem::gOutSamplingRate = samplingRate;
-    AudioSystem::gOutLatency = latency;
-
-    LOGV("AudioFlinger output changed!");
+void AudioSystem::AudioFlingerClient::a2dpEnabledChanged(bool enabled) {
+    gA2dpEnabled = enabled;        
+    LOGV("AudioFlinger A2DP enabled status changed! %d", enabled);
 }
 
 void AudioSystem::setErrorCallback(audio_error_callback cb) {
@@ -340,5 +353,31 @@
     gAudioErrorCallback = cb;
 }
 
+int AudioSystem::getOutput(int streamType)
+{  
+    if (streamType == DEFAULT) {
+        streamType = MUSIC;
+    }
+    if (gA2dpEnabled && routedToA2dpOutput(streamType)) {
+        return AUDIO_OUTPUT_A2DP;
+    } else {
+        return AUDIO_OUTPUT_HARDWARE;
+    }
+}
+
+bool AudioSystem::routedToA2dpOutput(int streamType) {
+    switch(streamType) {
+    case MUSIC:
+    case VOICE_CALL:
+    case BLUETOOTH_SCO:
+    case SYSTEM:
+        return true;
+    default:
+        return false;
+    }
+}
+
+
+
 }; // namespace android
 
diff --git a/media/libmedia/AudioTrack.cpp b/media/libmedia/AudioTrack.cpp
index 63b2012..1ffad46 100644
--- a/media/libmedia/AudioTrack.cpp
+++ b/media/libmedia/AudioTrack.cpp
@@ -128,22 +128,21 @@
        return NO_INIT;
     }
     int afSampleRate;
-    if (AudioSystem::getOutputSamplingRate(&afSampleRate) != NO_ERROR) {
+    if (AudioSystem::getOutputSamplingRate(&afSampleRate, streamType) != NO_ERROR) {
         return NO_INIT;
     }
     int afFrameCount;
-    if (AudioSystem::getOutputFrameCount(&afFrameCount) != NO_ERROR) {
+    if (AudioSystem::getOutputFrameCount(&afFrameCount, streamType) != NO_ERROR) {
         return NO_INIT;
     }
     uint32_t afLatency;
-    if (AudioSystem::getOutputLatency(&afLatency) != NO_ERROR) {
+    if (AudioSystem::getOutputLatency(&afLatency, streamType) != NO_ERROR) {
         return NO_INIT;
     }
 
-
     // handle default values first.
-    if (streamType == DEFAULT) {
-        streamType = MUSIC;
+    if (streamType == AudioSystem::DEFAULT) {
+        streamType = AudioSystem::MUSIC;
     }
     if (sampleRate == 0) {
         sampleRate = afSampleRate;
@@ -260,7 +259,7 @@
     mMarkerPosition = 0;
     mNewPosition = 0;
     mUpdatePeriod = 0;
-    
+
     return NO_ERROR;
 }
 
@@ -434,7 +433,7 @@
 {
     int afSamplingRate;
 
-    if (AudioSystem::getOutputSamplingRate(&afSamplingRate) != NO_ERROR) {
+    if (AudioSystem::getOutputSamplingRate(&afSamplingRate, mStreamType) != NO_ERROR) {
         return;
     }
     // Resampler implementation limits input sampling rate to 2 x output sampling rate.
diff --git a/media/libmedia/IAudioFlinger.cpp b/media/libmedia/IAudioFlinger.cpp
index 4215820..5cbb25c 100644
--- a/media/libmedia/IAudioFlinger.cpp
+++ b/media/libmedia/IAudioFlinger.cpp
@@ -53,7 +53,8 @@
     SET_PARAMETER,
     REGISTER_CLIENT,
     GET_INPUTBUFFERSIZE,
-    WAKE_UP
+    WAKE_UP,
+    IS_A2DP_ENABLED
 };
 
 class BpAudioFlinger : public BpInterface<IAudioFlinger>
@@ -123,42 +124,47 @@
         return interface_cast<IAudioRecord>(reply.readStrongBinder());
     }
 
-    virtual uint32_t sampleRate() const
+    virtual uint32_t sampleRate(int output) const
     {
         Parcel data, reply;
         data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor());
+        data.writeInt32(output);
         remote()->transact(SAMPLE_RATE, data, &reply);
         return reply.readInt32();
     }
 
-    virtual int channelCount() const
+    virtual int channelCount(int output) const
     {
         Parcel data, reply;
         data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor());
+        data.writeInt32(output);
         remote()->transact(CHANNEL_COUNT, data, &reply);
         return reply.readInt32();
     }
 
-    virtual int format() const
+    virtual int format(int output) const
     {
         Parcel data, reply;
         data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor());
+        data.writeInt32(output);
         remote()->transact(FORMAT, data, &reply);
         return reply.readInt32();
     }
 
-    virtual size_t frameCount() const
+    virtual size_t frameCount(int output) const
     {
         Parcel data, reply;
         data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor());
+        data.writeInt32(output);
         remote()->transact(FRAME_COUNT, data, &reply);
         return reply.readInt32();
     }
 
-    virtual uint32_t latency() const
+    virtual uint32_t latency(int output) const
     {
         Parcel data, reply;
         data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor());
+        data.writeInt32(output);
         remote()->transact(LATENCY, data, &reply);
         return reply.readInt32();
     }
@@ -333,6 +339,14 @@
         remote()->transact(WAKE_UP, data, &reply);
         return;
     }
+
+    virtual bool isA2dpEnabled() const
+    {
+        Parcel data, reply;
+        data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor());
+        remote()->transact(IS_A2DP_ENABLED, data, &reply);
+        return (bool)reply.readInt32();
+    }
 };
 
 IMPLEMENT_META_INTERFACE(AudioFlinger, "android.media.IAudioFlinger");
@@ -385,27 +399,32 @@
         } break;
         case SAMPLE_RATE: {
             CHECK_INTERFACE(IAudioFlinger, data, reply);
-            reply->writeInt32( sampleRate() );
+            int output = data.readInt32();
+            reply->writeInt32( sampleRate(output) );
             return NO_ERROR;
         } break;
         case CHANNEL_COUNT: {
             CHECK_INTERFACE(IAudioFlinger, data, reply);
-            reply->writeInt32( channelCount() );
+            int output = data.readInt32();
+            reply->writeInt32( channelCount(output) );
             return NO_ERROR;
         } break;
         case FORMAT: {
             CHECK_INTERFACE(IAudioFlinger, data, reply);
-            reply->writeInt32( format() );
+            int output = data.readInt32();
+            reply->writeInt32( format(output) );
             return NO_ERROR;
         } break;
         case FRAME_COUNT: {
             CHECK_INTERFACE(IAudioFlinger, data, reply);
-            reply->writeInt32( frameCount() );
+            int output = data.readInt32();
+            reply->writeInt32( frameCount(output) );
             return NO_ERROR;
         } break;
         case LATENCY: {
             CHECK_INTERFACE(IAudioFlinger, data, reply);
-            reply->writeInt32( latency() );
+            int output = data.readInt32();
+            reply->writeInt32( latency(output) );
             return NO_ERROR;
         } break;
          case SET_MASTER_VOLUME: {
@@ -519,7 +538,11 @@
             wakeUp();
             return NO_ERROR;
         } break;
-
+        case IS_A2DP_ENABLED: {
+            CHECK_INTERFACE(IAudioFlinger, data, reply);
+            reply->writeInt32( (int)isA2dpEnabled() );
+            return NO_ERROR;
+        } break;
         default:
             return BBinder::onTransact(code, data, reply, flags);
     }
diff --git a/media/libmedia/IAudioFlingerClient.cpp b/media/libmedia/IAudioFlingerClient.cpp
index d956266..5feb11f 100644
--- a/media/libmedia/IAudioFlingerClient.cpp
+++ b/media/libmedia/IAudioFlingerClient.cpp
@@ -38,13 +38,11 @@
     {
     }
 
-    void audioOutputChanged(uint32_t frameCount, uint32_t samplingRate, uint32_t latency)
+    void a2dpEnabledChanged(bool enabled)
     {
         Parcel data, reply;
         data.writeInterfaceToken(IAudioFlingerClient::getInterfaceDescriptor());
-        data.writeInt32(frameCount);
-        data.writeInt32(samplingRate);
-        data.writeInt32(latency);
+        data.writeInt32((int)enabled);
         remote()->transact(AUDIO_OUTPUT_CHANGED, data, &reply);
     }
 };
@@ -65,10 +63,8 @@
     switch(code) {
         case AUDIO_OUTPUT_CHANGED: {
             CHECK_INTERFACE(IAudioFlingerClient, data, reply);
-            uint32_t frameCount = data.readInt32();
-            uint32_t samplingRate = data.readInt32();
-            uint32_t latency = data.readInt32();
-            audioOutputChanged(frameCount, samplingRate, latency);
+            bool enabled = (bool)data.readInt32();
+            a2dpEnabledChanged(enabled);
             return NO_ERROR;
         } break;
         default:
diff --git a/media/libmedia/IMediaRecorder.cpp b/media/libmedia/IMediaRecorder.cpp
index 1f6d599..507d03e 100644
--- a/media/libmedia/IMediaRecorder.cpp
+++ b/media/libmedia/IMediaRecorder.cpp
@@ -39,7 +39,8 @@
     SET_OUTPUT_FORMAT,
     SET_VIDEO_ENCODER,
     SET_AUDIO_ENCODER,
-    SET_OUTPUT_FILE,
+    SET_OUTPUT_FILE_PATH,
+    SET_OUTPUT_FILE_FD,
     SET_VIDEO_SIZE,
     SET_VIDEO_FRAMERATE,
     SET_PREVIEW_SURFACE,
@@ -139,7 +140,18 @@
         Parcel data, reply;
         data.writeInterfaceToken(IMediaRecorder::getInterfaceDescriptor());
         data.writeCString(path);
-        remote()->transact(SET_OUTPUT_FILE, data, &reply);
+        remote()->transact(SET_OUTPUT_FILE_PATH, data, &reply);
+        return reply.readInt32();
+    }
+
+    status_t setOutputFile(int fd, int64_t offset, int64_t length) {
+        LOGV("setOutputFile(%d, %lld, %lld)", fd, offset, length);
+        Parcel data, reply;
+        data.writeInterfaceToken(IMediaRecorder::getInterfaceDescriptor());
+        data.writeFileDescriptor(fd);
+        data.writeInt64(offset);
+        data.writeInt64(length);
+        remote()->transact(SET_OUTPUT_FILE_FD, data, &reply);
         return reply.readInt32();
     }
 
@@ -330,13 +342,22 @@
             return NO_ERROR;
 
         } break;
-        case SET_OUTPUT_FILE: {
-            LOGV("SET_OUTPUT_FILE");
+        case SET_OUTPUT_FILE_PATH: {
+            LOGV("SET_OUTPUT_FILE_PATH");
             CHECK_INTERFACE(IMediaRecorder, data, reply);
             const char* path = data.readCString();
             reply->writeInt32(setOutputFile(path));
             return NO_ERROR;
         } break;
+        case SET_OUTPUT_FILE_FD: {
+            LOGV("SET_OUTPUT_FILE_FD");
+            CHECK_INTERFACE(IMediaRecorder, data, reply);
+            int fd = dup(data.readFileDescriptor());
+            int64_t offset = data.readInt64();
+            int64_t length = data.readInt64();
+            reply->writeInt32(setOutputFile(fd, offset, length));
+            return NO_ERROR;
+        } break;
         case SET_VIDEO_SIZE: {
             LOGV("SET_VIDEO_SIZE");
             CHECK_INTERFACE(IMediaRecorder, data, reply);
diff --git a/media/libmedia/JetPlayer.cpp b/media/libmedia/JetPlayer.cpp
index ead24d4..9bd75c2 100644
--- a/media/libmedia/JetPlayer.cpp
+++ b/media/libmedia/JetPlayer.cpp
@@ -96,7 +96,7 @@
 
     // create the output AudioTrack
     mAudioTrack = new AudioTrack();
-    mAudioTrack->set(AudioTrack::MUSIC,  //TODO parametrize this
+    mAudioTrack->set(AudioSystem::MUSIC,  //TODO parametrize this
             pLibConfig->sampleRate,
             1, // format = PCM 16bits per sample,
             pLibConfig->numChannels,
diff --git a/media/libmedia/ToneGenerator.cpp b/media/libmedia/ToneGenerator.cpp
index fa36460..7fafc56 100644
--- a/media/libmedia/ToneGenerator.cpp
+++ b/media/libmedia/ToneGenerator.cpp
@@ -93,7 +93,7 @@
 
     mState = TONE_IDLE;
 
-    if (AudioSystem::getOutputSamplingRate(&mSamplingRate) != NO_ERROR) {
+    if (AudioSystem::getOutputSamplingRate(&mSamplingRate, streamType) != NO_ERROR) {
         LOGE("Unable to marshal AudioFlinger");
         return;
     }
@@ -182,7 +182,7 @@
             mLock.lock();
             if (mState == TONE_STARTING) {
                 if (mWaitCbkCond.waitRelative(mLock, seconds(1)) != NO_ERROR) {
-                    LOGE("--- timed out");
+                    LOGE("--- Immediate start timed out");
                     mState = TONE_IDLE;
                 }
             }
@@ -200,7 +200,7 @@
             }
             LOGV("cond received");
         } else {
-            LOGE("--- timed out");
+            LOGE("--- Delayed start timed out");
             mState = TONE_IDLE;
         }
     }
@@ -235,7 +235,7 @@
         if (lStatus == NO_ERROR) {
             LOGV("track stop complete, time %d", (unsigned int)(systemTime()/1000000));
         } else {
-            LOGE("--- timed out");
+            LOGE("--- Stop timed out");
             mState = TONE_IDLE;
             mpAudioTrack->stop();
         }
diff --git a/media/libmedia/mediaplayer.cpp b/media/libmedia/mediaplayer.cpp
index 31ff507..bd8579c 100644
--- a/media/libmedia/mediaplayer.cpp
+++ b/media/libmedia/mediaplayer.cpp
@@ -82,7 +82,7 @@
     mListener = NULL;
     mCookie = NULL;
     mDuration = -1;
-    mStreamType = AudioTrack::MUSIC;
+    mStreamType = AudioSystem::MUSIC;
     mCurrentPosition = -1;
     mSeekPosition = -1;
     mCurrentState = MEDIA_PLAYER_IDLE;
diff --git a/media/libmedia/mediarecorder.cpp b/media/libmedia/mediarecorder.cpp
index 6ee4c0d..4ab26ac 100644
--- a/media/libmedia/mediarecorder.cpp
+++ b/media/libmedia/mediarecorder.cpp
@@ -248,7 +248,33 @@
 
     status_t ret = mMediaRecorder->setOutputFile(path);
     if (OK != ret) {
-        LOGV("setAudioEncoder failed: %d", ret);
+        LOGV("setOutputFile failed: %d", ret);
+        mCurrentState = MEDIA_RECORDER_ERROR;
+        return UNKNOWN_ERROR;
+    }
+    mIsOutputFileSet = true;
+    return ret;
+}
+
+status_t MediaRecorder::setOutputFile(int fd, int64_t offset, int64_t length)
+{
+    LOGV("setOutputFile(%d, %lld, %lld)", fd, offset, length);
+    if(mMediaRecorder == NULL) {
+        LOGE("media recorder is not initialized yet");
+        return INVALID_OPERATION;
+    }
+    if (mIsOutputFileSet) {
+        LOGE("output file has already been set");
+        return INVALID_OPERATION;
+    }
+    if (!(mCurrentState & MEDIA_RECORDER_DATASOURCE_CONFIGURED)) {
+        LOGE("setOutputFile called in an invalid state(%d)", mCurrentState);
+        return INVALID_OPERATION;
+    }
+
+    status_t ret = mMediaRecorder->setOutputFile(fd, offset, length);
+    if (OK != ret) {
+        LOGV("setOutputFile failed: %d", ret);
         mCurrentState = MEDIA_RECORDER_ERROR;
         return UNKNOWN_ERROR;
     }
@@ -306,7 +332,7 @@
         return INVALID_OPERATION;
     }
     if (!(mCurrentState & MEDIA_RECORDER_DATASOURCE_CONFIGURED)) {
-        LOGE("setVideoFrameRate called in an invalid state: %d", mCurrentState);
+        LOGE("prepare called in an invalid state: %d", mCurrentState);
         return INVALID_OPERATION;
     }
 
@@ -328,7 +354,7 @@
         return INVALID_OPERATION;
     }
     if (mCurrentState & MEDIA_RECORDER_ERROR) {
-        LOGE("setVideoFrameRate called in an invalid state: %d", mCurrentState);
+        LOGE("getMaxAmplitude called in an invalid state: %d", mCurrentState);
         return INVALID_OPERATION;
     }
 
diff --git a/media/libmediaplayerservice/MediaPlayerService.cpp b/media/libmediaplayerservice/MediaPlayerService.cpp
index 9e366e2..97e3536 100644
--- a/media/libmediaplayerservice/MediaPlayerService.cpp
+++ b/media/libmediaplayerservice/MediaPlayerService.cpp
@@ -818,7 +818,7 @@
 MediaPlayerService::AudioOutput::AudioOutput()
 {
     mTrack = 0;
-    mStreamType = AudioTrack::MUSIC;
+    mStreamType = AudioSystem::MUSIC;
     mLeftVolume = 1.0;
     mRightVolume = 1.0;
     mLatency = 0;
@@ -900,15 +900,15 @@
     int afFrameCount;
     int frameCount;
 
-    if (AudioSystem::getOutputFrameCount(&afFrameCount) != NO_ERROR) {
+    if (AudioSystem::getOutputFrameCount(&afFrameCount, mStreamType) != NO_ERROR) {
         return NO_INIT;
     }
-    if (AudioSystem::getOutputSamplingRate(&afSampleRate) != NO_ERROR) {
+    if (AudioSystem::getOutputSamplingRate(&afSampleRate, mStreamType) != NO_ERROR) {
         return NO_INIT;
     }
 
-    frameCount = (sampleRate*afFrameCount)/afSampleRate;
-    AudioTrack *t = new AudioTrack(mStreamType, sampleRate, format, channelCount, frameCount*bufferCount);
+    frameCount = (sampleRate*afFrameCount*bufferCount)/afSampleRate;
+    AudioTrack *t = new AudioTrack(mStreamType, sampleRate, format, channelCount, frameCount);
     if ((t == 0) || (t->initCheck() != NO_ERROR)) {
         LOGE("Unable to create audio track");
         delete t;
diff --git a/media/libmediaplayerservice/MediaRecorderClient.cpp b/media/libmediaplayerservice/MediaRecorderClient.cpp
index f326a0e..e8ba17f 100644
--- a/media/libmediaplayerservice/MediaRecorderClient.cpp
+++ b/media/libmediaplayerservice/MediaRecorderClient.cpp
@@ -121,6 +121,17 @@
     return mRecorder->setOutputFile(path);
 }
 
+status_t MediaRecorderClient::setOutputFile(int fd, int64_t offset, int64_t length)
+{
+    LOGV("setOutputFile(%d, %lld, %lld)", fd, offset, length);
+    Mutex::Autolock lock(mLock);
+    if (mRecorder == NULL) {
+        LOGE("recorder is not initialized");
+        return NO_INIT;
+    }
+    return mRecorder->setOutputFile(fd, offset, length);
+}
+
 status_t MediaRecorderClient::setVideoSize(int width, int height)
 {
     LOGV("setVideoSize(%dx%d)", width, height);
diff --git a/media/libmediaplayerservice/MediaRecorderClient.h b/media/libmediaplayerservice/MediaRecorderClient.h
index 3158017..2b80c10 100644
--- a/media/libmediaplayerservice/MediaRecorderClient.h
+++ b/media/libmediaplayerservice/MediaRecorderClient.h
@@ -36,6 +36,7 @@
     virtual     status_t        setVideoEncoder(int ve);
     virtual     status_t        setAudioEncoder(int ae);
     virtual     status_t        setOutputFile(const char* path);
+    virtual     status_t        setOutputFile(int fd, int64_t offset, int64_t length);
     virtual     status_t        setVideoSize(int width, int height);
     virtual     status_t        setVideoFrameRate(int frames_per_second);
     virtual     status_t        prepare();
diff --git a/media/libmediaplayerservice/MidiFile.cpp b/media/libmediaplayerservice/MidiFile.cpp
index 7ce2fab..d03caa5 100644
--- a/media/libmediaplayerservice/MidiFile.cpp
+++ b/media/libmediaplayerservice/MidiFile.cpp
@@ -58,7 +58,7 @@
 MidiFile::MidiFile() :
     mEasData(NULL), mEasHandle(NULL), mAudioBuffer(NULL),
     mPlayTime(-1), mDuration(-1), mState(EAS_STATE_ERROR),
-    mStreamType(AudioTrack::MUSIC), mLoop(false), mExit(false),
+    mStreamType(AudioSystem::MUSIC), mLoop(false), mExit(false),
     mPaused(false), mRender(false), mTid(-1)
 {
     LOGV("constructor");
diff --git a/media/libmediaplayerservice/VorbisPlayer.cpp b/media/libmediaplayerservice/VorbisPlayer.cpp
index 009d628..0ad335f 100644
--- a/media/libmediaplayerservice/VorbisPlayer.cpp
+++ b/media/libmediaplayerservice/VorbisPlayer.cpp
@@ -55,7 +55,7 @@
 
 VorbisPlayer::VorbisPlayer() :
     mAudioBuffer(NULL), mPlayTime(-1), mDuration(-1), mState(STATE_ERROR),
-    mStreamType(AudioTrack::MUSIC), mLoop(false), mAndroidLoop(false),
+    mStreamType(AudioSystem::MUSIC), mLoop(false), mAndroidLoop(false),
     mExit(false), mPaused(false), mRender(false), mRenderTid(-1)
 {
     LOGV("constructor\n");
diff --git a/preloaded-classes b/preloaded-classes
index 1ace628..61390db 100644
--- a/preloaded-classes
+++ b/preloaded-classes
@@ -340,7 +340,7 @@
 android.view.VelocityTracker
 android.view.View
 android.view.View$AttachInfo
-android.view.View$AttachInfo$SoundEffectPlayer
+android.view.View$AttachInfo$Callbacks
 android.view.View$BaseSavedState$1
 android.view.View$MeasureSpec
 android.view.View$ScrollabilityCache
diff --git a/services/java/com/android/server/GadgetService.java b/services/java/com/android/server/GadgetService.java
index 5ef0fb9..ddf3afe 100644
--- a/services/java/com/android/server/GadgetService.java
+++ b/services/java/com/android/server/GadgetService.java
@@ -31,9 +31,10 @@
 import android.content.res.TypedArray;
 import android.content.res.XmlResourceParser;
 import android.gadget.GadgetManager;
-import android.gadget.GadgetInfo;
+import android.gadget.GadgetProviderInfo;
 import android.net.Uri;
 import android.os.Binder;
+import android.os.Bundle;
 import android.os.RemoteException;
 import android.os.SystemClock;
 import android.util.AttributeSet;
@@ -78,7 +79,7 @@
 
     static class Provider {
         int uid;
-        GadgetInfo info;
+        GadgetProviderInfo info;
         ArrayList<GadgetId> instances = new ArrayList();
         PendingIntent broadcast;
         
@@ -106,7 +107,7 @@
     PackageManager mPackageManager;
     AlarmManager mAlarmManager;
     ArrayList<Provider> mInstalledProviders = new ArrayList();
-    int mNextGadgetId = 1;
+    int mNextGadgetId = GadgetManager.INVALID_GADGET_ID + 1;
     ArrayList<GadgetId> mGadgetIds = new ArrayList();
     ArrayList<Host> mHosts = new ArrayList();
 
@@ -128,7 +129,6 @@
         // update the provider list.
         IntentFilter filter = new IntentFilter();
         filter.addAction(Intent.ACTION_PACKAGE_ADDED);
-        filter.addAction(Intent.ACTION_PACKAGE_CHANGED);
         filter.addAction(Intent.ACTION_PACKAGE_REMOVED);
         filter.addDataScheme("package");
         mContext.registerReceiver(mBroadcastReceiver, filter);
@@ -148,7 +148,7 @@
             int N = mInstalledProviders.size();
             pw.println("Providers: (size=" + N + ")");
             for (int i=0; i<N; i++) {
-                GadgetInfo info = mInstalledProviders.get(i).info;
+                GadgetProviderInfo info = mInstalledProviders.get(i).info;
                 pw.println("  [" + i + "] provder=" + info.provider
                         + " min=(" + info.minWidth + "x" + info.minHeight + ")"
                         + " updatePeriodMillis=" + info.updatePeriodMillis
@@ -265,7 +265,7 @@
         if (p != null) {
             p.instances.remove(id);
             // send the broacast saying that this gadgetId has been deleted
-            Intent intent = new Intent(GadgetManager.GADGET_DELETED_ACTION);
+            Intent intent = new Intent(GadgetManager.ACTION_GADGET_DELETED);
             intent.setComponent(p.info.provider);
             intent.putExtra(GadgetManager.EXTRA_GADGET_ID, id.gadgetId);
             mContext.sendBroadcast(intent);
@@ -274,7 +274,7 @@
                 cancelBroadcasts(p);
 
                 // send the broacast saying that the provider is not in use any more
-                intent = new Intent(GadgetManager.GADGET_DISABLED_ACTION);
+                intent = new Intent(GadgetManager.ACTION_GADGET_DISABLED);
                 intent.setComponent(p.info.provider);
                 mContext.sendBroadcast(intent);
             }
@@ -331,7 +331,7 @@
         }
     }
 
-    public GadgetInfo getGadgetInfo(int gadgetId) {
+    public GadgetProviderInfo getGadgetInfo(int gadgetId) {
         synchronized (mGadgetIds) {
             GadgetId id = lookupGadgetIdLocked(gadgetId);
             if (id != null) {
@@ -351,10 +351,10 @@
         }
     }
 
-    public List<GadgetInfo> getInstalledProviders() {
+    public List<GadgetProviderInfo> getInstalledProviders() {
         synchronized (mGadgetIds) {
             final int N = mInstalledProviders.size();
-            ArrayList<GadgetInfo> result = new ArrayList(N);
+            ArrayList<GadgetProviderInfo> result = new ArrayList(N);
             for (int i=0; i<N; i++) {
                 result.add(mInstalledProviders.get(i).info);
             }
@@ -364,7 +364,7 @@
 
     public void updateGadgetIds(int[] gadgetIds, RemoteViews views) {
         if (gadgetIds == null) {
-            throw new IllegalArgumentException("bad gadgetIds");
+            return;
         }
         if (gadgetIds.length == 0) {
             return;
@@ -408,7 +408,7 @@
                     // the lock is held, but this is a oneway call
                     id.host.callbacks.updateGadget(id.gadgetId, views);
                 } catch (RemoteException e) {
-                    // It failed, remove the callback. No need to prune because
+                    // It failed; remove the callback. No need to prune because
                     // we know that this host is still referenced by this instance.
                     id.host.callbacks = null;
                 }
@@ -524,10 +524,7 @@
     void getGadgetList() {
         PackageManager pm = mPackageManager;
 
-        // TODO: We have these as different actions.  I wonder if it makes more sense to
-        // have like a GADGET_ACTION, and then subcommands.  It's kind of arbitrary that
-        // we look for GADGET_UPDATE_ACTION and not any of the other gadget actions.
-        Intent intent = new Intent(GadgetManager.GADGET_UPDATE_ACTION);
+        Intent intent = new Intent(GadgetManager.ACTION_GADGET_UPDATE);
         List<ResolveInfo> broadcastReceivers = pm.queryBroadcastReceivers(intent,
                 PackageManager.GET_META_DATA);
 
@@ -538,11 +535,14 @@
         }
     }
 
-    void addProviderLocked(ResolveInfo ri) {
-        Provider p = parseGadgetInfoXml(new ComponentName(ri.activityInfo.packageName,
+    boolean addProviderLocked(ResolveInfo ri) {
+        Provider p = parseProviderInfoXml(new ComponentName(ri.activityInfo.packageName,
                     ri.activityInfo.name), ri);
         if (p != null) {
             mInstalledProviders.add(p);
+            return true;
+        } else {
+            return false;
         }
     }
 
@@ -568,16 +568,18 @@
     }
 
     void sendEnableIntentLocked(Provider p) {
-        Intent intent = new Intent(GadgetManager.GADGET_ENABLED_ACTION);
+        Intent intent = new Intent(GadgetManager.ACTION_GADGET_ENABLED);
         intent.setComponent(p.info.provider);
         mContext.sendBroadcast(intent);
     }
 
     void sendUpdateIntentLocked(Provider p, int[] gadgetIds) {
-        Intent intent = new Intent(GadgetManager.GADGET_UPDATE_ACTION);
-        intent.putExtra(GadgetManager.EXTRA_GADGET_IDS, gadgetIds);
-        intent.setComponent(p.info.provider);
-        mContext.sendBroadcast(intent);
+        if (gadgetIds != null && gadgetIds.length > 0) {
+            Intent intent = new Intent(GadgetManager.ACTION_GADGET_UPDATE);
+            intent.putExtra(GadgetManager.EXTRA_GADGET_IDS, gadgetIds);
+            intent.setComponent(p.info.provider);
+            mContext.sendBroadcast(intent);
+        }
     }
 
     void registerForBroadcastsLocked(Provider p, int[] gadgetIds) {
@@ -587,7 +589,7 @@
             // PendingIntent.getBroadcast will update the extras.
             boolean alreadyRegistered = p.broadcast != null;
             int instancesSize = p.instances.size();
-            Intent intent = new Intent(GadgetManager.GADGET_UPDATE_ACTION);
+            Intent intent = new Intent(GadgetManager.ACTION_GADGET_UPDATE);
             intent.putExtra(GadgetManager.EXTRA_GADGET_IDS, gadgetIds);
             intent.setComponent(p.info.provider);
             long token = Binder.clearCallingIdentity();
@@ -614,16 +616,16 @@
         return gadgetIds;
     }
 
-    private Provider parseGadgetInfoXml(ComponentName component, ResolveInfo ri) {
+    private Provider parseProviderInfoXml(ComponentName component, ResolveInfo ri) {
         Provider p = null;
 
         ActivityInfo activityInfo = ri.activityInfo;
         XmlResourceParser parser = null;
         try {
             parser = activityInfo.loadXmlMetaData(mPackageManager,
-                    GadgetManager.GADGET_PROVIDER_META_DATA);
+                    GadgetManager.META_DATA_GADGET_PROVIDER);
             if (parser == null) {
-                Log.w(TAG, "No " + GadgetManager.GADGET_PROVIDER_META_DATA + " meta-data for "
+                Log.w(TAG, "No " + GadgetManager.META_DATA_GADGET_PROVIDER + " meta-data for "
                         + "gadget provider '" + component + '\'');
                 return null;
             }
@@ -644,7 +646,7 @@
             }
 
             p = new Provider();
-            GadgetInfo info = p.info = new GadgetInfo();
+            GadgetProviderInfo info = p.info = new GadgetProviderInfo();
 
             info.provider = component;
             p.uid = activityInfo.applicationInfo.uid;
@@ -672,6 +674,7 @@
             // of what a client process passes to us should not be fatal for the
             // system process.
             Log.w(TAG, "XML parsing failed for gadget provider '" + component + '\'', e);
+            return null;
         } finally {
             if (parser != null) parser.close();
         }
@@ -979,20 +982,26 @@
                 
                 if (Intent.ACTION_PACKAGE_ADDED.equals(action)) {
                     synchronized (mGadgetIds) {
-                        addProvidersForPackageLocked(pkgName);
-                        saveStateLocked();
-                    }
-                }
-                else if (Intent.ACTION_PACKAGE_CHANGED.equals(action)) {
-                    synchronized (mGadgetIds) {
-                        updateProvidersForPackageLocked(pkgName);
+                        Bundle extras = intent.getExtras();
+                        if (extras != null && extras.getBoolean(Intent.EXTRA_REPLACING, false)) {
+                            // The package was just upgraded
+                            updateProvidersForPackageLocked(pkgName);
+                        } else {
+                            // The package was just added
+                            addProvidersForPackageLocked(pkgName);
+                        }
                         saveStateLocked();
                     }
                 }
                 else if (Intent.ACTION_PACKAGE_REMOVED.equals(action)) {
-                    synchronized (mGadgetIds) {
-                        removeProvidersForPackageLocked(pkgName);
-                        saveStateLocked();
+                    Bundle extras = intent.getExtras();
+                    if (extras != null && extras.getBoolean(Intent.EXTRA_REPLACING, false)) {
+                        // The package is being updated.  We'll receive a PACKAGE_ADDED shortly.
+                    } else {
+                        synchronized (mGadgetIds) {
+                            removeProvidersForPackageLocked(pkgName);
+                            saveStateLocked();
+                        }
                     }
                 }
             }
@@ -1002,7 +1011,7 @@
     // TODO: If there's a better way of matching an intent filter against the
     // packages for a given package, use that.
     void addProvidersForPackageLocked(String pkgName) {
-        Intent intent = new Intent(GadgetManager.GADGET_UPDATE_ACTION);
+        Intent intent = new Intent(GadgetManager.ACTION_GADGET_UPDATE);
         List<ResolveInfo> broadcastReceivers = mPackageManager.queryBroadcastReceivers(intent,
                 PackageManager.GET_META_DATA);
 
@@ -1021,7 +1030,7 @@
     // packages for a given package, use that.
     void updateProvidersForPackageLocked(String pkgName) {
         HashSet<String> keep = new HashSet();
-        Intent intent = new Intent(GadgetManager.GADGET_UPDATE_ACTION);
+        Intent intent = new Intent(GadgetManager.ACTION_GADGET_UPDATE);
         List<ResolveInfo> broadcastReceivers = mPackageManager.queryBroadcastReceivers(intent,
                 PackageManager.GET_META_DATA);
 
@@ -1031,17 +1040,53 @@
             ResolveInfo ri = broadcastReceivers.get(i);
             ActivityInfo ai = ri.activityInfo;
             if (pkgName.equals(ai.packageName)) {
-                Provider p = lookupProviderLocked(new ComponentName(ai.packageName, ai.name));
+                ComponentName component = new ComponentName(ai.packageName, ai.name);
+                Provider p = lookupProviderLocked(component);
                 if (p == null) {
-                    addProviderLocked(ri);
+                    if (addProviderLocked(ri)) {
+                        keep.add(ai.name);
+                    }
+                } else {
+                    Provider parsed = parseProviderInfoXml(component, ri);
+                    if (parsed != null) {
+                        keep.add(ai.name);
+                        // Use the new GadgetProviderInfo.
+                        GadgetProviderInfo oldInfo = p.info;
+                        p.info = parsed.info;
+                        // If it's enabled
+                        final int M = p.instances.size();
+                        if (M > 0) {
+                            int[] gadgetIds = getGadgetIds(p);
+                            // Reschedule for the new updatePeriodMillis (don't worry about handling
+                            // it specially if updatePeriodMillis didn't change because we just sent
+                            // an update, and the next one will be updatePeriodMillis from now).
+                            cancelBroadcasts(p);
+                            registerForBroadcastsLocked(p, gadgetIds);
+                            // If it's currently showing, call back with the new GadgetProviderInfo.
+                            for (int j=0; j<M; j++) {
+                                GadgetId id = p.instances.get(j);
+                                if (id.host != null && id.host.callbacks != null) {
+                                    try {
+                                        id.host.callbacks.providerChanged(id.gadgetId, p.info);
+                                    } catch (RemoteException ex) {
+                                        // It failed; remove the callback. No need to prune because
+                                        // we know that this host is still referenced by this
+                                        // instance.
+                                        id.host.callbacks = null;
+                                    }
+                                }
+                            }
+                            // Now that we've told the host, push out an update.
+                            sendUpdateIntentLocked(p, gadgetIds);
+                        }
+                    }
                 }
-                keep.add(ai.name);
             }
         }
 
         // prune the ones we don't want to keep
         N = mInstalledProviders.size();
-        for (int i=0; i<N; i++) {
+        for (int i=N-1; i>=0; i--) {
             Provider p = mInstalledProviders.get(i);
             if (pkgName.equals(p.info.provider.getPackageName())
                     && !keep.contains(p.info.provider.getClassName())) {
@@ -1052,7 +1097,7 @@
 
     void removeProvidersForPackageLocked(String pkgName) {
         int N = mInstalledProviders.size();
-        for (int i=0; i<N; i++) {
+        for (int i=N-1; i>=0; i--) {
             Provider p = mInstalledProviders.get(i);
             if (pkgName.equals(p.info.provider.getPackageName())) {
                 removeProviderLocked(i, p);
@@ -1064,7 +1109,7 @@
         // By now, we have removed any gadgets that were in any hosts here,
         // so we don't need to worry about sending DISABLE broadcasts to them.
         N = mHosts.size();
-        for (int i=0; i<N; i++) {
+        for (int i=N-1; i>=0; i--) {
             Host host = mHosts.get(i);
             if (pkgName.equals(host.packageName)) {
                 deleteHostLocked(host);
diff --git a/services/java/com/android/server/InputMethodManagerService.java b/services/java/com/android/server/InputMethodManagerService.java
index ee49365..7588129 100644
--- a/services/java/com/android/server/InputMethodManagerService.java
+++ b/services/java/com/android/server/InputMethodManagerService.java
@@ -55,8 +55,10 @@
 import android.os.Parcel;
 import android.os.RemoteException;
 import android.os.ServiceManager;
+import android.os.SystemClock;
 import android.provider.Settings;
 import android.text.TextUtils;
+import android.util.EventLog;
 import android.util.Log;
 import android.util.PrintWriterPrinter;
 import android.util.Printer;
@@ -98,6 +100,10 @@
     static final int MSG_UNBIND_METHOD = 3000;
     static final int MSG_BIND_METHOD = 3010;
     
+    static final long TIME_TO_RECONNECT = 10*1000;
+    
+    static final int LOG_IMF_FORCE_RECONNECT_IME = 32000;
+    
     final Context mContext;
     final Handler mHandler;
     final SettingsObserver mSettingsObserver;
@@ -248,6 +254,12 @@
     IInputMethod mCurMethod;
     
     /**
+     * Time that we last initiated a bind to the input method, to determine
+     * if we should try to disconnect and reconnect to it.
+     */
+    long mLastBindTime;
+    
+    /**
      * Have we called mCurMethod.bindInput()?
      */
     boolean mBoundToMethod;
@@ -486,7 +498,6 @@
     }
 
     public void systemReady() {
-        
     }
     
     public List<InputMethodInfo> getInputMethodList() {
@@ -571,7 +582,7 @@
         }
     }
     
-    private int getShowFlags() {
+    private int getImeShowFlags() {
         int flags = 0;
         if (mShowForced) {
             flags |= InputMethod.SHOW_FORCED
@@ -582,6 +593,16 @@
         return flags;
     }
     
+    private int getAppShowFlags() {
+        int flags = 0;
+        if (mShowForced) {
+            flags |= InputMethodManager.SHOW_FORCED;
+        } else if (!mShowExplicitlyRequested) {
+            flags |= InputMethodManager.SHOW_IMPLICIT;
+        }
+        return flags;
+    }
+    
     InputBindResult attachNewInputLocked(boolean initial, boolean needResult) {
         if (!mBoundToMethod) {
             executeOrSendMessage(mCurMethod, mCaller.obtainMessageOO(
@@ -598,7 +619,7 @@
         }
         if (mShowRequested) {
             if (DEBUG) Log.v(TAG, "Attach new input asks to show input");
-            showCurrentInputLocked(getShowFlags());
+            showCurrentInputLocked(getAppShowFlags());
         }
         return needResult
                 ? new InputBindResult(session.session, mCurId, mCurSeq)
@@ -666,14 +687,31 @@
                 return attachNewInputLocked(initial, needResult);
             }
             if (mHaveConnection) {
-                if (mCurMethod != null && !cs.sessionRequested) {
-                    cs.sessionRequested = true;
-                    if (DEBUG) Log.v(TAG, "Creating new session for client " + cs);
-                    executeOrSendMessage(mCurMethod, mCaller.obtainMessageOO(
-                            MSG_CREATE_SESSION, mCurMethod,
-                            new MethodCallback(mCurMethod)));
+                if (mCurMethod != null) {
+                    if (!cs.sessionRequested) {
+                        cs.sessionRequested = true;
+                        if (DEBUG) Log.v(TAG, "Creating new session for client " + cs);
+                        executeOrSendMessage(mCurMethod, mCaller.obtainMessageOO(
+                                MSG_CREATE_SESSION, mCurMethod,
+                                new MethodCallback(mCurMethod)));
+                    }
+                    // Return to client, and we will get back with it when
+                    // we have had a session made for it.
+                    return new InputBindResult(null, mCurId, mCurSeq);
+                } else if (SystemClock.uptimeMillis()
+                        < (mLastBindTime+TIME_TO_RECONNECT)) {
+                    // In this case we have connected to the service, but
+                    // don't yet have its interface.  If it hasn't been too
+                    // long since we did the connection, we'll return to
+                    // the client and wait to get the service interface so
+                    // we can report back.  If it has been too long, we want
+                    // to fall through so we can try a disconnect/reconnect
+                    // to see if we can get back in touch with the service.
+                    return new InputBindResult(null, mCurId, mCurSeq);
+                } else {
+                    EventLog.writeEvent(LOG_IMF_FORCE_RECONNECT_IME, mCurMethodId,
+                            SystemClock.uptimeMillis()-mLastBindTime, 0);
                 }
-                return new InputBindResult(null, mCurId, mCurSeq);
             }
         }
         
@@ -682,6 +720,11 @@
             throw new IllegalArgumentException("Unknown id: " + mCurMethodId);
         }
         
+        if (mHaveConnection) {
+            mContext.unbindService(this);
+            mHaveConnection = false;
+        }
+        
         if (mCurToken != null) {
             try {
                 if (DEBUG) Log.v(TAG, "Removing window token: " + mCurToken);
@@ -691,16 +734,12 @@
             mCurToken = null;
         }
         
-        if (mHaveConnection) {
-            mContext.unbindService(this);
-            mHaveConnection = false;
-        }
-        
         clearCurMethod();
         
         mCurIntent = new Intent(InputMethod.SERVICE_INTERFACE);
         mCurIntent.setComponent(info.getComponent());
         if (mContext.bindService(mCurIntent, this, Context.BIND_AUTO_CREATE)) {
+            mLastBindTime = SystemClock.uptimeMillis();
             mHaveConnection = true;
             mCurId = info.getId();
             mCurToken = new Binder();
@@ -758,7 +797,8 @@
 
     void onSessionCreated(IInputMethod method, IInputMethodSession session) {
         synchronized (mMethodMap) {
-            if (mCurMethod == method) {
+            if (mCurMethod != null && method != null
+                    && mCurMethod.asBinder() == method.asBinder()) {
                 if (mCurClient != null) {
                     mCurClient.curSession = new SessionState(mCurClient,
                             method, session);
@@ -781,6 +821,7 @@
             }
             mCurMethod = null;
         }
+        mStatusBar.setIconVisibility(mInputMethodIcon, false);
     }
     
     public void onServiceDisconnected(ComponentName name) {
@@ -790,6 +831,9 @@
             if (mCurMethod != null && mCurIntent != null
                     && name.equals(mCurIntent.getComponent())) {
                 clearCurMethod();
+                // We consider this to be a new bind attempt, since the system
+                // should now try to restart the service for us.
+                mLastBindTime = SystemClock.uptimeMillis();
                 mShowRequested = mInputShown;
                 mInputShown = false;
                 if (mCurClient != null) {
@@ -800,23 +844,28 @@
         }
     }
 
-    public void updateStatusIcon(int iconId, String iconPackage) {
-        if (iconId == 0) {
-            Log.d(TAG, "hide the small icon for the input method");
-            mStatusBar.setIconVisibility(mInputMethodIcon, false);
-        } else {
-            Log.d(TAG, "show a small icon for the input method");
-
-            if (iconPackage != null
-                    && iconPackage
-                            .equals(InputMethodManager.BUILDIN_INPUTMETHOD_PACKAGE)) {
-                iconPackage = null;
+    public void updateStatusIcon(IBinder token, String packageName, int iconId) {
+        long ident = Binder.clearCallingIdentity();
+        try {
+            if (token == null || mCurToken != token) {
+                Log.w(TAG, "Ignoring setInputMethod of token: " + token);
+                return;
             }
-
-            mInputMethodData.iconId = iconId;
-            mInputMethodData.iconPackage = iconPackage;
-            mStatusBar.updateIcon(mInputMethodIcon, mInputMethodData, null);
-            mStatusBar.setIconVisibility(mInputMethodIcon, true);
+            
+            synchronized (mMethodMap) {
+                if (iconId == 0) {
+                    if (DEBUG) Log.d(TAG, "hide the small icon for the input method");
+                    mStatusBar.setIconVisibility(mInputMethodIcon, false);
+                } else if (packageName != null) {
+                    if (DEBUG) Log.d(TAG, "show a small icon for the input method");
+                    mInputMethodData.iconId = iconId;
+                    mInputMethodData.iconPackage = packageName;
+                    mStatusBar.updateIcon(mInputMethodIcon, mInputMethodData, null);
+                    mStatusBar.setIconVisibility(mInputMethodIcon, true);
+                }
+            }
+        } finally {
+            Binder.restoreCallingIdentity(ident);
         }
     }
 
@@ -860,23 +909,28 @@
     }
     
     public void showSoftInput(IInputMethodClient client, int flags) {
-        synchronized (mMethodMap) {
-            if (mCurClient == null || client == null
-                    || mCurClient.client.asBinder() != client.asBinder()) {
-                try {
-                    // We need to check if this is the current client with
-                    // focus in the window manager, to allow this call to
-                    // be made before input is started in it.
-                    if (!mIWindowManager.inputMethodClientHasFocus(client)) {
-                        Log.w(TAG, "Ignoring showSoftInput of: " + client);
-                        return;
+        long ident = Binder.clearCallingIdentity();
+        try {
+            synchronized (mMethodMap) {
+                if (mCurClient == null || client == null
+                        || mCurClient.client.asBinder() != client.asBinder()) {
+                    try {
+                        // We need to check if this is the current client with
+                        // focus in the window manager, to allow this call to
+                        // be made before input is started in it.
+                        if (!mIWindowManager.inputMethodClientHasFocus(client)) {
+                            Log.w(TAG, "Ignoring showSoftInput of: " + client);
+                            return;
+                        }
+                    } catch (RemoteException e) {
                     }
-                } catch (RemoteException e) {
                 }
+    
+                if (DEBUG) Log.v(TAG, "Client requesting input be shown");
+                showCurrentInputLocked(flags);
             }
-
-            if (DEBUG) Log.v(TAG, "Client requesting input be shown");
-            showCurrentInputLocked(flags);
+        } finally {
+            Binder.restoreCallingIdentity(ident);
         }
     }
     
@@ -891,29 +945,44 @@
         }
         if (mCurMethod != null) {
             executeOrSendMessage(mCurMethod, mCaller.obtainMessageIO(
-                    MSG_SHOW_SOFT_INPUT, getShowFlags(), mCurMethod));
+                    MSG_SHOW_SOFT_INPUT, getImeShowFlags(), mCurMethod));
             mInputShown = true;
+        } else if (mHaveConnection && SystemClock.uptimeMillis()
+                < (mLastBindTime+TIME_TO_RECONNECT)) {
+            // The client has asked to have the input method shown, but
+            // we have been sitting here too long with a connection to the
+            // service and no interface received, so let's disconnect/connect
+            // to try to prod things along.
+            EventLog.writeEvent(LOG_IMF_FORCE_RECONNECT_IME, mCurMethodId,
+                    SystemClock.uptimeMillis()-mLastBindTime,1);
+            mContext.unbindService(this);
+            mContext.bindService(mCurIntent, this, Context.BIND_AUTO_CREATE);
         }
     }
     
     public void hideSoftInput(IInputMethodClient client, int flags) {
-        synchronized (mMethodMap) {
-            if (mCurClient == null || client == null
-                    || mCurClient.client.asBinder() != client.asBinder()) {
-                try {
-                    // We need to check if this is the current client with
-                    // focus in the window manager, to allow this call to
-                    // be made before input is started in it.
-                    if (!mIWindowManager.inputMethodClientHasFocus(client)) {
-                        Log.w(TAG, "Ignoring hideSoftInput of: " + client);
-                        return;
+        long ident = Binder.clearCallingIdentity();
+        try {
+            synchronized (mMethodMap) {
+                if (mCurClient == null || client == null
+                        || mCurClient.client.asBinder() != client.asBinder()) {
+                    try {
+                        // We need to check if this is the current client with
+                        // focus in the window manager, to allow this call to
+                        // be made before input is started in it.
+                        if (!mIWindowManager.inputMethodClientHasFocus(client)) {
+                            Log.w(TAG, "Ignoring hideSoftInput of: " + client);
+                            return;
+                        }
+                    } catch (RemoteException e) {
                     }
-                } catch (RemoteException e) {
                 }
+    
+                if (DEBUG) Log.v(TAG, "Client requesting input be hidden");
+                hideCurrentInputLocked(flags);
             }
-
-            if (DEBUG) Log.v(TAG, "Client requesting input be hidden");
-            hideCurrentInputLocked(flags);
+        } finally {
+            Binder.restoreCallingIdentity(ident);
         }
     }
     
@@ -942,70 +1011,75 @@
     public void windowGainedFocus(IInputMethodClient client,
             boolean viewHasFocus, boolean isTextEditor, int softInputMode,
             boolean first, int windowFlags) {
-        synchronized (mMethodMap) {
-            if (DEBUG) Log.v(TAG, "windowGainedFocus: " + client.asBinder()
-                    + " viewHasFocus=" + viewHasFocus
-                    + " isTextEditor=" + isTextEditor
-                    + " softInputMode=#" + Integer.toHexString(softInputMode)
-                    + " first=" + first + " flags=#"
-                    + Integer.toHexString(windowFlags));
-            
-            if (mCurClient == null || client == null
-                    || mCurClient.client.asBinder() != client.asBinder()) {
-                try {
-                    // We need to check if this is the current client with
-                    // focus in the window manager, to allow this call to
-                    // be made before input is started in it.
-                    if (!mIWindowManager.inputMethodClientHasFocus(client)) {
-                        Log.w(TAG, "Ignoring focus gain of: " + client);
-                        return;
+        long ident = Binder.clearCallingIdentity();
+        try {
+            synchronized (mMethodMap) {
+                if (DEBUG) Log.v(TAG, "windowGainedFocus: " + client.asBinder()
+                        + " viewHasFocus=" + viewHasFocus
+                        + " isTextEditor=" + isTextEditor
+                        + " softInputMode=#" + Integer.toHexString(softInputMode)
+                        + " first=" + first + " flags=#"
+                        + Integer.toHexString(windowFlags));
+                
+                if (mCurClient == null || client == null
+                        || mCurClient.client.asBinder() != client.asBinder()) {
+                    try {
+                        // We need to check if this is the current client with
+                        // focus in the window manager, to allow this call to
+                        // be made before input is started in it.
+                        if (!mIWindowManager.inputMethodClientHasFocus(client)) {
+                            Log.w(TAG, "Ignoring focus gain of: " + client);
+                            return;
+                        }
+                    } catch (RemoteException e) {
                     }
-                } catch (RemoteException e) {
+                }
+    
+                switch (softInputMode&WindowManager.LayoutParams.SOFT_INPUT_MASK_STATE) {
+                    case WindowManager.LayoutParams.SOFT_INPUT_STATE_UNSPECIFIED:
+                        if (!isTextEditor || (softInputMode &
+                                WindowManager.LayoutParams.SOFT_INPUT_MASK_ADJUST)
+                                != WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE) {
+                            if (WindowManager.LayoutParams.mayUseInputMethod(windowFlags)) {
+                                // There is no focus view, and this window will
+                                // be behind any soft input window, so hide the
+                                // soft input window if it is shown.
+                                if (DEBUG) Log.v(TAG, "Unspecified window will hide input");
+                                hideCurrentInputLocked(InputMethodManager.HIDE_NOT_ALWAYS);
+                            }
+                        } else if (isTextEditor && (softInputMode &
+                                WindowManager.LayoutParams.SOFT_INPUT_MASK_ADJUST)
+                                == WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE
+                                && (softInputMode &
+                                        WindowManager.LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION) != 0) {
+                            // There is a focus view, and we are navigating forward
+                            // into the window, so show the input window for the user.
+                            if (DEBUG) Log.v(TAG, "Unspecified window will show input");
+                            showCurrentInputLocked(InputMethodManager.SHOW_IMPLICIT);
+                        }
+                        break;
+                    case WindowManager.LayoutParams.SOFT_INPUT_STATE_UNCHANGED:
+                        // Do nothing.
+                        break;
+                    case WindowManager.LayoutParams.SOFT_INPUT_STATE_HIDDEN:
+                        if (DEBUG) Log.v(TAG, "Window asks to hide input");
+                        hideCurrentInputLocked(0);
+                        break;
+                    case WindowManager.LayoutParams.SOFT_INPUT_STATE_VISIBLE:
+                        if ((softInputMode &
+                                WindowManager.LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION) != 0) {
+                            if (DEBUG) Log.v(TAG, "Window asks to show input going forward");
+                            showCurrentInputLocked(InputMethodManager.SHOW_IMPLICIT);
+                        }
+                        break;
+                    case WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_VISIBLE:
+                        if (DEBUG) Log.v(TAG, "Window asks to always show input");
+                        showCurrentInputLocked(InputMethodManager.SHOW_IMPLICIT);
+                        break;
                 }
             }
-
-            switch (softInputMode&WindowManager.LayoutParams.SOFT_INPUT_MASK_STATE) {
-                case WindowManager.LayoutParams.SOFT_INPUT_STATE_UNSPECIFIED:
-                    if (!isTextEditor || (softInputMode &
-                            WindowManager.LayoutParams.SOFT_INPUT_MASK_ADJUST)
-                            != WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE) {
-                        if (WindowManager.LayoutParams.mayUseInputMethod(windowFlags)) {
-                            // There is no focus view, and this window will
-                            // be behind any soft input window, so hide the
-                            // soft input window if it is shown.
-                            if (DEBUG) Log.v(TAG, "Unspecified window will hide input");
-                            hideCurrentInputLocked(InputMethodManager.HIDE_NOT_ALWAYS);
-                        }
-                    } else if (isTextEditor && (softInputMode &
-                            WindowManager.LayoutParams.SOFT_INPUT_MASK_ADJUST)
-                            == WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE
-                            && (softInputMode &
-                                    WindowManager.LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION) != 0) {
-                        // There is a focus view, and we are navigating forward
-                        // into the window, so show the input window for the user.
-                        if (DEBUG) Log.v(TAG, "Unspecified window will show input");
-                        showCurrentInputLocked(InputMethodManager.SHOW_IMPLICIT);
-                    }
-                    break;
-                case WindowManager.LayoutParams.SOFT_INPUT_STATE_UNCHANGED:
-                    // Do nothing.
-                    break;
-                case WindowManager.LayoutParams.SOFT_INPUT_STATE_HIDDEN:
-                    if (DEBUG) Log.v(TAG, "Window asks to hide input");
-                    hideCurrentInputLocked(0);
-                    break;
-                case WindowManager.LayoutParams.SOFT_INPUT_STATE_VISIBLE:
-                    if ((softInputMode &
-                            WindowManager.LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION) != 0) {
-                        if (DEBUG) Log.v(TAG, "Window asks to show input going forward");
-                        showCurrentInputLocked(InputMethodManager.SHOW_IMPLICIT);
-                    }
-                    break;
-                case WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_VISIBLE:
-                    if (DEBUG) Log.v(TAG, "Window asks to always show input");
-                    showCurrentInputLocked(InputMethodManager.SHOW_IMPLICIT);
-                    break;
-            }
+        } finally {
+            Binder.restoreCallingIdentity(ident);
         }
     }
     
@@ -1022,7 +1096,7 @@
 
     public void setInputMethod(IBinder token, String id) {
         synchronized (mMethodMap) {
-            if (mCurToken == null) {
+            if (token == null) {
                 if (mContext.checkCallingOrSelfPermission(
                         android.Manifest.permission.WRITE_SECURE_SETTINGS)
                         != PackageManager.PERMISSION_GRANTED) {
@@ -1032,19 +1106,31 @@
                 }
             } else if (mCurToken != token) {
                 Log.w(TAG, "Ignoring setInputMethod of token: " + token);
+                return;
             }
 
-            setInputMethodLocked(id);
+            long ident = Binder.clearCallingIdentity();
+            try {
+                setInputMethodLocked(id);
+            } finally {
+                Binder.restoreCallingIdentity(ident);
+            }
         }
     }
 
     public void hideMySoftInput(IBinder token, int flags) {
         synchronized (mMethodMap) {
-            if (mCurToken == null || mCurToken != token) {
+            if (token == null || mCurToken != token) {
                 Log.w(TAG, "Ignoring hideInputMethod of token: " + token);
+                return;
             }
 
-            hideCurrentInputLocked(flags);
+            long ident = Binder.clearCallingIdentity();
+            try {
+                hideCurrentInputLocked(flags);
+            } finally {
+                Binder.restoreCallingIdentity(ident);
+            }
         }
     }
 
@@ -1209,7 +1295,7 @@
     
     // ----------------------------------------------------------------------
     
-    public void showInputMethodMenu() {
+    void showInputMethodMenu() {
         if (DEBUG) Log.v(TAG, "Show switching menu");
 
         hideInputMethodMenu();
@@ -1309,83 +1395,88 @@
                         + android.Manifest.permission.WRITE_SECURE_SETTINGS);
             }
             
-            // Make sure this is a valid input method.
-            InputMethodInfo imm = mMethodMap.get(id);
-            if (imm == null) {
+            long ident = Binder.clearCallingIdentity();
+            try {
+                // Make sure this is a valid input method.
+                InputMethodInfo imm = mMethodMap.get(id);
                 if (imm == null) {
-                    throw new IllegalArgumentException("Unknown id: " + mCurMethodId);
-                }
-            }
-            
-            StringBuilder builder = new StringBuilder(256);
-            
-            boolean removed = false;
-            String firstId = null;
-            
-            // Look through the currently enabled input methods.
-            String enabledStr = Settings.Secure.getString(mContext.getContentResolver(),
-                    Settings.Secure.ENABLED_INPUT_METHODS);
-            if (enabledStr != null) {
-                final TextUtils.SimpleStringSplitter splitter = mStringColonSplitter;
-                splitter.setString(enabledStr);
-                while (splitter.hasNext()) {
-                    String curId = splitter.next();
-                    if (curId.equals(id)) {
-                        if (enabled) {
-                            // We are enabling this input method, but it is
-                            // already enabled.  Nothing to do.  The previous
-                            // state was enabled.
-                            return true;
-                        }
-                        // We are disabling this input method, and it is
-                        // currently enabled.  Skip it to remove from the
-                        // new list.
-                        removed = true;
-                    } else if (!enabled) {
-                        // We are building a new list of input methods that
-                        // doesn't contain the given one.
-                        if (firstId == null) firstId = curId;
-                        if (builder.length() > 0) builder.append(':');
-                        builder.append(curId);
+                    if (imm == null) {
+                        throw new IllegalArgumentException("Unknown id: " + mCurMethodId);
                     }
                 }
-            }
-            
-            if (!enabled) {
-                if (!removed) {
-                    // We are disabling the input method but it is already
-                    // disabled.  Nothing to do.  The previous state was
-                    // disabled.
-                    return false;
+                
+                StringBuilder builder = new StringBuilder(256);
+                
+                boolean removed = false;
+                String firstId = null;
+                
+                // Look through the currently enabled input methods.
+                String enabledStr = Settings.Secure.getString(mContext.getContentResolver(),
+                        Settings.Secure.ENABLED_INPUT_METHODS);
+                if (enabledStr != null) {
+                    final TextUtils.SimpleStringSplitter splitter = mStringColonSplitter;
+                    splitter.setString(enabledStr);
+                    while (splitter.hasNext()) {
+                        String curId = splitter.next();
+                        if (curId.equals(id)) {
+                            if (enabled) {
+                                // We are enabling this input method, but it is
+                                // already enabled.  Nothing to do.  The previous
+                                // state was enabled.
+                                return true;
+                            }
+                            // We are disabling this input method, and it is
+                            // currently enabled.  Skip it to remove from the
+                            // new list.
+                            removed = true;
+                        } else if (!enabled) {
+                            // We are building a new list of input methods that
+                            // doesn't contain the given one.
+                            if (firstId == null) firstId = curId;
+                            if (builder.length() > 0) builder.append(':');
+                            builder.append(curId);
+                        }
+                    }
                 }
-                // Update the setting with the new list of input methods.
-                Settings.Secure.putString(mContext.getContentResolver(),
-                        Settings.Secure.ENABLED_INPUT_METHODS, builder.toString());
-                // We the disabled input method is currently selected, switch
-                // to another one.
-                String selId = Settings.Secure.getString(mContext.getContentResolver(),
-                        Settings.Secure.DEFAULT_INPUT_METHOD);
-                if (id.equals(selId)) {
+                
+                if (!enabled) {
+                    if (!removed) {
+                        // We are disabling the input method but it is already
+                        // disabled.  Nothing to do.  The previous state was
+                        // disabled.
+                        return false;
+                    }
+                    // Update the setting with the new list of input methods.
                     Settings.Secure.putString(mContext.getContentResolver(),
-                            Settings.Secure.DEFAULT_INPUT_METHOD,
-                            firstId != null ? firstId : "");
+                            Settings.Secure.ENABLED_INPUT_METHODS, builder.toString());
+                    // We the disabled input method is currently selected, switch
+                    // to another one.
+                    String selId = Settings.Secure.getString(mContext.getContentResolver(),
+                            Settings.Secure.DEFAULT_INPUT_METHOD);
+                    if (id.equals(selId)) {
+                        Settings.Secure.putString(mContext.getContentResolver(),
+                                Settings.Secure.DEFAULT_INPUT_METHOD,
+                                firstId != null ? firstId : "");
+                    }
+                    // Previous state was enabled.
+                    return true;
                 }
-                // Previous state was enabled.
-                return true;
+                
+                // Add in the newly enabled input method.
+                if (enabledStr == null || enabledStr.length() == 0) {
+                    enabledStr = id;
+                } else {
+                    enabledStr = enabledStr + ':' + id;
+                }
+                
+                Settings.Secure.putString(mContext.getContentResolver(),
+                        Settings.Secure.ENABLED_INPUT_METHODS, enabledStr);
+                
+                // Previous state was disabled.
+                return false;
+            } finally {
+                Binder.restoreCallingIdentity(ident);
             }
-            
-            // Add in the newly enabled input method.
-            if (enabledStr == null || enabledStr.length() == 0) {
-                enabledStr = id;
-            } else {
-                enabledStr = enabledStr + ':' + id;
-            }
-            
-            Settings.Secure.putString(mContext.getContentResolver(),
-                    Settings.Secure.ENABLED_INPUT_METHODS, enabledStr);
-            
-            // Previous state was disabled.
-            return false;
         }
     }
     
diff --git a/services/java/com/android/server/LocationManagerService.java b/services/java/com/android/server/LocationManagerService.java
index bc6fd71..db4daa5 100644
--- a/services/java/com/android/server/LocationManagerService.java
+++ b/services/java/com/android/server/LocationManagerService.java
@@ -132,7 +132,7 @@
     private static final int MESSAGE_HEARTBEAT = 1;
     private static final int MESSAGE_ACQUIRE_WAKE_LOCK = 2;
     private static final int MESSAGE_RELEASE_WAKE_LOCK = 3;
-    private static final int MESSAGE_SET_NETWORK_LOCATION_PROVIDER = 4;
+    private static final int MESSAGE_INSTALL_NETWORK_LOCATION_PROVIDER = 4;
 
     // Alarm manager and wakelock variables
     private final static String ALARM_INTENT = "com.android.location.ALARM_INTENT";
@@ -565,13 +565,21 @@
         }
     }
 
-    public void setNetworkLocationProvider(INetworkLocationProvider provider) {
-        mLocationHandler.removeMessages(MESSAGE_SET_NETWORK_LOCATION_PROVIDER);
+    public void setInstallCallback(InstallCallback callback) {
+        mLocationHandler.removeMessages(MESSAGE_INSTALL_NETWORK_LOCATION_PROVIDER);
         Message m = Message.obtain(mLocationHandler, 
-                MESSAGE_SET_NETWORK_LOCATION_PROVIDER, provider);
+                MESSAGE_INSTALL_NETWORK_LOCATION_PROVIDER, callback);
         mLocationHandler.sendMessageAtFrontOfQueue(m);
     }
 
+    public void setNetworkLocationProvider(INetworkLocationProvider provider) {
+        mNetworkLocationInterface = provider;
+        provider.addListener(getPackageNames());
+        mNetworkLocationProvider = (LocationProviderImpl)provider;
+        LocationProviderImpl.addProvider(mNetworkLocationProvider);
+        updateProviders();
+    }
+
     public void setLocationCollector(ILocationCollector collector) {
         mCollector = collector;
         if (mGpsLocationProvider != null) {
@@ -1598,16 +1606,12 @@
                     // Update wakelock status so the next alarm is set before releasing wakelock
                     updateWakelockStatus(mScreenOn);
                     releaseWakeLock();
-                } else if (msg.what == MESSAGE_SET_NETWORK_LOCATION_PROVIDER) {
+                } else if (msg.what == MESSAGE_INSTALL_NETWORK_LOCATION_PROVIDER) {
                     synchronized (LocationManagerService.class) {
-                        Log.d(TAG, "adding network location provider");
-                        mNetworkLocationInterface = 
-                                (INetworkLocationProvider)msg.obj;
-                        mNetworkLocationInterface.addListener(getPackageNames());
-                        mNetworkLocationProvider = 
-                                (LocationProviderImpl)mNetworkLocationInterface;
-                        LocationProviderImpl.addProvider(mNetworkLocationProvider);
-                        updateProviders();
+                        Log.d(TAG, "installing network location provider");
+                        INetworkLocationManager.InstallCallback callback =
+                                (INetworkLocationManager.InstallCallback)msg.obj;
+                        callback.installNetworkLocationProvider(mContext, LocationManagerService.this);
                     }
                 }
             } catch (Exception e) {
diff --git a/services/java/com/android/server/PackageManagerService.java b/services/java/com/android/server/PackageManagerService.java
index 221ba46..c490e42 100644
--- a/services/java/com/android/server/PackageManagerService.java
+++ b/services/java/com/android/server/PackageManagerService.java
@@ -3219,12 +3219,15 @@
                         Log.i(TAG, "Observer no longer exists.");
                     }
                 }
-                // There appears to be a subtle deadlock condition if the sendPackageBroadcast call appears
-                // in the synchronized block above.
+                // There appears to be a subtle deadlock condition if the sendPackageBroadcast
+                // call appears in the synchronized block above.
                 if (res.returnCode == PackageManager.INSTALL_SUCCEEDED) {
                     res.removedInfo.sendBroadcast(false, true);
                     Bundle extras = new Bundle(1);
                     extras.putInt(Intent.EXTRA_UID, res.uid);
+                    if (res.removedInfo.removedPackage != null) {
+                        extras.putBoolean(Intent.EXTRA_REPLACING, true);
+                    }
                     sendPackageBroadcast(Intent.ACTION_PACKAGE_ADDED,
                                          res.pkg.applicationInfo.packageName,
                                          extras);
diff --git a/services/java/com/android/server/PowerManagerService.java b/services/java/com/android/server/PowerManagerService.java
index 7c111d3..6974b5e 100644
--- a/services/java/com/android/server/PowerManagerService.java
+++ b/services/java/com/android/server/PowerManagerService.java
@@ -1001,11 +1001,9 @@
                 }
             }
             else {
-                synchronized (mLocks) {
-                    EventLog.writeEvent(LOG_POWER_SCREEN_BROADCAST_STOP, 4,
-                            mBroadcastWakeLock.mCount);
-                    mBroadcastWakeLock.release();
-                }
+                // If we're in this case, then this handler is running for a previous
+                // paired transaction.  mBroadcastWakeLock will already have been released
+                // in sendNotificationLocked.
             }
         }
     };
diff --git a/services/java/com/android/server/WifiService.java b/services/java/com/android/server/WifiService.java
index c009fac..eece581 100644
--- a/services/java/com/android/server/WifiService.java
+++ b/services/java/com/android/server/WifiService.java
@@ -87,10 +87,13 @@
 
     private final LockList mLocks = new LockList();
     /**
-     * See {@link Settings.System#WIFI_IDLE_MS}. This is the default value if a
-     * Settings.System value is not present.
+     * See {@link Settings.Gservices#WIFI_IDLE_MS}. This is the default value if a
+     * Settings.Gservices value is not present. This timeout value is chosen as
+     * the approximate point at which the battery drain caused by Wi-Fi
+     * being enabled but not active exceeds the battery drain caused by
+     * re-establishing a connection to the mobile data network.
      */
-    private static final long DEFAULT_IDLE_MILLIS = 2 * 60 * 1000; /* 2 minutes */
+    private static final long DEFAULT_IDLE_MILLIS = 15 * 60 * 1000; /* 15 minutes */
 
     private static final String WAKELOCK_TAG = "WifiService";
 
@@ -101,7 +104,7 @@
      * provides a bit of extra margin.
      * <p>
      * See {@link android.provider.Settings.Secure#WIFI_MOBILE_DATA_TRANSITION_WAKELOCK_TIMEOUT_MS}.
-     * This is the default value if a Settings.System value is not present.
+     * This is the default value if a Settings.Secure value is not present.
      */
     private static final int DEFAULT_WAKELOCK_TIMEOUT = 8000;
 
@@ -1364,7 +1367,7 @@
      * in the current regulatory domain. This method should be used only
      * if the correct number of channels cannot be determined automatically
      * for some reason. If the operation is successful, the new value is
-     * persisted as a System setting.
+     * persisted as a Secure setting.
      * @param numChannels the number of allowed channels. Must be greater than 0
      * and less than or equal to 16.
      * @return {@code true} if the operation succeeds, {@code false} otherwise, e.g.,
@@ -1446,8 +1449,8 @@
         public void onReceive(Context context, Intent intent) {
             String action = intent.getAction();
 
-            long idleMillis = Settings.System.getLong(mContext.getContentResolver(),
-                                                  Settings.System.WIFI_IDLE_MS, DEFAULT_IDLE_MILLIS);
+            long idleMillis = Settings.Gservices.getLong(mContext.getContentResolver(),
+                                                  Settings.Gservices.WIFI_IDLE_MS, DEFAULT_IDLE_MILLIS);
             int stayAwakeConditions =
                     Settings.System.getInt(mContext.getContentResolver(),
                                            Settings.System.STAY_ON_WHILE_PLUGGED_IN, 0);
diff --git a/services/java/com/android/server/WindowManagerService.java b/services/java/com/android/server/WindowManagerService.java
index 09f5d8f..fed6d12 100644
--- a/services/java/com/android/server/WindowManagerService.java
+++ b/services/java/com/android/server/WindowManagerService.java
@@ -768,27 +768,55 @@
         if (willMove && w != null) {
             final WindowState curTarget = mInputMethodTarget;
             if (curTarget != null && curTarget.mAppToken != null) {
-                int curIndex = -1;
-                if (DEBUG_INPUT_METHOD) Log.v(TAG, "mNextAppTransition=" 
-                        + mNextAppTransition + " curTarget animating="
-                        + curTarget.isAnimating()
-                        + " layer=" + curTarget.mAnimLayer
-                        + " new layer=" + w.mAnimLayer);
-                if (mNextAppTransition != WindowManagerPolicy.TRANSIT_NONE) {
-                    // If we are currently setting up for an animation,
-                    // hold everything until we can find out what will happen.
-                    mInputMethodTargetWaitingAnim = true;
-                    curIndex = localmWindows.indexOf(curTarget);
-                } else if (curTarget.isAnimating() &&
-                        curTarget.mAnimLayer > w.mAnimLayer) {
-                    // If the window we are currently targeting is involved
-                    // with an animation, and it is on top of the next target
-                    // we will be over, then hold off on moving until
-                    // that is done.
-                    curIndex = localmWindows.indexOf(curTarget);
+                
+                // Now some fun for dealing with window animations that
+                // modify the Z order.  We need to look at all windows below
+                // the current target that are in this app, finding the highest
+                // visible one in layering.
+                AppWindowToken token = curTarget.mAppToken;
+                WindowState highestTarget = null;
+                int highestPos = 0;
+                if (token.animating || token.animation != null) {
+                    int pos = 0;
+                    pos = localmWindows.indexOf(curTarget);
+                    while (pos >= 0) {
+                        WindowState win = (WindowState)localmWindows.get(pos);
+                        if (win.mAppToken != token) {
+                            break;
+                        }
+                        if (!win.mRemoved) {
+                            if (highestTarget == null || win.mAnimLayer >
+                                    highestTarget.mAnimLayer) {
+                                highestTarget = win;
+                                highestPos = pos;
+                            }
+                        }
+                        pos--;
+                    }
                 }
-                if (curIndex >= 0) {
-                    return curIndex + 1;
+                
+                if (highestTarget != null) {
+                    if (DEBUG_INPUT_METHOD) Log.v(TAG, "mNextAppTransition=" 
+                            + mNextAppTransition + " " + highestTarget
+                            + " animating=" + highestTarget.isAnimating()
+                            + " layer=" + highestTarget.mAnimLayer
+                            + " new layer=" + w.mAnimLayer);
+                    
+                    if (mNextAppTransition != WindowManagerPolicy.TRANSIT_NONE) {
+                        // If we are currently setting up for an animation,
+                        // hold everything until we can find out what will happen.
+                        mInputMethodTargetWaitingAnim = true;
+                        mInputMethodTarget = highestTarget;
+                        return highestPos + 1;
+                    } else if (highestTarget.isAnimating() &&
+                            highestTarget.mAnimLayer > w.mAnimLayer) {
+                        // If the window we are currently targeting is involved
+                        // with an animation, and it is on top of the next target
+                        // we will be over, then hold off on moving until
+                        // that is done.
+                        mInputMethodTarget = highestTarget;
+                        return highestPos + 1;
+                    }
                 }
             }
         }
@@ -891,12 +919,27 @@
         }
     }
     
+    void logWindowList(String prefix) {
+        int N = mWindows.size();
+        while (N > 0) {
+            N--;
+            Log.v(TAG, prefix + "#" + N + ": " + mWindows.get(N));
+        }
+    }
+    
     void moveInputMethodDialogsLocked(int pos) {
         ArrayList<WindowState> dialogs = mInputMethodDialogs;
+        
         final int N = dialogs.size();
+        if (DEBUG_INPUT_METHOD) Log.v(TAG, "Removing " + N + " dialogs w/pos=" + pos);
         for (int i=0; i<N; i++) {
             pos = tmpRemoveWindowLocked(pos, dialogs.get(i));
         }
+        if (DEBUG_INPUT_METHOD) {
+            Log.v(TAG, "Window list w/pos=" + pos);
+            logWindowList("  ");
+        }
+        
         if (pos >= 0) {
             final AppWindowToken targetAppToken = mInputMethodTarget.mAppToken;
             if (pos < mWindows.size()) {
@@ -905,17 +948,26 @@
                     pos++;
                 }
             }
+            if (DEBUG_INPUT_METHOD) Log.v(TAG, "Adding " + N + " dialogs at pos=" + pos);
             for (int i=0; i<N; i++) {
                 WindowState win = dialogs.get(i);
                 win.mTargetAppToken = targetAppToken;
                 pos = reAddWindowLocked(pos, win);
             }
+            if (DEBUG_INPUT_METHOD) {
+                Log.v(TAG, "Final window list:");
+                logWindowList("  ");
+            }
             return;
         }
         for (int i=0; i<N; i++) {
             WindowState win = dialogs.get(i);
             win.mTargetAppToken = null;
             reAddWindowToListInOrderLocked(win);
+            if (DEBUG_INPUT_METHOD) {
+                Log.v(TAG, "No IM target, final list:");
+                logWindowList("  ");
+            }
         }
     }
     
@@ -971,9 +1023,21 @@
             }
             
             if (imWin != null) {
+                if (DEBUG_INPUT_METHOD) {
+                    Log.v(TAG, "Moving IM from " + imPos);
+                    logWindowList("  ");
+                }
                 imPos = tmpRemoveWindowLocked(imPos, imWin);
+                if (DEBUG_INPUT_METHOD) {
+                    Log.v(TAG, "List after moving with new pos " + imPos + ":");
+                    logWindowList("  ");
+                }
                 imWin.mTargetAppToken = mInputMethodTarget.mAppToken;
                 reAddWindowLocked(imPos, imWin);
+                if (DEBUG_INPUT_METHOD) {
+                    Log.v(TAG, "List after moving IM to " + imPos + ":");
+                    logWindowList("  ");
+                }
                 if (DN > 0) moveInputMethodDialogsLocked(imPos+1);
             } else {
                 moveInputMethodDialogsLocked(imPos);
@@ -984,9 +1048,14 @@
             // because they aren't currently associated with a focus window.
             
             if (imWin != null) {
+                if (DEBUG_INPUT_METHOD) Log.v(TAG, "Moving IM from " + imPos);
                 tmpRemoveWindowLocked(0, imWin);
                 imWin.mTargetAppToken = null;
                 reAddWindowToListInOrderLocked(imWin);
+                if (DEBUG_INPUT_METHOD) {
+                    Log.v(TAG, "List with no IM target:");
+                    logWindowList("  ");
+                }
                 if (DN > 0) moveInputMethodDialogsLocked(-1);;
             } else {
                 moveInputMethodDialogsLocked(-1);;
@@ -1233,7 +1302,7 @@
         if (win.mSurface != null && !mDisplayFrozen) {
             // If we are not currently running the exit animation, we
             // need to see about starting one.
-            if (wasVisible=win.isVisibleLw()) {
+            if (wasVisible=win.isWinVisibleLw()) {
                 
                 int transit = WindowManagerPolicy.TRANSIT_EXIT;
                 if (win.getAttrs().type == TYPE_APPLICATION_STARTING) {
@@ -1277,6 +1346,12 @@
         mKeyWaiter.releasePendingPointerLocked(win.mSession);
         mKeyWaiter.releasePendingTrackballLocked(win.mSession);
         
+        win.mRemoved = true;
+        
+        if (mInputMethodTarget == win) {
+            moveInputMethodWindowsIfNeededLocked(false);
+        }
+        
         mPolicy.removeWindowLw(win);
         win.removeLocked();
 
@@ -1501,7 +1576,7 @@
                         if (win.getAttrs().type == TYPE_APPLICATION_STARTING) {
                             transit = WindowManagerPolicy.TRANSIT_PREVIEW_DONE;
                         }
-                        if (win.isVisibleLw() &&
+                        if (win.isWinVisibleLw() &&
                               applyAnimationLocked(win, transit, false)) {
                             win.mExiting = true;
                             mKeyWaiter.finishedKey(session, client, true,
@@ -1511,13 +1586,13 @@
                             // an exit.
                             win.mExiting = true;
                         } else {
+                            if (mInputMethodWindow == win) {
+                                mInputMethodWindow = null;
+                            }
                             win.destroySurfaceLocked();
                         }
                     }
                 }
-                if (mInputMethodWindow == win) {
-                    mInputMethodWindow = null;
-                }
                 outSurface.clear();
             }
 
@@ -1620,7 +1695,7 @@
 
     private boolean applyAnimationLocked(WindowState win,
             int transit, boolean isEntrance) {
-        if (win.mAnimating && win.mAnimationIsEntrance == isEntrance) {
+        if (win.mLocalAnimating && win.mAnimationIsEntrance == isEntrance) {
             // If we are trying to apply an animation, but already running
             // an animation of the same type, then just leave that one alone.
             return true;
@@ -1666,6 +1741,7 @@
                     Log.v(TAG, "Loaded animation " + a + " for " + win, e);
                 }
                 win.setAnimation(a);
+                win.mAnimationIsEntrance = isEntrance;
             }
         } else {
             win.clearAnimation();
@@ -2724,7 +2800,7 @@
         boolean added = false;
         for (int j=0; j<NCW; j++) {
             WindowState cwin = (WindowState)win.mChildWindows.get(j);
-            if (cwin.mSubLayer >= 0) {
+            if (!added && cwin.mSubLayer >= 0) {
                 mWindows.add(index, win);
                 index++;
                 added = true;
@@ -4645,8 +4721,8 @@
         KeyQ() {
             super(mContext);
             PowerManager pm = (PowerManager)mContext.getSystemService(Context.POWER_SERVICE);
-            mHoldingScreen = pm.newWakeLock(PowerManager.SCREEN_BRIGHT_WAKE_LOCK
-                    | PowerManager.ON_AFTER_RELEASE, "KEEP_SCREEN_ON_FLAG");
+            mHoldingScreen = pm.newWakeLock(PowerManager.SCREEN_BRIGHT_WAKE_LOCK,
+                    "KEEP_SCREEN_ON_FLAG");
             mHoldingScreen.setReferenceCounted(false);
         }
 
@@ -4769,8 +4845,7 @@
                 if (holding) {
                     mHoldingScreen.acquire();
                 } else {
-                    long curTime = SystemClock.uptimeMillis();
-                    mPowerManager.userActivity(curTime, false, LocalPowerManager.OTHER_EVENT);
+                    mPolicy.screenOnStopped();
                     mHoldingScreen.release();
                 }
             }
@@ -5095,6 +5170,19 @@
             }
         }
 
+        public boolean performHapticFeedback(IWindow window, int effectId,
+                boolean always) {
+            synchronized(mWindowMap) {
+                long ident = Binder.clearCallingIdentity();
+                try {
+                    return mPolicy.performHapticFeedback(
+                            windowForClientLocked(this, window), effectId, always);
+                } finally {
+                    Binder.restoreCallingIdentity(ident);
+                }
+            }
+        }
+        
         void windowAddedLocked() {
             if (mSurfaceSession == null) {
                 if (localLOGV) Log.v(
@@ -5255,9 +5343,11 @@
 
         // Currently running animation.
         boolean mAnimating;
+        boolean mLocalAnimating;
         Animation mAnimation;
         boolean mAnimationIsEntrance;
         boolean mHasTransformation;
+        boolean mHasLocalTransformation;
         final Transformation mTransformation = new Transformation();
 
         // This is set after IWindowSession.relayout() has been called at
@@ -5297,6 +5387,9 @@
         // been updated for the new orientation.
         boolean mOrientationChanging;
         
+        // Is this window now (or just being) removed?
+        boolean mRemoved;
+        
         WindowState(Session s, IWindow c, WindowToken token,
                WindowState attachedWindow, WindowManager.LayoutParams a,
                int viewVisibility) {
@@ -5516,6 +5609,7 @@
             if (localLOGV) Log.v(
                 TAG, "Setting animation in " + this + ": " + anim);
             mAnimating = false;
+            mLocalAnimating = false;
             mAnimation = anim;
             mAnimation.restrictDuration(MAX_ANIMATION_DURATION);
             mAnimation.scaleCurrentDuration(mWindowAnimationScale);
@@ -5524,6 +5618,7 @@
         public void clearAnimation() {
             if (mAnimation != null) {
                 mAnimating = true;
+                mLocalAnimating = false;
                 mAnimation = null;
             }
         }
@@ -5752,13 +5847,15 @@
                 
                 if (!mDrawPending && !mCommitDrawPending && mAnimation != null) {
                     mHasTransformation = true;
-                    if (!mAnimating) {
+                    mHasLocalTransformation = true;
+                    if (!mLocalAnimating) {
                         if (DEBUG_ANIM) Log.v(
                             TAG, "Starting animation in " + this +
                             " @ " + currentTime + ": ww=" + mFrame.width() + " wh=" + mFrame.height() +
                             " dw=" + dw + " dh=" + dh + " scale=" + mWindowAnimationScale);
                         mAnimation.initialize(mFrame.width(), mFrame.height(), dw, dh);
                         mAnimation.setStartTime(currentTime);
+                        mLocalAnimating = true;
                         mAnimating = true;
                     }
                     mTransformation.clear();
@@ -5767,9 +5864,6 @@
                     if (DEBUG_ANIM) Log.v(
                         TAG, "Stepped animation in " + this +
                         ": more=" + more + ", xform=" + mTransformation);
-                    if (mAppToken != null && mAppToken.hasTransformation) {
-                        mTransformation.compose(mAppToken.transformation);
-                    }
                     if (more) {
                         // we're not done!
                         return true;
@@ -5780,10 +5874,19 @@
                     mAnimation = null;
                     //WindowManagerService.this.dump();
                 }
-                if (mAppToken != null && mAppToken.hasTransformation) {
+                mHasLocalTransformation = false;
+                if ((!mLocalAnimating || mAnimationIsEntrance) && mAppToken != null
+                        && mAppToken.hasTransformation) {
+                    // When our app token is animating, we kind-of pretend like
+                    // we are as well.  Note the mLocalAnimating mAnimationIsEntrance
+                    // part of this check means that we will only do this if
+                    // our window is not currently exiting, or it is not
+                    // locally animating itself.  The idea being that one that
+                    // is exiting and doing a local animation should be removed
+                    // once that animation is done.
                     mAnimating = true;
                     mHasTransformation = true;
-                    mTransformation.set(mAppToken.transformation);
+                    mTransformation.clear();
                     return false;
                 } else if (mHasTransformation) {
                     // Little trick to get through the path below to act like
@@ -5796,10 +5899,11 @@
                 // If the display is frozen, and there is a pending animation,
                 // clear it and make sure we run the cleanup code.
                 mAnimating = true;
+                mLocalAnimating = true;
                 mAnimation = null;
             }
             
-            if (!mAnimating) {
+            if (!mAnimating && !mLocalAnimating) {
                 return false;
             }
 
@@ -5809,6 +5913,7 @@
                 + (mAppToken != null ? mAppToken.reportedVisible : false));
             
             mAnimating = false;
+            mLocalAnimating = false;
             mAnimation = null;
             mAnimLayer = mLayer;
             if (mIsImWindow) {
@@ -5817,6 +5922,7 @@
             if (DEBUG_LAYERS) Log.v(TAG, "Stepping win " + this
                     + " anim layer: " + mAnimLayer);
             mHasTransformation = false;
+            mHasLocalTransformation = false;
             mPolicyVisibility = mPolicyVisibilityAfterAnim;
             mTransformation.clear();
             if (mHasDrawn
@@ -5891,10 +5997,15 @@
         }
         
         void computeShownFrameLocked() {
-            final boolean selfTransformation = mHasTransformation;
-            final boolean attachedTransformation = (mAttachedWindow != null
-                    && mAttachedWindow.mHasTransformation);
-            if (selfTransformation || attachedTransformation) {
+            final boolean selfTransformation = mHasLocalTransformation;
+            Transformation attachedTransformation =
+                    (mAttachedWindow != null && mAttachedWindow.mHasLocalTransformation)
+                    ? mAttachedWindow.mTransformation : null;
+            Transformation appTransformation =
+                    (mAppToken != null && mAppToken.hasTransformation)
+                    ? mAppToken.transformation : null;
+            if (selfTransformation || attachedTransformation != null
+                    || appTransformation != null) {
                 // cache often used attributes locally  
                 final Rect frame = mFrame;
                 final float tmpFloats[] = mTmpFloats;
@@ -5905,8 +6016,11 @@
                 if (selfTransformation) {
                     tmpMatrix.preConcat(mTransformation.getMatrix());
                 }
-                if (attachedTransformation) {
-                    tmpMatrix.preConcat(mAttachedWindow.mTransformation.getMatrix());
+                if (attachedTransformation != null) {
+                    tmpMatrix.preConcat(attachedTransformation.getMatrix());
+                }
+                if (appTransformation != null) {
+                    tmpMatrix.preConcat(appTransformation.getMatrix());
                 }
 
                 // "convert" it into SurfaceFlinger's format
@@ -5940,8 +6054,11 @@
                     if (selfTransformation) {
                         mShownAlpha *= mTransformation.getAlpha();
                     }
-                    if (attachedTransformation) {
-                        mShownAlpha *= mAttachedWindow.mTransformation.getAlpha();
+                    if (attachedTransformation != null) {
+                        mShownAlpha *= attachedTransformation.getAlpha();
+                    }
+                    if (appTransformation != null) {
+                        mShownAlpha *= appTransformation.getAlpha();
                     }
                 } else {
                     //Log.i(TAG, "Not applying alpha transform");
@@ -5965,7 +6082,7 @@
         /**
          * Is this window visible?  It is not visible if there is no
          * surface, or we are in the process of running an exit animation
-         * that will remove the surface.
+         * that will remove the surface, or its app token has been hidden.
          */
         public boolean isVisibleLw() {
             final AppWindowToken atoken = mAppToken;
@@ -5975,6 +6092,18 @@
         }
 
         /**
+         * Is this window visible, ignoring its app token?  It is not visible
+         * if there is no surface, or we are in the process of running an exit animation
+         * that will remove the surface.
+         */
+        public boolean isWinVisibleLw() {
+            final AppWindowToken atoken = mAppToken;
+            return mSurface != null && mPolicyVisibility && !mAttachedHidden
+                    && (atoken == null || !atoken.hiddenRequested || atoken.animating)
+                    && !mExiting && !mDestroying;
+        }
+
+        /**
          * The same as isVisible(), but follows the current hidden state of
          * the associated app token, not the pending requested hidden state.
          */
@@ -6203,6 +6332,7 @@
             pw.println(prefix + "mShownAlpha=" + mShownAlpha
                   + " mAlpha=" + mAlpha + " mLastAlpha=" + mLastAlpha);
             pw.println(prefix + "mAnimating=" + mAnimating
+                    + " mLocalAnimating=" + mLocalAnimating
                     + " mAnimationIsEntrance=" + mAnimationIsEntrance
                     + " mAnimation=" + mAnimation);
             pw.println(prefix + "XForm: has=" + mHasTransformation
@@ -6213,7 +6343,8 @@
                   + " mHasDrawn=" + mHasDrawn);
             pw.println(prefix + "mExiting=" + mExiting
                     + " mRemoveOnExit=" + mRemoveOnExit
-                    + " mDestroying=" + mDestroying);
+                    + " mDestroying=" + mDestroying
+                    + " mRemoved=" + mRemoved);
             pw.println(prefix + "mOrientationChanging=" + mOrientationChanging
                     + " mAppFreezing=" + mAppFreezing);
         }
@@ -7959,6 +8090,9 @@
                 i--;
                 WindowState win = mDestroySurface.get(i);
                 win.mDestroying = false;
+                if (mInputMethodWindow == win) {
+                    mInputMethodWindow = null;
+                }
                 win.destroySurfaceLocked();
             } while (i > 0);
             mDestroySurface.clear();
diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java
index f5efe4b..e391da3 100644
--- a/services/java/com/android/server/am/ActivityManagerService.java
+++ b/services/java/com/android/server/am/ActivityManagerService.java
@@ -159,7 +159,12 @@
     static final int LOG_AM_BROADCAST_DISCARD_APP = 30025;
     static final int LOG_AM_CREATE_SERVICE = 30030;
     static final int LOG_AM_DESTROY_SERVICE = 30031;
-
+    static final int LOG_AM_PROCESS_CRASHED_TOO_MUCH = 30032;
+    static final int LOG_AM_DROP_PROCESS = 30033;
+    static final int LOG_AM_SERVICE_CRASHED_TOO_MUCH = 30034;
+    static final int LOG_AM_SCHEDULE_SERVICE_RESTART = 30035;
+    static final int LOG_AM_PROVIDER_LOST_PROCESS = 30036;
+    
     static final int LOG_BOOT_PROGRESS_AMS_READY = 3040;
     static final int LOG_BOOT_PROGRESS_ENABLE_SCREEN = 3050;
 
@@ -1787,7 +1792,7 @@
         }
     }
 
-    private final void startPausingLocked(boolean userLeaving) {
+    private final void startPausingLocked(boolean userLeaving, boolean uiSleeping) {
         if (mPausingActivity != null) {
             RuntimeException e = new RuntimeException();
             Log.e(TAG, "Trying to pause when pause is already pending for "
@@ -1840,9 +1845,15 @@
 
         if (mPausingActivity != null) {
             // Have the window manager pause its key dispatching until the new
-            // activity has started...
-            prev.pauseKeyDispatchingLocked();
-            
+            // activity has started.  If we're pausing the activity just because
+            // the screen is being turned off and the UI is sleeping, don't interrupt
+            // key dispatch; the same activity will pick it up again on wakeup.
+            if (!uiSleeping) {
+                prev.pauseKeyDispatchingLocked();
+            } else {
+                if (DEBUG_PAUSE) Log.v(TAG, "Key dispatch not paused for screen off");
+            }
+
             // Schedule a pause timeout in case the app doesn't respond.
             // We don't give it much time because this directly impacts the
             // responsiveness seen by the user.
@@ -2188,7 +2199,7 @@
         // can be resumed...
         if (mResumedActivity != null) {
             if (DEBUG_SWITCH) Log.v(TAG, "Skip resume: need to start pausing");
-            startPausingLocked(userLeaving);
+            startPausingLocked(userLeaving, false);
             return true;
         }
 
@@ -2605,8 +2616,7 @@
                 r.app.thread.scheduleNewIntent(ar, r);
                 sent = true;
             } catch (Exception e) {
-                Log.w(TAG,
-                      "Exception thrown sending new intent to " + r, e);
+                Log.w(TAG, "Exception thrown sending new intent to " + r, e);
             }
         }
         if (!sent) {
@@ -3456,7 +3466,7 @@
             if (mPausingActivity == null) {
                 if (DEBUG_PAUSE) Log.v(TAG, "Finish needs to pause: " + r);
                 if (DEBUG_USER_LEAVING) Log.v(TAG, "finish() => pause with userLeaving=false");
-                startPausingLocked(false);
+                startPausingLocked(false, false);
             }
 
         } else if (r.state != ActivityState.PAUSING) {
@@ -3590,9 +3600,7 @@
                 r.app.thread.scheduleSendResult(r, list);
                 return;
             } catch (Exception e) {
-                Log.w(TAG,
-                      "Exception thrown sending result to " + r,
-                      e);
+                Log.w(TAG, "Exception thrown sending result to " + r, e);
             }
         }
 
@@ -3778,8 +3786,7 @@
         r.configChangeFlags = 0;
         
         if (!mLRUActivities.remove(r)) {
-            Log.w(TAG, "Activity " + r
-                  + " being finished, but not in LRU list");
+            Log.w(TAG, "Activity " + r + " being finished, but not in LRU list");
         }
         
         return removedFromHistory;
@@ -4217,7 +4224,7 @@
                 } catch (RemoteException e) {
                 }
                 if (pkgUid == -1) {
-                    Log.w(TAG, "Invalid packageName:"+packageName);
+                    Log.w(TAG, "Invalid packageName:" + packageName);
                     return false;
                 }
                 if (uid == pkgUid || checkComponentPermission(
@@ -4270,7 +4277,7 @@
                 } catch (RemoteException e) {
                 }
                 if (pkgUid == -1) {
-                    Log.w(TAG, "Invalid packageName:"+packageName);
+                    Log.w(TAG, "Invalid packageName: " + packageName);
                     return;
                 }
                 restartPackageLocked(packageName, pkgUid);
@@ -4423,6 +4430,7 @@
         if (app == null) {
             Log.w(TAG, "No pending application record for pid " + pid
                     + " (IApplicationThread " + thread + "); dropping process");
+            EventLog.writeEvent(LOG_AM_DROP_PROCESS, pid);
             if (pid > 0 && pid != MY_PID) {
                 Process.killProcess(pid);
             } else {
@@ -6579,10 +6587,10 @@
             if (caller != null) {
                 r = getRecordForAppLocked(caller);
                 if (r == null) {
-                throw new SecurityException(
-                        "Unable to find app for caller " + caller
-                      + " (pid=" + Binder.getCallingPid()
-                      + ") when getting content provider " + name);
+                    throw new SecurityException(
+                            "Unable to find app for caller " + caller
+                          + " (pid=" + Binder.getCallingPid()
+                          + ") when getting content provider " + name);
                 }
             }
 
@@ -6739,6 +6747,10 @@
                             + cpi.applicationInfo.packageName + "/"
                             + cpi.applicationInfo.uid + " for provider "
                             + name + ": launching app became null");
+                    EventLog.writeEvent(LOG_AM_PROVIDER_LOST_PROCESS,
+                            cpi.applicationInfo.packageName,
+                            cpi.applicationInfo.uid, name);
+                    return null;
                 }
                 try {
                     cpr.wait();
@@ -6844,9 +6856,6 @@
                 ContentProviderRecord dst =
                     (ContentProviderRecord)r.pubProviders.get(src.info.name);
                 if (dst != null) {
-                    dst.provider = src.provider;
-                    dst.app = r;
-
                     mProvidersByClass.put(dst.info.name, dst);
                     String names[] = dst.info.authority.split(";");
                     for (int j = 0; j < names.length; j++) {
@@ -6863,6 +6872,8 @@
                         }
                     }
                     synchronized (dst) {
+                        dst.provider = src.provider;
+                        dst.app = r;
                         dst.notifyAll();
                     }
                     updateOomAdjLocked(r);
@@ -6993,7 +7004,7 @@
             if (mPausingActivity == null) {
                 if (DEBUG_PAUSE) Log.v(TAG, "Sleep needs to pause...");
                 if (DEBUG_USER_LEAVING) Log.v(TAG, "Sleep => pause with userLeaving=false");
-                startPausingLocked(false);
+                startPausingLocked(false, true);
             }
         }
     }
@@ -7499,6 +7510,8 @@
             // This process loses!
             Log.w(TAG, "Process " + app.info.processName
                     + " has crashed too many times: killing!");
+            EventLog.writeEvent(LOG_AM_PROCESS_CRASHED_TOO_MUCH,
+                    app.info.processName, app.info.uid);
             killServicesLocked(app, false);
             for (int i=mHistory.size()-1; i>=0; i--) {
                 HistoryRecord r = (HistoryRecord)mHistory.get(i);
@@ -8429,6 +8442,8 @@
                 if (sr.crashCount >= 2) {
                     Log.w(TAG, "Service crashed " + sr.crashCount
                             + " times, stopping: " + sr);
+                    EventLog.writeEvent(LOG_AM_SERVICE_CRASHED_TOO_MUCH,
+                            sr.crashCount, sr.shortName, app.pid);
                     bringDownServiceLocked(sr, true);
                 } else if (!allowRestart) {
                     bringDownServiceLocked(sr, true);
@@ -8447,7 +8462,10 @@
 
     private final void removeDyingProviderLocked(ProcessRecord proc,
             ContentProviderRecord cpr) {
-        cpr.launchingApp = null;
+        synchronized (cpr) {
+            cpr.launchingApp = null;
+            cpr.notifyAll();
+        }
         
         mProvidersByClass.remove(cpr.info.name);
         String names[] = cpr.info.authority.split(";");
@@ -8529,6 +8547,8 @@
                             break;
                         }
                     }
+                } else {
+                    i = NL;
                 }
 
                 if (i >= NL) {
@@ -8602,7 +8622,7 @@
         mProcessesOnHold.remove(app);
 
         if (restart) {
-            // We have component that still need to be running in the
+            // We have components that still need to be running in the
             // process, so re-launch it.
             mProcessNames.put(app.processName, app.info.uid, app);
             startProcessLocked(app, "restart", app.processName);
@@ -8952,6 +8972,8 @@
         r.nextRestartTime = SystemClock.uptimeMillis() + r.restartDelay;
         Log.w(TAG, "Scheduling restart of crashed service "
                 + r.shortName + " in " + r.restartDelay + "ms");
+        EventLog.writeEvent(LOG_AM_SCHEDULE_SERVICE_RESTART,
+                r.shortName, r.restartDelay);
 
         Message msg = Message.obtain();
         msg.what = SERVICE_ERROR_MSG;
@@ -11660,7 +11682,7 @@
 
                 // We can finish this one if we have its icicle saved and
                 // it is not persistent.
-                if ((r.haveState || !r.stateNotNeeded)
+                if ((r.haveState || !r.stateNotNeeded) && !r.visible
                         && r.stopped && !r.persistent && !r.finishing) {
                     final int origSize = mLRUActivities.size();
                     destroyActivityLocked(r, true);
diff --git a/services/java/com/android/server/am/UsageStatsService.java b/services/java/com/android/server/am/UsageStatsService.java
index 001987f..3922f39 100755
--- a/services/java/com/android/server/am/UsageStatsService.java
+++ b/services/java/com/android/server/am/UsageStatsService.java
@@ -22,13 +22,24 @@
 import android.os.Binder;
 import android.os.IBinder;
 import com.android.internal.os.PkgUsageStats;
+import android.os.Parcel;
 import android.os.Process;
 import android.os.ServiceManager;
 import android.os.SystemClock;
 import android.util.Log;
+import java.io.File;
 import java.io.FileDescriptor;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
 import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.Calendar;
+import java.util.Collections;
+import java.util.Date;
 import java.util.HashMap;
+import java.util.List;
 import java.util.Map;
 import java.util.Set;
 
@@ -44,35 +55,257 @@
     private static final String TAG = "UsageStats";
     static IUsageStats sService;
     private Context mContext;
-    private String mFileName;
+    // structure used to maintain statistics since the last checkin.
     final private Map<String, PkgUsageStatsExtended> mStats;
+    // Lock to update package stats. Methods suffixed by SLOCK should invoked with
+    // this lock held
+    final Object mStatsLock;
+    // Lock to write to file. Methods suffixed by FLOCK should invoked with
+    // this lock held.
+    final Object mFileLock;
+    // Order of locks is mFileLock followed by mStatsLock to avoid deadlocks
     private String mResumedPkg;
+    private File mFile;
+    //private File mBackupFile;
+    private long mLastWriteRealTime;
+    private int _FILE_WRITE_INTERVAL = 30*60*1000; //ms
+    private static final String _PREFIX_DELIMIT=".";
+    private String mFilePrefix;
+    private Calendar mCal;
+    private static final int  _MAX_NUM_FILES = 10;
+    private long mLastTime;
     
     private class PkgUsageStatsExtended {
         int mLaunchCount;
         long mUsageTime;
-        long mChgTime;
+        long mPausedTime;
+        long mResumedTime;
+        
         PkgUsageStatsExtended() {
             mLaunchCount = 0;
             mUsageTime = 0;
-            mChgTime =  SystemClock.elapsedRealtime();
         }
         void updateResume() {
             mLaunchCount ++;
-            mChgTime = SystemClock.elapsedRealtime();
+            mResumedTime = SystemClock.elapsedRealtime();
         }
         void updatePause() {
-            long currTime = SystemClock.elapsedRealtime();
-            mUsageTime += (currTime - mChgTime);
-            mChgTime = currTime;
+            mPausedTime =  SystemClock.elapsedRealtime();
+            mUsageTime += (mPausedTime - mResumedTime);
+        }
+        void clear() {
+            mLaunchCount = 0;
+            mUsageTime = 0;
         }
     }
     
-    UsageStatsService(String filename) {
-        mFileName = filename;
+    UsageStatsService(String fileName) {
         mStats = new HashMap<String, PkgUsageStatsExtended>();
+        mStatsLock = new Object();
+        mFileLock = new Object();
+        mFilePrefix = fileName;
+        mCal = Calendar.getInstance();
+        // Update current stats which are binned by date
+        String uFileName = getCurrentDateStr(mFilePrefix);
+        mFile = new File(uFileName);
+        readStatsFromFile();
+        mLastWriteRealTime = SystemClock.elapsedRealtime();
+        mLastTime = new Date().getTime();
+    }
+
+    /*
+     * Utility method to convert date into string.
+     */
+    private String getCurrentDateStr(String prefix) {
+        mCal.setTime(new Date());
+        StringBuilder sb = new StringBuilder();
+        if (prefix != null) {
+            sb.append(prefix);
+            sb.append(".");
+        }
+        int mm = mCal.get(Calendar.MONTH) - Calendar.JANUARY +1;
+        if (mm < 10) {
+            sb.append("0");
+        }
+        sb.append(mm);
+        int dd = mCal.get(Calendar.DAY_OF_MONTH);
+        if (dd < 10) {
+            sb.append("0");
+        }
+        sb.append(dd);
+        sb.append(mCal.get(Calendar.YEAR));
+        return sb.toString();
     }
     
+    private Parcel getParcelForFile(File file) throws IOException {
+        FileInputStream stream = new FileInputStream(file);
+        byte[] raw = readFully(stream);
+        Parcel in = Parcel.obtain();
+        in.unmarshall(raw, 0, raw.length);
+        in.setDataPosition(0);
+        stream.close();
+        return in;
+    }
+    
+    private void readStatsFromFile() {
+        File newFile = mFile;
+        synchronized (mFileLock) {
+            try {
+                if (newFile.exists()) {
+                    readStatsFLOCK(newFile);
+                } else {
+                    // Check for file limit before creating a new file
+                    checkFileLimitFLOCK();
+                    newFile.createNewFile();
+                }
+            } catch (IOException e) {
+                Log.w(TAG,"Error : " + e + " reading data from file:" + newFile);
+            }
+        }
+    }
+    
+    private void readStatsFLOCK(File file) throws IOException {
+        Parcel in = getParcelForFile(file);
+        while (in.dataAvail() > 0) {
+            String pkgName = in.readString();
+            PkgUsageStatsExtended pus = new PkgUsageStatsExtended();
+            pus.mLaunchCount = in.readInt();
+            pus.mUsageTime = in.readLong();
+            synchronized (mStatsLock) {
+                mStats.put(pkgName, pus);
+            }
+        }
+    }
+
+    private ArrayList<String> getUsageStatsFileListFLOCK() {
+        File dir = getUsageFilesDir();
+        if (dir == null) {
+            Log.w(TAG, "Couldnt find writable directory for usage stats file");
+            return null;
+        }
+        // Check if there are too many files in the system and delete older files
+        String fList[] = dir.list();
+        if (fList == null) {
+            return null;
+        }
+        File pre = new File(mFilePrefix);
+        String filePrefix = pre.getName();
+        // file name followed by dot
+        int prefixLen = filePrefix.length()+1;
+        ArrayList<String> fileList = new ArrayList<String>();
+        for (String file : fList) {
+            int index = file.indexOf(filePrefix);
+            if (index == -1) {
+                continue;
+            }
+            if (file.endsWith(".bak")) {
+                continue;
+            }
+            fileList.add(file);
+        }
+        return fileList;
+    }
+    
+    private File getUsageFilesDir() {
+        if (mFilePrefix == null) {
+            return null;
+        }
+        File pre = new File(mFilePrefix);
+        return new File(pre.getParent());
+    }
+    
+    private void checkFileLimitFLOCK() {
+        File dir = getUsageFilesDir();
+        if (dir == null) {
+            Log.w(TAG, "Couldnt find writable directory for usage stats file");
+            return;
+        }
+        // Get all usage stats output files
+        ArrayList<String> fileList = getUsageStatsFileListFLOCK();
+        if (fileList == null) {
+            // Strange but we dont have to delete any thing
+            return;
+        }
+        int count = fileList.size();
+        if (count <= _MAX_NUM_FILES) {
+            return;
+        }
+        // Sort files
+        Collections.sort(fileList);
+        count -= _MAX_NUM_FILES;
+        // Delete older files
+        for (int i = 0; i < count; i++) {
+            String fileName = fileList.get(i);
+            File file = new File(dir, fileName);
+            Log.i(TAG, "Deleting file : "+fileName);
+            file.delete();
+        }
+    }
+    
+    private void writeStatsToFile() {
+        synchronized (mFileLock) {
+            long currTime = new Date().getTime();
+            boolean dayChanged =  ((currTime - mLastTime) >= (24*60*60*1000));
+            long currRealTime = SystemClock.elapsedRealtime();
+            if (((currRealTime-mLastWriteRealTime) < _FILE_WRITE_INTERVAL) &&
+                    (!dayChanged)) {
+                // wait till the next update
+                return;
+            }
+            // Get the most recent file
+            String todayStr = getCurrentDateStr(mFilePrefix);
+            // Copy current file to back up
+            File backupFile =  new File(mFile.getPath() + ".bak");
+            mFile.renameTo(backupFile);
+            try {
+                checkFileLimitFLOCK();
+                mFile.createNewFile();
+                // Write mStats to file
+                writeStatsFLOCK();
+                mLastWriteRealTime = currRealTime;
+                mLastTime = currTime;
+                if (dayChanged) {
+                    // clear stats
+                    synchronized (mStats) {
+                        mStats.clear();
+                    }
+                    mFile = new File(todayStr);
+                }
+                // Delete the backup file
+                if (backupFile != null) {
+                    backupFile.delete();
+                }
+            } catch (IOException e) {
+                Log.w(TAG, "Failed writing stats to file:" + mFile);
+                if (backupFile != null) {
+                    backupFile.renameTo(mFile);
+                }
+            }
+        }
+    }
+
+    private void writeStatsFLOCK() throws IOException {
+        FileOutputStream stream = new FileOutputStream(mFile);
+        Parcel out = Parcel.obtain();
+        writeStatsToParcelFLOCK(out);
+        stream.write(out.marshall());
+        out.recycle();
+        stream.flush();
+        stream.close();
+    }
+
+    private void writeStatsToParcelFLOCK(Parcel out) {
+        synchronized (mStatsLock) {
+            Set<String> keys = mStats.keySet();
+            for (String key : keys) {
+                PkgUsageStatsExtended pus = mStats.get(key);
+                out.writeString(key);
+                out.writeInt(pus.mLaunchCount);
+                out.writeLong(pus.mUsageTime);
+            }
+        }
+    }
+
     public void publish(Context context) {
         mContext = context;
         ServiceManager.addService(SERVICE_NAME, asBinder());
@@ -99,12 +332,14 @@
             return;
         } 
         if (localLOGV) Log.i(TAG, "started component:"+pkgName);
-        PkgUsageStatsExtended pus = mStats.get(pkgName);
-        if (pus == null) {
-            pus = new PkgUsageStatsExtended();
-            mStats.put(pkgName, pus);
+        synchronized (mStatsLock) {
+            PkgUsageStatsExtended pus = mStats.get(pkgName);
+            if (pus == null) {
+                pus = new PkgUsageStatsExtended();
+                mStats.put(pkgName, pus);
+            }
+            pus.updateResume();
         }
-        pus.updateResume();
         mResumedPkg = pkgName;
     }
 
@@ -120,13 +355,17 @@
             return;
         }
         if (localLOGV) Log.i(TAG, "paused component:"+pkgName);
-        PkgUsageStatsExtended pus = mStats.get(pkgName);
-        if (pus == null) {
-            // Weird some error here
-            Log.w(TAG, "No package stats for pkg:"+pkgName);
-            return;
+        synchronized (mStatsLock) {
+            PkgUsageStatsExtended pus = mStats.get(pkgName);
+            if (pus == null) {
+                // Weird some error here
+                Log.w(TAG, "No package stats for pkg:"+pkgName);
+                return;
+            }
+            pus.updatePause();
         }
-        pus.updatePause();
+        // Persist data to file
+        writeStatsToFile();
     }
     
     public void enforceCallingPermission() {
@@ -145,17 +384,19 @@
                 ((pkgName = componentName.getPackageName()) == null)) {
             return null;
         }
-        PkgUsageStatsExtended pus = mStats.get(pkgName);
-        if (pus == null) {
-            return null;
+        synchronized (mStatsLock) {
+            PkgUsageStatsExtended pus = mStats.get(pkgName);
+            if (pus == null) {
+               return null;
+            }
+            return new PkgUsageStats(pkgName, pus.mLaunchCount, pus.mUsageTime);
         }
-        return new PkgUsageStats(pkgName, pus.mLaunchCount, pus.mUsageTime);
     }
     
     public PkgUsageStats[] getAllPkgUsageStats() {
         mContext.enforceCallingOrSelfPermission(
                 android.Manifest.permission.PACKAGE_USAGE_STATS, null);
-        synchronized (mStats) {
+        synchronized (mStatsLock) {
             Set<String> keys = mStats.keySet();
             int size = keys.size();
             if (size <= 0) {
@@ -172,21 +413,120 @@
         }
     }
     
-    @Override
-    protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
-        StringBuilder sb = new StringBuilder();
-        synchronized (mStats) {
-            Set<String> keys = mStats.keySet();
-            for (String key: keys) {
-                PkgUsageStatsExtended ps = mStats.get(key);
-                sb.append("pkg="); 
-                sb.append(key);
-                sb.append(", launchCount=");
-                sb.append(ps.mLaunchCount);
-                sb.append(", usageTime=");
-                sb.append(ps.mUsageTime+" ms\n");
+    static byte[] readFully(FileInputStream stream) throws java.io.IOException {
+        int pos = 0;
+        int avail = stream.available();
+        byte[] data = new byte[avail];
+        while (true) {
+            int amt = stream.read(data, pos, data.length-pos);
+            if (amt <= 0) {
+                return data;
             }
+            pos += amt;
+            avail = stream.available();
+            if (avail > data.length-pos) {
+                byte[] newData = new byte[pos+avail];
+                System.arraycopy(data, 0, newData, 0, pos);
+                data = newData;
+            }
+        }
+    }
+    
+    private void collectDumpInfoFLOCK(PrintWriter pw, String[] args) {
+        List<String> fileList = getUsageStatsFileListFLOCK();
+        if (fileList == null) {
+            return;
+        }
+        final boolean isCheckinRequest = scanArgs(args, "-c");
+        Collections.sort(fileList);
+        File usageFile = new File(mFilePrefix);
+        String dirName = usageFile.getParent();
+        File dir = new File(dirName);
+        String filePrefix = usageFile.getName();
+        // file name followed by dot
+        int prefixLen = filePrefix.length()+1;
+        String todayStr = getCurrentDateStr(null);
+        for (String file : fileList) {
+            File dFile = new File(dir, file);
+            String dateStr = file.substring(prefixLen);
+            try {
+                Parcel in = getParcelForFile(dFile);
+                collectDumpInfoFromParcelFLOCK(in, pw, dateStr, isCheckinRequest);
+                if (isCheckinRequest && !todayStr.equalsIgnoreCase(dateStr)) {
+                    // Delete old file after collecting info only for checkin requests
+                    dFile.delete();
+                }
+            } catch (FileNotFoundException e) {
+                Log.w(TAG, "Failed with "+e+" when collecting dump info from file : " + file);
+                return;
+            } catch (IOException e) {
+                Log.w(TAG, "Failed with "+e+" when collecting dump info from file : "+file);
+            }      
+        }
+    }
+    
+    private void collectDumpInfoFromParcelFLOCK(Parcel in, PrintWriter pw,
+            String date, boolean isCheckinRequest) {
+        StringBuilder sb = new StringBuilder();
+        sb.append("Date:");
+        sb.append(date);
+        boolean first = true;
+        while (in.dataAvail() > 0) {
+            String pkgName = in.readString();
+            int launchCount = in.readInt();
+            long usageTime = in.readLong();
+            if (isCheckinRequest) {
+                if (!first) {
+                    sb.append(",");
+                }
+                sb.append(pkgName);
+                sb.append(",");
+                sb.append(launchCount);
+                sb.append(",");
+                sb.append(usageTime);
+                sb.append("ms");
+            } else {
+                if (first) {
+                    sb.append("\n");
+                }
+                sb.append("pkg=");
+                sb.append(pkgName);
+                sb.append(", launchCount=");
+                sb.append(launchCount);
+                sb.append(", usageTime=");
+                sb.append(usageTime);
+                sb.append(" ms\n");
+            }
+            first = false;
         }
         pw.write(sb.toString());
     }
+    
+    /**
+     * Searches array of arguments for the specified string
+     * @param args array of argument strings
+     * @param value value to search for
+     * @return true if the value is contained in the array
+     */
+    private static boolean scanArgs(String[] args, String value) {
+        if (args != null) {
+            for (String arg : args) {
+                if (value.equals(arg)) {
+                    return true;
+                }
+            }
+        }
+        return false;
+    }
+    
+    @Override
+    /*
+     * The data persisted to file is parsed and the stats are computed. 
+     */
+    protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+        synchronized (mFileLock) {
+            collectDumpInfoFLOCK(pw, args);
+        }
+    }
+
 }
diff --git a/tests/AndroidTests/AndroidManifest.xml b/tests/AndroidTests/AndroidManifest.xml
index 230456a..36f7b9b 100644
--- a/tests/AndroidTests/AndroidManifest.xml
+++ b/tests/AndroidTests/AndroidManifest.xml
@@ -44,6 +44,7 @@
     <uses-permission android:name="android.permission.CLEAR_APP_CACHE" />
     <uses-permission android:name="android.permission.CLEAR_APP_USER_DATA" />
     <uses-permission android:name="android.permission.GET_PACKAGE_SIZE" />
+    <uses-permission android:name="android.permission.BLUETOOTH" />
     <uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
     <uses-permission android:name="android.permission.READ_PHONE_STATE" />
     <uses-permission android:name="android.permission.INTERNET" />
diff --git a/tests/AndroidTests/src/com/android/unit_tests/MenuTest.java b/tests/AndroidTests/src/com/android/unit_tests/MenuTest.java
index d184543..c436726 100644
--- a/tests/AndroidTests/src/com/android/unit_tests/MenuTest.java
+++ b/tests/AndroidTests/src/com/android/unit_tests/MenuTest.java
@@ -131,20 +131,7 @@
                                               makeKeyEvent(KeyEvent.KEYCODE_A,
                                                            KeyEvent.META_SYM_ON)));
     }
-
-    @LargeTest
-    public void testIsNotShortcutWithMultipleMetas() throws Exception {
-        mMenu.setQwertyMode(true);
-        mMenu.add(0, 0, 0, "test").setShortcut('2', 'a');
-        Assert.assertFalse(mMenu.isShortcutKey(
-                'a',
-                makeKeyEvent(KeyEvent.KEYCODE_A, KeyEvent.META_SYM_ON & KeyEvent.META_ALT_ON)));
-        Assert.assertFalse(mMenu.isShortcutKey(
-                'a', makeKeyEvent(KeyEvent.KEYCODE_A, KeyEvent.META_SYM_ON)));
-        Assert.assertFalse(mMenu.isShortcutKey(
-                'a', makeKeyEvent(KeyEvent.KEYCODE_A, KeyEvent.META_SHIFT_ON)));
-    }
-
+    
     @SmallTest
     public void testIsShortcutWithUpperCaseAlpha() throws Exception {
         mMenu.setQwertyMode(true);
diff --git a/tests/AndroidTests/src/com/android/unit_tests/TextUtilsTest.java b/tests/AndroidTests/src/com/android/unit_tests/TextUtilsTest.java
index 8c1c91f..51e841c 100644
--- a/tests/AndroidTests/src/com/android/unit_tests/TextUtilsTest.java
+++ b/tests/AndroidTests/src/com/android/unit_tests/TextUtilsTest.java
@@ -262,7 +262,7 @@
         Map<String, String> fixes = Maps.newHashMap();
         fixes.put("a", "<a@gmail.com>");
         fixes.put("a b", "<ab@gmail.com>");
-        fixes.put("a@b", "<a@gmail.com>");
+        fixes.put("a@b", "<a@b>");
         
         for (Map.Entry<String, String> e : fixes.entrySet()) {
             assertEquals(e.getValue(), validator.fixText(e.getKey()).toString());
diff --git a/tests/DumpRenderTree/compare_layout_results.py b/tests/DumpRenderTree/compare_layout_results.py
index 4383dbb..c4285f1 100644
--- a/tests/DumpRenderTree/compare_layout_results.py
+++ b/tests/DumpRenderTree/compare_layout_results.py
@@ -6,6 +6,7 @@
 
 import optparse
 import os
+import sys
 
 def DiffResults(marker, new_results, old_results, diff_results, strip_reason):
    """ Given two result files, generate diff and
@@ -45,7 +46,7 @@
        diff_file.writelines("- " + line)
        missing_count += 1
 
-   print marker + "  >>> New = " + str(new_count) + " , Missing = " + str(missing_count) 
+   print marker + "  >>> added " + str(new_count) + " tests, removed " + str(missing_count) + " tests" 
 
    diff_file.writelines("\n\n")
 
@@ -55,24 +56,32 @@
    return
 
 def main(options, args):
-  results_dir = options.results_directory
+  results_dir = os.path.abspath(options.results_directory)
   ref_dir = options.ref_directory
-  if os.path.exists(results_dir + "/layout_tests_diff.txt"):
-    os.remove(results_dir + "/layout_tests_diff.txt")
 
-  files=["passed", "nontext", "crashed"]
+  # if ref_dir is null, cannonify ref_dir to the script dir.
+  if not ref_dir:
+    script_self = sys.argv[0]
+    script_dir = os.path.dirname(script_self)
+    ref_dir = os.path.join(script_dir, "results")
+
+  ref_dir = os.path.abspath(ref_dir)
+
+  diff_result = os.path.join(results_dir, "layout_tests_diff.txt") 
+  if os.path.exists(diff_result):
+    os.remove(diff_result)
+
+  files=["passed", "failed", "nontext", "crashed"]
   for f in files:
-    DiffResults(f, results_dir + "layout_tests_" + f + ".txt",
-              ref_dir + "layout_tests_" + f + ".txt", results_dir + "layout_tests_diff.txt", False)
-
-  for f in ["failed"]:
-    DiffResults(f, results_dir + "layout_tests_" + f + ".txt",
-              ref_dir + "layout_tests_" + f + ".txt", results_dir + "layout_tests_diff.txt", True)
+    result_file_name = "layout_tests_" + f + ".txt"
+    DiffResults(f, os.path.join(results_dir, result_file_name),
+                os.path.join(ref_dir, result_file_name), diff_result,
+                f == "failed")
 
 if '__main__' == __name__:
   option_parser = optparse.OptionParser()
   option_parser.add_option("", "--ref-directory",
-                           default="results/",
+                           default=None,
                            dest="ref_directory",
                            help="directory name under which results are stored.")
 
diff --git a/tests/DumpRenderTree/run_layout_tests.py b/tests/DumpRenderTree/run_layout_tests.py
index b4eb685..433271e 100755
--- a/tests/DumpRenderTree/run_layout_tests.py
+++ b/tests/DumpRenderTree/run_layout_tests.py
@@ -48,6 +48,86 @@
   fp.close()
   return lines
 
+def DumpRenderTreeFinished(adb_cmd):
+  """ Check if DumpRenderTree finished running tests
+  
+  Args:
+    output: adb_cmd string
+  """
+  
+  # pull /sdcard/running_test.txt, if the content is "#DONE", it's done
+  shell_cmd_str = adb_cmd + " shell cat /sdcard/running_test.txt"
+  adb_output = subprocess.Popen(shell_cmd_str, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE).communicate()[0]
+  return adb_output.strip() == "#DONE"
+
+def DiffResults(marker, new_results, old_results, diff_results, strip_reason):
+   """ Given two result files, generate diff and
+       write to diff_results file. All arguments are absolute paths
+       to files.
+   """
+   old_file = open(old_results, "r")
+   new_file = open(new_results, "r")
+   diff_file = open(diff_results, "a") 
+
+   # Read lines from each file
+   ndict = new_file.readlines()
+   cdict = old_file.readlines()
+
+   # Write marker to diff file
+   diff_file.writelines(marker + "\n")
+   diff_file.writelines("###############\n")
+
+   # Strip reason from result lines
+   if strip_reason is True:
+     for i in range(0, len(ndict)):
+       ndict[i] = ndict[i].split(' ')[0] + "\n"
+     for i in range(0, len(cdict)):
+       cdict[i] = cdict[i].split(' ')[0] + "\n"
+
+   # Find results in new_results missing in old_results
+   new_count=0
+   for line in ndict:
+     if line not in cdict:
+       diff_file.writelines("+ " + line)
+       new_count += 1
+
+   # Find results in old_results missing in new_results
+   missing_count=0
+   for line in cdict:
+     if line not in ndict:
+       diff_file.writelines("- " + line)
+       missing_count += 1
+
+   logging.info(marker + "  >>> " + str(new_count) + " new, " + str(missing_count) + " misses")
+
+   diff_file.writelines("\n\n")
+
+   old_file.close()
+   new_file.close()
+   diff_file.close()
+   return
+
+def CompareResults(ref_dir, results_dir):
+  """Compare results in two directories
+
+  Args:
+    ref_dir: the reference directory having layout results as references
+    results_dir: the results directory
+  """
+  logging.info("Comparing results to " + ref_dir)
+
+  diff_result = os.path.join(results_dir, "layout_tests_diff.txt") 
+  if os.path.exists(diff_result):
+    os.remove(diff_result)
+
+  files=["passed", "failed", "nontext", "crashed"]
+  for f in files:
+    result_file_name = "layout_tests_" + f + ".txt"
+    DiffResults(f, os.path.join(results_dir, result_file_name),
+                os.path.join(ref_dir, result_file_name), diff_result,
+                f == "failed")
+  logging.info("Detailed diffs are in " + diff_result)
+
 def main(options, args):
   """Run the tests. Will call sys.exit when complete.
   
@@ -84,7 +164,7 @@
        sys.exit(1)
 
 
-  logging.info("Starting tests")
+  logging.info("Running tests")
 
   # Count crashed tests.
   crashed_tests = []
@@ -98,7 +178,7 @@
   # Call LayoutTestsAutoTest::startLayoutTests.
   shell_cmd_str = adb_cmd + " shell am instrument -e class com.android.dumprendertree.LayoutTestsAutoTest#startLayoutTests -e path \"" + path + "\" -e timeout " + timeout_ms + " -w com.android.dumprendertree/.LayoutTestsAutoRunner"
   adb_output = subprocess.Popen(shell_cmd_str, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE).communicate()[0]
-  while adb_output.find('Process crashed') != -1:
+  while not DumpRenderTreeFinished(adb_cmd):
     # Get the running_test.txt
     logging.error("DumpRenderTree crashed, output:\n" + adb_output)
 
@@ -118,8 +198,8 @@
     logging.error("Error happened : " + adb_output)
     sys.exit(1)
 
-  logging.info("Done");
   logging.debug(adb_output);
+  logging.info("Done\n");
 
   # Pull results from /sdcard
   results_dir = options.results_directory
@@ -152,8 +232,21 @@
   nontext_tests = CountLineNumber(results_dir + "/layout_tests_nontext.txt")
   logging.info(str(nontext_tests) + " no dumpAsText")
 
-  logging.info("Results are stored under: " + results_dir)
+  logging.info("Results are stored under: " + results_dir + "\n")
 
+  # Comparing results to references to find new fixes and regressions.
+  results_dir = os.path.abspath(options.results_directory)
+  ref_dir = options.ref_directory
+
+  # if ref_dir is null, cannonify ref_dir to the script dir.
+  if not ref_dir:
+    script_self = sys.argv[0]
+    script_dir = os.path.dirname(script_self)
+    ref_dir = os.path.join(script_dir, "results")
+
+  ref_dir = os.path.abspath(ref_dir)
+
+  CompareResults(ref_dir, results_dir)
 
 if '__main__' == __name__:
   option_parser = optparse.OptionParser()
@@ -171,6 +264,11 @@
                            help="pass options to adb, such as -d -e, etc");
   option_parser.add_option("", "--results-directory",
                            default="layout-test-results",
-                           help="directory name under which results are stored.")
+                           help="directory which results are stored.")
+  option_parser.add_option("", "--ref-directory",
+                           default=None,
+                           dest="ref_directory",
+                           help="directory where reference results are stored.")
+
   options, args = option_parser.parse_args();
   main(options, args)
diff --git a/tests/DumpRenderTree/src/com/android/dumprendertree/HTMLHostActivity.java b/tests/DumpRenderTree/src/com/android/dumprendertree/HTMLHostActivity.java
index c77d98a..86bfad7 100644
--- a/tests/DumpRenderTree/src/com/android/dumprendertree/HTMLHostActivity.java
+++ b/tests/DumpRenderTree/src/com/android/dumprendertree/HTMLHostActivity.java
@@ -68,9 +68,12 @@
       }
     }
 
-    public void nontext(String layout_file) {
+    public void nontext(String layout_file, boolean has_results) {
       try {
           mBufferedOutputNontextStream.write(layout_file.getBytes());
+          if (has_results) {
+              mBufferedOutputNontextStream.write(" : has expected results".getBytes());
+          }
           mBufferedOutputNontextStream.write('\n');
           mBufferedOutputNontextStream.flush();
       } catch(Exception e) {
@@ -299,6 +302,9 @@
         resetTestStatus();
 
         if (testIndex == mTestList.size()) {
+            if (!mSingleTestMode) {
+                updateTestStatus("#DONE");
+            }
             finished();
             return;
         }
@@ -385,9 +391,9 @@
         }
     }
 
-    public void nontextCase(String file) {
+    public void nontextCase(String file, boolean has_expected_results) {
         Log.v("Layout test:", file + " nontext");
-        mResultRecorder.nontext(file);
+        mResultRecorder.nontext(file, has_expected_results);
     }
  
     public void setCallback(HTMLHostCallbackInterface callback) {
@@ -447,8 +453,11 @@
         }
         
         File nontext_result = new File(short_file + "-android-results.txt");
-        if (nontext_result.exists())
-            mResultRecorder.nontext(test_path);
+        if (nontext_result.exists()) {
+            // Check if the test has expected results.
+            File expected = new File(short_file + "-expected.txt");
+            nontextCase(test_path, expected.exists());
+        }
     }
     
     public void finished() {
diff --git a/tests/ImfTest/AndroidManifest.xml b/tests/ImfTest/AndroidManifest.xml
index 627ee6dc..55e5d38 100755
--- a/tests/ImfTest/AndroidManifest.xml
+++ b/tests/ImfTest/AndroidManifest.xml
@@ -19,7 +19,7 @@
             </intent-filter>
         </activity>
         
-        <activity android:name=".samples.AppAdjustmentBigEditTextNonScrollablePanScan" android:label="Big ET !Scroll Pan/Scan">
+        <activity android:name=".samples.BigEditTextActivityNonScrollablePanScan" android:label="Big ET !Scroll Pan/Scan">
             <intent-filter>
                 <action android:name="android.intent.action.MAIN"/>
                 <category android:name="android.intent.category.LAUNCHER" />
@@ -35,7 +35,7 @@
             </intent-filter>
         </activity>
         
-        <activity android:name=".samples.AppAdjustmentBigEditTextNonScrollableResize" android:label="Big ET !Scroll Resize">
+        <activity android:name=".samples.BigEditTextActivityNonScrollableResize" android:label="Big ET !Scroll Resize">
             <intent-filter>
                 <action android:name="android.intent.action.MAIN"/>
                 <category android:name="android.intent.category.LAUNCHER" />
@@ -43,7 +43,7 @@
             </intent-filter>
         </activity>
         
-        <activity android:name=".samples.AppAdjustmentBigEditTextScrollablePanScan" android:label="Big ET Scroll Pan/Scan">
+        <activity android:name=".samples.BigEditTextActivityScrollablePanScan" android:label="Big ET Scroll Pan/Scan">
             <intent-filter>
                 <action android:name="android.intent.action.MAIN"/>
                 <category android:name="android.intent.category.LAUNCHER" />
@@ -51,7 +51,7 @@
             </intent-filter>
         </activity>
         
-        <activity android:name=".samples.AppAdjustmentBigEditTextScrollableResize" android:label="Big ET Scroll Resize">
+        <activity android:name=".samples.BigEditTextActivityScrollableResize" android:label="Big ET Scroll Resize">
             <intent-filter>
                 <action android:name="android.intent.action.MAIN"/>
                 <category android:name="android.intent.category.LAUNCHER" />
@@ -59,7 +59,7 @@
             </intent-filter>
         </activity>
 
-        <activity android:name=".samples.AppAdjustmentEditTextDialog" android:label="ET Dialog">
+        <activity android:name=".samples.EditTextActivityDialog" android:label="ET Dialog">
             <intent-filter>
                 <action android:name="android.intent.action.MAIN"/>
                 <category android:name="android.intent.category.LAUNCHER" />
@@ -130,14 +130,6 @@
                 <category android:name="android.intent.category.IMF_TEST" />
             </intent-filter>
         </activity>   
-          
-        <activity android:name=".samples.OneEditTextActivityLandscape" android:label="OneEditTextActivityLandscape" android:screenOrientation="landscape">
-            <intent-filter>
-                <action android:name="android.intent.action.MAIN"/>
-                <category android:name="android.intent.category.LAUNCHER" />
-                <category android:name="android.intent.category.IMF_TEST" />
-            </intent-filter>
-        </activity>  
         
         <activity android:name=".samples.DialogActivity" android:label="DialogActivity" android:screenOrientation="portrait">
             <intent-filter>
diff --git a/core/java/android/gadget/GadgetInfo.aidl b/tests/ImfTest/res/values/config.xml
similarity index 74%
copy from core/java/android/gadget/GadgetInfo.aidl
copy to tests/ImfTest/res/values/config.xml
index 7231545..5ae40a3 100644
--- a/core/java/android/gadget/GadgetInfo.aidl
+++ b/tests/ImfTest/res/values/config.xml
@@ -1,5 +1,7 @@
-/*
- * Copyright (c) 2007, The Android Open Source Project
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/**
+ * Copyright (c) 2009, The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License"); 
  * you may not use this file except in compliance with the License. 
@@ -13,7 +15,7 @@
  * See the License for the specific language governing permissions and 
  * limitations under the License.
  */
-
-package android.gadget;
-
-parcelable GadgetInfo;
+-->
+<resources>
+    <bool name="def_expect_ime_autopop">false</bool>
+</resources>
diff --git a/tests/ImfTest/src/com/android/imftest/samples/AppAdjustmentBigEditTextNonScrollablePanScan.java b/tests/ImfTest/src/com/android/imftest/samples/AppAdjustmentBigEditTextNonScrollablePanScan.java
deleted file mode 100644
index 15a29c8..0000000
--- a/tests/ImfTest/src/com/android/imftest/samples/AppAdjustmentBigEditTextNonScrollablePanScan.java
+++ /dev/null
@@ -1,35 +0,0 @@
-package com.android.imftest.samples;
-
-import com.android.imftest.R;
-
-import android.app.Activity;
-import android.os.Bundle;
-import android.view.ViewGroup;
-import android.view.WindowManager;
-import android.widget.EditText;
-import android.widget.LinearLayout;
-
-public class AppAdjustmentBigEditTextNonScrollablePanScan extends Activity {
-    
-    private LinearLayout mLayout;
-    
-    @Override
-    protected void onCreate(Bundle icicle) {
-        super.onCreate(icicle);
-        
-        getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_PAN);
-        
-        mLayout = new LinearLayout(this);
-        mLayout.setOrientation(LinearLayout.VERTICAL);
-        mLayout.setLayoutParams(new ViewGroup.LayoutParams(
-                ViewGroup.LayoutParams.FILL_PARENT,
-                ViewGroup.LayoutParams.FILL_PARENT));
-        
-        EditText editText = (EditText) getLayoutInflater().inflate(R.layout.full_screen_edit_text, mLayout, false);
-        
-        mLayout.addView(editText);
-        
-        setContentView(mLayout);
-    }
-
-}
diff --git a/tests/ImfTest/src/com/android/imftest/samples/AppAdjustmentBigEditTextNonScrollableResize.java b/tests/ImfTest/src/com/android/imftest/samples/AppAdjustmentBigEditTextNonScrollableResize.java
deleted file mode 100644
index 0726823..0000000
--- a/tests/ImfTest/src/com/android/imftest/samples/AppAdjustmentBigEditTextNonScrollableResize.java
+++ /dev/null
@@ -1,35 +0,0 @@
-package com.android.imftest.samples;
-
-import com.android.imftest.R;
-
-import android.app.Activity;
-import android.os.Bundle;
-import android.view.ViewGroup;
-import android.view.WindowManager;
-import android.widget.EditText;
-import android.widget.LinearLayout;
-
-public class AppAdjustmentBigEditTextNonScrollableResize extends Activity {
-    
-    private LinearLayout mLayout;
-    
-    @Override
-    protected void onCreate(Bundle icicle) {
-        super.onCreate(icicle);
-        
-        getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE);
-        
-        mLayout = new LinearLayout(this);
-        mLayout.setOrientation(LinearLayout.VERTICAL);
-        mLayout.setLayoutParams(new ViewGroup.LayoutParams(
-                ViewGroup.LayoutParams.FILL_PARENT,
-                ViewGroup.LayoutParams.FILL_PARENT));
-        
-        EditText editText = (EditText) getLayoutInflater().inflate(R.layout.full_screen_edit_text, mLayout, false);
-        
-        mLayout.addView(editText);
-        
-        setContentView(mLayout);
-    }
-
-}
diff --git a/tests/ImfTest/src/com/android/imftest/samples/AppAdjustmentBigEditTextScrollablePanScan.java b/tests/ImfTest/src/com/android/imftest/samples/AppAdjustmentBigEditTextScrollablePanScan.java
deleted file mode 100644
index 50a980b..0000000
--- a/tests/ImfTest/src/com/android/imftest/samples/AppAdjustmentBigEditTextScrollablePanScan.java
+++ /dev/null
@@ -1,44 +0,0 @@
-package com.android.imftest.samples;
-
-import com.android.imftest.R;
-
-import android.app.Activity;
-import android.os.Bundle;
-import android.view.ViewGroup;
-import android.view.WindowManager;
-import android.widget.EditText;
-import android.widget.LinearLayout;
-import android.widget.ScrollView;
-
-public class AppAdjustmentBigEditTextScrollablePanScan extends Activity {
-    
-    private ScrollView mScrollView;
-    private LinearLayout mLayout;
-    
-    @Override
-    protected void onCreate(Bundle icicle) {
-        super.onCreate(icicle);
-        
-        getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_PAN);
-        
-        mScrollView = new ScrollView(this);
-        mScrollView.setFillViewport(true);
-        mScrollView.setLayoutParams(new ViewGroup.LayoutParams(
-                ViewGroup.LayoutParams.FILL_PARENT,
-                ViewGroup.LayoutParams.FILL_PARENT));
-        
-        mLayout = new LinearLayout(this);
-        mLayout.setOrientation(LinearLayout.VERTICAL);
-        mLayout.setLayoutParams(new ViewGroup.LayoutParams(
-                ViewGroup.LayoutParams.FILL_PARENT,
-                ViewGroup.LayoutParams.FILL_PARENT));
-        
-        EditText editText = (EditText) getLayoutInflater().inflate(R.layout.full_screen_edit_text, mScrollView, false);
-        
-        mLayout.addView(editText);
-        mScrollView.addView(mLayout);
-        
-        setContentView(mScrollView);
-    }
-
-}
diff --git a/tests/ImfTest/src/com/android/imftest/samples/AppAdjustmentBigEditTextScrollableResize.java b/tests/ImfTest/src/com/android/imftest/samples/AppAdjustmentBigEditTextScrollableResize.java
deleted file mode 100644
index a256878..0000000
--- a/tests/ImfTest/src/com/android/imftest/samples/AppAdjustmentBigEditTextScrollableResize.java
+++ /dev/null
@@ -1,44 +0,0 @@
-package com.android.imftest.samples;
-
-import com.android.imftest.R;
-
-import android.app.Activity;
-import android.os.Bundle;
-import android.view.ViewGroup;
-import android.view.WindowManager;
-import android.widget.EditText;
-import android.widget.LinearLayout;
-import android.widget.ScrollView;
-
-public class AppAdjustmentBigEditTextScrollableResize extends Activity {
-    
-    private ScrollView mScrollView;
-    private LinearLayout mLayout;
-    
-    @Override
-    protected void onCreate(Bundle icicle) {
-        super.onCreate(icicle);
-        
-        getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE);
-        
-        mScrollView = new ScrollView(this);
-        mScrollView.setFillViewport(true);
-        mScrollView.setLayoutParams(new ViewGroup.LayoutParams(
-                ViewGroup.LayoutParams.FILL_PARENT,
-                ViewGroup.LayoutParams.FILL_PARENT));
-        
-        mLayout = new LinearLayout(this);
-        mLayout.setOrientation(LinearLayout.VERTICAL);
-        mLayout.setLayoutParams(new ViewGroup.LayoutParams(
-                ViewGroup.LayoutParams.FILL_PARENT,
-                ViewGroup.LayoutParams.FILL_PARENT));
-        
-        EditText editText = (EditText) getLayoutInflater().inflate(R.layout.full_screen_edit_text, mScrollView, false);
-        
-        mLayout.addView(editText);
-        mScrollView.addView(mLayout);
-        
-        setContentView(mScrollView);
-    }
-
-}
diff --git a/tests/ImfTest/src/com/android/imftest/samples/BigEditTextActivityNonScrollablePanScan.java b/tests/ImfTest/src/com/android/imftest/samples/BigEditTextActivityNonScrollablePanScan.java
new file mode 100644
index 0000000..9754381
--- /dev/null
+++ b/tests/ImfTest/src/com/android/imftest/samples/BigEditTextActivityNonScrollablePanScan.java
@@ -0,0 +1,49 @@
+package com.android.imftest.samples;
+
+import com.android.imftest.R;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.WindowManager;
+import android.widget.EditText;
+import android.widget.LinearLayout;
+import android.widget.ScrollView;
+
+public class BigEditTextActivityNonScrollablePanScan extends Activity {
+    
+    private View mRootView;
+    private View mDefaultFocusedView;
+    
+    @Override
+    protected void onCreate(Bundle icicle) {
+        super.onCreate(icicle);
+        
+        getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_PAN);
+        
+        mRootView = new LinearLayout(this);
+        ((LinearLayout) mRootView).setOrientation(LinearLayout.VERTICAL);
+        mRootView.setLayoutParams(new ViewGroup.LayoutParams(
+                ViewGroup.LayoutParams.FILL_PARENT,
+                ViewGroup.LayoutParams.FILL_PARENT));
+        
+        View view = getLayoutInflater().inflate(
+                R.layout.full_screen_edit_text, ((LinearLayout) mRootView), false);
+        
+        ((LinearLayout) mRootView).addView(view);
+        
+        mDefaultFocusedView = view.findViewById(R.id.data);
+        
+        setContentView(mRootView);
+    }
+
+    public View getRootView() {
+        return mRootView;
+    }
+    
+    public View getDefaultFocusedView() {
+        return mDefaultFocusedView;
+    }
+
+}
diff --git a/tests/ImfTest/src/com/android/imftest/samples/BigEditTextActivityNonScrollableResize.java b/tests/ImfTest/src/com/android/imftest/samples/BigEditTextActivityNonScrollableResize.java
new file mode 100644
index 0000000..701795f
--- /dev/null
+++ b/tests/ImfTest/src/com/android/imftest/samples/BigEditTextActivityNonScrollableResize.java
@@ -0,0 +1,49 @@
+package com.android.imftest.samples;
+
+import com.android.imftest.R;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.WindowManager;
+import android.widget.EditText;
+import android.widget.LinearLayout;
+import android.widget.ScrollView;
+
+public class BigEditTextActivityNonScrollableResize extends Activity {
+    
+    private View mRootView;
+    private View mDefaultFocusedView;
+    
+    @Override
+    protected void onCreate(Bundle icicle) {
+        super.onCreate(icicle);
+        
+        getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE);
+        
+        mRootView = new LinearLayout(this);
+        ((LinearLayout) mRootView).setOrientation(LinearLayout.VERTICAL);
+        mRootView.setLayoutParams(new ViewGroup.LayoutParams(
+                ViewGroup.LayoutParams.FILL_PARENT,
+                ViewGroup.LayoutParams.FILL_PARENT));
+        
+        View view = getLayoutInflater().inflate(
+                R.layout.full_screen_edit_text, ((LinearLayout) mRootView), false);
+        
+        ((LinearLayout) mRootView).addView(view);
+        
+        mDefaultFocusedView = view.findViewById(R.id.data);
+        
+        setContentView(mRootView);
+    }
+
+    public View getRootView() {
+        return mRootView;
+    }
+    
+    public View getDefaultFocusedView() {
+        return mDefaultFocusedView;
+    }
+
+}
diff --git a/tests/ImfTest/src/com/android/imftest/samples/BigEditTextActivityScrollablePanScan.java b/tests/ImfTest/src/com/android/imftest/samples/BigEditTextActivityScrollablePanScan.java
new file mode 100644
index 0000000..bb3f767
--- /dev/null
+++ b/tests/ImfTest/src/com/android/imftest/samples/BigEditTextActivityScrollablePanScan.java
@@ -0,0 +1,57 @@
+package com.android.imftest.samples;
+
+import com.android.imftest.R;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.WindowManager;
+import android.widget.EditText;
+import android.widget.LinearLayout;
+import android.widget.ScrollView;
+
+public class BigEditTextActivityScrollablePanScan extends Activity {
+    
+    private View mRootView;
+    private View mDefaultFocusedView;
+    private LinearLayout mLayout;
+    
+    @Override
+    protected void onCreate(Bundle icicle) {
+        super.onCreate(icicle);
+        
+        getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_PAN);
+        
+        mRootView = new ScrollView(this);
+        ((ScrollView) mRootView).setFillViewport(true);
+        mRootView.setLayoutParams(new ViewGroup.LayoutParams(
+                ViewGroup.LayoutParams.FILL_PARENT,
+                ViewGroup.LayoutParams.FILL_PARENT));
+        
+        mLayout = new LinearLayout(this);
+        mLayout.setOrientation(LinearLayout.VERTICAL);
+        mLayout.setLayoutParams(new ViewGroup.LayoutParams(
+                ViewGroup.LayoutParams.FILL_PARENT,
+                ViewGroup.LayoutParams.FILL_PARENT));
+        
+        View view = getLayoutInflater().inflate(
+                R.layout.full_screen_edit_text, ((ScrollView) mRootView), false);
+        
+        mLayout.addView(view);
+        
+        ((ScrollView) mRootView).addView(mLayout);
+        mDefaultFocusedView = view.findViewById(R.id.data);
+        
+        setContentView(mRootView);
+    }
+
+    public View getRootView() {
+        return mRootView;
+    }
+    
+    public View getDefaultFocusedView() {
+        return mDefaultFocusedView;
+    }
+
+}
diff --git a/tests/ImfTest/src/com/android/imftest/samples/BigEditTextActivityScrollableResize.java b/tests/ImfTest/src/com/android/imftest/samples/BigEditTextActivityScrollableResize.java
new file mode 100644
index 0000000..f2cae1c
--- /dev/null
+++ b/tests/ImfTest/src/com/android/imftest/samples/BigEditTextActivityScrollableResize.java
@@ -0,0 +1,57 @@
+package com.android.imftest.samples;
+
+import com.android.imftest.R;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.WindowManager;
+import android.widget.EditText;
+import android.widget.LinearLayout;
+import android.widget.ScrollView;
+
+public class BigEditTextActivityScrollableResize extends Activity {
+    
+    private View mRootView;
+    private View mDefaultFocusedView;
+    private LinearLayout mLayout;
+    
+    @Override
+    protected void onCreate(Bundle icicle) {
+        super.onCreate(icicle);
+        
+        getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE);
+        
+        mRootView = new ScrollView(this);
+        ((ScrollView) mRootView).setFillViewport(true);
+        mRootView.setLayoutParams(new ViewGroup.LayoutParams(
+                ViewGroup.LayoutParams.FILL_PARENT,
+                ViewGroup.LayoutParams.FILL_PARENT));
+        
+        mLayout = new LinearLayout(this);
+        mLayout.setOrientation(LinearLayout.VERTICAL);
+        mLayout.setLayoutParams(new ViewGroup.LayoutParams(
+                ViewGroup.LayoutParams.FILL_PARENT,
+                ViewGroup.LayoutParams.FILL_PARENT));
+        
+        View view = getLayoutInflater().inflate(
+                R.layout.full_screen_edit_text, ((ScrollView) mRootView), false);
+        
+        mLayout.addView(view);
+        
+        ((ScrollView) mRootView).addView(mLayout);
+        mDefaultFocusedView = view.findViewById(R.id.data);
+        
+        setContentView(mRootView);
+    }
+
+    public View getRootView() {
+        return mRootView;
+    }
+    
+    public View getDefaultFocusedView() {
+        return mDefaultFocusedView;
+    }
+
+}
diff --git a/tests/ImfTest/src/com/android/imftest/samples/BottomEditTextActivityPanScan.java b/tests/ImfTest/src/com/android/imftest/samples/BottomEditTextActivityPanScan.java
index d74b9dd..51f5045 100644
--- a/tests/ImfTest/src/com/android/imftest/samples/BottomEditTextActivityPanScan.java
+++ b/tests/ImfTest/src/com/android/imftest/samples/BottomEditTextActivityPanScan.java
@@ -17,21 +17,30 @@
  */
 public class BottomEditTextActivityPanScan extends Activity 
 {
-    private LayoutInflater mInflater;
+    private View mRootView;
+    private View mDefaultFocusedView;
+    
     @Override
     public void onCreate(Bundle savedInstanceState) 
     {
         super.onCreate(savedInstanceState);
         
-        LinearLayout layout = new LinearLayout(this);
-        layout.setOrientation(LinearLayout.VERTICAL);
+        mRootView = new LinearLayout(this);
+        ((LinearLayout) mRootView).setOrientation(LinearLayout.VERTICAL);
         
-        mInflater = getLayoutInflater();
-        
-        View view = mInflater.inflate(R.layout.one_edit_text_activity, layout, false);
-        layout.addView(view);
+        View view = getLayoutInflater().inflate(R.layout.one_edit_text_activity, ((LinearLayout) mRootView), false);
+        mDefaultFocusedView = view.findViewById(R.id.dialog_edit_text);
+        ((LinearLayout) mRootView).addView(view);
        
-        setContentView(layout);
+        setContentView(mRootView);
         this.getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_PAN);
     }  
+
+    public View getRootView() {
+        return mRootView;
+    }
+    
+    public View getDefaultFocusedView() {
+        return mDefaultFocusedView;
+    }
 }
\ No newline at end of file
diff --git a/tests/ImfTest/src/com/android/imftest/samples/BottomEditTextActivityResize.java b/tests/ImfTest/src/com/android/imftest/samples/BottomEditTextActivityResize.java
index 82da29a..eb94b4f 100644
--- a/tests/ImfTest/src/com/android/imftest/samples/BottomEditTextActivityResize.java
+++ b/tests/ImfTest/src/com/android/imftest/samples/BottomEditTextActivityResize.java
@@ -17,21 +17,30 @@
  */
 public class BottomEditTextActivityResize extends Activity 
 {
-    private LayoutInflater mInflater;
+    private View mRootView;
+    private View mDefaultFocusedView;
+    
     @Override
     public void onCreate(Bundle savedInstanceState) 
     {
         super.onCreate(savedInstanceState);
         
-        LinearLayout layout = new LinearLayout(this);
-        layout.setOrientation(LinearLayout.VERTICAL);
+        mRootView = new LinearLayout(this);
+        ((LinearLayout) mRootView).setOrientation(LinearLayout.VERTICAL);
         
-        mInflater = getLayoutInflater();
-        
-        View view = mInflater.inflate(R.layout.one_edit_text_activity, layout, false);
-        layout.addView(view);
+        View view = getLayoutInflater().inflate(R.layout.one_edit_text_activity, ((LinearLayout) mRootView), false);
+        mDefaultFocusedView = view.findViewById(R.id.dialog_edit_text);
+        ((LinearLayout) mRootView).addView(view);
        
-        setContentView(layout);
+        setContentView(mRootView);
         this.getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE);
     }  
+
+    public View getRootView() {
+        return mRootView;
+    }
+    
+    public View getDefaultFocusedView() {
+        return mDefaultFocusedView;
+    }
 }
\ No newline at end of file
diff --git a/tests/ImfTest/src/com/android/imftest/samples/ButtonActivity.java b/tests/ImfTest/src/com/android/imftest/samples/ButtonActivity.java
index 4233811..1191f19 100644
--- a/tests/ImfTest/src/com/android/imftest/samples/ButtonActivity.java
+++ b/tests/ImfTest/src/com/android/imftest/samples/ButtonActivity.java
@@ -13,6 +13,8 @@
 public class ButtonActivity extends Activity 
 {
     static boolean mKeyboardIsActive = false;
+    public static final int BUTTON_ID = 0;
+    private View mRootView;
     
     @Override
     public void onCreate(Bundle savedInstanceState) 
@@ -23,6 +25,8 @@
         final Button myButton = new Button(this);
         myButton.setClickable(true);
         myButton.setText("Keyboard UP!");
+        myButton.setId(BUTTON_ID);
+        myButton.setFocusableInTouchMode(true);
         myButton.setOnClickListener(new View.OnClickListener()
         {
             public void onClick (View v)
@@ -36,7 +40,8 @@
                 }
                 else
                 {
-                    imm.showSoftInput(null, 0);
+                    myButton.requestFocusFromTouch();
+                    imm.showSoftInput(v, 0);
                     myButton.setText("Keyboard DOWN!");
                 }
                
@@ -48,5 +53,10 @@
        layout.setOrientation(LinearLayout.VERTICAL);
        layout.addView(myButton);
        setContentView(layout);
+       mRootView = layout;
+    }
+    
+    public View getRootView() {
+        return mRootView;
     }
 }
diff --git a/tests/ImfTest/src/com/android/imftest/samples/AppAdjustmentEditTextDialog.java b/tests/ImfTest/src/com/android/imftest/samples/EditTextActivityDialog.java
similarity index 88%
rename from tests/ImfTest/src/com/android/imftest/samples/AppAdjustmentEditTextDialog.java
rename to tests/ImfTest/src/com/android/imftest/samples/EditTextActivityDialog.java
index e82f1d5..bd1e934 100644
--- a/tests/ImfTest/src/com/android/imftest/samples/AppAdjustmentEditTextDialog.java
+++ b/tests/ImfTest/src/com/android/imftest/samples/EditTextActivityDialog.java
@@ -14,7 +14,7 @@
 import android.widget.LinearLayout;
 import android.widget.ScrollView;
 
-public class AppAdjustmentEditTextDialog extends Activity {
+public class EditTextActivityDialog extends Activity {
     
     private static final int SCROLLABLE_DIALOG_ID = 0;
     private static final int NONSCROLLABLE_DIALOG_ID = 1;
@@ -75,18 +75,18 @@
         EditText editText;
         
         if (scrollable) {
-            layout = new ScrollView(AppAdjustmentEditTextDialog.this);
+            layout = new ScrollView(EditTextActivityDialog.this);
             ((ScrollView) layout).setMinimumHeight(mLayout.getHeight());
             
             ((ScrollView) layout).addView((
-                    LinearLayout) View.inflate(AppAdjustmentEditTextDialog.this, 
+                    LinearLayout) View.inflate(EditTextActivityDialog.this, 
                     R.layout.dialog_edit_text_no_scroll, null));
         } else {
-            layout = View.inflate(AppAdjustmentEditTextDialog.this, 
+            layout = View.inflate(EditTextActivityDialog.this, 
                     R.layout.dialog_edit_text_no_scroll, null);
         }
         
-        Dialog d = new Dialog(AppAdjustmentEditTextDialog.this);
+        Dialog d = new Dialog(EditTextActivityDialog.this);
         d.setTitle(getString(R.string.test_dialog));
         d.setCancelable(true);
         d.setContentView(layout);
diff --git a/tests/ImfTest/src/com/android/imftest/samples/EditTextActivityNoScrollPanScan.java b/tests/ImfTest/src/com/android/imftest/samples/EditTextActivityNoScrollPanScan.java
deleted file mode 100644
index b596023..0000000
--- a/tests/ImfTest/src/com/android/imftest/samples/EditTextActivityNoScrollPanScan.java
+++ /dev/null
@@ -1,38 +0,0 @@
-package com.android.imftest.samples;
-
-import android.app.Activity;
-import android.os.Bundle;
-import android.view.KeyEvent;
-import android.view.View;
-import android.view.ViewGroup;
-import android.view.WindowManager;
-import android.widget.LinearLayout;
-import android.view.inputmethod.InputMethodManager;
-import android.widget.EditText;
-import android.widget.Button;
-import android.widget.TextView;
-import android.widget.ScrollView;
-
-import com.android.internal.R;
-
-public class EditTextActivityNoScrollPanScan extends Activity 
-{
-   @Override
-   public void onCreate(Bundle savedInstanceState) 
-   {
-       super.onCreate(savedInstanceState);
-                
-       LinearLayout layout = new LinearLayout(this);
-       layout.setOrientation(LinearLayout.VERTICAL);
-       
-       String string = new String();
-       for (int i=0; i<9; i++) 
-       {
-           final EditText editText = new EditText(this);
-           editText.setText(string.valueOf(i));
-           layout.addView(editText);
-       }
-       setContentView(layout);
-       this.getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_PAN);
-    }  
-}
diff --git a/tests/ImfTest/src/com/android/imftest/samples/ManyEditTextActivityNoScrollPanScan.java b/tests/ImfTest/src/com/android/imftest/samples/ManyEditTextActivityNoScrollPanScan.java
index 4cb3af6a..54ab57a 100644
--- a/tests/ImfTest/src/com/android/imftest/samples/ManyEditTextActivityNoScrollPanScan.java
+++ b/tests/ImfTest/src/com/android/imftest/samples/ManyEditTextActivityNoScrollPanScan.java
@@ -20,22 +20,31 @@
  */
 public class ManyEditTextActivityNoScrollPanScan extends Activity 
 {
-   @Override
-   public void onCreate(Bundle savedInstanceState) 
-   {
-       super.onCreate(savedInstanceState);
-                
-       LinearLayout layout = new LinearLayout(this);
-       layout.setOrientation(LinearLayout.VERTICAL);
-       
-       String string = new String();
-       for (int i=0; i<9; i++) 
-       {
-           final EditText editText = new EditText(this);
-           editText.setText(string.valueOf(i));
-           layout.addView(editText);
-       }
-       setContentView(layout);
-       this.getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_PAN);
+    public static final int NUM_EDIT_TEXTS = 9;
+
+    private View mRootView;
+
+    @Override
+    public void onCreate(Bundle savedInstanceState) 
+    {
+        super.onCreate(savedInstanceState);
+
+        mRootView = new LinearLayout(this);
+        ((LinearLayout) mRootView).setOrientation(LinearLayout.VERTICAL);
+
+        for (int i=0; i<NUM_EDIT_TEXTS; i++) 
+        {
+            final EditText editText = new EditText(this);
+            editText.setText(String.valueOf(i));
+            editText.setId(i);
+            ((LinearLayout) mRootView).addView(editText);
+        }
+        setContentView(mRootView);
+        this.getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_PAN);
     }  
+
+    public View getRootView() {
+        return mRootView;
+    }
+
 }
diff --git a/tests/ImfTest/src/com/android/imftest/samples/ManyEditTextActivityScrollPanScan.java b/tests/ImfTest/src/com/android/imftest/samples/ManyEditTextActivityScrollPanScan.java
index bd32828..b228d34 100644
--- a/tests/ImfTest/src/com/android/imftest/samples/ManyEditTextActivityScrollPanScan.java
+++ b/tests/ImfTest/src/com/android/imftest/samples/ManyEditTextActivityScrollPanScan.java
@@ -20,26 +20,33 @@
  */
 public class ManyEditTextActivityScrollPanScan extends Activity 
 {
-   private ScrollView mScrollView;
-   @Override
-   public void onCreate(Bundle savedInstanceState) 
-   {
-       super.onCreate(savedInstanceState);
-       mScrollView = new ScrollView(this);
-       
-       LinearLayout layout = new LinearLayout(this);
-       layout.setOrientation(LinearLayout.VERTICAL);
-       
-       String string = new String();
-       for (int i=0; i<12; i++) 
-       {
-           final EditText editText = new EditText(this);
-           editText.setText(string.valueOf(i));
-           layout.addView(editText);
-       }
+    public static final int NUM_EDIT_TEXTS = 12;
 
-       mScrollView.addView(layout);
-       setContentView(mScrollView);
-       this.getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_PAN);
-    }  
+    private View mRootView;
+
+    @Override
+    public void onCreate(Bundle savedInstanceState) 
+    {
+        super.onCreate(savedInstanceState);
+        mRootView = new ScrollView(this);
+
+        LinearLayout layout = new LinearLayout(this);
+        layout.setOrientation(LinearLayout.VERTICAL);
+
+        for (int i=0; i<NUM_EDIT_TEXTS; i++) 
+        {
+            final EditText editText = new EditText(this);
+            editText.setText(String.valueOf(i));
+            editText.setId(i);
+            layout.addView(editText);
+        }
+
+        ((ScrollView) mRootView).addView(layout);
+        setContentView(mRootView);
+        this.getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_PAN);
+    }   
+
+    public View getRootView() {
+        return mRootView;
+    }
 }
\ No newline at end of file
diff --git a/tests/ImfTest/src/com/android/imftest/samples/ManyEditTextActivityScrollResize.java b/tests/ImfTest/src/com/android/imftest/samples/ManyEditTextActivityScrollResize.java
index eaaa98b..777fbae 100644
--- a/tests/ImfTest/src/com/android/imftest/samples/ManyEditTextActivityScrollResize.java
+++ b/tests/ImfTest/src/com/android/imftest/samples/ManyEditTextActivityScrollResize.java
@@ -2,6 +2,7 @@
 
 import android.app.Activity;
 import android.os.Bundle;
+import android.view.View;
 import android.view.WindowManager;
 import android.widget.LinearLayout;
 import android.widget.EditText;
@@ -12,26 +13,33 @@
  */
 public class ManyEditTextActivityScrollResize extends Activity 
 {
-    private ScrollView mScrollView;
+    public static final int NUM_EDIT_TEXTS = 12;
+    
+    private View mRootView;
+    
     @Override
     public void onCreate(Bundle savedInstanceState) 
     {
         super.onCreate(savedInstanceState);
-        mScrollView = new ScrollView(this);
+        mRootView = new ScrollView(this);
        
         LinearLayout layout = new LinearLayout(this);
         layout.setOrientation(LinearLayout.VERTICAL);
        
-        String string = new String();
-        for (int i=0; i<12; i++) 
+        for (int i=0; i<NUM_EDIT_TEXTS; i++) 
         {
             final EditText editText = new EditText(this);
-            editText.setText(string.valueOf(i));
+            editText.setText(String.valueOf(i));
+            editText.setId(i);
             layout.addView(editText);
         }
 
-        mScrollView.addView(layout);
-        setContentView(mScrollView);
-        this.getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE);
+        ((ScrollView) mRootView).addView(layout);
+        setContentView(mRootView);
+        this.getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_PAN);
     }  
+
+    public View getRootView() {
+        return mRootView;
+    } 
 }
\ No newline at end of file
diff --git a/tests/ImfTest/src/com/android/imftest/samples/OneEditTextActivityNotSelected.java b/tests/ImfTest/src/com/android/imftest/samples/OneEditTextActivityNotSelected.java
index 5fef884..88a3447 100644
--- a/tests/ImfTest/src/com/android/imftest/samples/OneEditTextActivityNotSelected.java
+++ b/tests/ImfTest/src/com/android/imftest/samples/OneEditTextActivityNotSelected.java
@@ -2,6 +2,7 @@
 
 import android.app.Activity;
 import android.os.Bundle;
+import android.os.Debug;
 import android.view.KeyEvent;
 import android.view.View;
 import android.view.ViewGroup;
@@ -20,21 +21,36 @@
  */
 public class OneEditTextActivityNotSelected extends Activity 
 {
-   @Override
-   public void onCreate(Bundle savedInstanceState) 
-   {
-       super.onCreate(savedInstanceState);
-                
-       LinearLayout layout = new LinearLayout(this);
-       layout.setOrientation(LinearLayout.VERTICAL);
-       
-       final EditText editText = new EditText(this);
-       final TextView textView = new TextView(this);
-       textView.setText("The focus is here.");
-       layout.addView(editText);
-       layout.addView(textView);
-  
-       setContentView(layout);
-       textView.requestFocus();
+    private View mRootView;
+    private View mDefaultFocusedView;
+    
+    @Override
+    public void onCreate(Bundle savedInstanceState) 
+    {
+        super.onCreate(savedInstanceState);
+
+        LinearLayout layout = new LinearLayout(this);
+        layout.setOrientation(LinearLayout.VERTICAL);
+        mRootView = new ScrollView(this);
+
+        EditText editText = new EditText(this);
+        Button button = new Button(this);
+        button.setText("The focus is here.");
+        button.setFocusableInTouchMode(true);
+        button.requestFocus();
+        mDefaultFocusedView = button;
+        layout.addView(button);
+        layout.addView(editText);
+
+        ((ScrollView) mRootView).addView(layout);
+        setContentView(mRootView);
     }  
+
+    public View getRootView() {
+        return mRootView;
+    }
+    
+    public View getDefaultFocusedView() {
+        return mDefaultFocusedView;
+    }
 }
diff --git a/tests/ImfTest/src/com/android/imftest/samples/OneEditTextActivitySelected.java b/tests/ImfTest/src/com/android/imftest/samples/OneEditTextActivitySelected.java
index 2fd19e8..1b80263 100644
--- a/tests/ImfTest/src/com/android/imftest/samples/OneEditTextActivitySelected.java
+++ b/tests/ImfTest/src/com/android/imftest/samples/OneEditTextActivitySelected.java
@@ -20,18 +20,32 @@
  */
 public class OneEditTextActivitySelected extends Activity 
 {
-   @Override
-   public void onCreate(Bundle savedInstanceState) 
-   {
-       super.onCreate(savedInstanceState);
-                
-       LinearLayout layout = new LinearLayout(this);
-       layout.setOrientation(LinearLayout.VERTICAL);
-       
-       final EditText editText = new EditText(this);
-       layout.addView(editText);
-  
-       setContentView(layout);
-       editText.requestFocus();
+    private View mRootView;
+    private View mDefaultFocusedView;
+    
+    @Override
+    public void onCreate(Bundle savedInstanceState) 
+    {
+        super.onCreate(savedInstanceState);
+
+        LinearLayout layout = new LinearLayout(this);
+        layout.setOrientation(LinearLayout.VERTICAL);
+        mRootView = new ScrollView(this);
+        
+        EditText editText = new EditText(this);
+        editText.requestFocus();
+        mDefaultFocusedView = editText;
+        layout.addView(editText);
+
+        ((ScrollView) mRootView).addView(layout);
+        setContentView(mRootView);
     }  
+
+    public View getRootView() {
+        return mRootView;
+    }
+    
+    public View getDefaultFocusedView() {
+        return mDefaultFocusedView;
+    }
 }
diff --git a/tests/ImfTest/tests/Android.mk b/tests/ImfTest/tests/Android.mk
new file mode 100755
index 0000000..0f1924c
--- /dev/null
+++ b/tests/ImfTest/tests/Android.mk
@@ -0,0 +1,16 @@
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+# We only want this apk build for tests.
+LOCAL_MODULE_TAGS := tests
+
+# Include all test java files.
+LOCAL_SRC_FILES := $(call all-subdir-java-files)
+
+LOCAL_JAVA_LIBRARIES := android.test.runner
+
+LOCAL_PACKAGE_NAME := ImfTestTests
+
+LOCAL_INSTRUMENTATION_FOR := ImfTest
+
+include $(BUILD_PACKAGE)
diff --git a/tests/ImfTest/tests/AndroidManifest.xml b/tests/ImfTest/tests/AndroidManifest.xml
new file mode 100755
index 0000000..122d202
--- /dev/null
+++ b/tests/ImfTest/tests/AndroidManifest.xml
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2007 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+  
+          http://www.apache.org/licenses/LICENSE-2.0
+  
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<!-- package name must be unique so suffix with "tests" so package loader doesn't ignore us -->
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="com.android.imftest.tests">
+
+    <application>
+        <uses-library android:name="android.test.runner" />
+    </application>
+
+    <!--
+    This declares that this app uses the instrumentation test runner targeting
+    the package of com.android.imftest.  To run the tests use the command:
+    "adb shell am instrument -w com.android.imftest.tests/android.test.InstrumentationTestRunner"
+    -->
+    <instrumentation android:name="android.test.InstrumentationTestRunner"
+                     android:targetPackage="com.android.imftest"
+                     android:label="imf tests"/>
+
+</manifest>
diff --git a/tests/ImfTest/tests/src/com/android/imftest/samples/BigEditTextActivityNonScrollablePanScanTests.java b/tests/ImfTest/tests/src/com/android/imftest/samples/BigEditTextActivityNonScrollablePanScanTests.java
new file mode 100755
index 0000000..a1c5fd2
--- /dev/null
+++ b/tests/ImfTest/tests/src/com/android/imftest/samples/BigEditTextActivityNonScrollablePanScanTests.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.imftest.samples;
+
+import android.test.suitebuilder.annotation.LargeTest;
+import android.view.View;
+
+import com.android.imftest.R;
+
+
+public class BigEditTextActivityNonScrollablePanScanTests extends ImfBaseTestCase<BigEditTextActivityNonScrollablePanScan> {
+
+	public final String TAG = "BigEditTextActivityNonScrollablePanScanTests";
+	
+    public BigEditTextActivityNonScrollablePanScanTests() {
+        super(BigEditTextActivityNonScrollablePanScan.class);
+    }
+	
+	@LargeTest
+	public void testAppAdjustmentPanScan() {
+	    // Give the IME 2 seconds to appear.
+	    pause(2000);
+        
+	    View rootView = ((BigEditTextActivityNonScrollablePanScan) mTargetActivity).getRootView();
+	    View servedView = ((BigEditTextActivityNonScrollablePanScan) mTargetActivity).getDefaultFocusedView();
+	        
+	    assertNotNull(rootView);
+	    assertNotNull(servedView);
+	    
+	    destructiveCheckImeInitialState(rootView, servedView);
+	    
+        verifyEditTextAdjustment(servedView, rootView.getMeasuredHeight());
+	}
+	
+}
diff --git a/tests/ImfTest/tests/src/com/android/imftest/samples/BigEditTextActivityNonScrollableResizeTests.java b/tests/ImfTest/tests/src/com/android/imftest/samples/BigEditTextActivityNonScrollableResizeTests.java
new file mode 100755
index 0000000..2e0b0eb
--- /dev/null
+++ b/tests/ImfTest/tests/src/com/android/imftest/samples/BigEditTextActivityNonScrollableResizeTests.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.imftest.samples;
+
+import android.test.suitebuilder.annotation.LargeTest;
+import android.view.View;
+
+import com.android.imftest.R;
+
+
+public class BigEditTextActivityNonScrollableResizeTests extends ImfBaseTestCase<BigEditTextActivityNonScrollableResize> {
+
+	public final String TAG = "BigEditTextActivityNonScrollableResizeTests";
+	
+    public BigEditTextActivityNonScrollableResizeTests() {
+        super(BigEditTextActivityNonScrollableResize.class);
+    }
+	
+	@LargeTest
+	public void testAppAdjustmentPanScan() {       // Give the IME 2 seconds to appear.
+        pause(2000);
+        
+        View rootView = ((BigEditTextActivityNonScrollableResize) mTargetActivity).getRootView();
+        View servedView = ((BigEditTextActivityNonScrollableResize) mTargetActivity).getDefaultFocusedView();
+         
+        assertNotNull(rootView);
+        assertNotNull(servedView);
+        
+        destructiveCheckImeInitialState(rootView, servedView);
+            
+        verifyEditTextAdjustment(servedView, rootView.getMeasuredHeight());
+	}
+	
+}
diff --git a/tests/ImfTest/tests/src/com/android/imftest/samples/BigEditTextActivityScrollablePanScanTests.java b/tests/ImfTest/tests/src/com/android/imftest/samples/BigEditTextActivityScrollablePanScanTests.java
new file mode 100755
index 0000000..d3eefb5
--- /dev/null
+++ b/tests/ImfTest/tests/src/com/android/imftest/samples/BigEditTextActivityScrollablePanScanTests.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.imftest.samples;
+
+import android.test.suitebuilder.annotation.LargeTest;
+import android.view.View;
+
+import com.android.imftest.R;
+
+
+public class BigEditTextActivityScrollablePanScanTests extends ImfBaseTestCase<BigEditTextActivityScrollablePanScan> {
+
+	public final String TAG = "BigEditTextActivityScrollablePanScanTests";
+	
+    public BigEditTextActivityScrollablePanScanTests() {
+        super(BigEditTextActivityScrollablePanScan.class);
+    }
+	
+	@LargeTest
+	public void testAppAdjustmentPanScan() {       // Give the IME 2 seconds to appear.
+        pause(2000);
+        
+        View rootView = ((BigEditTextActivityScrollablePanScan) mTargetActivity).getRootView();
+        View servedView = ((BigEditTextActivityScrollablePanScan) mTargetActivity).getDefaultFocusedView();
+         
+        assertNotNull(rootView);
+        assertNotNull(servedView);
+        
+        destructiveCheckImeInitialState(rootView, servedView);
+            
+        verifyEditTextAdjustment(servedView, rootView.getMeasuredHeight());
+	}
+	
+}
diff --git a/tests/ImfTest/tests/src/com/android/imftest/samples/BigEditTextActivityScrollableResizeTests.java b/tests/ImfTest/tests/src/com/android/imftest/samples/BigEditTextActivityScrollableResizeTests.java
new file mode 100755
index 0000000..5c40e6d
--- /dev/null
+++ b/tests/ImfTest/tests/src/com/android/imftest/samples/BigEditTextActivityScrollableResizeTests.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.imftest.samples;
+
+import android.test.suitebuilder.annotation.LargeTest;
+import android.view.View;
+
+import com.android.imftest.R;
+
+
+public class BigEditTextActivityScrollableResizeTests extends ImfBaseTestCase<BigEditTextActivityScrollableResize> {
+
+	public final String TAG = "BigEditTextActivityScrollableResizeTests";
+	
+    public BigEditTextActivityScrollableResizeTests() {
+        super(BigEditTextActivityScrollableResize.class);
+    }
+	
+	@LargeTest
+	public void testAppAdjustmentPanScan() {       
+	    // Give the IME 2 seconds to appear.
+        pause(2000);
+        
+        View rootView = ((BigEditTextActivityScrollableResize) mTargetActivity).getRootView();
+        View servedView = ((BigEditTextActivityScrollableResize) mTargetActivity).getDefaultFocusedView();
+          
+        assertNotNull(rootView);
+        assertNotNull(servedView);
+        
+        destructiveCheckImeInitialState(rootView, servedView);
+            
+        verifyEditTextAdjustment(servedView, rootView.getMeasuredHeight());
+	}
+	
+}
diff --git a/tests/ImfTest/tests/src/com/android/imftest/samples/BottomEditTextActivityPanScanTests.java b/tests/ImfTest/tests/src/com/android/imftest/samples/BottomEditTextActivityPanScanTests.java
new file mode 100755
index 0000000..9a93133
--- /dev/null
+++ b/tests/ImfTest/tests/src/com/android/imftest/samples/BottomEditTextActivityPanScanTests.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.imftest.samples;
+
+import android.test.suitebuilder.annotation.LargeTest;
+import android.view.View;
+
+import com.android.imftest.R;
+
+
+public class BottomEditTextActivityPanScanTests extends ImfBaseTestCase<BottomEditTextActivityPanScan> {
+
+	public final String TAG = "BottomEditTextActivityPanScanTests";
+	
+    public BottomEditTextActivityPanScanTests() {
+        super(BottomEditTextActivityPanScan.class);
+    }
+	
+	@LargeTest
+	public void testAppAdjustmentPanScan() {
+        // Give the IME 2 seconds to appear.
+        pause(2000);
+        
+        View rootView = ((BottomEditTextActivityPanScan) mTargetActivity).getRootView();
+        View servedView = ((BottomEditTextActivityPanScan) mTargetActivity).getDefaultFocusedView();
+        
+        assertNotNull(rootView);
+        assertNotNull(servedView);
+        
+        destructiveCheckImeInitialState(rootView, servedView);
+        
+        verifyEditTextAdjustment(servedView, rootView.getMeasuredHeight());
+	}
+	
+}
diff --git a/tests/ImfTest/tests/src/com/android/imftest/samples/BottomEditTextActivityResizeTests.java b/tests/ImfTest/tests/src/com/android/imftest/samples/BottomEditTextActivityResizeTests.java
new file mode 100755
index 0000000..9a69fd5
--- /dev/null
+++ b/tests/ImfTest/tests/src/com/android/imftest/samples/BottomEditTextActivityResizeTests.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.imftest.samples;
+
+import android.test.suitebuilder.annotation.LargeTest;
+import android.view.View;
+
+import com.android.imftest.R;
+
+
+public class BottomEditTextActivityResizeTests extends ImfBaseTestCase<BottomEditTextActivityResize> {
+
+    public final String TAG = "BottomEditTextActivityResizeTests";
+    
+    public BottomEditTextActivityResizeTests() {
+        super(BottomEditTextActivityResize.class);
+    }
+    
+    @LargeTest
+    public void testAppAdjustmentResize() {
+        // Give the IME 2 seconds to appear.
+        pause(2000);
+        
+        View rootView = ((BottomEditTextActivityResize) mTargetActivity).getRootView();
+        View servedView = ((BottomEditTextActivityResize) mTargetActivity).getDefaultFocusedView();
+        
+        assertNotNull(rootView);
+        assertNotNull(servedView);
+        
+        destructiveCheckImeInitialState(rootView, servedView);
+        
+        verifyEditTextAdjustment(servedView, rootView.getMeasuredHeight());
+    }
+    
+}
diff --git a/tests/ImfTest/tests/src/com/android/imftest/samples/ButtonActivityTest.java b/tests/ImfTest/tests/src/com/android/imftest/samples/ButtonActivityTest.java
new file mode 100755
index 0000000..ae900c3
--- /dev/null
+++ b/tests/ImfTest/tests/src/com/android/imftest/samples/ButtonActivityTest.java
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.imftest.samples;
+
+import android.test.suitebuilder.annotation.LargeTest;
+import android.view.KeyEvent;
+import android.widget.Button;
+
+
+public class ButtonActivityTest extends ImfBaseTestCase<ButtonActivity> {
+
+	final public String TAG = "ButtonActivityTest";
+	
+    public ButtonActivityTest() {
+        super(ButtonActivity.class);
+    }
+
+    @LargeTest
+    public void testButtonActivatesIme() {
+       
+        final Button button = (Button) mTargetActivity.findViewById(ButtonActivity.BUTTON_ID);
+        
+        // Push button
+        // Bring the target EditText into focus.
+        mTargetActivity.runOnUiThread(new Runnable() {
+            public void run() {
+                button.requestFocus();
+            }
+        });
+        
+        sendKeys(KeyEvent.KEYCODE_DPAD_CENTER);
+        
+        // Give it a couple seconds
+        pause(2000);
+        
+        // We should have initialized imm.mServedView and imm.mCurrentTextBoxAttribute
+        assertTrue(mImm.isActive());
+        // imm.mServedInputConnection should be null since Button doesn't override onCreateInputConnection().
+        assertFalse(mImm.isAcceptingText());
+        
+        destructiveCheckImeInitialState(mTargetActivity.getRootView(), button);
+        
+    }
+}
diff --git a/tests/ImfTest/tests/src/com/android/imftest/samples/ImfBaseTestCase.java b/tests/ImfTest/tests/src/com/android/imftest/samples/ImfBaseTestCase.java
new file mode 100755
index 0000000..61dc611
--- /dev/null
+++ b/tests/ImfTest/tests/src/com/android/imftest/samples/ImfBaseTestCase.java
@@ -0,0 +1,135 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.imftest.samples;
+
+import android.app.Activity;
+import android.os.SystemClock;
+import android.test.InstrumentationTestCase;
+import android.view.KeyEvent;
+import android.view.View;
+import android.view.WindowManager;
+import android.view.inputmethod.InputMethodManager;
+
+import com.android.imftest.R;
+
+public abstract class ImfBaseTestCase<T extends Activity> extends InstrumentationTestCase {
+
+    /*
+     * The amount of time we are willing to wait for the IME to appear after a user action
+     * before we give up and fail the test.
+     */
+    public final long WAIT_FOR_IME = 5000;
+
+    /*
+     * Unfortunately there is now way for us to know how tall the IME is, 
+     * so we have to hard code a minimum and maximum value.
+     */
+    public final int IME_MIN_HEIGHT = 150;
+    public final int IME_MAX_HEIGHT = 300;
+
+    public final String TARGET_PACKAGE_NAME = "com.android.imftest";
+    protected InputMethodManager mImm;
+    protected T mTargetActivity;
+    protected boolean mExpectAutoPop;
+    private Class<T> mTargetActivityClass;
+    
+    public ImfBaseTestCase(Class<T> activityClass) {
+        mTargetActivityClass = activityClass;
+    }
+    
+    @Override
+    public void setUp() throws Exception {
+        super.setUp();
+        
+        mTargetActivity = launchActivity(TARGET_PACKAGE_NAME, mTargetActivityClass, null);
+        mExpectAutoPop = mTargetActivity.getResources().getBoolean(R.bool.def_expect_ime_autopop);
+        mImm = InputMethodManager.getInstance(mTargetActivity);
+    }
+    
+    // Utility test methods
+    public void verifyEditTextAdjustment(final View editText, int rootViewHeight) {
+
+        int[] origLocation = new int[2];
+        int[] newLocation = new int[2];
+
+        // Tell the keyboard to go away.
+        mImm.hideSoftInputFromWindow(editText.getWindowToken(), 0);
+
+        // Bring the target EditText into focus.
+        mTargetActivity.runOnUiThread(new Runnable() {
+            public void run() {
+                editText.requestFocus();
+            }
+        });
+
+        // Get the original location of the EditText.
+        editText.getLocationOnScreen(origLocation);
+
+        // Tap the EditText to bring up the IME.
+        sendKeys(KeyEvent.KEYCODE_DPAD_CENTER);
+
+        // Wait until the EditText pops above the IME or until we hit the timeout.
+        editText.getLocationOnScreen(newLocation);
+        long timeoutTime = SystemClock.uptimeMillis() + WAIT_FOR_IME;
+        while (newLocation[1] > rootViewHeight - IME_MIN_HEIGHT && SystemClock.uptimeMillis() < timeoutTime) {
+            editText.getLocationOnScreen(newLocation);
+            pause(100);
+        }
+
+        assertTrue(newLocation[1] <= rootViewHeight - IME_MIN_HEIGHT);
+
+        // Tell the keyboard to go away.
+        mImm.hideSoftInputFromWindow(editText.getWindowToken(), 0);
+    }
+
+    public void destructiveCheckImeInitialState(View rootView, View servedView) {
+        if (mExpectAutoPop && (mTargetActivity.getWindow().getAttributes().
+                softInputMode&WindowManager.LayoutParams.SOFT_INPUT_MASK_ADJUST) 
+                == WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE) {
+            assertTrue(destructiveCheckImeUp(rootView, servedView));
+        } else {
+            assertFalse(destructiveCheckImeUp(rootView, servedView));
+        }
+    }
+    
+    public boolean destructiveCheckImeUp(View rootView, View servedView) {
+        int origHeight;
+        int newHeight;
+        
+        origHeight = rootView.getHeight();
+        
+        // Tell the keyboard to go away.
+        mImm.hideSoftInputFromWindow(servedView.getWindowToken(), 0);
+        
+        // Give it five seconds to adjust
+        newHeight = rootView.getHeight();
+        long timeoutTime = SystemClock.uptimeMillis() + WAIT_FOR_IME;
+        while (Math.abs(newHeight - origHeight) < IME_MIN_HEIGHT && SystemClock.uptimeMillis() < timeoutTime) {
+            newHeight = rootView.getHeight();
+        }
+        
+        return (Math.abs(origHeight - newHeight) >= IME_MIN_HEIGHT);
+    }
+    
+    void pause(int millis) {
+        try {
+            Thread.sleep(millis);
+        } catch (InterruptedException e) {
+        }
+    }
+
+}
diff --git a/tests/ImfTest/tests/src/com/android/imftest/samples/ManyEditTextActivityBaseTestCase.java b/tests/ImfTest/tests/src/com/android/imftest/samples/ManyEditTextActivityBaseTestCase.java
new file mode 100755
index 0000000..278efb1
--- /dev/null
+++ b/tests/ImfTest/tests/src/com/android/imftest/samples/ManyEditTextActivityBaseTestCase.java
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.imftest.samples;
+
+import android.app.Activity;
+import android.widget.EditText;
+
+
+public abstract class ManyEditTextActivityBaseTestCase<T extends Activity> extends ImfBaseTestCase<T> {
+  
+    public ManyEditTextActivityBaseTestCase(Class<T> activityClass){
+        super(activityClass);
+    }
+
+    public abstract void testAllEditTextsAdjust();
+
+    public void verifyAllEditTextAdjustment(int numEditTexts, int rootViewHeight) {
+
+        for (int i = 0; i < numEditTexts; i++) {
+            final EditText lastEditText = (EditText) mTargetActivity.findViewById(i);
+            verifyEditTextAdjustment(lastEditText, rootViewHeight);
+        }
+
+    }
+
+}
diff --git a/tests/ImfTest/tests/src/com/android/imftest/samples/ManyEditTextActivityNoScrollPanScanTests.java b/tests/ImfTest/tests/src/com/android/imftest/samples/ManyEditTextActivityNoScrollPanScanTests.java
new file mode 100755
index 0000000..4f8d14e
--- /dev/null
+++ b/tests/ImfTest/tests/src/com/android/imftest/samples/ManyEditTextActivityNoScrollPanScanTests.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.imftest.samples;
+
+import android.test.suitebuilder.annotation.LargeTest;
+
+
+public class ManyEditTextActivityNoScrollPanScanTests extends ManyEditTextActivityBaseTestCase<ManyEditTextActivityNoScrollPanScan> {
+
+    public final String TAG = "ManyEditTextActivityNoScrollPanScanTests";
+    
+    public ManyEditTextActivityNoScrollPanScanTests() {
+        super(ManyEditTextActivityNoScrollPanScan.class);
+    }
+
+   
+    @LargeTest
+    public void testAllEditTextsAdjust() {
+        verifyAllEditTextAdjustment(mTargetActivity.NUM_EDIT_TEXTS, 
+                mTargetActivity.getRootView().getMeasuredHeight());
+    }
+}
diff --git a/tests/ImfTest/tests/src/com/android/imftest/samples/ManyEditTextActivityScrollPanScanTests.java b/tests/ImfTest/tests/src/com/android/imftest/samples/ManyEditTextActivityScrollPanScanTests.java
new file mode 100755
index 0000000..7f98f7f
--- /dev/null
+++ b/tests/ImfTest/tests/src/com/android/imftest/samples/ManyEditTextActivityScrollPanScanTests.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.imftest.samples;
+
+import android.test.suitebuilder.annotation.LargeTest;
+
+
+public class ManyEditTextActivityScrollPanScanTests extends ManyEditTextActivityBaseTestCase<ManyEditTextActivityScrollPanScan> {
+
+    public final String TAG = "ManyEditTextActivityScrollPanScanTests";
+    
+    
+    public ManyEditTextActivityScrollPanScanTests() {
+        super(ManyEditTextActivityScrollPanScan.class);
+    }
+    
+    @LargeTest
+    public void testAllEditTextsAdjust() {
+        verifyAllEditTextAdjustment(mTargetActivity.NUM_EDIT_TEXTS, 
+                mTargetActivity.getRootView().getMeasuredHeight());
+    }
+
+}
diff --git a/tests/ImfTest/tests/src/com/android/imftest/samples/ManyEditTextActivityScrollResizeTests.java b/tests/ImfTest/tests/src/com/android/imftest/samples/ManyEditTextActivityScrollResizeTests.java
new file mode 100755
index 0000000..68dae87
--- /dev/null
+++ b/tests/ImfTest/tests/src/com/android/imftest/samples/ManyEditTextActivityScrollResizeTests.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.imftest.samples;
+
+import android.test.suitebuilder.annotation.LargeTest;
+
+
+public class ManyEditTextActivityScrollResizeTests extends ManyEditTextActivityBaseTestCase<ManyEditTextActivityScrollResize> {
+
+    public final String TAG = "ManyEditTextActivityScrollResizeTests";
+    
+    
+    public ManyEditTextActivityScrollResizeTests() {
+        super(ManyEditTextActivityScrollResize.class);
+    }
+
+    @LargeTest
+    public void testAllEditTextsAdjust() {
+        verifyAllEditTextAdjustment(mTargetActivity.NUM_EDIT_TEXTS, 
+                mTargetActivity.getRootView().getMeasuredHeight());
+    }
+
+}
diff --git a/tests/ImfTest/tests/src/com/android/imftest/samples/OneEditTextActivityNotSelectedTests.java b/tests/ImfTest/tests/src/com/android/imftest/samples/OneEditTextActivityNotSelectedTests.java
new file mode 100755
index 0000000..ed5b0c9
--- /dev/null
+++ b/tests/ImfTest/tests/src/com/android/imftest/samples/OneEditTextActivityNotSelectedTests.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.imftest.samples;
+
+import android.test.suitebuilder.annotation.LargeTest;
+import android.view.View;
+
+
+public class OneEditTextActivityNotSelectedTests extends ImfBaseTestCase<OneEditTextActivityNotSelected> {
+
+	public final String TAG = "OneEditTextActivityNotSelectedTests";
+	
+    public OneEditTextActivityNotSelectedTests() {
+        super(OneEditTextActivityNotSelected.class);
+    }
+    
+	@LargeTest
+	public void testSoftKeyboardNoAutoPop() {
+	    
+	    // Give the IME 2 seconds to appear.
+	    pause(2000);
+	    
+	    assertFalse(mImm.isAcceptingText());
+	    
+	    View rootView = ((OneEditTextActivityNotSelected) mTargetActivity).getRootView();
+        View servedView = ((OneEditTextActivityNotSelected) mTargetActivity).getDefaultFocusedView();
+        
+        assertNotNull(rootView);
+        assertNotNull(servedView);
+        
+        destructiveCheckImeInitialState(rootView, servedView);
+        
+        verifyEditTextAdjustment(servedView, rootView.getMeasuredHeight());
+	}
+	
+}
diff --git a/tests/ImfTest/tests/src/com/android/imftest/samples/OneEditTextActivitySelectedTests.java b/tests/ImfTest/tests/src/com/android/imftest/samples/OneEditTextActivitySelectedTests.java
new file mode 100755
index 0000000..42fcd66
--- /dev/null
+++ b/tests/ImfTest/tests/src/com/android/imftest/samples/OneEditTextActivitySelectedTests.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.imftest.samples;
+
+import com.android.imftest.R;
+
+import android.test.suitebuilder.annotation.LargeTest;
+import android.view.KeyEvent;
+import android.view.View;
+
+
+public class OneEditTextActivitySelectedTests extends ImfBaseTestCase<OneEditTextActivitySelected> {
+
+    public final String TAG = "OneEditTextActivitySelectedTests";
+    
+    public OneEditTextActivitySelectedTests() {
+        super(OneEditTextActivitySelected.class);
+    }
+    
+    @LargeTest
+    public void testSoftKeyboardAutoPop() {
+        
+        // Give the IME 2 seconds to appear.
+        pause(2000);
+        
+        assertTrue(mImm.isAcceptingText());
+        
+        View rootView = ((OneEditTextActivitySelected) mTargetActivity).getRootView();
+        View servedView = ((OneEditTextActivitySelected) mTargetActivity).getDefaultFocusedView();
+        
+        assertNotNull(rootView);
+        assertNotNull(servedView);
+        
+        destructiveCheckImeInitialState(rootView, servedView);
+        
+        verifyEditTextAdjustment(servedView, rootView.getMeasuredHeight());
+    }
+    
+}
diff --git a/tests/gadgets/GadgetHostTest/AndroidManifest.xml b/tests/gadgets/GadgetHostTest/AndroidManifest.xml
index cac2776..52e314f 100644
--- a/tests/gadgets/GadgetHostTest/AndroidManifest.xml
+++ b/tests/gadgets/GadgetHostTest/AndroidManifest.xml
@@ -17,12 +17,20 @@
                 <category android:name="android.intent.category.LAUNCHER" />
             </intent-filter>
         </activity>
-        <receiver android:name="TestGadgetProvider" android:label="@string/oh_hai"
-                    android:icon="@drawable/oh_hai_icon">
+
+        <!-- BEGIN_INCLUDE(GadgetProvider) -->
+        <receiver android:name="TestGadgetProvider"
+                    android:label="@string/oh_hai"
+                    android:icon="@drawable/oh_hai_icon"
+                    >
             <intent-filter>
                 <action android:name="android.gadget.action.GADGET_UPDATE" />
             </intent-filter>
-            <meta-data android:name="android.gadget.provider" android:resource="@xml/gadget_info" />
+            <meta-data android:name="android.gadget.provider"
+                        android:resource="@xml/gadget_info"
+                        />
         </receiver>
+        <!-- END_INCLUDE(GadgetProvider) -->
+        
     </application>
 </manifest>
diff --git a/tests/gadgets/GadgetHostTest/res/xml/gadget_info.xml b/tests/gadgets/GadgetHostTest/res/xml/gadget_info.xml
index 353df30..e0c4222 100644
--- a/tests/gadgets/GadgetHostTest/res/xml/gadget_info.xml
+++ b/tests/gadgets/GadgetHostTest/res/xml/gadget_info.xml
@@ -1,8 +1,10 @@
+<!-- BEGIN_INCLUDE(GadgetProviderInfo) -->
 <gadget-provider xmlns:android="http://schemas.android.com/apk/res/android"
     android:minWidth="40dp"
     android:minHeight="30dp"
-    android:updatePeriodMillis="3000"
+    android:updatePeriodMillis="86400000"
     android:initialLayout="@layout/test_gadget"
     android:configure="com.android.tests.gadgethost.TestGadgetConfigure"
     >
 </gadget-provider>
+<!-- END_INCLUDE(GadgetProviderInfo) -->
diff --git a/tests/gadgets/GadgetHostTest/src/com/android/tests/gadgethost/GadgetHostActivity.java b/tests/gadgets/GadgetHostTest/src/com/android/tests/gadgethost/GadgetHostActivity.java
index d3dcf41..0bd8926 100644
--- a/tests/gadgets/GadgetHostTest/src/com/android/tests/gadgethost/GadgetHostActivity.java
+++ b/tests/gadgets/GadgetHostTest/src/com/android/tests/gadgethost/GadgetHostActivity.java
@@ -23,7 +23,7 @@
 import android.content.SharedPreferences;
 import android.gadget.GadgetHost;
 import android.gadget.GadgetHostView;
-import android.gadget.GadgetInfo;
+import android.gadget.GadgetProviderInfo;
 import android.gadget.GadgetManager;
 import android.os.Bundle;
 import android.util.Log;
@@ -73,14 +73,13 @@
     };
 
     void discoverGadget(int requestCode) {
-        Intent intent = new Intent(GadgetManager.GADGET_PICK_ACTION);
-        intent.putExtra(GadgetManager.EXTRA_HOST_ID, HOST_ID);
+        Intent intent = new Intent(GadgetManager.ACTION_GADGET_PICK);
         intent.putExtra(GadgetManager.EXTRA_GADGET_ID, mHost.allocateGadgetId());
         startActivityForResult(intent, requestCode);
     }
 
     void configureGadget(int requestCode, int gadgetId, ComponentName configure) {
-        Intent intent = new Intent(GadgetManager.GADGET_CONFIGURE_ACTION);
+        Intent intent = new Intent(GadgetManager.ACTION_GADGET_CONFIGURE);
         intent.setComponent(configure);
         intent.putExtra(GadgetManager.EXTRA_GADGET_ID, gadgetId);
         SharedPreferences.Editor prefs = getPreferences(0).edit();
@@ -89,11 +88,13 @@
         startActivityForResult(intent, requestCode);
     }
 
-    void handleGadgetPickResult(int resultCode, Intent data) {
-        Bundle extras = data.getExtras();
+    void handleGadgetPickResult(int resultCode, Intent intent) {
+        // BEGIN_INCLUDE(getExtra_EXTRA_GADGET_ID)
+        Bundle extras = intent.getExtras();
         int gadgetId = extras.getInt(GadgetManager.EXTRA_GADGET_ID);
+        // END_INCLUDE(getExtra_EXTRA_GADGET_ID)
         if (resultCode == RESULT_OK) {
-            GadgetInfo gadget = mGadgetManager.getGadgetInfo(gadgetId);
+            GadgetProviderInfo gadget = mGadgetManager.getGadgetInfo(gadgetId);
 
             if (gadget.configure != null) {
                 // configure the gadget if we should
@@ -115,14 +116,14 @@
             return;
         }
         if (resultCode == RESULT_OK) {
-            GadgetInfo gadget = mGadgetManager.getGadgetInfo(gadgetId);
+            GadgetProviderInfo gadget = mGadgetManager.getGadgetInfo(gadgetId);
             addGadgetView(gadgetId, gadget);
         } else {
             mHost.deleteGadgetId(gadgetId);
         }
     }
 
-    void addGadgetView(int gadgetId, GadgetInfo gadget) {
+    void addGadgetView(int gadgetId, GadgetProviderInfo gadget) {
         // Inflate the gadget's RemoteViews
         GadgetHostView view = mHost.createView(this, gadgetId, gadget);
 
@@ -188,11 +189,10 @@
     }
 
     GadgetHost mHost = new GadgetHost(this, HOST_ID) {
-        protected GadgetHostView onCreateView(Context context, int gadgetId, GadgetInfo gadget) {
+        protected GadgetHostView onCreateView(Context context, int gadgetId, GadgetProviderInfo gadget) {
             return new MyGadgetView(gadgetId);
         }
     };
-
 }
 
 
diff --git a/tests/gadgets/GadgetHostTest/src/com/android/tests/gadgethost/TestGadgetProvider.java b/tests/gadgets/GadgetHostTest/src/com/android/tests/gadgethost/TestGadgetProvider.java
index 7614c9e..370a50b 100644
--- a/tests/gadgets/GadgetHostTest/src/com/android/tests/gadgethost/TestGadgetProvider.java
+++ b/tests/gadgets/GadgetHostTest/src/com/android/tests/gadgethost/TestGadgetProvider.java
@@ -37,16 +37,18 @@
         String action = intent.getAction();
         Log.d(TAG, "intent=" + intent);
 
-        if (GadgetManager.GADGET_ENABLED_ACTION.equals(action)) {
+        if (GadgetManager.ACTION_GADGET_ENABLED.equals(action)) {
             Log.d(TAG, "ENABLED");
         }
-        else if (GadgetManager.GADGET_DISABLED_ACTION.equals(action)) {
+        else if (GadgetManager.ACTION_GADGET_DISABLED.equals(action)) {
             Log.d(TAG, "DISABLED");
         }
-        else if (GadgetManager.GADGET_UPDATE_ACTION.equals(action)) {
+        else if (GadgetManager.ACTION_GADGET_UPDATE.equals(action)) {
             Log.d(TAG, "UPDATE");
+            // BEGIN_INCLUDE(getExtra_EXTRA_GADGET_IDS)
             Bundle extras = intent.getExtras();
             int[] gadgetIds = extras.getIntArray(GadgetManager.EXTRA_GADGET_IDS);
+            // END_INCLUDE(getExtra_EXTRA_GADGET_IDS)
 
             SharedPreferences prefs = context.getSharedPreferences(
                     TestGadgetProvider.PREFS_NAME, 0);
diff --git a/tests/gadgets/GadgetProviderTest/res/xml/gadget_info.xml b/tests/gadgets/GadgetProviderTest/res/xml/gadget_info.xml
index 0b8ca2e..0fc7812 100644
--- a/tests/gadgets/GadgetProviderTest/res/xml/gadget_info.xml
+++ b/tests/gadgets/GadgetProviderTest/res/xml/gadget_info.xml
@@ -1,7 +1,7 @@
 <gadget-provider xmlns:android="http://schemas.android.com/apk/res/android"
     android:minWidth="40dp"
     android:minHeight="30dp"
-    android:updatePeriodMillis="3000"
+    android:updatePeriodMillis="60000"
     android:initialLayout="@layout/test_gadget"
     >
 </gadget-provider>
diff --git a/tests/gadgets/GadgetProviderTest/src/com/android/tests/gadgetprovider/TestGadgetProvider.java b/tests/gadgets/GadgetProviderTest/src/com/android/tests/gadgetprovider/TestGadgetProvider.java
index 8622bc7..b81575f 100644
--- a/tests/gadgets/GadgetProviderTest/src/com/android/tests/gadgetprovider/TestGadgetProvider.java
+++ b/tests/gadgets/GadgetProviderTest/src/com/android/tests/gadgetprovider/TestGadgetProvider.java
@@ -34,13 +34,13 @@
         String action = intent.getAction();
         Log.d(TAG, "intent=" + intent);
 
-        if (GadgetManager.GADGET_ENABLED_ACTION.equals(action)) {
+        if (GadgetManager.ACTION_GADGET_ENABLED.equals(action)) {
             Log.d(TAG, "ENABLED");
         }
-        else if (GadgetManager.GADGET_DISABLED_ACTION.equals(action)) {
+        else if (GadgetManager.ACTION_GADGET_DISABLED.equals(action)) {
             Log.d(TAG, "DISABLED");
         }
-        else if (GadgetManager.GADGET_UPDATE_ACTION.equals(action)) {
+        else if (GadgetManager.ACTION_GADGET_UPDATE.equals(action)) {
             Log.d(TAG, "UPDATE");
             Bundle extras = intent.getExtras();
             int[] gadgetIds = extras.getIntArray(GadgetManager.EXTRA_GADGET_IDS);
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/Bridge.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/Bridge.java
index 39200a1..82fe365 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/Bridge.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/Bridge.java
@@ -789,6 +789,12 @@
         }
 
         @SuppressWarnings("unused")
+        public boolean performHapticFeedback(IWindow window, int effectId, boolean always) {
+            // pass for now.
+            return false;
+        }
+        
+        @SuppressWarnings("unused")
         public MotionEvent getPendingPointerMove(IWindow arg0) throws RemoteException {
             // pass for now.
             return null;
diff --git a/wifi/java/android/net/wifi/WifiStateTracker.java b/wifi/java/android/net/wifi/WifiStateTracker.java
index 0e70f8b..f0009be 100644
--- a/wifi/java/android/net/wifi/WifiStateTracker.java
+++ b/wifi/java/android/net/wifi/WifiStateTracker.java
@@ -1142,6 +1142,7 @@
         // Stop DHCP
         if (mDhcpTarget != null) {
             mDhcpTarget.setCancelCallback(true);
+            mDhcpTarget.removeMessages(EVENT_DHCP_START);
         }
         if (!NetworkUtils.stopDhcp(mInterfaceName)) {
             Log.e(TAG, "Could not stop DHCP");