Merge "Use Harfbuzz instead of ICU4C for computing advances"
diff --git a/Android.mk b/Android.mk
index a28bde2..de0112c 100644
--- a/Android.mk
+++ b/Android.mk
@@ -123,10 +123,10 @@
 	core/java/android/nfc/ILlcpServiceSocket.aidl \
 	core/java/android/nfc/ILlcpSocket.aidl \
 	core/java/android/nfc/INfcAdapter.aidl \
+	core/java/android/nfc/INfcAdapterExtras.aidl \
 	core/java/android/nfc/INfcTag.aidl \
 	core/java/android/nfc/IP2pInitiator.aidl \
 	core/java/android/nfc/IP2pTarget.aidl \
-    core/java/android/nfc/INfcSecureElement.aidl \
 	core/java/android/os/IHardwareService.aidl \
 	core/java/android/os/IMessenger.aidl \
 	core/java/android/os/INetworkManagementService.aidl \
diff --git a/CleanSpec.mk b/CleanSpec.mk
index 2eee813..023ce59 100644
--- a/CleanSpec.mk
+++ b/CleanSpec.mk
@@ -95,7 +95,7 @@
 $(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/APPS/PerfTest_intermediates/)
 $(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/APPS/RSTest_intermediates/)
 $(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/framework_intermediates/src/core/java/android/hardware/IUsbManager.java)
-
+$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/framework_intermediates/src/core/java/android/nfc)
 
 # ************************************************
 # NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST
diff --git a/api/12.xml b/api/12.xml
index 7835c7f..2646904 100644
--- a/api/12.xml
+++ b/api/12.xml
@@ -7913,6 +7913,17 @@
  visibility="public"
 >
 </field>
+<field name="resizeMode"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="16843619"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
 <field name="resizeable"
  type="int"
  transient="false"
@@ -9926,6 +9937,17 @@
  visibility="public"
 >
 </field>
+<field name="textCursorDrawable"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="16843618"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
 <field name="textEditNoPasteWindowLayout"
  type="int"
  transient="false"
@@ -21131,6 +21153,17 @@
 <parameter name="listener" type="android.animation.ValueAnimator.AnimatorUpdateListener">
 </parameter>
 </method>
+<method name="getAnimatedFraction"
+ return="float"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
 <method name="getAnimatedValue"
  return="java.lang.Object"
  abstract="false"
@@ -22680,6 +22713,19 @@
 <parameter name="id" type="int">
 </parameter>
 </method>
+<method name="dispatchGenericMotionEvent"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="ev" type="android.view.MotionEvent">
+</parameter>
+</method>
 <method name="dispatchKeyEvent"
  return="boolean"
  abstract="false"
@@ -23510,6 +23556,19 @@
  visibility="public"
 >
 </method>
+<method name="onGenericMotionEvent"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="event" type="android.view.MotionEvent">
+</parameter>
+</method>
 <method name="onKeyDown"
  return="boolean"
  abstract="false"
@@ -25027,6 +25086,17 @@
 <parameter name="packageName" type="java.lang.String">
 </parameter>
 </method>
+<field name="MOVE_TASK_NO_USER_ACTION"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="2"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
 <field name="MOVE_TASK_WITH_HOME"
  type="int"
  transient="false"
@@ -25458,6 +25528,16 @@
  visibility="public"
 >
 </field>
+<field name="persistentId"
+ type="int"
+ transient="false"
+ volatile="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
 </class>
 <class name="ActivityManager.RunningAppProcessInfo"
  extends="java.lang.Object"
@@ -27506,6 +27586,19 @@
  visibility="public"
 >
 </method>
+<method name="dispatchGenericMotionEvent"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="ev" type="android.view.MotionEvent">
+</parameter>
+</method>
 <method name="dispatchKeyEvent"
  return="boolean"
  abstract="false"
@@ -27861,6 +27954,19 @@
  visibility="public"
 >
 </method>
+<method name="onGenericMotionEvent"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="event" type="android.view.MotionEvent">
+</parameter>
+</method>
 <method name="onKeyDown"
  return="boolean"
  abstract="false"
@@ -28537,6 +28643,17 @@
  visibility="public"
 >
 </method>
+<method name="dismissAllowingStateLoss"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
 <method name="getDialog"
  return="android.app.Dialog"
  abstract="false"
@@ -28744,6 +28861,31 @@
  deprecated="not deprecated"
  visibility="public"
 >
+<method name="addCompletedDownload"
+ return="long"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="title" type="java.lang.String">
+</parameter>
+<parameter name="description" type="java.lang.String">
+</parameter>
+<parameter name="isMediaScannerScannable" type="boolean">
+</parameter>
+<parameter name="mimeType" type="java.lang.String">
+</parameter>
+<parameter name="path" type="java.lang.String">
+</parameter>
+<parameter name="length" type="long">
+</parameter>
+<parameter name="showNotification" type="boolean">
+</parameter>
+</method>
 <method name="enqueue"
  return="long"
  abstract="false"
@@ -29147,6 +29289,17 @@
  visibility="public"
 >
 </field>
+<field name="INTENT_EXTRAS_SORT_BY_SIZE"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;android.app.DownloadManager.extra_sortBySize&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
 <field name="PAUSED_QUEUED_FOR_WIFI"
  type="int"
  transient="false"
@@ -29538,6 +29691,17 @@
  visibility="public"
 >
 </field>
+<field name="VISIBILITY_VISIBLE_NOTIFY_ONLY_COMPLETION"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="3"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
 </class>
 <class name="ExpandableListActivity"
  extends="android.app.Activity"
@@ -30233,9 +30397,26 @@
  synchronized="false"
  static="false"
  final="false"
+ deprecated="deprecated"
+ visibility="public"
+>
+<parameter name="attrs" type="android.util.AttributeSet">
+</parameter>
+<parameter name="savedInstanceState" type="android.os.Bundle">
+</parameter>
+</method>
+<method name="onInflate"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
  deprecated="not deprecated"
  visibility="public"
 >
+<parameter name="activity" type="android.app.Activity">
+</parameter>
 <parameter name="attrs" type="android.util.AttributeSet">
 </parameter>
 <parameter name="savedInstanceState" type="android.os.Bundle">
@@ -30582,6 +30763,19 @@
 <parameter name="visibleCrumbs" type="int">
 </parameter>
 </method>
+<method name="setOnBreadCrumbClickListener"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="listener" type="android.app.FragmentBreadCrumbs.OnBreadCrumbClickListener">
+</parameter>
+</method>
 <method name="setParentTitle"
  return="void"
  abstract="false"
@@ -30615,6 +30809,29 @@
 </parameter>
 </method>
 </class>
+<interface name="FragmentBreadCrumbs.OnBreadCrumbClickListener"
+ abstract="true"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<method name="onBreadCrumbClick"
+ return="boolean"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="backStack" type="android.app.FragmentManager.BackStackEntry">
+</parameter>
+<parameter name="flags" type="int">
+</parameter>
+</method>
+</interface>
 <class name="FragmentManager"
  extends="java.lang.Object"
  abstract="true"
@@ -35162,6 +35379,17 @@
  visibility="public"
 >
 </field>
+<field name="EXTRA_NEW_SEARCH"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;new_search&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
 <field name="EXTRA_SELECT_QUERY"
  type="java.lang.String"
  transient="false"
@@ -39602,6 +39830,50 @@
  visibility="public"
 >
 </field>
+<field name="RESIZE_BOTH"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="3"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="RESIZE_HORIZONTAL"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="1"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="RESIZE_NONE"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="0"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="RESIZE_VERTICAL"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="2"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
 <field name="autoAdvanceViewId"
  type="int"
  transient="false"
@@ -39692,6 +39964,16 @@
  visibility="public"
 >
 </field>
+<field name="resizeMode"
+ type="int"
+ transient="false"
+ volatile="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
 <field name="updatePeriodMillis"
  type="int"
  transient="false"
@@ -49100,6 +49382,17 @@
  visibility="public"
 >
 </field>
+<field name="USB_SERVICE"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;usb&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
 <field name="VIBRATOR_SERVICE"
  type="java.lang.String"
  transient="false"
@@ -52954,6 +53247,17 @@
  visibility="public"
 >
 </field>
+<field name="ACTION_MY_PACKAGE_REPLACED"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;android.intent.action.MY_PACKAGE_REPLACED&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
 <field name="ACTION_NEW_OUTGOING_CALL"
  type="java.lang.String"
  transient="false"
@@ -52998,6 +53302,17 @@
  visibility="public"
 >
 </field>
+<field name="ACTION_PACKAGE_FIRST_LAUNCH"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;android.intent.action.PACKAGE_FIRST_LAUNCH&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
 <field name="ACTION_PACKAGE_INSTALL"
  type="java.lang.String"
  transient="false"
@@ -54273,6 +54588,17 @@
  visibility="public"
 >
 </field>
+<field name="FLAG_EXCLUDE_STOPPED_PACKAGES"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="16"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
 <field name="FLAG_FROM_BACKGROUND"
  type="int"
  transient="false"
@@ -54306,6 +54632,17 @@
  visibility="public"
 >
 </field>
+<field name="FLAG_INCLUDE_STOPPED_PACKAGES"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="32"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
 <field name="FLAG_RECEIVER_REGISTERED_ONLY"
  type="int"
  transient="false"
@@ -58121,6 +58458,17 @@
  visibility="public"
 >
 </field>
+<field name="FLAG_STOPPED"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="2097152"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
 <field name="FLAG_SUPPORTS_LARGE_SCREENS"
  type="int"
  transient="false"
@@ -60936,6 +61284,28 @@
  visibility="public"
 >
 </field>
+<field name="FEATURE_USB_ACCESSORY"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;android.hardware.usb.accessory&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="FEATURE_USB_HOST"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;android.hardware.usb.host&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
 <field name="FEATURE_WIFI"
  type="java.lang.String"
  transient="false"
@@ -72295,6 +72665,33 @@
 <parameter name="message" type="java.lang.String">
 </parameter>
 </constructor>
+<constructor name="DrmErrorEvent"
+ type="android.drm.DrmErrorEvent"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="uniqueId" type="int">
+</parameter>
+<parameter name="type" type="int">
+</parameter>
+<parameter name="message" type="java.lang.String">
+</parameter>
+<parameter name="attributes" type="java.util.HashMap&lt;java.lang.String, java.lang.Object&gt;">
+</parameter>
+</constructor>
+<field name="TYPE_ACQUIRE_DRM_INFO_FAILED"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="2008"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
 <field name="TYPE_NOT_SUPPORTED"
  type="int"
  transient="false"
@@ -72394,7 +72791,36 @@
 </parameter>
 <parameter name="message" type="java.lang.String">
 </parameter>
+<parameter name="attributes" type="java.util.HashMap&lt;java.lang.String, java.lang.Object&gt;">
+</parameter>
 </constructor>
+<constructor name="DrmEvent"
+ type="android.drm.DrmEvent"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="protected"
+>
+<parameter name="uniqueId" type="int">
+</parameter>
+<parameter name="type" type="int">
+</parameter>
+<parameter name="message" type="java.lang.String">
+</parameter>
+</constructor>
+<method name="getAttribute"
+ return="java.lang.Object"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="key" type="java.lang.String">
+</parameter>
+</method>
 <method name="getMessage"
  return="java.lang.String"
  abstract="false"
@@ -72428,6 +72854,17 @@
  visibility="public"
 >
 </method>
+<field name="DRM_INFO_OBJECT"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;drm_info_object&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
 <field name="DRM_INFO_STATUS_OBJECT"
  type="java.lang.String"
  transient="false"
@@ -72604,6 +73041,22 @@
 <parameter name="message" type="java.lang.String">
 </parameter>
 </constructor>
+<constructor name="DrmInfoEvent"
+ type="android.drm.DrmInfoEvent"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="uniqueId" type="int">
+</parameter>
+<parameter name="type" type="int">
+</parameter>
+<parameter name="message" type="java.lang.String">
+</parameter>
+<parameter name="attributes" type="java.util.HashMap&lt;java.lang.String, java.lang.Object&gt;">
+</parameter>
+</constructor>
 <field name="TYPE_ACCOUNT_ALREADY_REGISTERED"
  type="int"
  transient="false"
@@ -72648,6 +73101,17 @@
  visibility="public"
 >
 </field>
+<field name="TYPE_RIGHTS_REMOVED"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="6"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
 <field name="TYPE_WAIT_FOR_RIGHTS"
  type="int"
  transient="false"
@@ -73375,8 +73839,6 @@
 </parameter>
 <parameter name="event" type="android.drm.DrmEvent">
 </parameter>
-<parameter name="attributes" type="java.util.HashMap&lt;java.lang.String, java.lang.Object&gt;">
-</parameter>
 </method>
 </interface>
 <interface name="DrmManagerClient.OnInfoListener"
@@ -76250,6 +76712,17 @@
 <parameter name="offsetXY" type="int[]">
 </parameter>
 </method>
+<method name="getByteCount"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
 <method name="getConfig"
  return="android.graphics.Bitmap.Config"
  abstract="false"
@@ -76272,6 +76745,17 @@
  visibility="public"
 >
 </method>
+<method name="getGenerationId"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
 <method name="getHeight"
  return="int"
  abstract="false"
@@ -76489,6 +76973,19 @@
  visibility="public"
 >
 </method>
+<method name="sameAs"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="other" type="android.graphics.Bitmap">
+</parameter>
+</method>
 <method name="setDensity"
  return="void"
  abstract="false"
@@ -76502,6 +76999,19 @@
 <parameter name="density" type="int">
 </parameter>
 </method>
+<method name="setHasAlpha"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="hasAlpha" type="boolean">
+</parameter>
+</method>
 <method name="setPixel"
  return="void"
  abstract="false"
@@ -77337,6 +77847,23 @@
  visibility="public"
 >
 </method>
+<method name="rotate"
+ return="void"
+ abstract="false"
+ native="true"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="x" type="float">
+</parameter>
+<parameter name="y" type="float">
+</parameter>
+<parameter name="z" type="float">
+</parameter>
+</method>
 <method name="rotateX"
  return="void"
  abstract="false"
@@ -77387,6 +77914,23 @@
  visibility="public"
 >
 </method>
+<method name="setLocation"
+ return="void"
+ abstract="false"
+ native="true"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="x" type="float">
+</parameter>
+<parameter name="y" type="float">
+</parameter>
+<parameter name="z" type="float">
+</parameter>
+</method>
 <method name="translate"
  return="void"
  abstract="false"
@@ -90487,7 +91031,7 @@
 <method name="addCallbackBuffer"
  return="void"
  abstract="false"
- native="true"
+ native="false"
  synchronized="false"
  static="false"
  final="true"
@@ -93951,6 +94495,1334 @@
 </field>
 </class>
 </package>
+<package name="android.hardware.usb"
+>
+<class name="UsbAccessory"
+ extends="java.lang.Object"
+ abstract="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<implements name="android.os.Parcelable">
+</implements>
+<method name="describeContents"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getDescription"
+ return="java.lang.String"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getManufacturer"
+ return="java.lang.String"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getModel"
+ return="java.lang.String"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getSerial"
+ return="java.lang.String"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getUri"
+ return="java.lang.String"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getVersion"
+ return="java.lang.String"
+ 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="parcel" 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>
+</class>
+<class name="UsbConstants"
+ extends="java.lang.Object"
+ abstract="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<constructor name="UsbConstants"
+ type="android.hardware.usb.UsbConstants"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</constructor>
+<field name="USB_CLASS_APP_SPEC"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="254"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="USB_CLASS_AUDIO"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="1"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="USB_CLASS_CDC_DATA"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="10"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="USB_CLASS_COMM"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="2"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="USB_CLASS_CONTENT_SEC"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="13"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="USB_CLASS_CSCID"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="11"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="USB_CLASS_HID"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="3"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="USB_CLASS_HUB"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="9"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="USB_CLASS_MASS_STORAGE"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="8"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="USB_CLASS_MISC"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="239"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="USB_CLASS_PER_INTERFACE"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="0"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="USB_CLASS_PHYSICA"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="5"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="USB_CLASS_PRINTER"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="7"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="USB_CLASS_STILL_IMAGE"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="6"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="USB_CLASS_VENDOR_SPEC"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="255"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="USB_CLASS_VIDEO"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="14"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="USB_CLASS_WIRELESS_CONTROLLER"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="224"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="USB_DIR_IN"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="128"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="USB_DIR_OUT"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="0"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="USB_ENDPOINT_DIR_MASK"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="128"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="USB_ENDPOINT_NUMBER_MASK"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="15"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="USB_ENDPOINT_XFERTYPE_MASK"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="3"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="USB_ENDPOINT_XFER_BULK"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="2"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="USB_ENDPOINT_XFER_CONTROL"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="0"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="USB_ENDPOINT_XFER_INT"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="3"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="USB_ENDPOINT_XFER_ISOC"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="1"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="USB_INTERFACE_SUBCLASS_BOOT"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="1"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="USB_SUBCLASS_VENDOR_SPEC"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="255"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="USB_TYPE_CLASS"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="32"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="USB_TYPE_MASK"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="96"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="USB_TYPE_RESERVED"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="96"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="USB_TYPE_STANDARD"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="0"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="USB_TYPE_VENDOR"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="64"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+</class>
+<class name="UsbDevice"
+ extends="java.lang.Object"
+ abstract="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<implements name="android.os.Parcelable">
+</implements>
+<method name="describeContents"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getDeviceClass"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getDeviceId"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getDeviceId"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="name" type="java.lang.String">
+</parameter>
+</method>
+<method name="getDeviceName"
+ return="java.lang.String"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getDeviceName"
+ return="java.lang.String"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="id" type="int">
+</parameter>
+</method>
+<method name="getDeviceProtocol"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getDeviceSubclass"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getInterface"
+ return="android.hardware.usb.UsbInterface"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="index" type="int">
+</parameter>
+</method>
+<method name="getInterfaceCount"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getProductId"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getVendorId"
+ 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="parcel" 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>
+</class>
+<class name="UsbDeviceConnection"
+ extends="java.lang.Object"
+ abstract="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<method name="bulkTransfer"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="endpoint" type="android.hardware.usb.UsbEndpoint">
+</parameter>
+<parameter name="buffer" type="byte[]">
+</parameter>
+<parameter name="length" type="int">
+</parameter>
+<parameter name="timeout" type="int">
+</parameter>
+</method>
+<method name="claimInterface"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="intf" type="android.hardware.usb.UsbInterface">
+</parameter>
+<parameter name="force" type="boolean">
+</parameter>
+</method>
+<method name="close"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="controlTransfer"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="requestType" type="int">
+</parameter>
+<parameter name="request" type="int">
+</parameter>
+<parameter name="value" type="int">
+</parameter>
+<parameter name="index" type="int">
+</parameter>
+<parameter name="buffer" type="byte[]">
+</parameter>
+<parameter name="length" type="int">
+</parameter>
+<parameter name="timeout" type="int">
+</parameter>
+</method>
+<method name="getFileDescriptor"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getSerial"
+ return="java.lang.String"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="releaseInterface"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="intf" type="android.hardware.usb.UsbInterface">
+</parameter>
+</method>
+<method name="requestWait"
+ return="android.hardware.usb.UsbRequest"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+</class>
+<class name="UsbEndpoint"
+ extends="java.lang.Object"
+ abstract="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<implements name="android.os.Parcelable">
+</implements>
+<method name="describeContents"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getAddress"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getAttributes"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getDirection"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getEndpointNumber"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getInterval"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getMaxPacketSize"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getType"
+ 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="parcel" 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>
+</class>
+<class name="UsbInterface"
+ extends="java.lang.Object"
+ abstract="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<implements name="android.os.Parcelable">
+</implements>
+<method name="describeContents"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getEndpoint"
+ return="android.hardware.usb.UsbEndpoint"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="index" type="int">
+</parameter>
+</method>
+<method name="getEndpointCount"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getId"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getInterfaceClass"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getInterfaceProtocol"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getInterfaceSubclass"
+ 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="parcel" 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>
+</class>
+<class name="UsbManager"
+ extends="java.lang.Object"
+ abstract="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<method name="getAccessoryList"
+ return="android.hardware.usb.UsbAccessory[]"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getDeviceList"
+ return="java.util.HashMap&lt;java.lang.String, android.hardware.usb.UsbDevice&gt;"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="hasPermission"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="device" type="android.hardware.usb.UsbDevice">
+</parameter>
+</method>
+<method name="hasPermission"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="accessory" type="android.hardware.usb.UsbAccessory">
+</parameter>
+</method>
+<method name="openAccessory"
+ return="android.os.ParcelFileDescriptor"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="accessory" type="android.hardware.usb.UsbAccessory">
+</parameter>
+</method>
+<method name="openDevice"
+ return="android.hardware.usb.UsbDeviceConnection"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="device" type="android.hardware.usb.UsbDevice">
+</parameter>
+</method>
+<method name="requestPermission"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="device" type="android.hardware.usb.UsbDevice">
+</parameter>
+<parameter name="pi" type="android.app.PendingIntent">
+</parameter>
+</method>
+<method name="requestPermission"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="accessory" type="android.hardware.usb.UsbAccessory">
+</parameter>
+<parameter name="pi" type="android.app.PendingIntent">
+</parameter>
+</method>
+<field name="ACTION_USB_ACCESSORY_ATTACHED"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;android.hardware.usb.action.USB_ACCESSORY_ATTACHED&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="ACTION_USB_ACCESSORY_DETACHED"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;android.hardware.usb.action.USB_ACCESSORY_DETACHED&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="ACTION_USB_DEVICE_ATTACHED"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;android.hardware.usb.action.USB_DEVICE_ATTACHED&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="ACTION_USB_DEVICE_DETACHED"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;android.hardware.usb.action.USB_DEVICE_DETACHED&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="EXTRA_ACCESSORY"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;accessory&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="EXTRA_DEVICE"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;device&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="EXTRA_PERMISSION_GRANTED"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;permission&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+</class>
+<class name="UsbRequest"
+ extends="java.lang.Object"
+ abstract="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<constructor name="UsbRequest"
+ type="android.hardware.usb.UsbRequest"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</constructor>
+<method name="cancel"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="close"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getClientData"
+ return="java.lang.Object"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getEndpoint"
+ return="android.hardware.usb.UsbEndpoint"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="initialize"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="connection" type="android.hardware.usb.UsbDeviceConnection">
+</parameter>
+<parameter name="endpoint" type="android.hardware.usb.UsbEndpoint">
+</parameter>
+</method>
+<method name="queue"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="buffer" type="java.nio.ByteBuffer">
+</parameter>
+<parameter name="length" type="int">
+</parameter>
+</method>
+<method name="setClientData"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="data" type="java.lang.Object">
+</parameter>
+</method>
+</class>
+</package>
 <package name="android.inputmethodservice"
 >
 <class name="AbstractInputMethodService"
@@ -110689,6 +112561,1268 @@
 </method>
 </interface>
 </package>
+<package name="android.mtp"
+>
+<class name="MtpConstants"
+ extends="java.lang.Object"
+ abstract="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<constructor name="MtpConstants"
+ type="android.mtp.MtpConstants"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</constructor>
+<method name="isAbstractObject"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="format" type="int">
+</parameter>
+</method>
+<field name="ASSOCIATION_TYPE_GENERIC_FOLDER"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="1"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="FORMAT_3GP_CONTAINER"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="47492"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="FORMAT_AAC"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="47363"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="FORMAT_ABSTRACT_AUDIO_ALBUM"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="47619"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="FORMAT_ABSTRACT_AUDIO_PLAYLIST"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="47625"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="FORMAT_ABSTRACT_AV_PLAYLIST"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="47621"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="FORMAT_ABSTRACT_DOCUMENT"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="47745"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="FORMAT_ABSTRACT_IMAGE_ALBUM"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="47618"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="FORMAT_ABSTRACT_MEDIACAST"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="47627"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="FORMAT_ABSTRACT_MULTIMEDIA_ALBUM"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="47617"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="FORMAT_ABSTRACT_VIDEO_ALBUM"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="47620"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="FORMAT_ABSTRACT_VIDEO_PLAYLIST"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="47626"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="FORMAT_AIFF"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="12295"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="FORMAT_ASF"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="12300"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="FORMAT_ASSOCIATION"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="12289"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="FORMAT_ASX_PLAYLIST"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="47635"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="FORMAT_AUDIBLE"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="47364"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="FORMAT_AVI"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="12298"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="FORMAT_BMP"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="14340"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="FORMAT_DPOF"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="12294"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="FORMAT_EXECUTABLE"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="12291"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="FORMAT_EXIF_JPEG"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="14337"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="FORMAT_FLAC"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="47366"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="FORMAT_GIF"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="14343"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="FORMAT_HTML"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="12293"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="FORMAT_JFIF"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="14344"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="FORMAT_JP2"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="14351"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="FORMAT_JPX"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="14352"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="FORMAT_M3U_PLAYLIST"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="47633"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="FORMAT_MP2"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="47491"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="FORMAT_MP3"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="12297"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="FORMAT_MP4_CONTAINER"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="47490"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="FORMAT_MPEG"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="12299"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="FORMAT_MPL_PLAYLIST"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="47634"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="FORMAT_MS_EXCEL_SPREADSHEET"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="47749"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="FORMAT_MS_POWERPOINT_PRESENTATION"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="47750"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="FORMAT_MS_WORD_DOCUMENT"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="47747"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="FORMAT_OGG"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="47362"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="FORMAT_PICT"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="14346"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="FORMAT_PLS_PLAYLIST"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="47636"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="FORMAT_PNG"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="14347"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="FORMAT_SCRIPT"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="12290"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="FORMAT_TEXT"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="12292"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="FORMAT_TIFF"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="14349"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="FORMAT_TIFF_EP"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="14338"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="FORMAT_UNDEFINED"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="12288"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="FORMAT_UNDEFINED_AUDIO"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="47360"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="FORMAT_UNDEFINED_COLLECTION"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="47616"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="FORMAT_UNDEFINED_DOCUMENT"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="47744"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="FORMAT_UNDEFINED_FIRMWARE"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="47106"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="FORMAT_UNDEFINED_VIDEO"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="47488"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="FORMAT_WAV"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="12296"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="FORMAT_WINDOWS_IMAGE_FORMAT"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="47233"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="FORMAT_WMA"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="47361"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="FORMAT_WMV"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="47489"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="FORMAT_WPL_PLAYLIST"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="47632"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="FORMAT_XML_DOCUMENT"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="47746"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="PROTECTION_STATUS_NONE"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="0"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="PROTECTION_STATUS_NON_TRANSFERABLE_DATA"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="32771"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="PROTECTION_STATUS_READ_ONLY"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="32769"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="PROTECTION_STATUS_READ_ONLY_DATA"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="32770"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+</class>
+<class name="MtpDevice"
+ extends="java.lang.Object"
+ abstract="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<constructor name="MtpDevice"
+ type="android.mtp.MtpDevice"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="device" type="android.hardware.usb.UsbDevice">
+</parameter>
+</constructor>
+<method name="close"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="deleteObject"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="objectHandle" type="int">
+</parameter>
+</method>
+<method name="getDeviceId"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getDeviceInfo"
+ return="android.mtp.MtpDeviceInfo"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getDeviceName"
+ return="java.lang.String"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getObject"
+ return="byte[]"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="objectHandle" type="int">
+</parameter>
+<parameter name="objectSize" type="int">
+</parameter>
+</method>
+<method name="getObjectHandles"
+ return="int[]"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="storageId" type="int">
+</parameter>
+<parameter name="format" type="int">
+</parameter>
+<parameter name="objectHandle" type="int">
+</parameter>
+</method>
+<method name="getObjectInfo"
+ return="android.mtp.MtpObjectInfo"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="objectHandle" type="int">
+</parameter>
+</method>
+<method name="getParent"
+ return="long"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="objectHandle" type="int">
+</parameter>
+</method>
+<method name="getStorageId"
+ return="long"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="objectHandle" type="int">
+</parameter>
+</method>
+<method name="getStorageIds"
+ return="int[]"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getStorageInfo"
+ return="android.mtp.MtpStorageInfo"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="storageId" type="int">
+</parameter>
+</method>
+<method name="getThumbnail"
+ return="byte[]"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="objectHandle" type="int">
+</parameter>
+</method>
+<method name="importFile"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="objectHandle" type="int">
+</parameter>
+<parameter name="destPath" type="java.lang.String">
+</parameter>
+</method>
+<method name="open"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="connection" type="android.hardware.usb.UsbDeviceConnection">
+</parameter>
+</method>
+</class>
+<class name="MtpDeviceInfo"
+ extends="java.lang.Object"
+ abstract="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<method name="getManufacturer"
+ return="java.lang.String"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getModel"
+ return="java.lang.String"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getSerialNumber"
+ return="java.lang.String"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getVersion"
+ return="java.lang.String"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+</class>
+<class name="MtpObjectInfo"
+ extends="java.lang.Object"
+ abstract="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<method name="getAssociationDesc"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getAssociationType"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getCompressedSize"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getDateCreated"
+ return="long"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getDateModified"
+ return="long"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getFormat"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getImagePixDepth"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getImagePixHeight"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getImagePixWidth"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getKeywords"
+ return="java.lang.String"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getName"
+ return="java.lang.String"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getObjectHandle"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getParent"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getProtectionStatus"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getSequenceNumber"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getStorageId"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getThumbCompressedSize"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getThumbFormat"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getThumbPixHeight"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getThumbPixWidth"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+</class>
+<class name="MtpStorageInfo"
+ extends="java.lang.Object"
+ abstract="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<method name="getDescription"
+ return="java.lang.String"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getFreeSpace"
+ return="long"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getMaxCapacity"
+ return="long"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getStorageId"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getVolumeIdentifier"
+ return="java.lang.String"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+</class>
+</package>
 <package name="android.net"
 >
 <class name="ConnectivityManager"
@@ -112470,6 +115604,71 @@
 <parameter name="uid" type="int">
 </parameter>
 </method>
+<method name="getUidRxPackets"
+ return="long"
+ abstract="false"
+ native="true"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="uid" type="int">
+</parameter>
+</method>
+<method name="getUidTcpRxBytes"
+ return="long"
+ abstract="false"
+ native="true"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="uid" type="int">
+</parameter>
+</method>
+<method name="getUidTcpRxSegments"
+ return="long"
+ abstract="false"
+ native="true"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="uid" type="int">
+</parameter>
+</method>
+<method name="getUidTcpTxBytes"
+ return="long"
+ abstract="false"
+ native="true"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="uid" type="int">
+</parameter>
+</method>
+<method name="getUidTcpTxSegments"
+ return="long"
+ abstract="false"
+ native="true"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="uid" type="int">
+</parameter>
+</method>
 <method name="getUidTxBytes"
  return="long"
  abstract="false"
@@ -112483,6 +115682,71 @@
 <parameter name="uid" type="int">
 </parameter>
 </method>
+<method name="getUidTxPackets"
+ return="long"
+ abstract="false"
+ native="true"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="uid" type="int">
+</parameter>
+</method>
+<method name="getUidUdpRxBytes"
+ return="long"
+ abstract="false"
+ native="true"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="uid" type="int">
+</parameter>
+</method>
+<method name="getUidUdpRxPackets"
+ return="long"
+ abstract="false"
+ native="true"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="uid" type="int">
+</parameter>
+</method>
+<method name="getUidUdpTxBytes"
+ return="long"
+ abstract="false"
+ native="true"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="uid" type="int">
+</parameter>
+</method>
+<method name="getUidUdpTxPackets"
+ return="long"
+ abstract="false"
+ native="true"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="uid" type="int">
+</parameter>
+</method>
 <field name="UNSUPPORTED"
  type="int"
  transient="false"
@@ -114291,7 +117555,7 @@
  type="android.net.http.SslCertificate"
  static="false"
  final="false"
- deprecated="not deprecated"
+ deprecated="deprecated"
  visibility="public"
 >
 <parameter name="issuedTo" type="java.lang.String">
@@ -114606,6 +117870,497 @@
 </field>
 </class>
 </package>
+<package name="android.net.rtp"
+>
+<class name="AudioCodec"
+ extends="java.lang.Object"
+ abstract="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<method name="getCodec"
+ return="android.net.rtp.AudioCodec"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="type" type="int">
+</parameter>
+<parameter name="rtpmap" type="java.lang.String">
+</parameter>
+<parameter name="fmtp" type="java.lang.String">
+</parameter>
+</method>
+<method name="getCodecs"
+ return="android.net.rtp.AudioCodec[]"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<field name="AMR"
+ type="android.net.rtp.AudioCodec"
+ transient="false"
+ volatile="false"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="GSM"
+ type="android.net.rtp.AudioCodec"
+ transient="false"
+ volatile="false"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="GSM_EFR"
+ type="android.net.rtp.AudioCodec"
+ transient="false"
+ volatile="false"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="PCMA"
+ type="android.net.rtp.AudioCodec"
+ transient="false"
+ volatile="false"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="PCMU"
+ type="android.net.rtp.AudioCodec"
+ transient="false"
+ volatile="false"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="fmtp"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="rtpmap"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="type"
+ type="int"
+ transient="false"
+ volatile="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+</class>
+<class name="AudioGroup"
+ extends="java.lang.Object"
+ abstract="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<constructor name="AudioGroup"
+ type="android.net.rtp.AudioGroup"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</constructor>
+<method name="clear"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getMode"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getStreams"
+ return="android.net.rtp.AudioStream[]"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="sendDtmf"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="event" type="int">
+</parameter>
+</method>
+<method name="setMode"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="mode" type="int">
+</parameter>
+</method>
+<field name="MODE_ECHO_SUPPRESSION"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="3"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="MODE_MUTED"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="1"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="MODE_NORMAL"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="2"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="MODE_ON_HOLD"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="0"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+</class>
+<class name="AudioStream"
+ extends="android.net.rtp.RtpStream"
+ abstract="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<constructor name="AudioStream"
+ type="android.net.rtp.AudioStream"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="address" type="java.net.InetAddress">
+</parameter>
+<exception name="SocketException" type="java.net.SocketException">
+</exception>
+</constructor>
+<method name="getCodec"
+ return="android.net.rtp.AudioCodec"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getDtmfType"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getGroup"
+ return="android.net.rtp.AudioGroup"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="isBusy"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="join"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="group" type="android.net.rtp.AudioGroup">
+</parameter>
+</method>
+<method name="setCodec"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="codec" type="android.net.rtp.AudioCodec">
+</parameter>
+</method>
+<method name="setDtmfType"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="type" type="int">
+</parameter>
+</method>
+</class>
+<class name="RtpStream"
+ extends="java.lang.Object"
+ abstract="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<method name="associate"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="address" type="java.net.InetAddress">
+</parameter>
+<parameter name="port" type="int">
+</parameter>
+</method>
+<method name="getLocalAddress"
+ return="java.net.InetAddress"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getLocalPort"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getMode"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getRemoteAddress"
+ return="java.net.InetAddress"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getRemotePort"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="isBusy"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="release"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="setMode"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="mode" type="int">
+</parameter>
+</method>
+<field name="MODE_NORMAL"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="0"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="MODE_RECEIVE_ONLY"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="2"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="MODE_SEND_ONLY"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="1"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+</class>
+</package>
 <package name="android.net.sip"
 >
 <class name="SipAudioCall"
@@ -115629,6 +119384,17 @@
  visibility="public"
 >
 </method>
+<method name="getAuthUserName"
+ return="java.lang.String"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
 <method name="getAutoRegistration"
  return="boolean"
  abstract="false"
@@ -115831,6 +119597,19 @@
  visibility="public"
 >
 </method>
+<method name="setAuthUserName"
+ return="android.net.sip.SipProfile.Builder"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="name" type="java.lang.String">
+</parameter>
+</method>
 <method name="setAutoRegistration"
  return="android.net.sip.SipProfile.Builder"
  abstract="false"
@@ -117871,6 +121650,17 @@
  visibility="public"
 >
 </field>
+<field name="WIFI_MODE_FULL_HIGH_PERF"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="3"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
 <field name="WIFI_MODE_SCAN_ONLY"
  type="int"
  transient="false"
@@ -140064,6 +143854,17 @@
  visibility="public"
 >
 </field>
+<field name="HONEYCOMB_MR1"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="12"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
 </class>
 <class name="Bundle"
  extends="java.lang.Object"
@@ -140323,6 +144124,21 @@
 <parameter name="key" type="java.lang.String">
 </parameter>
 </method>
+<method name="getCharSequence"
+ return="java.lang.CharSequence"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="key" type="java.lang.String">
+</parameter>
+<parameter name="defaultValue" type="java.lang.CharSequence">
+</parameter>
+</method>
 <method name="getCharSequenceArray"
  return="java.lang.CharSequence[]"
  abstract="false"
@@ -140656,6 +144472,21 @@
 <parameter name="key" type="java.lang.String">
 </parameter>
 </method>
+<method name="getString"
+ return="java.lang.String"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="key" type="java.lang.String">
+</parameter>
+<parameter name="defaultValue" type="java.lang.String">
+</parameter>
+</method>
 <method name="getStringArray"
  return="java.lang.String[]"
  abstract="false"
@@ -146208,6 +150039,17 @@
  visibility="public"
 >
 </method>
+<method name="detachFd"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
 <method name="fromSocket"
  return="android.os.ParcelFileDescriptor"
  abstract="false"
@@ -146221,6 +150063,17 @@
 <parameter name="socket" type="java.net.Socket">
 </parameter>
 </method>
+<method name="getFd"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
 <method name="getFileDescriptor"
  return="java.io.FileDescriptor"
  abstract="false"
@@ -152705,6 +156558,17 @@
  visibility="public"
 >
 </field>
+<field name="EXTRA_CREATE_NEW_TAB"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;create_new_tab&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
 <field name="EXTRA_HEADERS"
  type="java.lang.String"
  transient="false"
@@ -161661,6 +165525,19 @@
  visibility="public"
 >
 </method>
+<method name="getVersion"
+ return="java.lang.String"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="context" type="android.content.Context">
+</parameter>
+</method>
 <field name="ACTION_IMAGE_CAPTURE"
  type="java.lang.String"
  transient="false"
@@ -191324,7 +195201,7 @@
  synchronized="false"
  static="false"
  final="false"
- deprecated="not deprecated"
+ deprecated="deprecated"
  visibility="public"
 >
 <parameter name="contextStart" type="int">
@@ -194265,10 +198142,10 @@
  synchronized="false"
  static="true"
  final="false"
- deprecated="not deprecated"
+ deprecated="deprecated"
  visibility="public"
 >
-<parameter name="addr" type="int">
+<parameter name="ipv4Address" type="int">
 </parameter>
 </method>
 <method name="formatShortFileSize"
@@ -195282,6 +199159,23 @@
 <parameter name="buffer" type="android.text.Spannable">
 </parameter>
 </method>
+<method name="onGenericMotionEvent"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="widget" type="android.widget.TextView">
+</parameter>
+<parameter name="text" type="android.text.Spannable">
+</parameter>
+<parameter name="event" type="android.view.MotionEvent">
+</parameter>
+</method>
 <method name="onKeyDown"
  return="boolean"
  abstract="false"
@@ -196355,6 +200249,23 @@
 <parameter name="text" type="android.text.Spannable">
 </parameter>
 </method>
+<method name="onGenericMotionEvent"
+ return="boolean"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="widget" type="android.widget.TextView">
+</parameter>
+<parameter name="text" type="android.text.Spannable">
+</parameter>
+<parameter name="event" type="android.view.MotionEvent">
+</parameter>
+</method>
 <method name="onKeyDown"
  return="boolean"
  abstract="true"
@@ -203019,6 +206930,223 @@
 </parameter>
 </method>
 </class>
+<class name="LruCache"
+ extends="java.lang.Object"
+ abstract="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<constructor name="LruCache"
+ type="android.util.LruCache"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="maxSize" type="int">
+</parameter>
+</constructor>
+<method name="create"
+ return="V"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="protected"
+>
+<parameter name="key" type="K">
+</parameter>
+</method>
+<method name="createCount"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="true"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="entryRemoved"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="protected"
+>
+<parameter name="evicted" type="boolean">
+</parameter>
+<parameter name="key" type="K">
+</parameter>
+<parameter name="oldValue" type="V">
+</parameter>
+<parameter name="newValue" type="V">
+</parameter>
+</method>
+<method name="evictAll"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="evictionCount"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="true"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="get"
+ return="V"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="key" type="K">
+</parameter>
+</method>
+<method name="hitCount"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="true"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="maxSize"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="true"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="missCount"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="true"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="put"
+ return="V"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="key" type="K">
+</parameter>
+<parameter name="value" type="V">
+</parameter>
+</method>
+<method name="putCount"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="true"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="remove"
+ return="V"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="key" type="K">
+</parameter>
+</method>
+<method name="size"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="true"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="sizeOf"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="protected"
+>
+<parameter name="key" type="K">
+</parameter>
+<parameter name="value" type="V">
+</parameter>
+</method>
+<method name="snapshot"
+ return="java.util.Map&lt;K, V&gt;"
+ abstract="false"
+ native="false"
+ synchronized="true"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="toString"
+ return="java.lang.String"
+ abstract="false"
+ native="false"
+ synchronized="true"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+</class>
 <class name="MalformedJsonException"
  extends="java.io.IOException"
  abstract="false"
@@ -206986,9 +211114,35 @@
  deprecated="not deprecated"
  visibility="public"
 >
-<parameter name="rangeType" type="int">
+<parameter name="axis" type="int">
 </parameter>
 </method>
+<method name="getMotionRange"
+ return="android.view.InputDevice.MotionRange"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="axis" type="int">
+</parameter>
+<parameter name="source" type="int">
+</parameter>
+</method>
+<method name="getMotionRanges"
+ return="java.util.List&lt;android.view.InputDevice.MotionRange&gt;"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
 <method name="getName"
  return="java.lang.String"
  abstract="false"
@@ -207076,7 +211230,7 @@
  value="8"
  static="true"
  final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
  visibility="public"
 >
 </field>
@@ -207087,7 +211241,7 @@
  value="2"
  static="true"
  final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
  visibility="public"
 >
 </field>
@@ -207098,7 +211252,7 @@
  value="3"
  static="true"
  final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
  visibility="public"
 >
 </field>
@@ -207109,7 +211263,7 @@
  value="6"
  static="true"
  final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
  visibility="public"
 >
 </field>
@@ -207120,7 +211274,7 @@
  value="7"
  static="true"
  final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
  visibility="public"
 >
 </field>
@@ -207131,7 +211285,7 @@
  value="4"
  static="true"
  final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
  visibility="public"
 >
 </field>
@@ -207142,7 +211296,7 @@
  value="5"
  static="true"
  final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
  visibility="public"
 >
 </field>
@@ -207153,7 +211307,7 @@
  value="0"
  static="true"
  final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
  visibility="public"
 >
 </field>
@@ -207164,7 +211318,7 @@
  value="1"
  static="true"
  final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
  visibility="public"
 >
 </field>
@@ -207190,6 +211344,17 @@
  visibility="public"
 >
 </field>
+<field name="SOURCE_CLASS_JOYSTICK"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="16"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
 <field name="SOURCE_CLASS_MASK"
  type="int"
  transient="false"
@@ -207245,6 +211410,28 @@
  visibility="public"
 >
 </field>
+<field name="SOURCE_GAMEPAD"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="1025"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="SOURCE_JOYSTICK"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="16777232"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
 <field name="SOURCE_KEYBOARD"
  type="int"
  transient="false"
@@ -207320,6 +211507,17 @@
  deprecated="not deprecated"
  visibility="public"
 >
+<method name="getAxis"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
 <method name="getFlat"
  return="float"
  abstract="false"
@@ -207375,6 +211573,17 @@
  visibility="public"
 >
 </method>
+<method name="getSource"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
 </class>
 <class name="InputEvent"
  extends="java.lang.Object"
@@ -208215,6 +212424,17 @@
 <parameter name="c" type="int">
 </parameter>
 </method>
+<method name="getDeviceId"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
 <method name="getDisplayLabel"
  return="char"
  abstract="false"
@@ -208388,6 +212608,17 @@
  visibility="public"
 >
 </method>
+<method name="getSource"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
 <method name="getUnicodeChar"
  return="int"
  abstract="false"
@@ -208491,6 +212722,19 @@
  visibility="public"
 >
 </method>
+<method name="isGamepadButton"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="keyCode" type="int">
+</parameter>
+</method>
 <method name="isLongPress"
  return="boolean"
  abstract="false"
@@ -208603,6 +212847,32 @@
  visibility="public"
 >
 </method>
+<method name="keyCodeFromString"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="symbolicName" type="java.lang.String">
+</parameter>
+</method>
+<method name="keyCodeToString"
+ return="java.lang.String"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="keyCode" type="int">
+</parameter>
+</method>
 <method name="metaStateHasModifiers"
  return="boolean"
  abstract="false"
@@ -208644,6 +212914,19 @@
 <parameter name="metaState" type="int">
 </parameter>
 </method>
+<method name="setSource"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="source" type="int">
+</parameter>
+</method>
 <method name="startTracking"
  return="void"
  abstract="false"
@@ -209087,6 +213370,182 @@
  visibility="public"
 >
 </field>
+<field name="KEYCODE_BUTTON_1"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="188"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="KEYCODE_BUTTON_10"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="197"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="KEYCODE_BUTTON_11"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="198"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="KEYCODE_BUTTON_12"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="199"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="KEYCODE_BUTTON_13"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="200"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="KEYCODE_BUTTON_14"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="201"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="KEYCODE_BUTTON_15"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="202"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="KEYCODE_BUTTON_16"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="203"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="KEYCODE_BUTTON_2"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="189"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="KEYCODE_BUTTON_3"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="190"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="KEYCODE_BUTTON_4"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="191"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="KEYCODE_BUTTON_5"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="192"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="KEYCODE_BUTTON_6"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="193"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="KEYCODE_BUTTON_7"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="194"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="KEYCODE_BUTTON_8"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="195"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="KEYCODE_BUTTON_9"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="196"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
 <field name="KEYCODE_BUTTON_A"
  type="int"
  transient="false"
@@ -212678,6 +217137,32 @@
 <parameter name="metaState" type="int">
 </parameter>
 </method>
+<method name="axisFromString"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="symbolicName" type="java.lang.String">
+</parameter>
+</method>
+<method name="axisToString"
+ return="java.lang.String"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="axis" type="int">
+</parameter>
+</method>
 <method name="findPointerIndex"
  return="int"
  abstract="false"
@@ -212724,6 +217209,45 @@
  visibility="public"
 >
 </method>
+<method name="getAxisValue"
+ return="float"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="axis" type="int">
+</parameter>
+</method>
+<method name="getAxisValue"
+ return="float"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="axis" type="int">
+</parameter>
+<parameter name="pointerIndex" type="int">
+</parameter>
+</method>
+<method name="getDeviceId"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
 <method name="getDownTime"
  return="long"
  abstract="false"
@@ -212768,6 +217292,38 @@
  visibility="public"
 >
 </method>
+<method name="getHistoricalAxisValue"
+ return="float"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="axis" type="int">
+</parameter>
+<parameter name="pos" type="int">
+</parameter>
+</method>
+<method name="getHistoricalAxisValue"
+ return="float"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="axis" type="int">
+</parameter>
+<parameter name="pointerIndex" type="int">
+</parameter>
+<parameter name="pos" type="int">
+</parameter>
+</method>
 <method name="getHistoricalEventTime"
  return="long"
  abstract="false"
@@ -213205,6 +217761,17 @@
 <parameter name="pointerIndex" type="int">
 </parameter>
 </method>
+<method name="getSource"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
 <method name="getToolMajor"
  return="float"
  abstract="false"
@@ -213513,7 +218080,7 @@
  deprecated="not deprecated"
  visibility="public"
 >
-<parameter name="o" type="android.view.MotionEvent">
+<parameter name="other" type="android.view.MotionEvent">
 </parameter>
 </method>
 <method name="obtainNoHistory"
@@ -213526,7 +218093,7 @@
  deprecated="not deprecated"
  visibility="public"
 >
-<parameter name="o" type="android.view.MotionEvent">
+<parameter name="other" type="android.view.MotionEvent">
 </parameter>
 </method>
 <method name="offsetLocation"
@@ -213596,6 +218163,19 @@
 <parameter name="y" type="float">
 </parameter>
 </method>
+<method name="setSource"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="source" type="int">
+</parameter>
+</method>
 <method name="transform"
  return="void"
  abstract="false"
@@ -213646,6 +218226,17 @@
  visibility="public"
 >
 </field>
+<field name="ACTION_HOVER_MOVE"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="7"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
 <field name="ACTION_MASK"
  type="int"
  transient="false"
@@ -213811,6 +218402,17 @@
  visibility="public"
 >
 </field>
+<field name="ACTION_SCROLL"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="8"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
 <field name="ACTION_UP"
  type="int"
  transient="false"
@@ -213822,6 +218424,446 @@
  visibility="public"
 >
 </field>
+<field name="AXIS_BRAKE"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="23"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="AXIS_GAS"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="22"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="AXIS_GENERIC_1"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="32"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="AXIS_GENERIC_10"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="41"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="AXIS_GENERIC_11"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="42"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="AXIS_GENERIC_12"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="43"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="AXIS_GENERIC_13"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="44"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="AXIS_GENERIC_14"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="45"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="AXIS_GENERIC_15"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="46"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="AXIS_GENERIC_16"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="47"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="AXIS_GENERIC_2"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="33"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="AXIS_GENERIC_3"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="34"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="AXIS_GENERIC_4"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="35"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="AXIS_GENERIC_5"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="36"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="AXIS_GENERIC_6"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="37"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="AXIS_GENERIC_7"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="38"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="AXIS_GENERIC_8"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="39"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="AXIS_GENERIC_9"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="40"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="AXIS_HAT_X"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="15"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="AXIS_HAT_Y"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="16"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="AXIS_HSCROLL"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="10"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="AXIS_LTRIGGER"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="17"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="AXIS_ORIENTATION"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="8"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="AXIS_PRESSURE"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="2"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="AXIS_RTRIGGER"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="18"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="AXIS_RUDDER"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="20"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="AXIS_RX"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="12"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="AXIS_RY"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="13"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="AXIS_RZ"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="14"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="AXIS_SIZE"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="3"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="AXIS_THROTTLE"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="19"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="AXIS_TOOL_MAJOR"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="6"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="AXIS_TOOL_MINOR"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="7"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="AXIS_TOUCH_MAJOR"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="4"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="AXIS_TOUCH_MINOR"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="5"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="AXIS_VSCROLL"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="9"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="AXIS_WHEEL"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="21"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="AXIS_X"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="0"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="AXIS_Y"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="1"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="AXIS_Z"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="11"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
 <field name="CREATOR"
  type="android.os.Parcelable.Creator"
  transient="false"
@@ -213904,6 +218946,68 @@
  visibility="public"
 >
 </constructor>
+<constructor name="MotionEvent.PointerCoords"
+ type="android.view.MotionEvent.PointerCoords"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="other" type="android.view.MotionEvent.PointerCoords">
+</parameter>
+</constructor>
+<method name="clear"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="copyFrom"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="other" type="android.view.MotionEvent.PointerCoords">
+</parameter>
+</method>
+<method name="getAxisValue"
+ return="float"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="axis" type="int">
+</parameter>
+</method>
+<method name="setAxisValue"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="axis" type="int">
+</parameter>
+<parameter name="value" type="float">
+</parameter>
+</method>
 <field name="orientation"
  type="float"
  transient="false"
@@ -215890,6 +220994,19 @@
 <parameter name="focusableMode" type="int">
 </parameter>
 </method>
+<method name="addOnAttachStateChangeListener"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="listener" type="android.view.View.OnAttachStateChangeListener">
+</parameter>
+</method>
 <method name="addOnLayoutChangeListener"
  return="void"
  abstract="false"
@@ -215916,6 +221033,17 @@
 <parameter name="views" type="java.util.ArrayList&lt;android.view.View&gt;">
 </parameter>
 </method>
+<method name="animate"
+ return="android.view.ViewPropertyAnimator"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
 <method name="awakenScrollBars"
  return="boolean"
  abstract="false"
@@ -215990,6 +221118,17 @@
 <parameter name="autoScale" type="boolean">
 </parameter>
 </method>
+<method name="buildLayer"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
 <method name="cancelLongPress"
  return="void"
  abstract="false"
@@ -216204,6 +221343,19 @@
 <parameter name="canvas" type="android.graphics.Canvas">
 </parameter>
 </method>
+<method name="dispatchGenericMotionEvent"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="event" type="android.view.MotionEvent">
+</parameter>
+</method>
 <method name="dispatchKeyEvent"
  return="boolean"
  abstract="false"
@@ -218359,6 +223511,19 @@
 <parameter name="previouslyFocusedRect" type="android.graphics.Rect">
 </parameter>
 </method>
+<method name="onGenericMotionEvent"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="event" type="android.view.MotionEvent">
+</parameter>
+</method>
 <method name="onKeyDown"
  return="boolean"
  abstract="false"
@@ -218867,6 +224032,19 @@
 <parameter name="action" type="java.lang.Runnable">
 </parameter>
 </method>
+<method name="removeOnAttachStateChangeListener"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="listener" type="android.view.View.OnAttachStateChangeListener">
+</parameter>
+</method>
 <method name="removeOnLayoutChangeListener"
  return="void"
  abstract="false"
@@ -219191,6 +224369,19 @@
 <parameter name="bottom" type="int">
 </parameter>
 </method>
+<method name="setCameraDistance"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="distance" type="float">
+</parameter>
+</method>
 <method name="setClickable"
  return="void"
  abstract="false"
@@ -219611,6 +224802,19 @@
 <parameter name="l" type="android.view.View.OnFocusChangeListener">
 </parameter>
 </method>
+<method name="setOnGenericMotionListener"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="l" type="android.view.View.OnGenericMotionListener">
+</parameter>
+</method>
 <method name="setOnKeyListener"
  return="void"
  abstract="false"
@@ -221188,6 +226392,40 @@
 >
 </field>
 </class>
+<interface name="View.OnAttachStateChangeListener"
+ abstract="true"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<method name="onViewAttachedToWindow"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="v" type="android.view.View">
+</parameter>
+</method>
+<method name="onViewDetachedFromWindow"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="v" type="android.view.View">
+</parameter>
+</method>
+</interface>
 <interface name="View.OnClickListener"
  abstract="true"
  static="true"
@@ -221280,6 +226518,29 @@
 </parameter>
 </method>
 </interface>
+<interface name="View.OnGenericMotionListener"
+ abstract="true"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<method name="onGenericMotion"
+ return="boolean"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="v" type="android.view.View">
+</parameter>
+<parameter name="event" type="android.view.MotionEvent">
+</parameter>
+</method>
+</interface>
 <interface name="View.OnKeyListener"
  abstract="true"
  static="true"
@@ -221491,6 +226752,28 @@
  visibility="public"
 >
 </method>
+<method name="getKeyRepeatDelay"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getKeyRepeatTimeout"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
 <method name="getLongPressTimeout"
  return="int"
  abstract="false"
@@ -224081,6 +229364,314 @@
 </parameter>
 </method>
 </interface>
+<class name="ViewPropertyAnimator"
+ extends="java.lang.Object"
+ abstract="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<method name="alpha"
+ return="android.view.ViewPropertyAnimator"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="value" type="float">
+</parameter>
+</method>
+<method name="alphaBy"
+ return="android.view.ViewPropertyAnimator"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="value" type="float">
+</parameter>
+</method>
+<method name="rotation"
+ return="android.view.ViewPropertyAnimator"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="value" type="float">
+</parameter>
+</method>
+<method name="rotationBy"
+ return="android.view.ViewPropertyAnimator"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="value" type="float">
+</parameter>
+</method>
+<method name="rotationX"
+ return="android.view.ViewPropertyAnimator"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="value" type="float">
+</parameter>
+</method>
+<method name="rotationXBy"
+ return="android.view.ViewPropertyAnimator"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="value" type="float">
+</parameter>
+</method>
+<method name="rotationY"
+ return="android.view.ViewPropertyAnimator"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="value" type="float">
+</parameter>
+</method>
+<method name="rotationYBy"
+ return="android.view.ViewPropertyAnimator"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="value" type="float">
+</parameter>
+</method>
+<method name="scaleX"
+ return="android.view.ViewPropertyAnimator"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="value" type="float">
+</parameter>
+</method>
+<method name="scaleXBy"
+ return="android.view.ViewPropertyAnimator"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="value" type="float">
+</parameter>
+</method>
+<method name="scaleY"
+ return="android.view.ViewPropertyAnimator"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="value" type="float">
+</parameter>
+</method>
+<method name="scaleYBy"
+ return="android.view.ViewPropertyAnimator"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="value" type="float">
+</parameter>
+</method>
+<method name="setDuration"
+ return="android.view.ViewPropertyAnimator"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="duration" type="long">
+</parameter>
+</method>
+<method name="setInterpolator"
+ return="android.view.ViewPropertyAnimator"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="interpolator" type="android.animation.TimeInterpolator">
+</parameter>
+</method>
+<method name="setListener"
+ return="android.view.ViewPropertyAnimator"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="listener" type="android.animation.Animator.AnimatorListener">
+</parameter>
+</method>
+<method name="translationX"
+ return="android.view.ViewPropertyAnimator"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="value" type="float">
+</parameter>
+</method>
+<method name="translationXBy"
+ return="android.view.ViewPropertyAnimator"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="value" type="float">
+</parameter>
+</method>
+<method name="translationY"
+ return="android.view.ViewPropertyAnimator"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="value" type="float">
+</parameter>
+</method>
+<method name="translationYBy"
+ return="android.view.ViewPropertyAnimator"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="value" type="float">
+</parameter>
+</method>
+<method name="x"
+ return="android.view.ViewPropertyAnimator"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="value" type="float">
+</parameter>
+</method>
+<method name="xBy"
+ return="android.view.ViewPropertyAnimator"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="value" type="float">
+</parameter>
+</method>
+<method name="y"
+ return="android.view.ViewPropertyAnimator"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="value" type="float">
+</parameter>
+</method>
+<method name="yBy"
+ return="android.view.ViewPropertyAnimator"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="value" type="float">
+</parameter>
+</method>
+</class>
 <class name="ViewStub"
  extends="android.view.View"
  abstract="false"
@@ -225373,6 +230964,19 @@
 <parameter name="hardwareAccelerated" type="boolean">
 </parameter>
 </method>
+<method name="superDispatchGenericMotionEvent"
+ return="boolean"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="event" type="android.view.MotionEvent">
+</parameter>
+</method>
 <method name="superDispatchKeyEvent"
  return="boolean"
  abstract="true"
@@ -225718,6 +231322,19 @@
  deprecated="not deprecated"
  visibility="public"
 >
+<method name="dispatchGenericMotionEvent"
+ return="boolean"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="event" type="android.view.MotionEvent">
+</parameter>
+</method>
 <method name="dispatchKeyEvent"
  return="boolean"
  abstract="true"
@@ -228297,6 +233914,17 @@
  visibility="protected"
 >
 </method>
+<method name="getBackgroundColor"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
 <method name="getDetachWallpaper"
  return="boolean"
  abstract="false"
@@ -228582,6 +234210,19 @@
 <parameter name="listener" type="android.view.animation.Animation.AnimationListener">
 </parameter>
 </method>
+<method name="setBackgroundColor"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="bg" type="int">
+</parameter>
+</method>
 <method name="setDetachWallpaper"
  return="void"
  abstract="false"
@@ -233740,6 +239381,19 @@
 >
 <implements name="android.os.Parcelable">
 </implements>
+<method name="containsExtraValueKey"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="key" type="java.lang.String">
+</parameter>
+</method>
 <method name="describeContents"
  return="int"
  abstract="false"
@@ -233762,6 +239416,19 @@
  visibility="public"
 >
 </method>
+<method name="getExtraValueOf"
+ return="java.lang.String"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="key" type="java.lang.String">
+</parameter>
+</method>
 <method name="getIconResId"
  return="int"
  abstract="false"
@@ -234233,6 +239900,17 @@
  visibility="public"
 >
 </method>
+<method name="allowFileSchemeCookies"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
 <method name="getCookie"
  return="java.lang.String"
  abstract="false"
@@ -234314,6 +239992,19 @@
 <parameter name="accept" type="boolean">
 </parameter>
 </method>
+<method name="setAcceptFileSchemeCookies"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="accept" type="boolean">
+</parameter>
+</method>
 <method name="setCookie"
  return="void"
  abstract="false"
@@ -237984,7 +243675,7 @@
  synchronized="false"
  static="false"
  final="false"
- deprecated="not deprecated"
+ deprecated="deprecated"
  visibility="public"
 >
 </method>
@@ -238998,6 +244689,25 @@
 <parameter name="realm" type="java.lang.String">
 </parameter>
 </method>
+<method name="onReceivedLoginRequest"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="view" type="android.webkit.WebView">
+</parameter>
+<parameter name="realm" type="java.lang.String">
+</parameter>
+<parameter name="account" type="java.lang.String">
+</parameter>
+<parameter name="args" type="java.lang.String">
+</parameter>
+</method>
 <method name="onReceivedSslError"
  return="void"
  abstract="false"
@@ -245011,6 +250721,17 @@
 <parameter name="defStyle" type="int">
 </parameter>
 </constructor>
+<method name="getCalendarView"
+ return="android.widget.CalendarView"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
 <method name="getCalendarViewShown"
  return="boolean"
  abstract="false"
@@ -253386,6 +259107,21 @@
 <parameter name="started" type="boolean">
 </parameter>
 </method>
+<method name="setDisplayedChild"
+ 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="childIndex" type="int">
+</parameter>
+</method>
 <method name="setDouble"
  return="void"
  abstract="false"
diff --git a/api/current.xml b/api/current.xml
index a01658a..4db9c8f 100644
--- a/api/current.xml
+++ b/api/current.xml
@@ -22045,6 +22045,32 @@
 <parameter name="useLogo" type="boolean">
 </parameter>
 </method>
+<method name="setIcon"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="resId" type="int">
+</parameter>
+</method>
+<method name="setIcon"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="icon" type="android.graphics.drawable.Drawable">
+</parameter>
+</method>
 <method name="setListNavigationCallbacks"
  return="void"
  abstract="true"
@@ -22060,6 +22086,32 @@
 <parameter name="callback" type="android.app.ActionBar.OnNavigationListener">
 </parameter>
 </method>
+<method name="setLogo"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="resId" type="int">
+</parameter>
+</method>
+<method name="setLogo"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="logo" type="android.graphics.drawable.Drawable">
+</parameter>
+</method>
 <method name="setNavigationMode"
  return="void"
  abstract="true"
@@ -28643,6 +28695,17 @@
  visibility="public"
 >
 </method>
+<method name="dismissAllowingStateLoss"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
 <method name="getDialog"
  return="android.app.Dialog"
  abstract="false"
@@ -28850,7 +28913,7 @@
  deprecated="not deprecated"
  visibility="public"
 >
-<method name="completedDownload"
+<method name="addCompletedDownload"
  return="long"
  abstract="false"
  native="false"
@@ -30386,9 +30449,26 @@
  synchronized="false"
  static="false"
  final="false"
+ deprecated="deprecated"
+ visibility="public"
+>
+<parameter name="attrs" type="android.util.AttributeSet">
+</parameter>
+<parameter name="savedInstanceState" type="android.os.Bundle">
+</parameter>
+</method>
+<method name="onInflate"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
  deprecated="not deprecated"
  visibility="public"
 >
+<parameter name="activity" type="android.app.Activity">
+</parameter>
 <parameter name="attrs" type="android.util.AttributeSet">
 </parameter>
 <parameter name="savedInstanceState" type="android.os.Bundle">
@@ -72637,6 +72717,33 @@
 <parameter name="message" type="java.lang.String">
 </parameter>
 </constructor>
+<constructor name="DrmErrorEvent"
+ type="android.drm.DrmErrorEvent"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="uniqueId" type="int">
+</parameter>
+<parameter name="type" type="int">
+</parameter>
+<parameter name="message" type="java.lang.String">
+</parameter>
+<parameter name="attributes" type="java.util.HashMap&lt;java.lang.String, java.lang.Object&gt;">
+</parameter>
+</constructor>
+<field name="TYPE_ACQUIRE_DRM_INFO_FAILED"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="2008"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
 <field name="TYPE_NOT_SUPPORTED"
  type="int"
  transient="false"
@@ -72736,7 +72843,36 @@
 </parameter>
 <parameter name="message" type="java.lang.String">
 </parameter>
+<parameter name="attributes" type="java.util.HashMap&lt;java.lang.String, java.lang.Object&gt;">
+</parameter>
 </constructor>
+<constructor name="DrmEvent"
+ type="android.drm.DrmEvent"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="protected"
+>
+<parameter name="uniqueId" type="int">
+</parameter>
+<parameter name="type" type="int">
+</parameter>
+<parameter name="message" type="java.lang.String">
+</parameter>
+</constructor>
+<method name="getAttribute"
+ return="java.lang.Object"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="key" type="java.lang.String">
+</parameter>
+</method>
 <method name="getMessage"
  return="java.lang.String"
  abstract="false"
@@ -72770,6 +72906,17 @@
  visibility="public"
 >
 </method>
+<field name="DRM_INFO_OBJECT"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;drm_info_object&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
 <field name="DRM_INFO_STATUS_OBJECT"
  type="java.lang.String"
  transient="false"
@@ -72946,6 +73093,22 @@
 <parameter name="message" type="java.lang.String">
 </parameter>
 </constructor>
+<constructor name="DrmInfoEvent"
+ type="android.drm.DrmInfoEvent"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="uniqueId" type="int">
+</parameter>
+<parameter name="type" type="int">
+</parameter>
+<parameter name="message" type="java.lang.String">
+</parameter>
+<parameter name="attributes" type="java.util.HashMap&lt;java.lang.String, java.lang.Object&gt;">
+</parameter>
+</constructor>
 <field name="TYPE_ACCOUNT_ALREADY_REGISTERED"
  type="int"
  transient="false"
@@ -72990,6 +73153,17 @@
  visibility="public"
 >
 </field>
+<field name="TYPE_RIGHTS_REMOVED"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="6"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
 <field name="TYPE_WAIT_FOR_RIGHTS"
  type="int"
  transient="false"
@@ -73717,8 +73891,6 @@
 </parameter>
 <parameter name="event" type="android.drm.DrmEvent">
 </parameter>
-<parameter name="attributes" type="java.util.HashMap&lt;java.lang.String, java.lang.Object&gt;">
-</parameter>
 </method>
 </interface>
 <interface name="DrmManagerClient.OnInfoListener"
@@ -93214,6 +93386,17 @@
  visibility="public"
 >
 </field>
+<field name="TYPE_AMBIENT_TEMPERATURE"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="13"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
 <field name="TYPE_GRAVITY"
  type="int"
  transient="false"
@@ -93320,7 +93503,7 @@
  value="7"
  static="true"
  final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
  visibility="public"
 >
 </field>
@@ -94398,6 +94581,17 @@
  visibility="public"
 >
 </method>
+<method name="getDescription"
+ return="java.lang.String"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
 <method name="getManufacturer"
  return="java.lang.String"
  abstract="false"
@@ -94420,7 +94614,18 @@
  visibility="public"
 >
 </method>
-<method name="getType"
+<method name="getSerial"
+ return="java.lang.String"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getUri"
  return="java.lang.String"
  abstract="false"
  native="false"
@@ -94852,82 +95057,12 @@
  extends="java.lang.Object"
  abstract="false"
  static="false"
- final="true"
+ final="false"
  deprecated="not deprecated"
  visibility="public"
 >
 <implements name="android.os.Parcelable">
 </implements>
-<method name="bulkTransfer"
- return="int"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="endpoint" type="android.hardware.usb.UsbEndpoint">
-</parameter>
-<parameter name="buffer" type="byte[]">
-</parameter>
-<parameter name="length" type="int">
-</parameter>
-<parameter name="timeout" type="int">
-</parameter>
-</method>
-<method name="claimInterface"
- return="boolean"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="intf" type="android.hardware.usb.UsbInterface">
-</parameter>
-<parameter name="force" type="boolean">
-</parameter>
-</method>
-<method name="close"
- return="void"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-</method>
-<method name="controlTransfer"
- return="int"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="requestType" type="int">
-</parameter>
-<parameter name="request" type="int">
-</parameter>
-<parameter name="value" type="int">
-</parameter>
-<parameter name="index" type="int">
-</parameter>
-<parameter name="buffer" type="byte[]">
-</parameter>
-<parameter name="length" type="int">
-</parameter>
-<parameter name="timeout" type="int">
-</parameter>
-</method>
 <method name="describeContents"
  return="int"
  abstract="false"
@@ -95020,17 +95155,6 @@
  visibility="public"
 >
 </method>
-<method name="getFileDescriptor"
- return="int"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-</method>
 <method name="getInterface"
  return="android.hardware.usb.UsbInterface"
  abstract="false"
@@ -95066,17 +95190,6 @@
  visibility="public"
 >
 </method>
-<method name="getSerial"
- return="java.lang.String"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-</method>
 <method name="getVendorId"
  return="int"
  abstract="false"
@@ -95088,30 +95201,6 @@
  visibility="public"
 >
 </method>
-<method name="releaseInterface"
- return="boolean"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="intf" type="android.hardware.usb.UsbInterface">
-</parameter>
-</method>
-<method name="requestWait"
- return="android.hardware.usb.UsbRequest"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-</method>
 <method name="writeToParcel"
  return="void"
  abstract="false"
@@ -95138,11 +95227,136 @@
 >
 </field>
 </class>
+<class name="UsbDeviceConnection"
+ extends="java.lang.Object"
+ abstract="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<method name="bulkTransfer"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="endpoint" type="android.hardware.usb.UsbEndpoint">
+</parameter>
+<parameter name="buffer" type="byte[]">
+</parameter>
+<parameter name="length" type="int">
+</parameter>
+<parameter name="timeout" type="int">
+</parameter>
+</method>
+<method name="claimInterface"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="intf" type="android.hardware.usb.UsbInterface">
+</parameter>
+<parameter name="force" type="boolean">
+</parameter>
+</method>
+<method name="close"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="controlTransfer"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="requestType" type="int">
+</parameter>
+<parameter name="request" type="int">
+</parameter>
+<parameter name="value" type="int">
+</parameter>
+<parameter name="index" type="int">
+</parameter>
+<parameter name="buffer" type="byte[]">
+</parameter>
+<parameter name="length" type="int">
+</parameter>
+<parameter name="timeout" type="int">
+</parameter>
+</method>
+<method name="getFileDescriptor"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getSerial"
+ return="java.lang.String"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="releaseInterface"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="intf" type="android.hardware.usb.UsbInterface">
+</parameter>
+</method>
+<method name="requestWait"
+ return="android.hardware.usb.UsbRequest"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+</class>
 <class name="UsbEndpoint"
  extends="java.lang.Object"
  abstract="false"
  static="false"
- final="true"
+ final="false"
  deprecated="not deprecated"
  visibility="public"
 >
@@ -95181,17 +95395,6 @@
  visibility="public"
 >
 </method>
-<method name="getDevice"
- return="android.hardware.usb.UsbDevice"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-</method>
 <method name="getDirection"
  return="int"
  abstract="false"
@@ -95214,17 +95417,6 @@
  visibility="public"
 >
 </method>
-<method name="getInterface"
- return="android.hardware.usb.UsbInterface"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-</method>
 <method name="getInterval"
  return="int"
  abstract="false"
@@ -95305,17 +95497,6 @@
  visibility="public"
 >
 </method>
-<method name="getDevice"
- return="android.hardware.usb.UsbDevice"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-</method>
 <method name="getEndpoint"
  return="android.hardware.usb.UsbEndpoint"
  abstract="false"
@@ -95440,30 +95621,30 @@
  visibility="public"
 >
 </method>
-<method name="isFunctionEnabled"
+<method name="hasPermission"
  return="boolean"
  abstract="false"
  native="false"
  synchronized="false"
- static="true"
+ static="false"
  final="false"
  deprecated="not deprecated"
  visibility="public"
 >
-<parameter name="function" type="java.lang.String">
+<parameter name="device" type="android.hardware.usb.UsbDevice">
 </parameter>
 </method>
-<method name="isFunctionSupported"
+<method name="hasPermission"
  return="boolean"
  abstract="false"
  native="false"
  synchronized="false"
- static="true"
+ static="false"
  final="false"
  deprecated="not deprecated"
  visibility="public"
 >
-<parameter name="function" type="java.lang.String">
+<parameter name="accessory" type="android.hardware.usb.UsbAccessory">
 </parameter>
 </method>
 <method name="openAccessory"
@@ -95480,7 +95661,7 @@
 </parameter>
 </method>
 <method name="openDevice"
- return="boolean"
+ return="android.hardware.usb.UsbDeviceConnection"
  abstract="false"
  native="false"
  synchronized="false"
@@ -95492,6 +95673,36 @@
 <parameter name="device" type="android.hardware.usb.UsbDevice">
 </parameter>
 </method>
+<method name="requestPermission"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="device" type="android.hardware.usb.UsbDevice">
+</parameter>
+<parameter name="pi" type="android.app.PendingIntent">
+</parameter>
+</method>
+<method name="requestPermission"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="accessory" type="android.hardware.usb.UsbAccessory">
+</parameter>
+<parameter name="pi" type="android.app.PendingIntent">
+</parameter>
+</method>
 <field name="ACTION_USB_ACCESSORY_ATTACHED"
  type="java.lang.String"
  transient="false"
@@ -95536,17 +95747,6 @@
  visibility="public"
 >
 </field>
-<field name="ACTION_USB_STATE"
- type="java.lang.String"
- transient="false"
- volatile="false"
- value="&quot;android.hardware.usb.action.USB_STATE&quot;"
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
 <field name="EXTRA_ACCESSORY"
  type="java.lang.String"
  transient="false"
@@ -95569,99 +95769,11 @@
  visibility="public"
 >
 </field>
-<field name="USB_CONFIGURATION"
+<field name="EXTRA_PERMISSION_GRANTED"
  type="java.lang.String"
  transient="false"
  volatile="false"
- value="&quot;configuration&quot;"
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
-<field name="USB_CONNECTED"
- type="java.lang.String"
- transient="false"
- volatile="false"
- value="&quot;connected&quot;"
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
-<field name="USB_FUNCTION_ACCESSORY"
- type="java.lang.String"
- transient="false"
- volatile="false"
- value="&quot;accessory&quot;"
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
-<field name="USB_FUNCTION_ADB"
- type="java.lang.String"
- transient="false"
- volatile="false"
- value="&quot;adb&quot;"
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
-<field name="USB_FUNCTION_DISABLED"
- type="java.lang.String"
- transient="false"
- volatile="false"
- value="&quot;disabled&quot;"
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
-<field name="USB_FUNCTION_ENABLED"
- type="java.lang.String"
- transient="false"
- volatile="false"
- value="&quot;enabled&quot;"
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
-<field name="USB_FUNCTION_MASS_STORAGE"
- type="java.lang.String"
- transient="false"
- volatile="false"
- value="&quot;mass_storage&quot;"
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
-<field name="USB_FUNCTION_MTP"
- type="java.lang.String"
- transient="false"
- volatile="false"
- value="&quot;mtp&quot;"
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
-<field name="USB_FUNCTION_RNDIS"
- type="java.lang.String"
- transient="false"
- volatile="false"
- value="&quot;rndis&quot;"
+ value="&quot;permission&quot;"
  static="true"
  final="true"
  deprecated="not deprecated"
@@ -95739,6 +95851,8 @@
  deprecated="not deprecated"
  visibility="public"
 >
+<parameter name="connection" type="android.hardware.usb.UsbDeviceConnection">
+</parameter>
 <parameter name="endpoint" type="android.hardware.usb.UsbEndpoint">
 </parameter>
 </method>
@@ -105664,6 +105778,23 @@
  deprecated="not deprecated"
  visibility="public"
 >
+<parameter name="uri" type="java.lang.String">
+</parameter>
+<parameter name="headers" type="java.util.Map&lt;java.lang.String, java.lang.String&gt;">
+</parameter>
+<exception name="IllegalArgumentException" type="java.lang.IllegalArgumentException">
+</exception>
+</method>
+<method name="setDataSource"
+ return="void"
+ abstract="false"
+ native="true"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
 <parameter name="fd" type="java.io.FileDescriptor">
 </parameter>
 <parameter name="offset" type="long">
@@ -105751,6 +105882,17 @@
  visibility="public"
 >
 </field>
+<field name="METADATA_KEY_BITRATE"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="20"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
 <field name="METADATA_KEY_CD_TRACK_NUMBER"
  type="int"
  transient="false"
@@ -105828,6 +105970,28 @@
  visibility="public"
 >
 </field>
+<field name="METADATA_KEY_HAS_AUDIO"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="16"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="METADATA_KEY_HAS_VIDEO"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="17"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
 <field name="METADATA_KEY_MIMETYPE"
  type="int"
  transient="false"
@@ -105861,6 +106025,28 @@
  visibility="public"
 >
 </field>
+<field name="METADATA_KEY_VIDEO_HEIGHT"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="19"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="METADATA_KEY_VIDEO_WIDTH"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="18"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
 <field name="METADATA_KEY_WRITER"
  type="int"
  transient="false"
@@ -112512,255 +112698,6 @@
 </package>
 <package name="android.mtp"
 >
-<class name="MtpClient"
- extends="java.lang.Object"
- abstract="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<constructor name="MtpClient"
- type="android.mtp.MtpClient"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="context" type="android.content.Context">
-</parameter>
-</constructor>
-<method name="addListener"
- return="void"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="listener" type="android.mtp.MtpClient.Listener">
-</parameter>
-</method>
-<method name="close"
- return="void"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-</method>
-<method name="deleteObject"
- return="boolean"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="deviceName" type="java.lang.String">
-</parameter>
-<parameter name="objectHandle" type="int">
-</parameter>
-</method>
-<method name="getDevice"
- return="android.mtp.MtpDevice"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="deviceName" type="java.lang.String">
-</parameter>
-</method>
-<method name="getDevice"
- return="android.mtp.MtpDevice"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="id" type="int">
-</parameter>
-</method>
-<method name="getDeviceList"
- return="java.util.List&lt;android.mtp.MtpDevice&gt;"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-</method>
-<method name="getObject"
- return="byte[]"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="deviceName" type="java.lang.String">
-</parameter>
-<parameter name="objectHandle" type="int">
-</parameter>
-<parameter name="objectSize" type="int">
-</parameter>
-</method>
-<method name="getObjectInfo"
- return="android.mtp.MtpObjectInfo"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="deviceName" type="java.lang.String">
-</parameter>
-<parameter name="objectHandle" type="int">
-</parameter>
-</method>
-<method name="getObjectList"
- return="java.util.List&lt;android.mtp.MtpObjectInfo&gt;"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="deviceName" type="java.lang.String">
-</parameter>
-<parameter name="storageId" type="int">
-</parameter>
-<parameter name="objectHandle" type="int">
-</parameter>
-</method>
-<method name="getStorageList"
- return="java.util.List&lt;android.mtp.MtpStorageInfo&gt;"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="deviceName" type="java.lang.String">
-</parameter>
-</method>
-<method name="getThumbnail"
- return="byte[]"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="deviceName" type="java.lang.String">
-</parameter>
-<parameter name="objectHandle" type="int">
-</parameter>
-</method>
-<method name="importFile"
- return="boolean"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="deviceName" type="java.lang.String">
-</parameter>
-<parameter name="objectHandle" type="int">
-</parameter>
-<parameter name="destPath" type="java.lang.String">
-</parameter>
-</method>
-<method name="isCamera"
- return="boolean"
- abstract="false"
- native="false"
- synchronized="false"
- static="true"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="device" type="android.hardware.usb.UsbDevice">
-</parameter>
-</method>
-<method name="removeListener"
- return="void"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="listener" type="android.mtp.MtpClient.Listener">
-</parameter>
-</method>
-</class>
-<interface name="MtpClient.Listener"
- abstract="true"
- static="true"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<method name="deviceAdded"
- return="void"
- abstract="true"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="device" type="android.mtp.MtpDevice">
-</parameter>
-</method>
-<method name="deviceRemoved"
- return="void"
- abstract="true"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="device" type="android.mtp.MtpDevice">
-</parameter>
-</method>
-</interface>
 <class name="MtpConstants"
  extends="java.lang.Object"
  abstract="false"
@@ -113595,7 +113532,7 @@
 <parameter name="objectHandle" type="int">
 </parameter>
 </method>
-<method name="getStorageID"
+<method name="getStorageId"
  return="long"
  abstract="false"
  native="false"
@@ -113670,7 +113607,7 @@
  deprecated="not deprecated"
  visibility="public"
 >
-<parameter name="manager" type="android.hardware.usb.UsbManager">
+<parameter name="connection" type="android.hardware.usb.UsbDeviceConnection">
 </parameter>
 </method>
 </class>
@@ -118068,6 +118005,497 @@
 </field>
 </class>
 </package>
+<package name="android.net.rtp"
+>
+<class name="AudioCodec"
+ extends="java.lang.Object"
+ abstract="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<method name="getCodec"
+ return="android.net.rtp.AudioCodec"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="type" type="int">
+</parameter>
+<parameter name="rtpmap" type="java.lang.String">
+</parameter>
+<parameter name="fmtp" type="java.lang.String">
+</parameter>
+</method>
+<method name="getCodecs"
+ return="android.net.rtp.AudioCodec[]"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<field name="AMR"
+ type="android.net.rtp.AudioCodec"
+ transient="false"
+ volatile="false"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="GSM"
+ type="android.net.rtp.AudioCodec"
+ transient="false"
+ volatile="false"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="GSM_EFR"
+ type="android.net.rtp.AudioCodec"
+ transient="false"
+ volatile="false"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="PCMA"
+ type="android.net.rtp.AudioCodec"
+ transient="false"
+ volatile="false"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="PCMU"
+ type="android.net.rtp.AudioCodec"
+ transient="false"
+ volatile="false"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="fmtp"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="rtpmap"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="type"
+ type="int"
+ transient="false"
+ volatile="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+</class>
+<class name="AudioGroup"
+ extends="java.lang.Object"
+ abstract="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<constructor name="AudioGroup"
+ type="android.net.rtp.AudioGroup"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</constructor>
+<method name="clear"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getMode"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getStreams"
+ return="android.net.rtp.AudioStream[]"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="sendDtmf"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="event" type="int">
+</parameter>
+</method>
+<method name="setMode"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="mode" type="int">
+</parameter>
+</method>
+<field name="MODE_ECHO_SUPPRESSION"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="3"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="MODE_MUTED"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="1"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="MODE_NORMAL"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="2"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="MODE_ON_HOLD"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="0"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+</class>
+<class name="AudioStream"
+ extends="android.net.rtp.RtpStream"
+ abstract="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<constructor name="AudioStream"
+ type="android.net.rtp.AudioStream"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="address" type="java.net.InetAddress">
+</parameter>
+<exception name="SocketException" type="java.net.SocketException">
+</exception>
+</constructor>
+<method name="getCodec"
+ return="android.net.rtp.AudioCodec"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getDtmfType"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getGroup"
+ return="android.net.rtp.AudioGroup"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="isBusy"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="join"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="group" type="android.net.rtp.AudioGroup">
+</parameter>
+</method>
+<method name="setCodec"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="codec" type="android.net.rtp.AudioCodec">
+</parameter>
+</method>
+<method name="setDtmfType"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="type" type="int">
+</parameter>
+</method>
+</class>
+<class name="RtpStream"
+ extends="java.lang.Object"
+ abstract="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<method name="associate"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="address" type="java.net.InetAddress">
+</parameter>
+<parameter name="port" type="int">
+</parameter>
+</method>
+<method name="getLocalAddress"
+ return="java.net.InetAddress"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getLocalPort"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getMode"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getRemoteAddress"
+ return="java.net.InetAddress"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getRemotePort"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="isBusy"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="release"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="setMode"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="mode" type="int">
+</parameter>
+</method>
+<field name="MODE_NORMAL"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="0"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="MODE_RECEIVE_ONLY"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="2"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="MODE_SEND_ONLY"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="1"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+</class>
+</package>
 <package name="android.net.sip"
 >
 <class name="SipAudioCall"
@@ -143561,6 +143989,17 @@
  visibility="public"
 >
 </field>
+<field name="HONEYCOMB_MR1"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="12"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
 </class>
 <class name="Bundle"
  extends="java.lang.Object"
@@ -143820,6 +144259,21 @@
 <parameter name="key" type="java.lang.String">
 </parameter>
 </method>
+<method name="getCharSequence"
+ return="java.lang.CharSequence"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="key" type="java.lang.String">
+</parameter>
+<parameter name="defaultValue" type="java.lang.CharSequence">
+</parameter>
+</method>
 <method name="getCharSequenceArray"
  return="java.lang.CharSequence[]"
  abstract="false"
@@ -144153,6 +144607,21 @@
 <parameter name="key" type="java.lang.String">
 </parameter>
 </method>
+<method name="getString"
+ return="java.lang.String"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="key" type="java.lang.String">
+</parameter>
+<parameter name="defaultValue" type="java.lang.String">
+</parameter>
+</method>
 <method name="getStringArray"
  return="java.lang.String[]"
  abstract="false"
@@ -153593,6 +154062,17 @@
  visibility="public"
 >
 </method>
+<method name="getTitleRes"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
 <method name="getView"
  return="android.view.View"
  abstract="false"
@@ -154486,6 +154966,25 @@
 <parameter name="target" type="java.util.List&lt;android.preference.PreferenceActivity.Header&gt;">
 </parameter>
 </method>
+<method name="onBuildStartFragmentIntent"
+ return="android.content.Intent"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="fragmentName" type="java.lang.String">
+</parameter>
+<parameter name="args" type="android.os.Bundle">
+</parameter>
+<parameter name="titleRes" type="int">
+</parameter>
+<parameter name="shortTitleRes" type="int">
+</parameter>
+</method>
 <method name="onGetInitialHeader"
  return="android.preference.PreferenceActivity.Header"
  abstract="false"
@@ -154690,6 +155189,29 @@
 <parameter name="resultRequestCode" type="int">
 </parameter>
 </method>
+<method name="startWithFragment"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="fragmentName" type="java.lang.String">
+</parameter>
+<parameter name="args" type="android.os.Bundle">
+</parameter>
+<parameter name="resultTo" type="android.app.Fragment">
+</parameter>
+<parameter name="resultRequestCode" type="int">
+</parameter>
+<parameter name="titleRes" type="int">
+</parameter>
+<parameter name="shortTitleRes" type="int">
+</parameter>
+</method>
 <method name="switchToHeader"
  return="void"
  abstract="false"
@@ -154751,6 +155273,28 @@
  visibility="public"
 >
 </field>
+<field name="EXTRA_SHOW_FRAGMENT_SHORT_TITLE"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;:android:show_fragment_short_title&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="EXTRA_SHOW_FRAGMENT_TITLE"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;:android:show_fragment_title&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
 <field name="HEADER_ID_UNDEFINED"
  type="long"
  transient="false"
@@ -194867,7 +195411,7 @@
  synchronized="false"
  static="false"
  final="false"
- deprecated="not deprecated"
+ deprecated="deprecated"
  visibility="public"
 >
 <parameter name="contextStart" type="int">
@@ -201535,6 +202079,186 @@
 </parameter>
 </method>
 </class>
+<class name="CorrectionSpan"
+ extends="java.lang.Object"
+ abstract="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<implements name="android.text.ParcelableSpan">
+</implements>
+<constructor name="CorrectionSpan"
+ type="android.text.style.CorrectionSpan"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="context" type="android.content.Context">
+</parameter>
+<parameter name="suggests" type="java.util.List&lt;java.lang.CharSequence&gt;">
+</parameter>
+<parameter name="flags" type="int">
+</parameter>
+</constructor>
+<constructor name="CorrectionSpan"
+ type="android.text.style.CorrectionSpan"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="locale" type="java.util.Locale">
+</parameter>
+<parameter name="suggests" type="java.util.List&lt;java.lang.CharSequence&gt;">
+</parameter>
+<parameter name="flags" type="int">
+</parameter>
+</constructor>
+<constructor name="CorrectionSpan"
+ type="android.text.style.CorrectionSpan"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="context" type="android.content.Context">
+</parameter>
+<parameter name="locale" type="java.util.Locale">
+</parameter>
+<parameter name="suggests" type="java.util.List&lt;java.lang.CharSequence&gt;">
+</parameter>
+<parameter name="flags" type="int">
+</parameter>
+<parameter name="originalString" type="java.lang.String">
+</parameter>
+</constructor>
+<constructor name="CorrectionSpan"
+ type="android.text.style.CorrectionSpan"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="src" 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="getFlags"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getLocale"
+ return="java.lang.String"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getOriginalString"
+ return="java.lang.String"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getSpanTypeId"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getSuggests"
+ return="java.util.List&lt;java.lang.CharSequence&gt;"
+ 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="dest" 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="FLAG_DEFAULT"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="0"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="FLAG_VERBATIM"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="1"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+</class>
 <class name="DrawableMarginSpan"
  extends="java.lang.Object"
  abstract="false"
@@ -206638,21 +207362,6 @@
  visibility="public"
 >
 </method>
-<method name="entryEvicted"
- return="void"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="deprecated"
- visibility="protected"
->
-<parameter name="key" type="K">
-</parameter>
-<parameter name="value" type="V">
-</parameter>
-</method>
 <method name="entryRemoved"
  return="void"
  abstract="false"
@@ -210785,8 +211494,8 @@
  visibility="public"
 >
 </method>
-<method name="getMotionAxes"
- return="int[]"
+<method name="getMotionRange"
+ return="android.view.InputDevice.MotionRange"
  abstract="false"
  native="false"
  synchronized="false"
@@ -210795,6 +211504,8 @@
  deprecated="not deprecated"
  visibility="public"
 >
+<parameter name="axis" type="int">
+</parameter>
 </method>
 <method name="getMotionRange"
  return="android.view.InputDevice.MotionRange"
@@ -210808,6 +211519,19 @@
 >
 <parameter name="axis" type="int">
 </parameter>
+<parameter name="source" type="int">
+</parameter>
+</method>
+<method name="getMotionRanges"
+ return="java.util.List&lt;android.view.InputDevice.MotionRange&gt;"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
 </method>
 <method name="getName"
  return="java.lang.String"
@@ -211173,6 +211897,17 @@
  deprecated="not deprecated"
  visibility="public"
 >
+<method name="getAxis"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
 <method name="getFlat"
  return="float"
  abstract="false"
@@ -211228,6 +211963,17 @@
  visibility="public"
 >
 </method>
+<method name="getSource"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
 </class>
 <class name="InputEvent"
  extends="java.lang.Object"
@@ -212805,6 +213551,17 @@
  visibility="public"
 >
 </field>
+<field name="KEYCODE_3D_MODE"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="206"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
 <field name="KEYCODE_4"
  type="int"
  transient="false"
@@ -213960,6 +214717,17 @@
  visibility="public"
 >
 </field>
+<field name="KEYCODE_LANGUAGE_SWITCH"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="204"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
 <field name="KEYCODE_LEFT_BRACKET"
  type="int"
  transient="false"
@@ -213982,6 +214750,17 @@
  visibility="public"
 >
 </field>
+<field name="KEYCODE_MANNER_MODE"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="205"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
 <field name="KEYCODE_MEDIA_CLOSE"
  type="int"
  transient="false"
@@ -218068,6 +218847,28 @@
  visibility="public"
 >
 </field>
+<field name="AXIS_BRAKE"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="23"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="AXIS_GAS"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="22"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
 <field name="AXIS_GENERIC_1"
  type="int"
  transient="false"
@@ -218321,6 +219122,17 @@
  visibility="public"
 >
 </field>
+<field name="AXIS_RUDDER"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="20"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
 <field name="AXIS_RX"
  type="int"
  transient="false"
@@ -218365,6 +219177,17 @@
  visibility="public"
 >
 </field>
+<field name="AXIS_THROTTLE"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="19"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
 <field name="AXIS_TOOL_MAJOR"
  type="int"
  transient="false"
@@ -218420,6 +219243,17 @@
  visibility="public"
 >
 </field>
+<field name="AXIS_WHEEL"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="21"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
 <field name="AXIS_X"
  type="int"
  transient="false"
@@ -220388,7 +221222,7 @@
  deprecated="not deprecated"
  visibility="public"
 >
-<parameter name="ev" type="android.view.MotionEvent">
+<parameter name="event" type="android.view.MotionEvent">
 </parameter>
 </method>
 <method name="clear"
@@ -233109,7 +233943,7 @@
  value="500"
  static="true"
  final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
  visibility="public"
 >
 </field>
@@ -236159,6 +236993,27 @@
 <parameter name="newCursorPosition" type="int">
 </parameter>
 </method>
+<method name="setCorrectionSpan"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="token" type="android.os.IBinder">
+</parameter>
+<parameter name="correctionSpan" type="android.text.style.CorrectionSpan">
+</parameter>
+<parameter name="start" type="int">
+</parameter>
+<parameter name="end" type="int">
+</parameter>
+<parameter name="flags" type="int">
+</parameter>
+</method>
 <method name="setSelection"
  return="boolean"
  abstract="false"
@@ -237429,6 +238284,27 @@
 <parameter name="newCursorPosition" type="int">
 </parameter>
 </method>
+<method name="setCorrectionSpan"
+ return="boolean"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="token" type="android.os.IBinder">
+</parameter>
+<parameter name="correctionSpan" type="android.text.style.CorrectionSpan">
+</parameter>
+<parameter name="start" type="int">
+</parameter>
+<parameter name="end" type="int">
+</parameter>
+<parameter name="flags" type="int">
+</parameter>
+</method>
 <method name="setSelection"
  return="boolean"
  abstract="true"
@@ -237759,6 +238635,27 @@
 <parameter name="newCursorPosition" type="int">
 </parameter>
 </method>
+<method name="setCorrectionSpan"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="token" type="android.os.IBinder">
+</parameter>
+<parameter name="correctionSpan" type="android.text.style.CorrectionSpan">
+</parameter>
+<parameter name="start" type="int">
+</parameter>
+<parameter name="end" type="int">
+</parameter>
+<parameter name="flags" type="int">
+</parameter>
+</method>
 <method name="setSelection"
  return="boolean"
  abstract="false"
@@ -243264,7 +244161,7 @@
  synchronized="false"
  static="false"
  final="false"
- deprecated="not deprecated"
+ deprecated="deprecated"
  visibility="public"
 >
 </method>
@@ -244278,6 +245175,25 @@
 <parameter name="realm" type="java.lang.String">
 </parameter>
 </method>
+<method name="onReceivedLoginRequest"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="view" type="android.webkit.WebView">
+</parameter>
+<parameter name="realm" type="java.lang.String">
+</parameter>
+<parameter name="account" type="java.lang.String">
+</parameter>
+<parameter name="args" type="java.lang.String">
+</parameter>
+</method>
 <method name="onReceivedSslError"
  return="void"
  abstract="false"
@@ -263952,9 +264868,9 @@
 </parameter>
 <parameter name="start" type="int">
 </parameter>
-<parameter name="before" type="int">
+<parameter name="lengthBefore" type="int">
 </parameter>
-<parameter name="after" type="int">
+<parameter name="lengthAfter" type="int">
 </parameter>
 </method>
 <method name="onTextContextMenuItem"
@@ -264066,6 +264982,27 @@
 <parameter name="bottom" type="android.graphics.drawable.Drawable">
 </parameter>
 </method>
+<method name="setCorrectionSpan"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="token" type="android.os.IBinder">
+</parameter>
+<parameter name="span" type="android.text.style.CorrectionSpan">
+</parameter>
+<parameter name="start" type="int">
+</parameter>
+<parameter name="end" type="int">
+</parameter>
+<parameter name="flags" type="int">
+</parameter>
+</method>
 <method name="setCursorVisible"
  return="void"
  abstract="false"
diff --git a/cmds/stagefright/sf2.cpp b/cmds/stagefright/sf2.cpp
index 74649a9..c1d0803 100644
--- a/cmds/stagefright/sf2.cpp
+++ b/cmds/stagefright/sf2.cpp
@@ -1,3 +1,19 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
 #include <binder/ProcessState.h>
 
 #include <media/stagefright/foundation/hexdump.h>
diff --git a/cmds/stagefright/stream.cpp b/cmds/stagefright/stream.cpp
index 9246a00..bb84bd1 100644
--- a/cmds/stagefright/stream.cpp
+++ b/cmds/stagefright/stream.cpp
@@ -1,3 +1,19 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
 #include <binder/ProcessState.h>
 
 #include <media/IStreamSource.h>
diff --git a/core/java/android/app/ActionBar.java b/core/java/android/app/ActionBar.java
index fc5fac6..a9e84d7 100644
--- a/core/java/android/app/ActionBar.java
+++ b/core/java/android/app/ActionBar.java
@@ -160,6 +160,66 @@
     public abstract void setCustomView(int resId);
 
     /**
+     * Set the icon to display in the 'home' section of the action bar.
+     * The action bar will use an icon specified by its style or the
+     * activity icon by default.
+     *
+     * Whether the home section shows an icon or logo is controlled
+     * by the display option {@link #DISPLAY_USE_LOGO}.
+     *
+     * @param resId Resource ID of a drawable to show as an icon.
+     *
+     * @see #setDisplayUseLogoEnabled(boolean)
+     * @see #setDisplayShowHomeEnabled(boolean)
+     */
+    public abstract void setIcon(int resId);
+
+    /**
+     * Set the icon to display in the 'home' section of the action bar.
+     * The action bar will use an icon specified by its style or the
+     * activity icon by default.
+     *
+     * Whether the home section shows an icon or logo is controlled
+     * by the display option {@link #DISPLAY_USE_LOGO}.
+     *
+     * @param icon Drawable to show as an icon.
+     *
+     * @see #setDisplayUseLogoEnabled(boolean)
+     * @see #setDisplayShowHomeEnabled(boolean)
+     */
+    public abstract void setIcon(Drawable icon);
+
+    /**
+     * Set the logo to display in the 'home' section of the action bar.
+     * The action bar will use a logo specified by its style or the
+     * activity logo by default.
+     *
+     * Whether the home section shows an icon or logo is controlled
+     * by the display option {@link #DISPLAY_USE_LOGO}.
+     *
+     * @param resId Resource ID of a drawable to show as a logo.
+     *
+     * @see #setDisplayUseLogoEnabled(boolean)
+     * @see #setDisplayShowHomeEnabled(boolean)
+     */
+    public abstract void setLogo(int resId);
+
+    /**
+     * Set the logo to display in the 'home' section of the action bar.
+     * The action bar will use a logo specified by its style or the
+     * activity logo by default.
+     *
+     * Whether the home section shows an icon or logo is controlled
+     * by the display option {@link #DISPLAY_USE_LOGO}.
+     *
+     * @param logo Drawable to show as a logo.
+     *
+     * @see #setDisplayUseLogoEnabled(boolean)
+     * @see #setDisplayShowHomeEnabled(boolean)
+     */
+    public abstract void setLogo(Drawable logo);
+
+    /**
      * Set the adapter and navigation callback for list navigation mode.
      *
      * The supplied adapter will provide views for the expanded list as well as
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index 3a82c78..edfd6ef 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -4137,7 +4137,7 @@
             fragment.mInLayout = true;
             fragment.mImmediateActivity = this;
             fragment.mFragmentManager = mFragments;
-            fragment.onInflate(attrs, fragment.mSavedFragmentState);
+            fragment.onInflate(this, attrs, fragment.mSavedFragmentState);
             mFragments.addFragment(fragment, true);
 
         } else if (fragment.mInLayout) {
@@ -4156,7 +4156,7 @@
             // from last saved state), then give it the attributes to
             // initialize itself.
             if (!fragment.mRetaining) {
-                fragment.onInflate(attrs, fragment.mSavedFragmentState);
+                fragment.onInflate(this, attrs, fragment.mSavedFragmentState);
             }
             mFragments.moveToState(fragment);
         }
diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java
index 930c6b0..b6581e9 100644
--- a/core/java/android/app/ActivityManager.java
+++ b/core/java/android/app/ActivityManager.java
@@ -74,7 +74,7 @@
     static public int staticGetMemoryClass() {
         // Really brain dead right now -- just take this from the configured
         // vm heap size, and assume it is in megabytes and thus ends with "m".
-        String vmHeapSize = SystemProperties.get("dalvik.vm.growthlimit", "");
+        String vmHeapSize = SystemProperties.get("dalvik.vm.heapgrowthlimit", "");
         if (vmHeapSize != null && !"".equals(vmHeapSize)) {
             return Integer.parseInt(vmHeapSize.substring(0, vmHeapSize.length()-1));
         }
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index b409f2f..3e5b21f 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -45,6 +45,7 @@
 import android.net.IConnectivityManager;
 import android.net.Proxy;
 import android.net.ProxyProperties;
+import android.os.AsyncTask;
 import android.os.Bundle;
 import android.os.Debug;
 import android.os.Handler;
@@ -200,6 +201,8 @@
 
     static Handler sMainThreadHandler;  // set once in main()
 
+    Bundle mCoreSettings = null;
+
     private static final class ActivityClientRecord {
         IBinder token;
         int ident;
@@ -354,7 +357,6 @@
         boolean restrictedBackupMode;
         Configuration config;
         boolean handlingProfiling;
-        Bundle coreSettings;
         public String toString() {
             return "AppBindData{appInfo=" + appInfo + "}";
         }
@@ -559,6 +561,8 @@
                 ServiceManager.initServiceCache(services);
             }
 
+            setCoreSettings(coreSettings);
+
             AppBindData data = new AppBindData();
             data.processName = processName;
             data.appInfo = appInfo;
@@ -570,7 +574,6 @@
             data.debugMode = debugMode;
             data.restrictedBackupMode = isRestrictedBackupMode;
             data.config = config;
-            data.coreSettings = coreSettings;
             queueOrSendMessage(H.BIND_APPLICATION, data);
         }
 
@@ -898,8 +901,8 @@
             pw.println(String.format(format, objs));
         }
 
-        public void setCoreSettings(Bundle settings) {
-            queueOrSendMessage(H.SET_CORE_SETTINGS, settings);
+        public void setCoreSettings(Bundle coreSettings) {
+            queueOrSendMessage(H.SET_CORE_SETTINGS, coreSettings);
         }
     }
 
@@ -2720,10 +2723,8 @@
     }
 
     private void handleSetCoreSettings(Bundle coreSettings) {
-        if (mBoundApplication != null) {
-            synchronized (mBoundApplication) {
-                mBoundApplication.coreSettings = coreSettings;
-            }
+        synchronized (mPackages) {
+            mCoreSettings = coreSettings;
         }
     }
 
@@ -3427,6 +3428,14 @@
         Process.setArgV0(data.processName);
         android.ddm.DdmHandleAppName.setAppName(data.processName);
 
+        // If the app is Honeycomb MR1 or earlier, switch its AsyncTask
+        // implementation to use the pool executor.  Normally, we use the
+        // serialized executor as the default. This has to happen in the
+        // main thread so the main looper is set right.
+        if (data.appInfo.targetSdkVersion <= 12) {
+            AsyncTask.setDefaultExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
+        }
+
         /*
          * Before spawning a new process, reset the time zone to be the system time zone.
          * This needs to be done because the system time zone could have changed after the
@@ -3990,13 +3999,9 @@
     }
 
     public int getIntCoreSetting(String key, int defaultValue) {
-        if (mBoundApplication == null) {
-            return defaultValue;
-        }
-        synchronized (mBoundApplication) {
-            Bundle coreSettings = mBoundApplication.coreSettings;
-            if (coreSettings != null) {
-                return coreSettings.getInt(key, defaultValue);
+        synchronized (mPackages) {
+            if (mCoreSettings != null) {
+                return mCoreSettings.getInt(key, defaultValue);
             } else {
                 return defaultValue;
             }
diff --git a/core/java/android/app/AppGlobals.java b/core/java/android/app/AppGlobals.java
index 55515b8..2b6db8b 100644
--- a/core/java/android/app/AppGlobals.java
+++ b/core/java/android/app/AppGlobals.java
@@ -55,6 +55,11 @@
      * @return The core settings.
      */
     public static int getIntCoreSetting(String key, int defaultValue) {
-        return ActivityThread.currentActivityThread().getIntCoreSetting(key, defaultValue);
+        ActivityThread currentActivityThread = ActivityThread.currentActivityThread();
+        if (currentActivityThread != null) {
+            return currentActivityThread.getIntCoreSetting(key, defaultValue);
+        } else {
+            return defaultValue;
+        }
     }
 }
diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java
index 539e946..cc1f81c 100644
--- a/core/java/android/app/ContextImpl.java
+++ b/core/java/android/app/ContextImpl.java
@@ -401,10 +401,10 @@
                     return new UiModeManager();
                 }});
 
-        registerService(USB_SERVICE, new StaticServiceFetcher() {
-                public Object createStaticService() {
+        registerService(USB_SERVICE, new ServiceFetcher() {
+                public Object createService(ContextImpl ctx) {
                     IBinder b = ServiceManager.getService(USB_SERVICE);
-                    return new UsbManager(IUsbManager.Stub.asInterface(b));
+                    return new UsbManager(ctx, IUsbManager.Stub.asInterface(b));
                 }});
 
         registerService(VIBRATOR_SERVICE, new ServiceFetcher() {
diff --git a/core/java/android/app/DialogFragment.java b/core/java/android/app/DialogFragment.java
index dee1ef3..cce7cd6 100644
--- a/core/java/android/app/DialogFragment.java
+++ b/core/java/android/app/DialogFragment.java
@@ -258,6 +258,16 @@
         dismissInternal(false);
     }
 
+    /**
+     * Version of {@link #dismiss()} that uses
+     * {@link FragmentTransaction#commitAllowingStateLoss()
+     * FragmentTransaction.commitAllowingStateLoss()}.  See linked
+     * documentation for further details.
+     */
+    public void dismissAllowingStateLoss() {
+        dismissInternal(true);
+    }
+    
     void dismissInternal(boolean allowStateLoss) {
         if (mDismissed) {
             return;
diff --git a/core/java/android/app/DownloadManager.java b/core/java/android/app/DownloadManager.java
index d04fa57..b88e5cf 100644
--- a/core/java/android/app/DownloadManager.java
+++ b/core/java/android/app/DownloadManager.java
@@ -376,8 +376,8 @@
         /**
          * This download shows in the notifications after completion ONLY.
          * It is usuable only with
-         * {@link DownloadManager#completedDownload(String, String, boolean, String,
-         * String, long, boolean)}.
+         * {@link DownloadManager#addCompletedDownload(String, String,
+         * boolean, String, String, long, boolean)}.
          */
         public static final int VISIBILITY_VISIBLE_NOTIFY_ONLY_COMPLETION = 3;
 
@@ -1111,7 +1111,7 @@
      * @return  an ID for the download entry added to the downloads app, unique across the system
      * This ID is used to make future calls related to this download.
      */
-    public long completedDownload(String title, String description,
+    public long addCompletedDownload(String title, String description,
             boolean isMediaScannerScannable, String mimeType, String path, long length,
             boolean showNotification) {
         // make sure the input args are non-null/non-zero
diff --git a/core/java/android/app/Fragment.java b/core/java/android/app/Fragment.java
index 8982110f..53dc7c8 100644
--- a/core/java/android/app/Fragment.java
+++ b/core/java/android/app/Fragment.java
@@ -859,32 +859,57 @@
     }
     
     /**
+     * @deprecated Use {@link #onInflate(Activity, AttributeSet, Bundle)} instead.
+     */
+    @Deprecated
+    public void onInflate(AttributeSet attrs, Bundle savedInstanceState) {
+        mCalled = true;
+    }
+
+    /**
      * Called when a fragment is being created as part of a view layout
      * inflation, typically from setting the content view of an activity.  This
-     * will be called immediately after the fragment is created from a <fragment>
+     * may be called immediately after the fragment is created from a <fragment>
      * tag in a layout file.  Note this is <em>before</em> the fragment's
      * {@link #onAttach(Activity)} has been called; all you should do here is
-     * parse the attributes and save them away.  A convenient thing to do is
-     * simply copy them into a Bundle that is given to {@link #setArguments(Bundle)}.
+     * parse the attributes and save them away.
      * 
      * <p>This is called every time the fragment is inflated, even if it is
-     * being inflated into a new instance with saved state.  Because a fragment's
-     * arguments are retained across instances, it may make no sense to re-parse
-     * the attributes into new arguments.  You may want to first check
-     * {@link #getArguments()} and only parse the attributes if it returns null,
-     * the assumption being that if it is non-null those are the same arguments
-     * from the first time the fragment was inflated.  (That said, you may want
-     * to have layouts change for different configurations such as landscape
-     * and portrait, which can have different attributes.  If so, you will need
-     * to re-parse the attributes each time this is called to generate new
-     * arguments.)</p>
+     * being inflated into a new instance with saved state.  It typically makes
+     * sense to re-parse the parameters each time, to allow them to change with
+     * different configurations.</p>
+     *
+     * <p>Here is a typical implementation of a fragment that can take parameters
+     * both through attributes supplied here as well from {@link #getArguments()}:</p>
+     *
+     * {@sample development/samples/ApiDemos/src/com/example/android/apis/app/FragmentArguments.java
+     *      fragment}
+     *
+     * <p>Note that parsing the XML attributes uses a "styleable" resource.  The
+     * declaration for the styleable used here is:</p>
+     *
+     * {@sample development/samples/ApiDemos/res/values/attrs.xml fragment_arguments}
      * 
+     * <p>The fragment can then be declared within its activity's content layout
+     * through a tag like this:</p>
+     *
+     * {@sample development/samples/ApiDemos/res/layout/fragment_arguments.xml from_attributes}
+     *
+     * <p>This fragment can also be created dynamically from arguments given
+     * at runtime in the arguments Bundle; here is an example of doing so at
+     * creation of the containing activity:</p>
+     *
+     * {@sample development/samples/ApiDemos/src/com/example/android/apis/app/FragmentArguments.java
+     *      create}
+     *
+     * @param activity The Activity that is inflating this fragment.
      * @param attrs The attributes at the tag where the fragment is
      * being created.
      * @param savedInstanceState If the fragment is being re-created from
      * a previous saved state, this is the state.
      */
-    public void onInflate(AttributeSet attrs, Bundle savedInstanceState) {
+    public void onInflate(Activity activity, AttributeSet attrs, Bundle savedInstanceState) {
+        onInflate(attrs, savedInstanceState);
         mCalled = true;
     }
     
diff --git a/core/java/android/app/FragmentManager.java b/core/java/android/app/FragmentManager.java
index d8d0a5b..ab60cf0 100644
--- a/core/java/android/app/FragmentManager.java
+++ b/core/java/android/app/FragmentManager.java
@@ -660,6 +660,12 @@
         }
         
         if (f.mState < newState) {
+            // For fragments that are created from a layout, when restoring from
+            // state we don't want to allow them to be created until they are
+            // being reloaded from the layout.
+            if (f.mFromLayout && !f.mInLayout) {
+                return;
+            }
             if (f.mAnimatingAway != null) {
                 // The fragment is currently being animated...  but!  Now we
                 // want to move our state back up.  Give up on waiting for the
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index ccd65de..c9351af 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -416,7 +416,7 @@
         if (this.largeIcon != null) {
             that.largeIcon = Bitmap.createBitmap(this.largeIcon);
         }
-        that.iconLevel = that.iconLevel;
+        that.iconLevel = this.iconLevel;
         that.sound = this.sound; // android.net.Uri is immutable
         that.audioStreamType = this.audioStreamType;
 
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index 440cb54..efe2633 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -1150,8 +1150,12 @@
      * fail (most commonly returning {@link #ENCRYPTION_STATUS_ACTIVE}).
      *
      * <p>This policy controls encryption of the secure (application data) storage area.  Data
-     * written to other areas (e.g. the directory returned by
-     * {@link android.os.Environment#getExternalStorageDirectory()} may or may not be encrypted.
+     * written to other storage areas may or may not be encrypted, and this policy does not require
+     * or control the encryption of any other storage areas.
+     * There is one exception:  If {@link android.os.Environment#isExternalStorageEmulated()} is
+     * {@code true}, then the directory returned by
+     * {@link android.os.Environment#getExternalStorageDirectory()} must be written to disk
+     * within the encrypted storage area.
      *
      * <p>Important Note:  On some devices, it is possible to encrypt storage without requiring
      * the user to create a device PIN or Password.  In this case, the storage is encrypted, but
diff --git a/core/java/android/app/backup/WallpaperBackupHelper.java b/core/java/android/app/backup/WallpaperBackupHelper.java
index 6539711..55368d6 100644
--- a/core/java/android/app/backup/WallpaperBackupHelper.java
+++ b/core/java/android/app/backup/WallpaperBackupHelper.java
@@ -110,11 +110,16 @@
                     if (DEBUG) Slog.d(TAG, "Restoring wallpaper image w=" + options.outWidth
                             + " h=" + options.outHeight);
 
-                    // how much does the image differ from our preference?
+                    // How much does the image differ from our preference?  The threshold
+                    // here is set to accept any image larger than our target, because
+                    // scaling down is acceptable; but to reject images that are deemed
+                    // "too small" to scale up attractively.  The value 1.33 is just barely
+                    // too low to pass Nexus 1 or Droid wallpapers for use on a Xoom, but
+                    // will pass anything relatively larger.
                     double widthRatio = mDesiredMinWidth / options.outWidth;
                     double heightRatio = mDesiredMinHeight / options.outHeight;
-                    if (widthRatio > 0.8 && widthRatio < 1.25
-                            && heightRatio > 0.8 && heightRatio < 1.25) {
+                    if (widthRatio > 0 && widthRatio < 1.33
+                            && heightRatio > 0 && heightRatio < 1.33) {
                         // sufficiently close to our resolution; go ahead and use it
                         if (DEBUG) Slog.d(TAG, "wallpaper dimension match; using");
                         f.renameTo(new File(WALLPAPER_IMAGE));
diff --git a/core/java/android/bluetooth/BluetoothDeviceProfileState.java b/core/java/android/bluetooth/BluetoothDeviceProfileState.java
index 9855709..f4693c2 100644
--- a/core/java/android/bluetooth/BluetoothDeviceProfileState.java
+++ b/core/java/android/bluetooth/BluetoothDeviceProfileState.java
@@ -679,7 +679,6 @@
         @Override
         protected boolean processMessage(Message message) {
             log("IncomingA2dp State->Processing Message: " + message.what);
-            Message deferMsg = new Message();
             switch(message.what) {
                 case CONNECT_HFP_OUTGOING:
                     deferMessage(message);
diff --git a/core/java/android/database/sqlite/SQLiteCursor.java b/core/java/android/database/sqlite/SQLiteCursor.java
index 4c2d123..83f3891 100644
--- a/core/java/android/database/sqlite/SQLiteCursor.java
+++ b/core/java/android/database/sqlite/SQLiteCursor.java
@@ -241,7 +241,7 @@
         mColumnNameMap = null;
         mQuery = query;
 
-        query.mDatabase.lock();
+        query.mDatabase.lock(query.mSql);
         try {
             // Setup the list of columns
             int columnCount = mQuery.columnCountLocked();
@@ -419,7 +419,7 @@
                 // since we need to use a different database connection handle,
                 // re-compile the query
                 try {
-                    db.lock();
+                    db.lock(mQuery.mSql);
                 } catch (IllegalStateException e) {
                     // for backwards compatibility, just return false
                     Log.w(TAG, "requery() failed " + e.getMessage(), e);
diff --git a/core/java/android/database/sqlite/SQLiteDatabase.java b/core/java/android/database/sqlite/SQLiteDatabase.java
index 90a5b5d..2f2b4eb 100644
--- a/core/java/android/database/sqlite/SQLiteDatabase.java
+++ b/core/java/android/database/sqlite/SQLiteDatabase.java
@@ -230,9 +230,23 @@
     private static int sQueryLogTimeInMillis = 0;  // lazily initialized
     private static final int QUERY_LOG_SQL_LENGTH = 64;
     private static final String COMMIT_SQL = "COMMIT;";
+    private static final String BEGIN_SQL = "BEGIN;";
     private final Random mRandom = new Random();
+    /** the last non-commit/rollback sql statement in a transaction */
+    // guarded by 'this'
     private String mLastSqlStatement = null;
 
+    synchronized String getLastSqlStatement() {
+        return mLastSqlStatement;
+    }
+
+    synchronized void setLastSqlStatement(String sql) {
+        mLastSqlStatement = sql;
+    }
+
+    /** guarded by {@link #mLock} */
+    private long mTransStartTime;
+
     // String prefix for slow database query EventLog records that show
     // lock acquistions of the database.
     /* package */ static final String GET_LOCK_LOG_PREFIX = "GETLOCK:";
@@ -386,11 +400,16 @@
      *
      * @see #unlock()
      */
-    /* package */ void lock() {
-        lock(false);
+    /* package */ void lock(String sql) {
+        lock(sql, false);
     }
+
+    /* pachage */ void lock() {
+        lock(null, false);
+    }
+
     private static final long LOCK_WAIT_PERIOD = 30L;
-    private void lock(boolean forced) {
+    private void lock(String sql, boolean forced) {
         // make sure this method is NOT being called from a 'synchronized' method
         if (Thread.holdsLock(this)) {
             Log.w(TAG, "don't lock() while in a synchronized method");
@@ -398,6 +417,7 @@
         verifyDbIsOpen();
         if (!forced && !mLockingEnabled) return;
         boolean done = false;
+        long timeStart = SystemClock.uptimeMillis();
         while (!done) {
             try {
                 // wait for 30sec to acquire the lock
@@ -420,6 +440,9 @@
                 mLockAcquiredThreadTime = Debug.threadCpuTimeNanos();
             }
         }
+        if (sql != null) {
+            logTimeStat(sql, timeStart, GET_LOCK_LOG_PREFIX);
+        }
     }
     private static class DatabaseReentrantLock extends ReentrantLock {
         DatabaseReentrantLock(boolean fair) {
@@ -444,7 +467,11 @@
      * @see #unlockForced()
      */
     private void lockForced() {
-        lock(true);
+        lock(null, true);
+    }
+
+    private void lockForced(String sql) {
+        lock(sql, true);
     }
 
     /**
@@ -612,7 +639,7 @@
     private void beginTransaction(SQLiteTransactionListener transactionListener,
             boolean exclusive) {
         verifyDbIsOpen();
-        lockForced();
+        lockForced(BEGIN_SQL);
         boolean ok = false;
         try {
             // If this thread already had the lock then get out
@@ -635,6 +662,7 @@
             } else {
                 execSQL("BEGIN IMMEDIATE;");
             }
+            mTransStartTime = SystemClock.uptimeMillis();
             mTransactionListener = transactionListener;
             mTransactionIsSuccessful = true;
             mInnerTransactionIsSuccessful = false;
@@ -698,6 +726,8 @@
                         Log.i(TAG, "PRAGMA wal_Checkpoint done");
                     }
                 }
+                // log the transaction time to the Eventlog.
+                logTimeStat(getLastSqlStatement(), mTransStartTime, COMMIT_SQL);
             } else {
                 try {
                     execSQL("ROLLBACK;");
@@ -1855,24 +1885,7 @@
      * @throws SQLException if the SQL string is invalid
      */
     public void execSQL(String sql) throws SQLException {
-        int stmtType = DatabaseUtils.getSqlStatementType(sql);
-        if (stmtType == DatabaseUtils.STATEMENT_ATTACH) {
-            disableWriteAheadLogging();
-        }
-        long timeStart = SystemClock.uptimeMillis();
-        logTimeStat(mLastSqlStatement, timeStart, GET_LOCK_LOG_PREFIX);
         executeSql(sql, null);
-
-        if (stmtType == DatabaseUtils.STATEMENT_ATTACH) {
-            mHasAttachedDbs = true;
-        }
-        // Log commit statements along with the most recently executed
-        // SQL statement for disambiguation.
-        if (stmtType == DatabaseUtils.STATEMENT_COMMIT) {
-            logTimeStat(mLastSqlStatement, timeStart, COMMIT_SQL);
-        } else {
-            logTimeStat(sql, timeStart, null);
-        }
     }
 
     /**
@@ -1926,19 +1939,19 @@
     }
 
     private int executeSql(String sql, Object[] bindArgs) throws SQLException {
-        long timeStart = SystemClock.uptimeMillis();
-        int n;
+        if (DatabaseUtils.getSqlStatementType(sql) == DatabaseUtils.STATEMENT_ATTACH) {
+            disableWriteAheadLogging();
+            mHasAttachedDbs = true;
+        }
         SQLiteStatement statement = new SQLiteStatement(this, sql, bindArgs);
         try {
-            n = statement.executeUpdateDelete();
+            return statement.executeUpdateDelete();
         } catch (SQLiteDatabaseCorruptException e) {
             onCorruption();
             throw e;
         } finally {
             statement.close();
         }
-        logTimeStat(sql, timeStart);
-        return n;
     }
 
     @Override
@@ -2027,12 +2040,7 @@
         logTimeStat(sql, beginMillis, null);
     }
 
-    /* package */ void logTimeStat(String sql, long beginMillis, String prefix) {
-        // Keep track of the last statement executed here, as this is
-        // the common funnel through which all methods of hitting
-        // libsqlite eventually flow.
-        mLastSqlStatement = sql;
-
+    private void logTimeStat(String sql, long beginMillis, String prefix) {
         // Sample fast queries in proportion to the time taken.
         // Quantize the % first, so the logged sampling probability
         // exactly equals the actual sampling rate for this query.
@@ -2059,7 +2067,6 @@
         if (prefix != null) {
             sql = prefix + sql;
         }
-
         if (sql.length() > QUERY_LOG_SQL_LENGTH) sql = sql.substring(0, QUERY_LOG_SQL_LENGTH);
 
         // ActivityThread.currentPackageName() only returns non-null if the
diff --git a/core/java/android/database/sqlite/SQLiteDirectCursorDriver.java b/core/java/android/database/sqlite/SQLiteDirectCursorDriver.java
index de2fca9..a5e762e 100644
--- a/core/java/android/database/sqlite/SQLiteDirectCursorDriver.java
+++ b/core/java/android/database/sqlite/SQLiteDirectCursorDriver.java
@@ -42,7 +42,7 @@
         SQLiteQuery query = null;
 
         try {
-            mDatabase.lock();
+            mDatabase.lock(mSql);
             mDatabase.closePendingStatements();
             query = new SQLiteQuery(mDatabase, mSql, 0, selectionArgs);
 
diff --git a/core/java/android/database/sqlite/SQLiteProgram.java b/core/java/android/database/sqlite/SQLiteProgram.java
index 88246e8..89552dc 100644
--- a/core/java/android/database/sqlite/SQLiteProgram.java
+++ b/core/java/android/database/sqlite/SQLiteProgram.java
@@ -105,12 +105,9 @@
             case DatabaseUtils.STATEMENT_SELECT:
                 mStatementType = n | STATEMENT_CACHEABLE | STATEMENT_USE_POOLED_CONN;
                 break;
-            case DatabaseUtils.STATEMENT_ATTACH:
             case DatabaseUtils.STATEMENT_BEGIN:
             case DatabaseUtils.STATEMENT_COMMIT:
             case DatabaseUtils.STATEMENT_ABORT:
-            case DatabaseUtils.STATEMENT_DDL:
-            case DatabaseUtils.STATEMENT_UNPREPARED:
                 mStatementType = n | STATEMENT_DONT_PREPARE;
                 break;
             default:
@@ -353,13 +350,10 @@
 
     /* package */ void compileAndbindAllArgs() {
         if ((mStatementType & STATEMENT_DONT_PREPARE) > 0) {
-            // no need to prepare this SQL statement
-            if (SQLiteDebug.DEBUG_SQL_STATEMENTS) {
-                if (mBindArgs != null) {
-                    throw new IllegalArgumentException("no need to pass bindargs for this sql :" +
-                            mSql);
-                }
+            if (mBindArgs != null) {
+                throw new IllegalArgumentException("Can't pass bindargs for this sql :" + mSql);
             }
+            // no need to prepare this SQL statement
             return;
         }
         if (nStatement == 0) {
diff --git a/core/java/android/database/sqlite/SQLiteQuery.java b/core/java/android/database/sqlite/SQLiteQuery.java
index e9e0172..dc882d9 100644
--- a/core/java/android/database/sqlite/SQLiteQuery.java
+++ b/core/java/android/database/sqlite/SQLiteQuery.java
@@ -70,9 +70,8 @@
      */
     /* package */ int fillWindow(CursorWindow window,
             int maxRead, int lastPos) {
+        mDatabase.lock(mSql);
         long timeStart = SystemClock.uptimeMillis();
-        mDatabase.lock();
-        mDatabase.logTimeStat(mSql, timeStart, SQLiteDatabase.GET_LOCK_LOG_PREFIX);
         try {
             acquireReference();
             try {
diff --git a/core/java/android/database/sqlite/SQLiteStatement.java b/core/java/android/database/sqlite/SQLiteStatement.java
index c76cc6c..ff973a7 100644
--- a/core/java/android/database/sqlite/SQLiteStatement.java
+++ b/core/java/android/database/sqlite/SQLiteStatement.java
@@ -80,7 +80,8 @@
      */
     public int executeUpdateDelete() {
         try {
-            long timeStart = acquireAndLock(WRITE);
+            saveSqlAsLastSqlStatement();
+            acquireAndLock(WRITE);
             int numChanges = 0;
             if ((mStatementType & STATEMENT_DONT_PREPARE) > 0) {
                 // since the statement doesn't have to be prepared,
@@ -90,7 +91,6 @@
             } else {
                 numChanges = native_execute();
             }
-            mDatabase.logTimeStat(mSql, timeStart);
             return numChanges;
         } finally {
             releaseAndUnlock();
@@ -108,15 +108,22 @@
      */
     public long executeInsert() {
         try {
-            long timeStart = acquireAndLock(WRITE);
-            long lastInsertedRowId = native_executeInsert();
-            mDatabase.logTimeStat(mSql, timeStart);
-            return lastInsertedRowId;
+            saveSqlAsLastSqlStatement();
+            acquireAndLock(WRITE);
+            return native_executeInsert();
         } finally {
             releaseAndUnlock();
         }
     }
 
+    private void saveSqlAsLastSqlStatement() {
+        if (((mStatementType & SQLiteProgram.STATEMENT_TYPE_MASK) ==
+                DatabaseUtils.STATEMENT_UPDATE) ||
+                (mStatementType & SQLiteProgram.STATEMENT_TYPE_MASK) ==
+                DatabaseUtils.STATEMENT_BEGIN) {
+            mDatabase.setLastSqlStatement(mSql);
+        }
+    }
     /**
      * Execute a statement that returns a 1 by 1 table with a numeric value.
      * For example, SELECT COUNT(*) FROM table;
@@ -199,7 +206,7 @@
      *   <li>if the SQL statement is an update, start transaction if not already in one.
      *   otherwise, get lock on the database</li>
      *   <li>acquire reference on this object</li>
-     *   <li>and then return the current time _before_ the database lock was acquired</li>
+     *   <li>and then return the current time _after_ the database lock was acquired</li>
      * </ul>
      * <p>
      * This method removes the duplicate code from the other public
@@ -243,7 +250,7 @@
         }
         // do I have database lock? if not, grab it.
         if (!mDatabase.isDbLockedByCurrentThread()) {
-            mDatabase.lock();
+            mDatabase.lock(mSql);
             mState = LOCK_ACQUIRED;
         }
 
diff --git a/core/java/android/hardware/Camera.java b/core/java/android/hardware/Camera.java
index 97f0e1b..ed2b205 100644
--- a/core/java/android/hardware/Camera.java
+++ b/core/java/android/hardware/Camera.java
@@ -410,8 +410,9 @@
 
     /**
      * Starts capturing and drawing preview frames to the screen.
-     * Preview will not actually start until a surface is supplied with
-     * {@link #setPreviewDisplay(SurfaceHolder)}.
+     * Preview will not actually start until a surface is supplied
+     * with {@link #setPreviewDisplay(SurfaceHolder)} or
+     * {@link #setPreviewTexture(SurfaceTexture)}.
      *
      * <p>If {@link #setPreviewCallback(Camera.PreviewCallback)},
      * {@link #setOneShotPreviewCallback(Camera.PreviewCallback)}, or
diff --git a/core/java/android/hardware/Sensor.java b/core/java/android/hardware/Sensor.java
index f2b907b..a4ba3bd 100644
--- a/core/java/android/hardware/Sensor.java
+++ b/core/java/android/hardware/Sensor.java
@@ -66,7 +66,14 @@
     /** A constant describing a pressure sensor type */
     public static final int TYPE_PRESSURE = 6;
 
-    /** A constant describing a temperature sensor type */
+    /**
+     * A constant describing a temperature sensor type
+     *
+     * @deprecated use
+     *             {@link android.hardware.Sensor#TYPE_AMBIENT_TEMPERATURE
+     *             Sensor.TYPE_AMBIENT_TEMPERATURE} instead.
+     */
+    @Deprecated
     public static final int TYPE_TEMPERATURE = 7;
 
     /**
@@ -97,6 +104,9 @@
      */
     public static final int TYPE_ROTATION_VECTOR = 11;
 
+    /** A constant describing an ambient temperature sensor type */
+    public static final int TYPE_AMBIENT_TEMPERATURE = 13;
+
     /** 
      * A constant describing all sensor types.
      */
diff --git a/core/java/android/hardware/SensorEvent.java b/core/java/android/hardware/SensorEvent.java
index 78d7991..91f0098 100644
--- a/core/java/android/hardware/SensorEvent.java
+++ b/core/java/android/hardware/SensorEvent.java
@@ -305,6 +305,14 @@
      * positive in the counter-clockwise direction).
      * </p>
      * 
+     * <h4>{@link android.hardware.Sensor#TYPE_AMBIENT_TEMPERATURE Sensor.TYPE_AMBIENT_TEMPERATURE}:
+     * </h4>
+     *
+     * <ul>
+     * <p>
+     * values[0]: ambient (room) temperature in degree Celsius.
+     * </ul>
+     *
      * @see SensorEvent
      * @see GeomagneticField
      */
diff --git a/core/java/android/hardware/SensorManager.java b/core/java/android/hardware/SensorManager.java
index dd4096b..2111cce 100644
--- a/core/java/android/hardware/SensorManager.java
+++ b/core/java/android/hardware/SensorManager.java
@@ -2051,8 +2051,8 @@
         if (rv.length == 4) {
             Q[0] = rv[3];
         } else {
-            //In this case, the w component of the quaternion is known to be a positive number
-            Q[0] = (float)Math.sqrt(1 - rv[0]*rv[0] - rv[1]*rv[1] - rv[2]*rv[2]);
+            Q[0] = 1 - rv[0]*rv[0] - rv[1]*rv[1] - rv[2]*rv[2];
+            Q[0] = (Q[0] > 0) ? (float)Math.sqrt(Q[0]) : 0;
         }
         Q[1] = rv[0];
         Q[2] = rv[1];
diff --git a/core/java/android/hardware/usb/IUsbManager.aidl b/core/java/android/hardware/usb/IUsbManager.aidl
index be65bdb..5df2343 100644
--- a/core/java/android/hardware/usb/IUsbManager.aidl
+++ b/core/java/android/hardware/usb/IUsbManager.aidl
@@ -16,6 +16,7 @@
 
 package android.hardware.usb;
 
+import android.app.PendingIntent;
 import android.hardware.usb.UsbAccessory;
 import android.hardware.usb.UsbDevice;
 import android.os.Bundle;
@@ -43,13 +44,32 @@
     /* Sets the default package for a USB device
      * (or clears it if the package name is null)
      */
-    oneway void setDevicePackage(in UsbDevice device, String packageName);
+    void setDevicePackage(in UsbDevice device, String packageName);
 
-    /* Sets the default package for a USB device
+    /* Sets the default package for a USB accessory
      * (or clears it if the package name is null)
      */
     void setAccessoryPackage(in UsbAccessory accessory, String packageName);
 
+    /* Returns true if the caller has permission to access the device. */
+    boolean hasDevicePermission(in UsbDevice device);
+
+    /* Returns true if the caller has permission to access the accessory. */
+    boolean hasAccessoryPermission(in UsbAccessory accessory);
+
+    /* Requests permission for the given package to access the device.
+     * Will display a system dialog to query the user if permission
+     * had not already been given.
+     */
+    void requestDevicePermission(in UsbDevice device, String packageName, in PendingIntent pi);
+
+    /* Requests permission for the given package to access the accessory.
+     * Will display a system dialog to query the user if permission
+     * had not already been given. Result is returned via pi.
+     */
+    void requestAccessoryPermission(in UsbAccessory accessory, String packageName,
+            in PendingIntent pi);
+
     /* Grants permission for the given UID to access the device */
     void grantDevicePermission(in UsbDevice device, int uid);
 
@@ -57,8 +77,8 @@
     void grantAccessoryPermission(in UsbAccessory accessory, int uid);
 
     /* Returns true if the USB manager has default preferences or permissions for the package */
-    boolean hasDefaults(String packageName, int uid);
+    boolean hasDefaults(String packageName);
 
     /* Clears default preferences and permissions for the package */
-    oneway void clearDefaults(String packageName, int uid);
+    void clearDefaults(String packageName);
 }
diff --git a/core/java/android/hardware/usb/UsbAccessory.java b/core/java/android/hardware/usb/UsbAccessory.java
index 6cd9178..5e9ead0 100644
--- a/core/java/android/hardware/usb/UsbAccessory.java
+++ b/core/java/android/hardware/usb/UsbAccessory.java
@@ -30,18 +30,23 @@
 
     private final String mManufacturer;
     private final String mModel;
-    private final String mType;
+    private final String mDescription;
     private final String mVersion;
+    private final String mUri;
+    private final String mSerial;
 
     /**
      * UsbAccessory should only be instantiated by UsbService implementation
      * @hide
      */
-    public UsbAccessory(String manufacturer, String model, String type, String version) {
+    public UsbAccessory(String manufacturer, String model, String description,
+            String version, String uri, String serial) {
         mManufacturer = manufacturer;
         mModel = model;
-        mType = type;
+        mDescription = description;
         mVersion = version;
+        mUri = uri;
+        mSerial = serial;
     }
 
     /**
@@ -51,8 +56,10 @@
     public UsbAccessory(String[] strings) {
         mManufacturer = strings[0];
         mModel = strings[1];
-        mType = strings[2];
+        mDescription = strings[2];
         mVersion = strings[3];
+        mUri = strings[4];
+        mSerial = strings[5];
     }
 
     /**
@@ -74,12 +81,12 @@
     }
 
     /**
-     * Returns the type of the accessory.
+     * Returns a user visible description of the accessory.
      *
-     * @return the accessory type
+     * @return the accessory description
      */
-    public String getType() {
-        return mType;
+    public String getDescription() {
+        return mDescription;
     }
 
     /**
@@ -91,6 +98,28 @@
         return mVersion;
     }
 
+    /**
+     * Returns the URI for the accessory.
+     * This is an optional URI that might show information about the accessory
+     * or provide the option to download an application for the accessory
+     *
+     * @return the accessory URI
+     */
+    public String getUri() {
+        return mUri;
+    }
+
+    /**
+     * Returns the unique serial number for the accessory.
+     * This is an optional serial number that can be used to differentiate
+     * between individual accessories of the same model and manufacturer
+     *
+     * @return the unique serial number
+     */
+    public String getSerial() {
+        return mSerial;
+    }
+
     private static boolean compare(String s1, String s2) {
         if (s1 == null) return (s2 == null);
         return s1.equals(s2);
@@ -102,18 +131,32 @@
             UsbAccessory accessory = (UsbAccessory)obj;
             return (compare(mManufacturer, accessory.getManufacturer()) &&
                     compare(mModel, accessory.getModel()) &&
-                    compare(mType, accessory.getType()) &&
-                    compare(mVersion, accessory.getVersion()));
+                    compare(mDescription, accessory.getDescription()) &&
+                    compare(mVersion, accessory.getVersion()) &&
+                    compare(mUri, accessory.getUri()) &&
+                    compare(mSerial, accessory.getSerial()));
         }
         return false;
     }
 
     @Override
+    public int hashCode() {
+        return ((mManufacturer == null ? 0 : mManufacturer.hashCode()) ^
+                (mModel == null ? 0 : mModel.hashCode()) ^
+                (mDescription == null ? 0 : mDescription.hashCode()) ^
+                (mVersion == null ? 0 : mVersion.hashCode()) ^
+                (mUri == null ? 0 : mUri.hashCode()) ^
+                (mSerial == null ? 0 : mSerial.hashCode()));
+    }
+
+    @Override
     public String toString() {
         return "UsbAccessory[mManufacturer=" + mManufacturer +
                             ", mModel=" + mModel +
-                            ", mType=" + mType +
-                            ", mVersion=" + mVersion + "]";
+                            ", mDescription=" + mDescription +
+                            ", mVersion=" + mVersion +
+                            ", mUri=" + mUri +
+                            ", mSerial=" + mSerial + "]";
     }
 
     public static final Parcelable.Creator<UsbAccessory> CREATOR =
@@ -121,9 +164,11 @@
         public UsbAccessory createFromParcel(Parcel in) {
             String manufacturer = in.readString();
             String model = in.readString();
-            String type = in.readString();
+            String description = in.readString();
             String version = in.readString();
-            return new UsbAccessory(manufacturer, model, type, version);
+            String uri = in.readString();
+            String serial = in.readString();
+            return new UsbAccessory(manufacturer, model, description, version, uri, serial);
         }
 
         public UsbAccessory[] newArray(int size) {
@@ -138,7 +183,9 @@
     public void writeToParcel(Parcel parcel, int flags) {
         parcel.writeString(mManufacturer);
         parcel.writeString(mModel);
-        parcel.writeString(mType);
+        parcel.writeString(mDescription);
         parcel.writeString(mVersion);
+        parcel.writeString(mUri);
+        parcel.writeString(mSerial);
    }
 }
diff --git a/core/java/android/hardware/usb/UsbDevice.java b/core/java/android/hardware/usb/UsbDevice.java
index 37bd82b..9e536a7 100644
--- a/core/java/android/hardware/usb/UsbDevice.java
+++ b/core/java/android/hardware/usb/UsbDevice.java
@@ -19,33 +19,24 @@
 import android.os.Bundle;
 import android.os.Parcel;
 import android.os.Parcelable;
-import android.os.ParcelFileDescriptor;
 import android.util.Log;
 
 import java.io.FileDescriptor;
 
-
 /**
  * A class representing a USB device.
  */
-public final class UsbDevice implements Parcelable {
+public class UsbDevice implements Parcelable {
 
     private static final String TAG = "UsbDevice";
 
-    private String mName;
-    private int mVendorId;
-    private int mProductId;
-    private int mClass;
-    private int mSubclass;
-    private int mProtocol;
-    private Parcelable[] mInterfaces;
-
-    // used by the JNI code
-    private int mNativeContext;
-
-    private UsbDevice() {
-    }
-
+    private final String mName;
+    private final int mVendorId;
+    private final int mProductId;
+    private final int mClass;
+    private final int mSubclass;
+    private final int mProtocol;
+    private final Parcelable[] mInterfaces;
 
     /**
      * UsbDevice should only be instantiated by UsbService implementation
@@ -150,114 +141,6 @@
         return (UsbInterface)mInterfaces[index];
     }
 
-    /* package */ boolean open(ParcelFileDescriptor pfd) {
-        return native_open(mName, pfd.getFileDescriptor());
-    }
-
-    /**
-     * Releases all system resources related to the device.
-     */
-    public void close() {
-        native_close();
-    }
-
-    /**
-     * Returns an integer file descriptor for the device, or
-     * -1 if the device is not opened.
-     * This is intended for passing to native code to access the device
-     */
-    public int getFileDescriptor() {
-        return native_get_fd();
-    }
-
-    /**
-     * Claims exclusive access to a {@link android.hardware.usb.UsbInterface}.
-     * This must be done before sending or receiving data on any
-     * {@link android.hardware.usb.UsbEndpoint}s belonging to the interface
-     * @param intf the interface to claim
-     * @param force true to disconnect kernel driver if necessary
-     * @return true if the interface was successfully claimed
-     */
-    public boolean claimInterface(UsbInterface intf, boolean force) {
-        return native_claim_interface(intf.getId(), force);
-    }
-
-    /**
-     * Releases exclusive access to a {@link android.hardware.usb.UsbInterface}.
-     *
-     * @return true if the interface was successfully released
-     */
-    public boolean releaseInterface(UsbInterface intf) {
-        return native_release_interface(intf.getId());
-    }
-
-    /**
-     * Performs a control transaction on endpoint zero for this device.
-     * The direction of the transfer is determined by the request type.
-     * If requestType & {@link UsbConstants#USB_ENDPOINT_DIR_MASK} is
-     * {@link UsbConstants#USB_DIR_OUT}, then the transfer is a write,
-     * and if it is {@link UsbConstants#USB_DIR_IN}, then the transfer
-     * is a read.
-     *
-     * @param requestType request type for this transaction
-     * @param request request ID for this transaction
-     * @param value value field for this transaction
-     * @param index index field for this transaction
-     * @param buffer buffer for data portion of transaction,
-     * or null if no data needs to be sent or received
-     * @param length the length of the data to send or receive
-     * @param timeout in milliseconds
-     * @return length of data transferred (or zero) for success,
-     * or negative value for failure
-     */
-    public int controlTransfer(int requestType, int request, int value,
-            int index, byte[] buffer, int length, int timeout) {
-        return native_control_request(requestType, request, value, index, buffer, length, timeout);
-    }
-
-    /**
-     * Performs a bulk transaction on the given endpoint.
-     * The direction of the transfer is determined by the direction of the endpoint
-     *
-     * @param endpoint the endpoint for this transaction
-     * @param buffer buffer for data to send or receive,
-     * @param length the length of the data to send or receive
-     * @param timeout in milliseconds
-     * @return length of data transferred (or zero) for success,
-     * or negative value for failure
-     */
-    public int bulkTransfer(UsbEndpoint endpoint, byte[] buffer, int length, int timeout) {
-        return native_bulk_request(endpoint.getAddress(), buffer, length, timeout);
-    }
-
-    /**
-     * Waits for the result of a {@link android.hardware.usb.UsbRequest#queue} operation
-     * Note that this may return requests queued on multiple 
-     * {@link android.hardware.usb.UsbEndpoint}s.
-     * When multiple endpoints are in use, {@link android.hardware.usb.UsbRequest#getEndpoint} and
-     * {@link android.hardware.usb.UsbRequest#getClientData} can be useful in determining
-     * how to process the result of this function.
-     *
-     * @return a completed USB request, or null if an error occurred
-     */
-    public UsbRequest requestWait() {
-        UsbRequest request = native_request_wait();
-        if (request != null) {
-            request.dequeue();
-        }
-        return request;
-    }
-
-    /**
-     * Returns the serial number for the device.
-     * This will return null if the device has not been opened.
-     *
-     * @return the device serial number
-     */
-    public String getSerial() {
-        return native_get_serial();
-    }
-
     @Override
     public boolean equals(Object o) {
         if (o instanceof UsbDevice) {
@@ -270,6 +153,11 @@
     }
 
     @Override
+    public int hashCode() {
+        return mName.hashCode();
+    }
+
+    @Override
     public String toString() {
         return "UsbDevice[mName=" + mName + ",mVendorId=" + mVendorId +
                 ",mProductId=" + mProductId + ",mClass=" + mClass +
@@ -287,11 +175,7 @@
             int subClass = in.readInt();
             int protocol = in.readInt();
             Parcelable[] interfaces = in.readParcelableArray(UsbInterface.class.getClassLoader());
-            UsbDevice result = new UsbDevice(name, vendorId, productId, clasz, subClass, protocol, interfaces);
-            for (int i = 0; i < interfaces.length; i++) {
-                ((UsbInterface)interfaces[i]).setDevice(result);
-            }
-            return result;
+            return new UsbDevice(name, vendorId, productId, clasz, subClass, protocol, interfaces);
         }
 
         public UsbDevice[] newArray(int size) {
@@ -321,17 +205,6 @@
         return native_get_device_name(id);
     }
 
-    private native boolean native_open(String deviceName, FileDescriptor pfd);
-    private native void native_close();
-    private native int native_get_fd();
-    private native boolean native_claim_interface(int interfaceID, boolean force);
-    private native boolean native_release_interface(int interfaceID);
-    private native int native_control_request(int requestType, int request, int value,
-            int index, byte[] buffer, int length, int timeout);
-    private native int native_bulk_request(int endpoint, byte[] buffer, int length, int timeout);
-    private native UsbRequest native_request_wait();
-    private native String native_get_serial();
-
     private static native int native_get_device_id(String name);
     private static native String native_get_device_name(int id);
 }
diff --git a/core/java/android/hardware/usb/UsbDeviceConnection.java b/core/java/android/hardware/usb/UsbDeviceConnection.java
new file mode 100644
index 0000000..876287c
--- /dev/null
+++ b/core/java/android/hardware/usb/UsbDeviceConnection.java
@@ -0,0 +1,163 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.usb;
+
+import android.os.ParcelFileDescriptor;
+import android.util.Log;
+
+import java.io.FileDescriptor;
+
+
+/**
+ * A class representing a USB device.
+ */
+public class UsbDeviceConnection {
+
+    private static final String TAG = "UsbDeviceConnection";
+
+    private final UsbDevice mDevice;
+
+    // used by the JNI code
+    private int mNativeContext;
+
+    /**
+     * UsbDevice should only be instantiated by UsbService implementation
+     * @hide
+     */
+    public UsbDeviceConnection(UsbDevice device) {
+        mDevice = device;
+    }
+
+    /* package */ boolean open(String name, ParcelFileDescriptor pfd) {
+        return native_open(name, pfd.getFileDescriptor());
+    }
+
+    /**
+     * Releases all system resources related to the device.
+     */
+    public void close() {
+        native_close();
+    }
+
+    /**
+     * Returns an integer file descriptor for the device, or
+     * -1 if the device is not opened.
+     * This is intended for passing to native code to access the device
+     */
+    public int getFileDescriptor() {
+        return native_get_fd();
+    }
+
+    /**
+     * Claims exclusive access to a {@link android.hardware.usb.UsbInterface}.
+     * This must be done before sending or receiving data on any
+     * {@link android.hardware.usb.UsbEndpoint}s belonging to the interface
+     * @param intf the interface to claim
+     * @param force true to disconnect kernel driver if necessary
+     * @return true if the interface was successfully claimed
+     */
+    public boolean claimInterface(UsbInterface intf, boolean force) {
+        return native_claim_interface(intf.getId(), force);
+    }
+
+    /**
+     * Releases exclusive access to a {@link android.hardware.usb.UsbInterface}.
+     *
+     * @return true if the interface was successfully released
+     */
+    public boolean releaseInterface(UsbInterface intf) {
+        return native_release_interface(intf.getId());
+    }
+
+    /**
+     * Performs a control transaction on endpoint zero for this device.
+     * The direction of the transfer is determined by the request type.
+     * If requestType & {@link UsbConstants#USB_ENDPOINT_DIR_MASK} is
+     * {@link UsbConstants#USB_DIR_OUT}, then the transfer is a write,
+     * and if it is {@link UsbConstants#USB_DIR_IN}, then the transfer
+     * is a read.
+     *
+     * @param requestType request type for this transaction
+     * @param request request ID for this transaction
+     * @param value value field for this transaction
+     * @param index index field for this transaction
+     * @param buffer buffer for data portion of transaction,
+     * or null if no data needs to be sent or received
+     * @param length the length of the data to send or receive
+     * @param timeout in milliseconds
+     * @return length of data transferred (or zero) for success,
+     * or negative value for failure
+     */
+    public int controlTransfer(int requestType, int request, int value,
+            int index, byte[] buffer, int length, int timeout) {
+        return native_control_request(requestType, request, value, index, buffer, length, timeout);
+    }
+
+    /**
+     * Performs a bulk transaction on the given endpoint.
+     * The direction of the transfer is determined by the direction of the endpoint
+     *
+     * @param endpoint the endpoint for this transaction
+     * @param buffer buffer for data to send or receive,
+     * @param length the length of the data to send or receive
+     * @param timeout in milliseconds
+     * @return length of data transferred (or zero) for success,
+     * or negative value for failure
+     */
+    public int bulkTransfer(UsbEndpoint endpoint, byte[] buffer, int length, int timeout) {
+        return native_bulk_request(endpoint.getAddress(), buffer, length, timeout);
+    }
+
+    /**
+     * Waits for the result of a {@link android.hardware.usb.UsbRequest#queue} operation
+     * Note that this may return requests queued on multiple 
+     * {@link android.hardware.usb.UsbEndpoint}s.
+     * When multiple endpoints are in use, {@link android.hardware.usb.UsbRequest#getEndpoint} and
+     * {@link android.hardware.usb.UsbRequest#getClientData} can be useful in determining
+     * how to process the result of this function.
+     *
+     * @return a completed USB request, or null if an error occurred
+     */
+    public UsbRequest requestWait() {
+        UsbRequest request = native_request_wait();
+        if (request != null) {
+            request.dequeue();
+        }
+        return request;
+    }
+
+    /**
+     * Returns the serial number for the device.
+     * This will return null if the device has not been opened.
+     *
+     * @return the device serial number
+     */
+    public String getSerial() {
+        return native_get_serial();
+    }
+
+    private native boolean native_open(String deviceName, FileDescriptor pfd);
+    private native void native_close();
+    private native int native_get_fd();
+    private native boolean native_claim_interface(int interfaceID, boolean force);
+    private native boolean native_release_interface(int interfaceID);
+    private native int native_control_request(int requestType, int request, int value,
+            int index, byte[] buffer, int length, int timeout);
+    private native int native_bulk_request(int endpoint, byte[] buffer, int length, int timeout);
+    private native UsbRequest native_request_wait();
+    private native String native_get_serial();
+}
diff --git a/core/java/android/hardware/usb/UsbEndpoint.java b/core/java/android/hardware/usb/UsbEndpoint.java
index a48d88f..bc2c2c1 100644
--- a/core/java/android/hardware/usb/UsbEndpoint.java
+++ b/core/java/android/hardware/usb/UsbEndpoint.java
@@ -23,16 +23,12 @@
 /**
  * A class representing an endpoint on a {@link android.hardware.usb.UsbInterface}.
  */
-public final class UsbEndpoint implements Parcelable {
+public class UsbEndpoint implements Parcelable {
 
-    private int mAddress;
-    private int mAttributes;
-    private int mMaxPacketSize;
-    private int mInterval;
-    private UsbInterface mInterface;
-
-    private UsbEndpoint() {
-    }
+    private final int mAddress;
+    private final int mAttributes;
+    private final int mMaxPacketSize;
+    private final int mInterval;
 
     /**
      * UsbEndpoint should only be instantiated by UsbService implementation
@@ -119,29 +115,6 @@
         return mInterval;
     }
 
-    /**
-     * Returns the {@link android.hardware.usb.UsbInterface} this endpoint belongs to.
-     *
-     * @return the endpoint's interface
-     */
-    public UsbInterface getInterface() {
-        return mInterface;
-    }
-
-    /**
-     * Returns the {@link android.hardware.usb.UsbDevice} this endpoint belongs to.
-     *
-     * @return the endpoint's device
-     */
-    public UsbDevice getDevice() {
-        return mInterface.getDevice();
-    }
-
-    // only used for parcelling
-    /* package */ void setInterface(UsbInterface intf) {
-        mInterface = intf;
-    }
-
     @Override
     public String toString() {
         return "UsbEndpoint[mAddress=" + mAddress + ",mAttributes=" + mAttributes +
diff --git a/core/java/android/hardware/usb/UsbInterface.java b/core/java/android/hardware/usb/UsbInterface.java
index b3b0e81..2b4c7c0 100644
--- a/core/java/android/hardware/usb/UsbInterface.java
+++ b/core/java/android/hardware/usb/UsbInterface.java
@@ -25,15 +25,11 @@
  */
 public class UsbInterface implements Parcelable {
 
-    private int mId;
-    private int mClass;
-    private int mSubclass;
-    private int mProtocol;
-    private UsbDevice mDevice;
-    private Parcelable[] mEndpoints;
-
-    private UsbInterface() {
-    }
+    private final int mId;
+    private final int mClass;
+    private final int mSubclass;
+    private final int mProtocol;
+    private final Parcelable[] mEndpoints;
 
     /**
      * UsbInterface should only be instantiated by UsbService implementation
@@ -104,20 +100,6 @@
         return (UsbEndpoint)mEndpoints[index];
     }
 
-    /**
-     * Returns the {@link android.hardware.usb.UsbDevice} this interface belongs to.
-     *
-     * @return the interface's device
-     */
-    public UsbDevice getDevice() {
-        return mDevice;
-    }
-
-    // only used for parcelling
-    /* package */ void setDevice(UsbDevice device) {
-        mDevice = device;
-    }
-
     @Override
     public String toString() {
         return "UsbInterface[mId=" + mId + ",mClass=" + mClass +
@@ -133,11 +115,7 @@
             int subClass = in.readInt();
             int protocol = in.readInt();
             Parcelable[] endpoints = in.readParcelableArray(UsbEndpoint.class.getClassLoader());
-            UsbInterface result = new UsbInterface(id, Class, subClass, protocol, endpoints);
-            for (int i = 0; i < endpoints.length; i++) {
-                ((UsbEndpoint)endpoints[i]).setInterface(result);
-            }
-            return result;
+            return new UsbInterface(id, Class, subClass, protocol, endpoints);
         }
 
         public UsbInterface[] newArray(int size) {
diff --git a/core/java/android/hardware/usb/UsbManager.java b/core/java/android/hardware/usb/UsbManager.java
index 6683179..7bf278a 100644
--- a/core/java/android/hardware/usb/UsbManager.java
+++ b/core/java/android/hardware/usb/UsbManager.java
@@ -17,6 +17,8 @@
 
 package android.hardware.usb;
 
+import android.app.PendingIntent;
+import android.content.Context;
 import android.os.Bundle;
 import android.os.ParcelFileDescriptor;
 import android.os.RemoteException;
@@ -53,6 +55,8 @@
      * {@link #USB_FUNCTION_MASS_STORAGE}, {@link #USB_FUNCTION_ADB}, {@link #USB_FUNCTION_RNDIS},
      * {@link #USB_FUNCTION_MTP} and {@link #USB_FUNCTION_ACCESSORY}.
      * </ul>
+     *
+     * {@hide}
      */
     public static final String ACTION_USB_STATE =
             "android.hardware.usb.action.USB_STATE";
@@ -98,7 +102,7 @@
      *
      * This intent is sent when a USB accessory is detached.
      * <ul>
-     * <li> {@link #EXTRA_ACCESSORY} containing the {@link android.hardware.usb.UsbAccessory}
+     * <li> {@link #EXTRA_ACCESSORY} containing the {@link UsbAccessory}
      * for the attached accessory that was detached
      * </ul>
      */
@@ -108,42 +112,56 @@
     /**
      * Boolean extra indicating whether USB is connected or disconnected.
      * Used in extras for the {@link #ACTION_USB_STATE} broadcast.
+     *
+     * {@hide}
      */
     public static final String USB_CONNECTED = "connected";
 
     /**
      * Integer extra containing currently set USB configuration.
      * Used in extras for the {@link #ACTION_USB_STATE} broadcast.
+     *
+     * {@hide}
      */
     public static final String USB_CONFIGURATION = "configuration";
 
     /**
      * Name of the USB mass storage USB function.
      * Used in extras for the {@link #ACTION_USB_STATE} broadcast
+     *
+     * {@hide}
      */
     public static final String USB_FUNCTION_MASS_STORAGE = "mass_storage";
 
     /**
      * Name of the adb USB function.
      * Used in extras for the {@link #ACTION_USB_STATE} broadcast
+     *
+     * {@hide}
      */
     public static final String USB_FUNCTION_ADB = "adb";
 
     /**
      * Name of the RNDIS ethernet USB function.
      * Used in extras for the {@link #ACTION_USB_STATE} broadcast
+     *
+     * {@hide}
      */
     public static final String USB_FUNCTION_RNDIS = "rndis";
 
     /**
      * Name of the MTP USB function.
      * Used in extras for the {@link #ACTION_USB_STATE} broadcast
+     *
+     * {@hide}
      */
     public static final String USB_FUNCTION_MTP = "mtp";
 
     /**
      * Name of the Accessory USB function.
      * Used in extras for the {@link #ACTION_USB_STATE} broadcast
+     *
+     * {@hide}
      */
     public static final String USB_FUNCTION_ACCESSORY = "accessory";
 
@@ -151,6 +169,8 @@
      * Value indicating that a USB function is enabled.
      * Used in {@link #USB_CONFIGURATION} extras bundle for the
      * {@link #ACTION_USB_STATE} broadcast
+     *
+     * {@hide}
      */
     public static final String USB_FUNCTION_ENABLED = "enabled";
 
@@ -158,6 +178,8 @@
      * Value indicating that a USB function is disabled.
      * Used in {@link #USB_CONFIGURATION} extras bundle for the
      * {@link #ACTION_USB_STATE} broadcast
+     *
+     * {@hide}
      */
     public static final String USB_FUNCTION_DISABLED = "disabled";
 
@@ -176,12 +198,22 @@
      */
     public static final String EXTRA_ACCESSORY = "accessory";
 
-    private IUsbManager mService;
+    /**
+     * Name of extra added to the {@link android.app.PendingIntent}
+     * passed into {@link #requestPermission(UsbDevice, PendingIntent)}
+     * or {@link #requestPermission(UsbAccessory, PendingIntent)}
+     * containing a boolean value indicating whether the user granted permission or not.
+     */
+    public static final String EXTRA_PERMISSION_GRANTED = "permission";
+
+    private final Context mContext;
+    private final IUsbManager mService;
 
     /**
      * {@hide}
      */
-    public UsbManager(IUsbManager service) {
+    public UsbManager(Context context, IUsbManager service) {
+        mContext = context;
         mService = service;
     }
 
@@ -215,19 +247,22 @@
      * @param device the device to open
      * @return true if we successfully opened the device
      */
-    public boolean openDevice(UsbDevice device) {
+    public UsbDeviceConnection openDevice(UsbDevice device) {
         try {
-            ParcelFileDescriptor pfd = mService.openDevice(device.getDeviceName());
-            if (pfd == null) {
-                return false;
+            String deviceName = device.getDeviceName();
+            ParcelFileDescriptor pfd = mService.openDevice(deviceName);
+            if (pfd != null) {
+                UsbDeviceConnection connection = new UsbDeviceConnection(device);
+                boolean result = connection.open(deviceName, pfd);
+                pfd.close();
+                if (result) {
+                    return connection;
+                }
             }
-            boolean result = device.open(pfd);
-            pfd.close();
-            return result;
         } catch (Exception e) {
             Log.e(TAG, "exception in UsbManager.openDevice", e);
-            return false;
         }
+        return null;
     }
 
     /**
@@ -245,7 +280,7 @@
                 return new UsbAccessory[] { accessory };
             }
         } catch (RemoteException e) {
-            Log.e(TAG, "RemoteException in getAccessoryList" , e);
+            Log.e(TAG, "RemoteException in getAccessoryList", e);
             return null;
         }
     }
@@ -260,11 +295,99 @@
         try {
             return mService.openAccessory(accessory);
         } catch (RemoteException e) {
-            Log.e(TAG, "RemoteException in openAccessory" , e);
+            Log.e(TAG, "RemoteException in openAccessory", e);
             return null;
         }
     }
 
+    /**
+     * Returns true if the caller has permission to access the device.
+     * Permission might have been granted temporarily via
+     * {@link #requestPermission(UsbDevice, PendingIntent)} or
+     * by the user choosing the caller as the default application for the device.
+     *
+     * @param device to check permissions for
+     * @return true if caller has permission
+     */
+    public boolean hasPermission(UsbDevice device) {
+        try {
+            return mService.hasDevicePermission(device);
+        } catch (RemoteException e) {
+            Log.e(TAG, "RemoteException in hasPermission", e);
+            return false;
+        }
+    }
+
+    /**
+     * Returns true if the caller has permission to access the accessory.
+     * Permission might have been granted temporarily via
+     * {@link #requestPermission(UsbAccessory, PendingIntent)} or
+     * by the user choosing the caller as the default application for the accessory.
+     *
+     * @param accessory to check permissions for
+     * @return true if caller has permission
+     */
+    public boolean hasPermission(UsbAccessory accessory) {
+        try {
+            return mService.hasAccessoryPermission(accessory);
+        } catch (RemoteException e) {
+            Log.e(TAG, "RemoteException in hasPermission", e);
+            return false;
+        }
+    }
+
+    /**
+     * Requests temporary permission for the given package to access the device.
+     * This may result in a system dialog being displayed to the user
+     * if permission had not already been granted.
+     * Success or failure is returned via the {@link android.app.PendingIntent} pi.
+     * If successful, this grants the caller permission to access the device only
+     * until the device is disconnected.
+     *
+     * The following extras will be added to pi:
+     * <ul>
+     * <li> {@link #EXTRA_DEVICE} containing the device passed into this call
+     * <li> {@link #EXTRA_PERMISSION_GRANTED} containing boolean indicating whether
+     * permission was granted by the user
+     * </ul>
+     *
+     * @param device to request permissions for
+     * @param pi PendingIntent for returning result
+     */
+    public void requestPermission(UsbDevice device, PendingIntent pi) {
+        try {
+            mService.requestDevicePermission(device, mContext.getPackageName(), pi);
+        } catch (RemoteException e) {
+            Log.e(TAG, "RemoteException in requestPermission", e);
+        }
+    }
+
+    /**
+     * Requests temporary permission for the given package to access the accessory.
+     * This may result in a system dialog being displayed to the user
+     * if permission had not already been granted.
+     * Success or failure is returned via the {@link android.app.PendingIntent} pi.
+     * If successful, this grants the caller permission to access the accessory only
+     * until the device is disconnected.
+     *
+     * The following extras will be added to pi:
+     * <ul>
+     * <li> {@link #EXTRA_ACCESSORY} containing the accessory passed into this call
+     * <li> {@link #EXTRA_PERMISSION_GRANTED} containing boolean indicating whether
+     * permission was granted by the user
+     * </ul>
+     *
+     * @param accessory to request permissions for
+     * @param pi PendingIntent for returning result
+     */
+    public void requestPermission(UsbAccessory accessory, PendingIntent pi) {
+        try {
+            mService.requestAccessoryPermission(accessory, mContext.getPackageName(), pi);
+        } catch (RemoteException e) {
+            Log.e(TAG, "RemoteException in requestPermission", e);
+        }
+    }
+
     private static File getFunctionEnableFile(String function) {
         return new File("/sys/class/usb_composite/" + function + "/enable");
     }
@@ -275,6 +398,8 @@
      *
      * @param function name of the USB function
      * @return true if the USB function is supported.
+     *
+     * {@hide}
      */
     public static boolean isFunctionSupported(String function) {
         return getFunctionEnableFile(function).exists();
@@ -285,6 +410,8 @@
      *
      * @param function name of the USB function
      * @return true if the USB function is enabled.
+     *
+     * {@hide}
      */
     public static boolean isFunctionEnabled(String function) {
         try {
@@ -300,7 +427,7 @@
     /**
      * Enables or disables a USB function.
      *
-     * @hide
+     * {@hide}
      */
     public static boolean setFunctionEnabled(String function, boolean enable) {
         try {
diff --git a/core/java/android/hardware/usb/UsbRequest.java b/core/java/android/hardware/usb/UsbRequest.java
index 80085c1..5fe6c8c 100644
--- a/core/java/android/hardware/usb/UsbRequest.java
+++ b/core/java/android/hardware/usb/UsbRequest.java
@@ -23,9 +23,9 @@
 /**
  * A class representing USB request packet.
  * This can be used for both reading and writing data to or from a
- * {@link android.hardware.usb.UsbDevice}.
+ * {@link android.hardware.usb.UsbDeviceConnection}.
  * UsbRequests are sent asynchronously via {@link #queue} and the results
- * are read by {@link android.hardware.usb.UsbDevice#requestWait}.
+ * are read by {@link android.hardware.usb.UsbDeviceConnection#requestWait}.
  */
 public class UsbRequest {
 
@@ -53,10 +53,9 @@
      * @param endpoint the endpoint to be used for this request.
      * @return true if the request was successfully opened.
      */
-    public boolean initialize(UsbEndpoint endpoint) {
+    public boolean initialize(UsbDeviceConnection connection, UsbEndpoint endpoint) {
         mEndpoint = endpoint;
-        return native_init(endpoint.getDevice(),
-                endpoint.getAddress(), endpoint.getAttributes(),
+        return native_init(connection, endpoint.getAddress(), endpoint.getAttributes(),
                 endpoint.getMaxPacketSize(), endpoint.getInterval());
     }
 
@@ -94,7 +93,7 @@
      * This can be used in conjunction with {@link #setClientData}
      * to associate another object with this request, which can be useful for
      * maintaining state between calls to {@link #queue} and
-     * {@link android.hardware.usb.UsbDevice#requestWait}
+     * {@link android.hardware.usb.UsbDeviceConnection#requestWait}
      *
      * @return the client data for the request
      */
@@ -107,7 +106,7 @@
      * This can be used in conjunction with {@link #getClientData}
      * to associate another object with this request, which can be useful for
      * maintaining state between calls to {@link #queue} and
-     * {@link android.hardware.usb.UsbDevice#requestWait}
+     * {@link android.hardware.usb.UsbDeviceConnection#requestWait}
      *
      * @param data the client data for the request
      */
@@ -121,7 +120,7 @@
      * For IN endpoints, the endpoint will attempt to read the given number of bytes
      * into the specified buffer.
      * If the queueing operation is successful, we return true and the result will be
-     * returned via {@link android.hardware.usb.UsbDevice#requestWait}
+     * returned via {@link android.hardware.usb.UsbDeviceConnection#requestWait}
      *
      * @param buffer the buffer containing the bytes to write, or location to store
      * the results of a read
@@ -166,8 +165,8 @@
         return native_cancel();
     }
 
-    private native boolean native_init(UsbDevice device, int ep_address, int ep_attributes,
-            int ep_max_packet_size, int ep_interval);
+    private native boolean native_init(UsbDeviceConnection connection, int ep_address,
+            int ep_attributes, int ep_max_packet_size, int ep_interval);
     private native void native_close();
     private native boolean native_queue_array(byte[] buffer, int length, boolean out);
     private native void native_dequeue_array(byte[] buffer, int length, boolean out);
diff --git a/core/java/android/net/EthernetDataTracker.java b/core/java/android/net/EthernetDataTracker.java
new file mode 100644
index 0000000..df5fdd0
--- /dev/null
+++ b/core/java/android/net/EthernetDataTracker.java
@@ -0,0 +1,333 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net;
+
+import android.content.Context;
+import android.net.ConnectivityManager;
+import android.net.DhcpInfoInternal;
+import android.net.LinkAddress;
+import android.net.LinkCapabilities;
+import android.net.LinkProperties;
+import android.net.NetworkInfo;
+import android.net.NetworkInfo.DetailedState;
+import android.net.NetworkStateTracker;
+import android.net.NetworkUtils;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.INetworkManagementService;
+import android.os.Message;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.util.Log;
+
+import java.net.InetAddress;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.concurrent.atomic.AtomicInteger;
+
+/**
+ * This class tracks the data connection associated with Ethernet
+ * This is a singleton class and an instance will be created by
+ * ConnectivityService.
+ * @hide
+ */
+public class EthernetDataTracker implements NetworkStateTracker {
+    private static final String NETWORKTYPE = "ETHERNET";
+    private static final String TAG = "Ethernet";
+
+    private AtomicBoolean mTeardownRequested = new AtomicBoolean(false);
+    private AtomicBoolean mPrivateDnsRouteSet = new AtomicBoolean(false);
+    private AtomicInteger mDefaultGatewayAddr = new AtomicInteger(0);
+    private AtomicBoolean mDefaultRouteSet = new AtomicBoolean(false);
+
+    private LinkProperties mLinkProperties;
+    private LinkCapabilities mLinkCapabilities;
+    private NetworkInfo mNetworkInfo;
+    private InterfaceObserver mInterfaceObserver;
+
+    /* For sending events to connectivity service handler */
+    private Handler mCsHandler;
+    private Context mContext;
+
+    private static EthernetDataTracker sInstance;
+    private static String mIface = "";
+
+    private static class InterfaceObserver extends INetworkManagementEventObserver.Stub {
+        private EthernetDataTracker mTracker;
+
+        InterfaceObserver(EthernetDataTracker tracker) {
+            super();
+            mTracker = tracker;
+        }
+
+        public void interfaceLinkStatusChanged(String iface, boolean up) {
+            Log.d(TAG, "Interface " + iface + " link " + (up ? "up" : "down"));
+        }
+
+        public void interfaceAdded(String iface) {
+            mTracker.interfaceAdded(iface);
+        }
+
+        public void interfaceRemoved(String iface) {
+            mTracker.interfaceRemoved(iface);
+        }
+    }
+
+    private EthernetDataTracker() {
+        mNetworkInfo = new NetworkInfo(ConnectivityManager.TYPE_ETHERNET, 0, NETWORKTYPE, "");
+        mLinkProperties = new LinkProperties();
+        mLinkCapabilities = new LinkCapabilities();
+
+        mNetworkInfo.setIsAvailable(false);
+        setTeardownRequested(false);
+    }
+
+    private void interfaceAdded(String iface) {
+        if (!iface.matches("eth\\d"))
+            return;
+
+        Log.d(TAG, "Adding " + iface);
+
+        synchronized(mIface) {
+            if(!mIface.isEmpty())
+                return;
+            mIface = iface;
+        }
+
+        mNetworkInfo.setIsAvailable(true);
+        Message msg = mCsHandler.obtainMessage(EVENT_CONFIGURATION_CHANGED, mNetworkInfo);
+        msg.sendToTarget();
+
+        runDhcp();
+    }
+
+    private void interfaceRemoved(String iface) {
+        if (!iface.equals(mIface))
+            return;
+
+        Log.d(TAG, "Removing " + iface);
+
+        NetworkUtils.stopDhcp(mIface);
+
+        mLinkProperties.clear();
+        mNetworkInfo.setIsAvailable(false);
+        mNetworkInfo.setDetailedState(DetailedState.DISCONNECTED, null, null);
+
+        Message msg = mCsHandler.obtainMessage(EVENT_CONFIGURATION_CHANGED, mNetworkInfo);
+        msg.sendToTarget();
+
+        msg = mCsHandler.obtainMessage(EVENT_STATE_CHANGED, mNetworkInfo);
+        msg.sendToTarget();
+
+        mIface = "";
+    }
+
+    private void runDhcp() {
+        Thread dhcpThread = new Thread(new Runnable() {
+            public void run() {
+                DhcpInfoInternal dhcpInfoInternal = new DhcpInfoInternal();
+                if (!NetworkUtils.runDhcp(mIface, dhcpInfoInternal)) {
+                    Log.e(TAG, "DHCP request error:" + NetworkUtils.getDhcpError());
+                    return;
+                }
+                mLinkProperties = dhcpInfoInternal.makeLinkProperties();
+                mLinkProperties.setInterfaceName(mIface);
+
+                mNetworkInfo.setDetailedState(DetailedState.CONNECTED, null, null);
+                Message msg = mCsHandler.obtainMessage(EVENT_STATE_CHANGED, mNetworkInfo);
+                msg.sendToTarget();
+            }
+        });
+        dhcpThread.start();
+    }
+
+    public static synchronized EthernetDataTracker getInstance() {
+        if (sInstance == null) sInstance = new EthernetDataTracker();
+        return sInstance;
+    }
+
+    public Object Clone() throws CloneNotSupportedException {
+        throw new CloneNotSupportedException();
+    }
+
+    public void setTeardownRequested(boolean isRequested) {
+        mTeardownRequested.set(isRequested);
+    }
+
+    public boolean isTeardownRequested() {
+        return mTeardownRequested.get();
+    }
+
+    /**
+     * Begin monitoring connectivity
+     */
+    public void startMonitoring(Context context, Handler target) {
+        mContext = context;
+        mCsHandler = target;
+
+        // register for notifications from NetworkManagement Service
+        IBinder b = ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE);
+        INetworkManagementService service = INetworkManagementService.Stub.asInterface(b);
+        mInterfaceObserver = new InterfaceObserver(this);
+        try {
+            service.registerObserver(mInterfaceObserver);
+        } catch (RemoteException e) {
+            Log.e(TAG, "Could not register InterfaceObserver " + e);
+        }
+    }
+
+    /**
+     * Disable connectivity to a network
+     * TODO: do away with return value after making MobileDataStateTracker async
+     */
+    public boolean teardown() {
+        mTeardownRequested.set(true);
+        NetworkUtils.stopDhcp(mIface);
+        return true;
+    }
+
+    /**
+     * Re-enable connectivity to a network after a {@link #teardown()}.
+     */
+    public boolean reconnect() {
+        mTeardownRequested.set(false);
+        runDhcp();
+        return true;
+    }
+
+    /**
+     * Turn the wireless radio off for a network.
+     * @param turnOn {@code true} to turn the radio on, {@code false}
+     */
+    public boolean setRadio(boolean turnOn) {
+        return true;
+    }
+
+    /**
+     * @return true - If are we currently tethered with another device.
+     */
+    public synchronized boolean isAvailable() {
+        return mNetworkInfo.isAvailable();
+    }
+
+    /**
+     * Tells the underlying networking system that the caller wants to
+     * begin using the named feature. The interpretation of {@code feature}
+     * is completely up to each networking implementation.
+     * @param feature the name of the feature to be used
+     * @param callingPid the process ID of the process that is issuing this request
+     * @param callingUid the user ID of the process that is issuing this request
+     * @return an integer value representing the outcome of the request.
+     * The interpretation of this value is specific to each networking
+     * implementation+feature combination, except that the value {@code -1}
+     * always indicates failure.
+     * TODO: needs to go away
+     */
+    public int startUsingNetworkFeature(String feature, int callingPid, int callingUid) {
+        return -1;
+    }
+
+    /**
+     * Tells the underlying networking system that the caller is finished
+     * using the named feature. The interpretation of {@code feature}
+     * is completely up to each networking implementation.
+     * @param feature the name of the feature that is no longer needed.
+     * @param callingPid the process ID of the process that is issuing this request
+     * @param callingUid the user ID of the process that is issuing this request
+     * @return an integer value representing the outcome of the request.
+     * The interpretation of this value is specific to each networking
+     * implementation+feature combination, except that the value {@code -1}
+     * always indicates failure.
+     * TODO: needs to go away
+     */
+    public int stopUsingNetworkFeature(String feature, int callingPid, int callingUid) {
+        return -1;
+    }
+
+    /**
+     * @param enabled
+     */
+    public void setDataEnable(boolean enabled) {
+        Log.d(TAG, "setDataEnabled: IGNORING enabled=" + enabled);
+    }
+
+    /**
+     * Check if private DNS route is set for the network
+     */
+    public boolean isPrivateDnsRouteSet() {
+        return mPrivateDnsRouteSet.get();
+    }
+
+    /**
+     * Set a flag indicating private DNS route is set
+     */
+    public void privateDnsRouteSet(boolean enabled) {
+        mPrivateDnsRouteSet.set(enabled);
+    }
+
+    /**
+     * Fetch NetworkInfo for the network
+     */
+    public synchronized NetworkInfo getNetworkInfo() {
+        return mNetworkInfo;
+    }
+
+    /**
+     * Fetch LinkProperties for the network
+     */
+    public synchronized LinkProperties getLinkProperties() {
+        return new LinkProperties(mLinkProperties);
+    }
+
+   /**
+     * A capability is an Integer/String pair, the capabilities
+     * are defined in the class LinkSocket#Key.
+     *
+     * @return a copy of this connections capabilities, may be empty but never null.
+     */
+    public LinkCapabilities getLinkCapabilities() {
+        return new LinkCapabilities(mLinkCapabilities);
+    }
+
+    /**
+     * Fetch default gateway address for the network
+     */
+    public int getDefaultGatewayAddr() {
+        return mDefaultGatewayAddr.get();
+    }
+
+    /**
+     * Check if default route is set
+     */
+    public boolean isDefaultRouteSet() {
+        return mDefaultRouteSet.get();
+    }
+
+    /**
+     * Set a flag indicating default route is set for the network
+     */
+    public void defaultRouteSet(boolean enabled) {
+        mDefaultRouteSet.set(enabled);
+    }
+
+    /**
+     * Return the system properties name associated with the tcp buffer sizes
+     * for this network.
+     */
+    public String getTcpBufferSizesPropName() {
+        return "net.tcp.buffersize.wifi";
+    }
+}
diff --git a/core/java/android/net/http/HttpsConnection.java b/core/java/android/net/http/HttpsConnection.java
index d77e9d9..84765a5 100644
--- a/core/java/android/net/http/HttpsConnection.java
+++ b/core/java/android/net/http/HttpsConnection.java
@@ -289,11 +289,9 @@
         } else {
             // if we do not have a proxy, we simply connect to the host
             try {
-                sslSock = (SSLSocket) getSocketFactory().createSocket();
-
+                sslSock = (SSLSocket) getSocketFactory().createSocket(
+                        mHost.getHostName(), mHost.getPort());
                 sslSock.setSoTimeout(SOCKET_TIMEOUT);
-                sslSock.connect(new InetSocketAddress(mHost.getHostName(),
-                        mHost.getPort()));
             } catch(IOException e) {
                 if (sslSock != null) {
                     sslSock.close();
diff --git a/core/java/android/nfc/INfcAdapter.aidl b/core/java/android/nfc/INfcAdapter.aidl
index d439a48..870127c 100644
--- a/core/java/android/nfc/INfcAdapter.aidl
+++ b/core/java/android/nfc/INfcAdapter.aidl
@@ -28,7 +28,7 @@
 import android.nfc.INfcTag;
 import android.nfc.IP2pTarget;
 import android.nfc.IP2pInitiator;
-import android.nfc.INfcSecureElement;
+import android.nfc.INfcAdapterExtras;
 
 /**
  * @hide
@@ -41,13 +41,12 @@
     INfcTag getNfcTagInterface();
     IP2pTarget getP2pTargetInterface();
     IP2pInitiator getP2pInitiatorInterface();
-    INfcSecureElement getNfcSecureElementInterface();
+    INfcAdapterExtras getNfcAdapterExtrasInterface();
 
     // NfcAdapter-class related methods
     boolean isEnabled();
     NdefMessage localGet();
     void localSet(in NdefMessage message);
-    void openTagConnection(in Tag tag);
     void enableForegroundDispatch(in ComponentName activity, in PendingIntent intent,
             in IntentFilter[] filters, in TechListParcel techLists);
     void disableForegroundDispatch(in ComponentName activity);
@@ -59,12 +58,8 @@
     int createLlcpConnectionlessSocket(int sap);
     int createLlcpServiceSocket(int sap, String sn, int miu, int rw, int linearBufferLength);
     int createLlcpSocket(int sap, int miu, int rw, int linearBufferLength);
-    int deselectSecureElement();
     boolean disable();
     boolean enable();
     String getProperties(String param);
-    int[] getSecureElementList();
-    int getSelectedSecureElement();
-    int selectSecureElement(int seId);
     int setProperties(String param, String value);
-}
\ No newline at end of file
+}
diff --git a/core/java/android/nfc/INfcSecureElement.aidl b/core/java/android/nfc/INfcAdapterExtras.aidl
similarity index 63%
copy from core/java/android/nfc/INfcSecureElement.aidl
copy to core/java/android/nfc/INfcAdapterExtras.aidl
index aa98dd2..ab5c1a6 100755
--- a/core/java/android/nfc/INfcSecureElement.aidl
+++ b/core/java/android/nfc/INfcAdapterExtras.aidl
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2010 The Android Open Source Project
+ * Copyright (C) 2011 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -16,13 +16,15 @@
 
 package android.nfc;
 
+import android.os.Bundle;
+
 /**
  * {@hide}
  */
-interface INfcSecureElement {
-    int openSecureElementConnection();
-    int closeSecureElementConnection(int nativeHandle);
-    byte[] exchangeAPDU(int nativeHandle, in byte[] data);
-    int[] getSecureElementTechList(int nativeHandle);
-    byte[] getSecureElementUid(int nativeHandle);
-}
\ No newline at end of file
+interface INfcAdapterExtras {
+    Bundle open(IBinder b);
+    Bundle close();
+    Bundle transceive(in byte[] data_in);
+    int getCardEmulationRoute();
+    void setCardEmulationRoute(int route);    
+}
diff --git a/core/java/android/nfc/NfcAdapter.java b/core/java/android/nfc/NfcAdapter.java
index 8c56fda..4689804 100644
--- a/core/java/android/nfc/NfcAdapter.java
+++ b/core/java/android/nfc/NfcAdapter.java
@@ -157,31 +157,6 @@
     public static final String EXTRA_ID = "android.nfc.extra.ID";
 
     /**
-     * Broadcast Action: a transaction with a secure element has been detected.
-     * <p>
-     * Always contains the extra field
-     * {@link android.nfc.NfcAdapter#EXTRA_AID}
-     * @hide
-     */
-    @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
-    public static final String ACTION_TRANSACTION_DETECTED =
-            "android.nfc.action.TRANSACTION_DETECTED";
-
-    /**
-     * Broadcast Action: an RF field ON has been detected.
-     * @hide
-     */
-    public static final String ACTION_RF_FIELD_ON_DETECTED =
-            "android.nfc.action.RF_FIELD_ON_DETECTED";
-
-    /**
-     * Broadcast Action: an RF Field OFF has been detected.
-     * @hide
-     */
-    public static final String ACTION_RF_FIELD_OFF_DETECTED =
-            "android.nfc.action.RF_FIELD_OFF_DETECTED";
-
-    /**
      * Broadcast Action: an adapter's state changed between enabled and disabled.
      *
      * The new value is stored in the extra EXTRA_NEW_BOOLEAN_STATE and just contains
@@ -201,15 +176,6 @@
     public static final String EXTRA_NEW_BOOLEAN_STATE = "android.nfc.isEnabled";
 
     /**
-     * Mandatory byte array extra field in
-     * {@link android.nfc.NfcAdapter#ACTION_TRANSACTION_DETECTED}.
-     * <p>
-     * Contains the AID of the applet involved in the transaction.
-     * @hide
-     */
-    public static final String EXTRA_AID = "android.nfc.extra.AID";
-
-    /**
      * LLCP link status: The LLCP link is activated.
      * @hide
      */
@@ -691,39 +657,14 @@
     }
 
     /**
-     * Create an Nfc Secure Element Connection
      * @hide
      */
-    public NfcSecureElement createNfcSecureElementConnection() {
+    public INfcAdapterExtras getNfcAdapterExtrasInterface() {
         try {
-            return new NfcSecureElement(sService.getNfcSecureElementInterface());
+            return sService.getNfcAdapterExtrasInterface();
         } catch (RemoteException e) {
-            Log.e(TAG, "createNfcSecureElementConnection failed", e);
+            attemptDeadServiceRecovery(e);
             return null;
         }
     }
-
-    /**
-     * To change the Secure Element Card Emulation state (ON/OFF)
-     * @hide
-     */
-    public void changeNfcSecureElementCardEmulationState(boolean state)
-    {
-        int seId = 11259375;
-        if(state){
-            /* Enable card emulation */
-            try {
-                sService.selectSecureElement(seId);
-            } catch (RemoteException e) {
-                Log.e(TAG, "Enable card emulation failed", e);
-            }
-        }else{
-            /* Disable card emulation */
-            try {
-                sService.deselectSecureElement();
-            } catch (RemoteException e) {
-                Log.e(TAG, " card emulation failed", e);
-            }
-        }
-    }
 }
diff --git a/core/java/android/nfc/NfcSecureElement.java b/core/java/android/nfc/NfcSecureElement.java
deleted file mode 100755
index 3b5f39e..0000000
--- a/core/java/android/nfc/NfcSecureElement.java
+++ /dev/null
@@ -1,138 +0,0 @@
-/*
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.nfc;
-
-import android.nfc.tech.TagTechnology;
-import android.os.RemoteException;
-import android.util.Log;
-
-import java.io.IOException;
-
-//import android.util.Log;
-
-/**
- * This class provides the primary API for managing all aspects Secure Element.
- * Get an instance of this class by calling
- * Context.getSystemService(Context.NFC_SERVICE).
- * @hide
- */
-public final class NfcSecureElement {
-
-    private static final String TAG = "NfcSecureElement";
-
-    private INfcSecureElement mService;
-
-
-    /**
-     * @hide
-     */
-    public NfcSecureElement(INfcSecureElement mSecureElementService) {
-        mService = mSecureElementService;
-    }
-
-    public int openSecureElementConnection(String seType) throws IOException {
-        if (seType.equals("SmartMX")) {
-            try {
-                int handle = mService.openSecureElementConnection();
-                // Handle potential errors
-                if (handle != 0) {
-                    return handle;
-                } else {
-                    throw new IOException("SmartMX connection not allowed");
-                }
-            } catch (RemoteException e) {
-                Log.e(TAG, "RemoteException in openSecureElementConnection(): ", e);
-                return 0;
-            }
-
-        } else if (seType.equals("UICC")) {
-            return 0;
-        } else {
-        	throw new IOException("Wrong Secure Element type");
-        }
-    }
-
-
-    public byte [] exchangeAPDU(int handle,byte [] data) throws IOException {
-
-
-        // Perform exchange APDU
-        try {
-            byte[] response = mService.exchangeAPDU(handle, data);
-            // Handle potential errors
-            if (response == null) {
-            	throw new IOException("Exchange APDU failed");
-            }
-            return response;
-        } catch (RemoteException e) {
-            Log.e(TAG, "RemoteException in exchangeAPDU(): ", e);
-            return null;
-        }
-    }
-
-    public void closeSecureElementConnection(int handle) throws IOException {
-
-        try {
-            int status = mService.closeSecureElementConnection(handle);
-            // Handle potential errors
-            if (ErrorCodes.isError(status)) {
-            	throw new IOException("Error during the conection close");
-            };
-        } catch (RemoteException e) {
-            Log.e(TAG, "RemoteException in closeSecureElement(): ", e);
-        }
-    }
-
-
-    /**
-     * Returns target type. constants.
-     *
-     * @return Secure Element technology type. The possible values are defined in
-     * {@link TagTechnology}
-     *
-     */
-    public int[] getSecureElementTechList(int handle) throws IOException {
-        try {
-            return mService.getSecureElementTechList(handle);
-        } catch (RemoteException e) {
-            Log.e(TAG, "RemoteException in getType(): ", e);
-            return null;
-        }
-    }
-
-    /**
-     * Returns Secure Element UID.
-     *
-     * @return Secure Element UID.
-     */
-    public byte[] getSecureElementUid(int handle) throws IOException {
-
-        byte[] uid = null;
-        try {
-            uid = mService.getSecureElementUid(handle);
-            // Handle potential errors
-            if (uid == null) {
-                throw new IOException("Get Secure Element UID failed");
-            }
-            return uid;
-        } catch (RemoteException e) {
-            Log.e(TAG, "RemoteException in getType(): ", e);
-            return null;
-        }
-    }
-
-}
diff --git a/core/java/android/os/AsyncTask.java b/core/java/android/os/AsyncTask.java
index 1803604..64bba54 100644
--- a/core/java/android/os/AsyncTask.java
+++ b/core/java/android/os/AsyncTask.java
@@ -153,7 +153,6 @@
     private static final int MAXIMUM_POOL_SIZE = 128;
     private static final int KEEP_ALIVE = 1;
 
-
     private static final ThreadFactory sThreadFactory = new ThreadFactory() {
         private final AtomicInteger mCount = new AtomicInteger(1);
 
@@ -183,6 +182,7 @@
 
     private static final InternalHandler sHandler = new InternalHandler();
 
+    private static volatile Executor sDefaultExecutor = SERIAL_EXECUTOR;
     private final WorkerRunnable<Params, Result> mWorker;
     private final FutureTask<Result> mFuture;
 
@@ -240,6 +240,11 @@
         sHandler.getLooper();
     }
 
+    /** @hide */
+    public static void setDefaultExecutor(Executor exec) {
+        sDefaultExecutor = exec;
+    }
+
     /**
      * Creates a new asynchronous task. This constructor must be invoked on the UI thread.
      */
@@ -496,7 +501,7 @@
      *         {@link AsyncTask.Status#RUNNING} or {@link AsyncTask.Status#FINISHED}.
      */
     public final AsyncTask<Params, Progress, Result> execute(Params... params) {
-        return executeOnExecutor(THREAD_POOL_EXECUTOR, params);
+        return executeOnExecutor(sDefaultExecutor, params);
     }
 
     /**
@@ -559,7 +564,7 @@
      * a simple Runnable object.
      */
     public static void execute(Runnable runnable) {
-        THREAD_POOL_EXECUTOR.execute(runnable);
+        sDefaultExecutor.execute(runnable);
     }
 
     /**
diff --git a/core/java/android/os/Build.java b/core/java/android/os/Build.java
index 8d2607a..3bb0821 100644
--- a/core/java/android/os/Build.java
+++ b/core/java/android/os/Build.java
@@ -202,12 +202,12 @@
         public static final int GINGERBREAD = 9;
         
         /**
-         * Almost newest version of Android, version 2.3.3.
+         * February 2011: Android 2.3.3.
          */
         public static final int GINGERBREAD_MR1 = 10;
 
         /**
-         * Newest version of Android, version 3.0.
+         * February 2011: Android 3.0.
          *
          * <p>Applications targeting this or a later release will get these
          * new changes in behavior:</p>
@@ -225,6 +225,11 @@
          * </ul>
          */
         public static final int HONEYCOMB = 11;
+        
+        /**
+         * Newest version of Android, version 3.1.
+         */
+        public static final int HONEYCOMB_MR1 = 12;
     }
     
     /** The type of build, like "user" or "eng". */
diff --git a/core/java/android/os/Bundle.java b/core/java/android/os/Bundle.java
index 8eac7aa..c288f8a 100644
--- a/core/java/android/os/Bundle.java
+++ b/core/java/android/os/Bundle.java
@@ -1028,7 +1028,6 @@
         }
     }
 
-
     /**
      * Returns the value associated with the given key, or null if
      * no mapping of the desired type exists for the given key or a null
@@ -1052,6 +1051,28 @@
     }
 
     /**
+     * Returns the value associated with the given key, or defaultValue if
+     * no mapping of the desired type exists for the given key.
+     *
+     * @param key a String, or null
+     * @param defaultValue Value to return if key does not exist
+     * @return a String value, or null
+     */
+    public String getString(String key, String defaultValue) {
+        unparcel();
+        Object o = mMap.get(key);
+        if (o == null) {
+            return defaultValue;
+        }
+        try {
+            return (String) o;
+        } catch (ClassCastException e) {
+            typeWarning(key, o, "String", e);
+            return defaultValue;
+        }
+    }
+
+    /**
      * Returns the value associated with the given key, or null if
      * no mapping of the desired type exists for the given key or a null
      * value is explicitly associated with the key.
@@ -1074,6 +1095,28 @@
     }
 
     /**
+     * Returns the value associated with the given key, or defaultValue if
+     * no mapping of the desired type exists for the given key.
+     *
+     * @param key a String, or null
+     * @param defaultValue Value to return if key does not exist
+     * @return a CharSequence value, or null
+     */
+    public CharSequence getCharSequence(String key, CharSequence defaultValue) {
+        unparcel();
+        Object o = mMap.get(key);
+        if (o == null) {
+            return defaultValue;
+        }
+        try {
+            return (CharSequence) o;
+        } catch (ClassCastException e) {
+            typeWarning(key, o, "CharSequence", e);
+            return defaultValue;
+        }
+    }
+
+    /**
      * Returns the value associated with the given key, or null if
      * no mapping of the desired type exists for the given key or a null
      * value is explicitly associated with the key.
diff --git a/core/java/android/os/Environment.java b/core/java/android/os/Environment.java
index ec5030c..e308c2c 100644
--- a/core/java/android/os/Environment.java
+++ b/core/java/android/os/Environment.java
@@ -423,9 +423,16 @@
 
     /**
      * Returns whether the device has an external storage device which is
-     * emulated. If true, the device does not have real external storage
-     * and certain system services such as the package manager use this
+     * emulated. If true, the device does not have real external storage, and the directory
+     * returned by {@link #getExternalStorageDirectory()} will be allocated using a portion of
+     * the internal storage system.
+     *
+     * <p>Certain system services, such as the package manager, use this
      * to determine where to install an application.
+     *
+     * <p>Emulated external storage may also be encrypted - see
+     * {@link android.app.admin.DevicePolicyManager#setStorageEncryption(
+     * android.content.ComponentName, boolean)} for additional details.
      */
     public static boolean isExternalStorageEmulated() {
         if (mIsExternalStorageEmulated == null) {
diff --git a/core/java/android/os/Looper.java b/core/java/android/os/Looper.java
index 8204e3c..ccf642c 100644
--- a/core/java/android/os/Looper.java
+++ b/core/java/android/os/Looper.java
@@ -141,7 +141,8 @@
                     Log.wtf("Looper", "Thread identity changed from 0x"
                             + Long.toHexString(ident) + " to 0x"
                             + Long.toHexString(newIdent) + " while dispatching to "
-                            + msg.target + " " + msg.callback + " what=" + msg.what);
+                            + msg.target.getClass().getName() + " "
+                            + msg.callback + " what=" + msg.what);
                 }
                 
                 msg.recycle();
diff --git a/core/java/android/os/PowerManager.java b/core/java/android/os/PowerManager.java
index efb8415..57fdb0c 100644
--- a/core/java/android/os/PowerManager.java
+++ b/core/java/android/os/PowerManager.java
@@ -97,7 +97,8 @@
  *     </tbody>
  * </table>
  * 
- * 
+ * Any application using a WakeLock must request the {@code android.permission.WAKE_LOCK}
+ * permission in an {@code &lt;uses-permission&gt;} element of the application's manifest.
  */
 public class PowerManager
 {
@@ -188,8 +189,11 @@
     
     /**
      * Class lets you say that you need to have the device on.
-     *
-     * <p>Call release when you are done and don't need the lock anymore.
+     * <p>
+     * Call release when you are done and don't need the lock anymore.
+     * <p>
+     * Any application using a WakeLock must request the {@code android.permission.WAKE_LOCK}
+     * permission in an {@code &lt;uses-permission&gt;} element of the application's manifest.
      */
     public class WakeLock
     {
diff --git a/core/java/android/preference/CheckBoxPreference.java b/core/java/android/preference/CheckBoxPreference.java
index f16a7e4..2bf6c7b 100644
--- a/core/java/android/preference/CheckBoxPreference.java
+++ b/core/java/android/preference/CheckBoxPreference.java
@@ -24,8 +24,10 @@
 import android.os.Parcelable;
 import android.util.AttributeSet;
 import android.view.View;
+import android.view.ViewGroup;
 import android.view.accessibility.AccessibilityEvent;
 import android.view.accessibility.AccessibilityManager;
+import android.widget.CheckBox;
 import android.widget.Checkable;
 import android.widget.TextView;
 
@@ -90,8 +92,16 @@
                     checkboxView.isEnabled()) {
                 mSendAccessibilityEventViewClickedType = false;
 
-                int eventType = AccessibilityEvent.TYPE_VIEW_CLICKED;
-                checkboxView.sendAccessibilityEventUnchecked(AccessibilityEvent.obtain(eventType));
+                // we send an event on behalf of the check box because in onBind the latter
+                // is detached from its parent and such views do not send accessibility events
+                AccessibilityEvent event = AccessibilityEvent.obtain(
+                        AccessibilityEvent.TYPE_VIEW_CLICKED);
+                event.setClassName(checkboxView.getClass().getName());
+                event.setPackageName(getContext().getPackageName());
+                event.setEnabled(checkboxView.isEnabled());
+                event.setContentDescription(checkboxView.getContentDescription());
+                event.setChecked(((Checkable) checkboxView).isChecked());
+                mAccessibilityManager.sendAccessibilityEvent(event);
             }
         }
 
diff --git a/core/java/android/preference/Preference.java b/core/java/android/preference/Preference.java
index 7d37e5b..5e1be21 100644
--- a/core/java/android/preference/Preference.java
+++ b/core/java/android/preference/Preference.java
@@ -89,6 +89,7 @@
 
     private int mOrder = DEFAULT_ORDER;
     private CharSequence mTitle;
+    private int mTitleRes;
     private CharSequence mSummary;
     /**
      * mIconResId is overridden by mIcon, if mIcon is specified.
@@ -214,6 +215,7 @@
                     break;
                     
                 case com.android.internal.R.styleable.Preference_title:
+                    mTitleRes = a.getResourceId(attr, 0);
                     mTitle = a.getString(attr);
                     break;
                     
@@ -582,6 +584,7 @@
      */
     public void setTitle(CharSequence title) {
         if (title == null && mTitle != null || title != null && !title.equals(mTitle)) {
+            mTitleRes = 0;
             mTitle = title;
             notifyChanged();
         }
@@ -595,9 +598,21 @@
      */
     public void setTitle(int titleResId) {
         setTitle(mContext.getString(titleResId));
+        mTitleRes = titleResId;
     }
     
     /**
+     * Returns the title resource ID of this Preference.  If the title did
+     * not come from a resource, 0 is returned.
+     *
+     * @return The title resource.
+     * @see #setTitle(int)
+     */
+    public int getTitleRes() {
+        return mTitleRes;
+    }
+
+    /**
      * Returns the title of this Preference.
      * 
      * @return The title.
diff --git a/core/java/android/preference/PreferenceActivity.java b/core/java/android/preference/PreferenceActivity.java
index 2b609ea..15d5898 100644
--- a/core/java/android/preference/PreferenceActivity.java
+++ b/core/java/android/preference/PreferenceActivity.java
@@ -132,13 +132,28 @@
 
     /**
      * When starting this activity and using {@link #EXTRA_SHOW_FRAGMENT},
-     * this extra can also be specify to supply a Bundle of arguments to pass
+     * this extra can also be specified to supply a Bundle of arguments to pass
      * to that fragment when it is instantiated during the initial creation
      * of PreferenceActivity.
      */
     public static final String EXTRA_SHOW_FRAGMENT_ARGUMENTS = ":android:show_fragment_args";
 
     /**
+     * When starting this activity and using {@link #EXTRA_SHOW_FRAGMENT},
+     * this extra can also be specify to supply the title to be shown for
+     * that fragment.
+     */
+    public static final String EXTRA_SHOW_FRAGMENT_TITLE = ":android:show_fragment_title";
+
+    /**
+     * When starting this activity and using {@link #EXTRA_SHOW_FRAGMENT},
+     * this extra can also be specify to supply the short title to be shown for
+     * that fragment.
+     */
+    public static final String EXTRA_SHOW_FRAGMENT_SHORT_TITLE
+            = ":android:show_fragment_short_title";
+
+    /**
      * When starting this activity, the invoking Intent can contain this extra
      * boolean that the header list should not be displayed.  This is most often
      * used in conjunction with {@link #EXTRA_SHOW_FRAGMENT} to launch
@@ -488,7 +503,12 @@
     protected void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
 
-        setContentView(com.android.internal.R.layout.preference_list_content);
+        if (getResources().getConfiguration().isLayoutSizeAtLeast(
+                Configuration.SCREENLAYOUT_SIZE_LARGE)) {
+            setContentView(com.android.internal.R.layout.preference_list_content_large);
+        } else {
+            setContentView(com.android.internal.R.layout.preference_list_content);
+        }
 
         mListFooter = (FrameLayout)findViewById(com.android.internal.R.id.list_footer);
         mPrefsContainer = (ViewGroup) findViewById(com.android.internal.R.id.prefs_frame);
@@ -496,6 +516,8 @@
         mSinglePane = hidingHeaders || !onIsMultiPane();
         String initialFragment = getIntent().getStringExtra(EXTRA_SHOW_FRAGMENT);
         Bundle initialArguments = getIntent().getBundleExtra(EXTRA_SHOW_FRAGMENT_ARGUMENTS);
+        int initialTitle = getIntent().getIntExtra(EXTRA_SHOW_FRAGMENT_TITLE, 0);
+        int initialShortTitle = getIntent().getIntExtra(EXTRA_SHOW_FRAGMENT_SHORT_TITLE, 0);
 
         if (savedInstanceState != null) {
             // We are restarting from a previous saved state; used that to
@@ -516,6 +538,12 @@
                 // new fragment mode, but don't need to compute and show
                 // the headers.
                 switchToHeader(initialFragment, initialArguments);
+                if (initialTitle != 0) {
+                    CharSequence initialTitleStr = getText(initialTitle);
+                    CharSequence initialShortTitleStr = initialShortTitle != 0
+                            ? getText(initialShortTitle) : null;
+                    showBreadCrumbs(initialTitleStr, initialShortTitleStr);
+                }
 
             } else {
                 // We need to try to build the headers.
@@ -557,7 +585,12 @@
         } else {
             // If there are no headers, we are in the old "just show a screen
             // of preferences" mode.
-            setContentView(com.android.internal.R.layout.preference_list_content_single);
+            if (getResources().getConfiguration().isLayoutSizeAtLeast(
+                    Configuration.SCREENLAYOUT_SIZE_LARGE)) {
+                setContentView(com.android.internal.R.layout.preference_list_content_single_large);
+            } else {
+                setContentView(com.android.internal.R.layout.preference_list_content_single);
+            }
             mListFooter = (FrameLayout) findViewById(com.android.internal.R.id.list_footer);
             mPrefsContainer = (ViewGroup) findViewById(com.android.internal.R.id.prefs);
             mPreferenceManager = new PreferenceManager(this, FIRST_REQUEST_CODE);
@@ -942,7 +975,8 @@
 
     /**
      * Called when the user selects an item in the header list.  The default
-     * implementation will call either {@link #startWithFragment(String, Bundle, Fragment, int)}
+     * implementation will call either
+     * {@link #startWithFragment(String, Bundle, Fragment, int, int, int)}
      * or {@link #switchToHeader(Header)} as appropriate.
      *
      * @param header The header that was selected.
@@ -951,7 +985,14 @@
     public void onHeaderClick(Header header, int position) {
         if (header.fragment != null) {
             if (mSinglePane) {
-                startWithFragment(header.fragment, header.fragmentArguments, null, 0);
+                int titleRes = header.breadCrumbTitleRes;
+                int shortTitleRes = header.breadCrumbShortTitleRes;
+                if (titleRes == 0) {
+                    titleRes = header.titleRes;
+                    shortTitleRes = 0;
+                }
+                startWithFragment(header.fragment, header.fragmentArguments, null, 0,
+                        titleRes, shortTitleRes);
             } else {
                 switchToHeader(header);
             }
@@ -961,6 +1002,41 @@
     }
 
     /**
+     * Called by {@link #startWithFragment(String, Bundle, Fragment, int, int, int)} when
+     * in single-pane mode, to build an Intent to launch a new activity showing
+     * the selected fragment.  The default implementation constructs an Intent
+     * that re-launches the current activity with the appropriate arguments to
+     * display the fragment.
+     * 
+     * @param fragmentName The name of the fragment to display.
+     * @param args Optional arguments to supply to the fragment.
+     * @param titleRes Optional resource ID of title to show for this item.
+     * @param titleRes Optional resource ID of short title to show for this item.
+     * @return Returns an Intent that can be launched to display the given
+     * fragment.
+     */
+    public Intent onBuildStartFragmentIntent(String fragmentName, Bundle args,
+            int titleRes, int shortTitleRes) {
+        Intent intent = new Intent(Intent.ACTION_MAIN);
+        intent.setClass(this, getClass());
+        intent.putExtra(EXTRA_SHOW_FRAGMENT, fragmentName);
+        intent.putExtra(EXTRA_SHOW_FRAGMENT_ARGUMENTS, args);
+        intent.putExtra(EXTRA_SHOW_FRAGMENT_TITLE, titleRes);
+        intent.putExtra(EXTRA_SHOW_FRAGMENT_SHORT_TITLE, shortTitleRes);
+        intent.putExtra(EXTRA_NO_HEADERS, true);
+        return intent;
+    }
+    
+    /**
+     * Like {@link #startWithFragment(String, Bundle, Fragment, int, int, int)}
+     * but uses a 0 titleRes.
+     */
+    public void startWithFragment(String fragmentName, Bundle args,
+            Fragment resultTo, int resultRequestCode) {
+        startWithFragment(fragmentName, args, resultTo, resultRequestCode, 0, 0);
+    }
+
+    /**
      * Start a new instance of this activity, showing only the given
      * preference fragment.  When launched in this mode, the header list
      * will be hidden and the given preference fragment will be instantiated
@@ -968,14 +1044,18 @@
      *
      * @param fragmentName The name of the fragment to display.
      * @param args Optional arguments to supply to the fragment.
+     * @param resultTo Option fragment that should receive the result of
+     * the activity launch.
+     * @param resultRequestCode If resultTo is non-null, this is the request
+     * code in which to report the result.
+     * @param titleRes Resource ID of string to display for the title of
+     * this set of preferences.
+     * @param titleRes Resource ID of string to display for the short title of
+     * this set of preferences.
      */
     public void startWithFragment(String fragmentName, Bundle args,
-            Fragment resultTo, int resultRequestCode) {
-        Intent intent = new Intent(Intent.ACTION_MAIN);
-        intent.setClass(this, getClass());
-        intent.putExtra(EXTRA_SHOW_FRAGMENT, fragmentName);
-        intent.putExtra(EXTRA_SHOW_FRAGMENT_ARGUMENTS, args);
-        intent.putExtra(EXTRA_NO_HEADERS, true);
+            Fragment resultTo, int resultRequestCode, int titleRes, int shortTitleRes) {
+        Intent intent = onBuildStartFragmentIntent(fragmentName, args, titleRes, shortTitleRes);
         if (resultTo == null) {
             startActivity(intent);
         } else {
@@ -992,16 +1072,16 @@
         if (mFragmentBreadCrumbs == null) {
             View crumbs = findViewById(android.R.id.title);
             // For screens with a different kind of title, don't create breadcrumbs.
-            if (!(crumbs instanceof FragmentBreadCrumbs)) return;
-            mFragmentBreadCrumbs = (FragmentBreadCrumbs) findViewById(android.R.id.title);
+            try {
+                mFragmentBreadCrumbs = (FragmentBreadCrumbs)crumbs;
+            } catch (ClassCastException e) {
+                return;
+            }
             if (mFragmentBreadCrumbs == null) {
-                mFragmentBreadCrumbs = new FragmentBreadCrumbs(this);
-                ActionBar actionBar = getActionBar();
-                if (actionBar != null) {
-                    actionBar.setDisplayOptions(ActionBar.DISPLAY_SHOW_CUSTOM,
-                            ActionBar.DISPLAY_SHOW_TITLE | ActionBar.DISPLAY_SHOW_CUSTOM);
-                    actionBar.setCustomView(mFragmentBreadCrumbs);
+                if (title != null) {
+                    setTitle(title);
                 }
+                return;
             }
             mFragmentBreadCrumbs.setMaxVisible(2);
             mFragmentBreadCrumbs.setActivity(this);
@@ -1049,7 +1129,7 @@
         FragmentTransaction transaction = getFragmentManager().beginTransaction();
         transaction.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE);
         transaction.replace(com.android.internal.R.id.prefs, f);
-        transaction.commit();
+        transaction.commitAllowingStateLoss();
     }
 
     /**
@@ -1144,7 +1224,7 @@
         } else {
             transaction.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE);
         }
-        transaction.commit();
+        transaction.commitAllowingStateLoss();
     }
 
     /**
@@ -1169,7 +1249,7 @@
     public void startPreferencePanel(String fragmentClass, Bundle args, int titleRes,
             CharSequence titleText, Fragment resultTo, int resultRequestCode) {
         if (mSinglePane) {
-            startWithFragment(fragmentClass, args, resultTo, resultRequestCode);
+            startWithFragment(fragmentClass, args, resultTo, resultRequestCode, titleRes, 0);
         } else {
             Fragment f = Fragment.instantiate(this, fragmentClass, args);
             if (resultTo != null) {
@@ -1184,7 +1264,7 @@
             }
             transaction.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN);
             transaction.addToBackStack(BACK_STACK_PREFS);
-            transaction.commit();
+            transaction.commitAllowingStateLoss();
         }
     }
     
@@ -1215,7 +1295,8 @@
     
     @Override
     public boolean onPreferenceStartFragment(PreferenceFragment caller, Preference pref) {
-        startPreferencePanel(pref.getFragment(), pref.getExtras(), 0, pref.getTitle(), null, 0);
+        startPreferencePanel(pref.getFragment(), pref.getExtras(), pref.getTitleRes(),
+                pref.getTitle(), null, 0);
         return true;
     }
 
diff --git a/core/java/android/preference/PreferenceFragment.java b/core/java/android/preference/PreferenceFragment.java
index 4e22ba0..7511e14 100644
--- a/core/java/android/preference/PreferenceFragment.java
+++ b/core/java/android/preference/PreferenceFragment.java
@@ -20,6 +20,7 @@
 import android.app.Fragment;
 import android.content.Intent;
 import android.content.SharedPreferences;
+import android.content.res.Configuration;
 import android.os.Bundle;
 import android.os.Handler;
 import android.os.Message;
@@ -151,8 +152,14 @@
     @Override
     public View onCreateView(LayoutInflater inflater, ViewGroup container,
             Bundle savedInstanceState) {
-        return inflater.inflate(com.android.internal.R.layout.preference_list_fragment,
-                container, false);
+        if (getResources().getConfiguration().isLayoutSizeAtLeast(
+                Configuration.SCREENLAYOUT_SIZE_LARGE)) {
+            return inflater.inflate(com.android.internal.R.layout.preference_list_fragment_large,
+                    container, false);
+        } else {
+            return inflater.inflate(com.android.internal.R.layout.preference_list_fragment,
+                    container, false);
+        }
     }
 
     @Override
diff --git a/core/java/android/provider/MediaStore.java b/core/java/android/provider/MediaStore.java
index b59421e..bb8d874 100644
--- a/core/java/android/provider/MediaStore.java
+++ b/core/java/android/provider/MediaStore.java
@@ -166,7 +166,6 @@
      * If the EXTRA_OUTPUT is present, then the full-sized image will be written to the Uri
      * value of EXTRA_OUTPUT.
      * @see #EXTRA_OUTPUT
-     * @see #EXTRA_VIDEO_QUALITY
      */
     public final static String ACTION_IMAGE_CAPTURE = "android.media.action.IMAGE_CAPTURE";
 
@@ -181,6 +180,9 @@
      * written to the standard location for videos, and the Uri of that location will be
      * returned in the data field of the Uri.
      * @see #EXTRA_OUTPUT
+     * @see #EXTRA_VIDEO_QUALITY
+     * @see #EXTRA_SIZE_LIMIT
+     * @see #EXTRA_DURATION_LIMIT
      */
     public final static String ACTION_VIDEO_CAPTURE = "android.media.action.VIDEO_CAPTURE";
 
diff --git a/core/java/android/provider/Telephony.java b/core/java/android/provider/Telephony.java
index d2d2557..6ff9f0e 100644
--- a/core/java/android/provider/Telephony.java
+++ b/core/java/android/provider/Telephony.java
@@ -90,12 +90,18 @@
         public static final String PERSON_ID = "person";
 
         /**
-         * The date the message was sent
+         * The date the message was received
          * <P>Type: INTEGER (long)</P>
          */
         public static final String DATE = "date";
 
         /**
+         * The date the message was sent
+         * <P>Type: INTEGER (long)</P>
+         */
+        public static final String DATE_SENT = "date_sent";
+
+        /**
          * Has the message been read
          * <P>Type: INTEGER (boolean)</P>
          */
@@ -650,12 +656,18 @@
         public static final int MESSAGE_BOX_OUTBOX = 4;
 
         /**
-         * The date the message was sent.
+         * The date the message was received.
          * <P>Type: INTEGER (long)</P>
          */
         public static final String DATE = "date";
 
         /**
+         * The date the message was sent.
+         * <P>Type: INTEGER (long)</P>
+         */
+        public static final String DATE_SENT = "date_sent";
+
+        /**
          * The box which the message belong to, for example, MESSAGE_BOX_INBOX.
          * <P>Type: INTEGER</P>
          */
diff --git a/core/java/android/speech/RecognitionService.java b/core/java/android/speech/RecognitionService.java
index 75a5ed5..32b2d8f 100644
--- a/core/java/android/speech/RecognitionService.java
+++ b/core/java/android/speech/RecognitionService.java
@@ -68,6 +68,8 @@
 
     private static final int MSG_CANCEL = 3;
 
+    private static final int MSG_RESET = 4;
+
     private final Handler mHandler = new Handler() {
         @Override
         public void handleMessage(Message msg) {
@@ -81,6 +83,10 @@
                     break;
                 case MSG_CANCEL:
                     dispatchCancel((IRecognitionListener) msg.obj);
+                    break;
+                case MSG_RESET:
+                    dispatchClearCallback();
+                    break;
             }
         }
     };
@@ -128,6 +134,10 @@
         }
     }
 
+    private void dispatchClearCallback() {
+        mCurrentCallback = null;
+    }
+
     private class StartListeningArgs {
         public final Intent mIntent;
 
@@ -241,7 +251,7 @@
          * @param error code is defined in {@link SpeechRecognizer}
          */
         public void error(int error) throws RemoteException {
-            mCurrentCallback = null;
+            Message.obtain(mHandler, MSG_RESET).sendToTarget();
             mListener.onError(error);
         }
 
@@ -278,7 +288,7 @@
          *        {@link SpeechRecognizer#RESULTS_RECOGNITION} as a parameter
          */
         public void results(Bundle results) throws RemoteException {
-            mCurrentCallback = null;
+            Message.obtain(mHandler, MSG_RESET).sendToTarget();
             mListener.onResults(results);
         }
 
diff --git a/core/java/android/speech/tts/TextToSpeech.java b/core/java/android/speech/tts/TextToSpeech.java
index 6d7b7ce..95830ec 100755
--- a/core/java/android/speech/tts/TextToSpeech.java
+++ b/core/java/android/speech/tts/TextToSpeech.java
@@ -44,6 +44,8 @@
  */
 public class TextToSpeech {
 
+    private static final String TAG = "TextToSpeech";
+
     /**
      * Denotes a successful operation.
      */
@@ -414,8 +416,10 @@
 
         /**
          * {@hide}
+         * Total number of cached speech parameters.
+         * This number should be equal to (max param position/2) + 1.
          */
-        protected static final int NB_CACHED_PARAMS = 20;
+        protected static final int NB_CACHED_PARAMS = 10;
     }
 
     /**
@@ -577,29 +581,16 @@
                 mITts.addSpeech(mPackageName, text, packagename, resourceId);
                 return SUCCESS;
             } catch (RemoteException e) {
-                // TTS died; restart it.
-                Log.e("TextToSpeech.java - addSpeech", "RemoteException");
-                e.printStackTrace();
-                mStarted = false;
-                initTts();
+                restart("addSpeech", e);
             } catch (NullPointerException e) {
-                // TTS died; restart it.
-                Log.e("TextToSpeech.java - addSpeech", "NullPointerException");
-                e.printStackTrace();
-                mStarted = false;
-                initTts();
+                restart("addSpeech", e);
             } catch (IllegalStateException e) {
-                // TTS died; restart it.
-                Log.e("TextToSpeech.java - addSpeech", "IllegalStateException");
-                e.printStackTrace();
-                mStarted = false;
-                initTts();
+                restart("addSpeech", e);
             }
             return ERROR;
         }
     }
 
-
     /**
      * Adds a mapping between a string of text and a sound file. Using this, it
      * is possible to add custom pronounciations for a string of text.
@@ -624,23 +615,11 @@
                 mITts.addSpeechFile(mPackageName, text, filename);
                 return SUCCESS;
             } catch (RemoteException e) {
-                // TTS died; restart it.
-                Log.e("TextToSpeech.java - addSpeech", "RemoteException");
-                e.printStackTrace();
-                mStarted = false;
-                initTts();
+                restart("addSpeech", e);
             } catch (NullPointerException e) {
-                // TTS died; restart it.
-                Log.e("TextToSpeech.java - addSpeech", "NullPointerException");
-                e.printStackTrace();
-                mStarted = false;
-                initTts();
+                restart("addSpeech", e);
             } catch (IllegalStateException e) {
-                // TTS died; restart it.
-                Log.e("TextToSpeech.java - addSpeech", "IllegalStateException");
-                e.printStackTrace();
-                mStarted = false;
-                initTts();
+                restart("addSpeech", e);
             }
             return ERROR;
         }
@@ -681,23 +660,11 @@
                 mITts.addEarcon(mPackageName, earcon, packagename, resourceId);
                 return SUCCESS;
             } catch (RemoteException e) {
-                // TTS died; restart it.
-                Log.e("TextToSpeech.java - addEarcon", "RemoteException");
-                e.printStackTrace();
-                mStarted = false;
-                initTts();
+                restart("addEarcon", e);
             } catch (NullPointerException e) {
-                // TTS died; restart it.
-                Log.e("TextToSpeech.java - addEarcon", "NullPointerException");
-                e.printStackTrace();
-                mStarted = false;
-                initTts();
+                restart("addEarcon", e);
             } catch (IllegalStateException e) {
-                // TTS died; restart it.
-                Log.e("TextToSpeech.java - addEarcon", "IllegalStateException");
-                e.printStackTrace();
-                mStarted = false;
-                initTts();
+                restart("addEarcon", e);
             }
             return ERROR;
         }
@@ -728,23 +695,11 @@
                 mITts.addEarconFile(mPackageName, earcon, filename);
                 return SUCCESS;
             } catch (RemoteException e) {
-                // TTS died; restart it.
-                Log.e("TextToSpeech.java - addEarcon", "RemoteException");
-                e.printStackTrace();
-                mStarted = false;
-                initTts();
+                restart("addEarcon", e);
             } catch (NullPointerException e) {
-                // TTS died; restart it.
-                Log.e("TextToSpeech.java - addEarcon", "NullPointerException");
-                e.printStackTrace();
-                mStarted = false;
-                initTts();
+                restart("addEarcon", e);
             } catch (IllegalStateException e) {
-                // TTS died; restart it.
-                Log.e("TextToSpeech.java - addEarcon", "IllegalStateException");
-                e.printStackTrace();
-                mStarted = false;
-                initTts();
+                restart("addEarcon", e);
             }
             return ERROR;
         }
@@ -788,27 +743,15 @@
                 }
                 result = mITts.speak(mPackageName, text, queueMode, mCachedParams);
             } catch (RemoteException e) {
-                // TTS died; restart it.
-                Log.e("TextToSpeech.java - speak", "RemoteException");
-                e.printStackTrace();
-                mStarted = false;
-                initTts();
+                restart("speak", e);
             } catch (NullPointerException e) {
-                // TTS died; restart it.
-                Log.e("TextToSpeech.java - speak", "NullPointerException");
-                e.printStackTrace();
-                mStarted = false;
-                initTts();
+                restart("speak", e);
             } catch (IllegalStateException e) {
-                // TTS died; restart it.
-                Log.e("TextToSpeech.java - speak", "IllegalStateException");
-                e.printStackTrace();
-                mStarted = false;
-                initTts();
+                restart("speak", e);
             } finally {
                 resetCachedParams();
-                return result;
             }
+            return result;
         }
     }
 
@@ -847,27 +790,15 @@
                 }
                 result = mITts.playEarcon(mPackageName, earcon, queueMode, null);
             } catch (RemoteException e) {
-                // TTS died; restart it.
-                Log.e("TextToSpeech.java - playEarcon", "RemoteException");
-                e.printStackTrace();
-                mStarted = false;
-                initTts();
+                restart("playEarcon", e);
             } catch (NullPointerException e) {
-                // TTS died; restart it.
-                Log.e("TextToSpeech.java - playEarcon", "NullPointerException");
-                e.printStackTrace();
-                mStarted = false;
-                initTts();
+                restart("playEarcon", e);
             } catch (IllegalStateException e) {
-                // TTS died; restart it.
-                Log.e("TextToSpeech.java - playEarcon", "IllegalStateException");
-                e.printStackTrace();
-                mStarted = false;
-                initTts();
+                restart("playEarcon", e);
             } finally {
                 resetCachedParams();
-                return result;
             }
+            return result;
         }
     }
 
@@ -899,27 +830,15 @@
                 }
                 result = mITts.playSilence(mPackageName, durationInMs, queueMode, mCachedParams);
             } catch (RemoteException e) {
-                // TTS died; restart it.
-                Log.e("TextToSpeech.java - playSilence", "RemoteException");
-                e.printStackTrace();
-                mStarted = false;
-                initTts();
+                restart("playSilence", e);
             } catch (NullPointerException e) {
-                // TTS died; restart it.
-                Log.e("TextToSpeech.java - playSilence", "NullPointerException");
-                e.printStackTrace();
-                mStarted = false;
-                initTts();
+                restart("playSilence", e);
             } catch (IllegalStateException e) {
-                // TTS died; restart it.
-                Log.e("TextToSpeech.java - playSilence", "IllegalStateException");
-                e.printStackTrace();
-                mStarted = false;
-                initTts();
+                restart("playSilence", e);
             } finally {
                 resetCachedParams();
-                return result;
             }
+            return result;
         }
     }
 
@@ -937,23 +856,11 @@
             try {
                 return mITts.isSpeaking();
             } catch (RemoteException e) {
-                // TTS died; restart it.
-                Log.e("TextToSpeech.java - isSpeaking", "RemoteException");
-                e.printStackTrace();
-                mStarted = false;
-                initTts();
+                restart("isSpeaking", e);
             } catch (NullPointerException e) {
-                // TTS died; restart it.
-                Log.e("TextToSpeech.java - isSpeaking", "NullPointerException");
-                e.printStackTrace();
-                mStarted = false;
-                initTts();
+                restart("isSpeaking", e);
             } catch (IllegalStateException e) {
-                // TTS died; restart it.
-                Log.e("TextToSpeech.java - isSpeaking", "IllegalStateException");
-                e.printStackTrace();
-                mStarted = false;
-                initTts();
+                restart("isSpeaking", e);
             }
             return false;
         }
@@ -975,26 +882,13 @@
             try {
                 result = mITts.stop(mPackageName);
             } catch (RemoteException e) {
-                // TTS died; restart it.
-                Log.e("TextToSpeech.java - stop", "RemoteException");
-                e.printStackTrace();
-                mStarted = false;
-                initTts();
+                restart("stop", e);
             } catch (NullPointerException e) {
-                // TTS died; restart it.
-                Log.e("TextToSpeech.java - stop", "NullPointerException");
-                e.printStackTrace();
-                mStarted = false;
-                initTts();
+                restart("stop", e);
             } catch (IllegalStateException e) {
-                // TTS died; restart it.
-                Log.e("TextToSpeech.java - stop", "IllegalStateException");
-                e.printStackTrace();
-                mStarted = false;
-                initTts();
-            } finally {
-                return result;
+                restart("stop", e);
             }
+            return result;
         }
     }
 
@@ -1030,20 +924,11 @@
                     }
                 }
             } catch (NullPointerException e) {
-                // TTS died; restart it.
-                Log.e("TextToSpeech.java - setSpeechRate", "NullPointerException");
-                e.printStackTrace();
-                mStarted = false;
-                initTts();
+                restart("setSpeechRate", e);
             } catch (IllegalStateException e) {
-                // TTS died; restart it.
-                Log.e("TextToSpeech.java - setSpeechRate", "IllegalStateException");
-                e.printStackTrace();
-                mStarted = false;
-                initTts();
-            } finally {
-                return result;
+                restart("setSpeechRate", e);
             }
+            return result;
         }
     }
 
@@ -1075,20 +960,11 @@
                     result = SUCCESS;
                 }
             } catch (NullPointerException e) {
-                // TTS died; restart it.
-                Log.e("TextToSpeech.java - setPitch", "NullPointerException");
-                e.printStackTrace();
-                mStarted = false;
-                initTts();
+                restart("setPitch", e);
             } catch (IllegalStateException e) {
-                // TTS died; restart it.
-                Log.e("TextToSpeech.java - setPitch", "IllegalStateException");
-                e.printStackTrace();
-                mStarted = false;
-                initTts();
-            } finally {
-                return result;
+                restart("setPitch", e);
             }
+            return result;
         }
     }
 
@@ -1139,26 +1015,13 @@
                     }
                 }
             } catch (RemoteException e) {
-                // TTS died; restart it.
-                Log.e("TextToSpeech.java - setLanguage", "RemoteException");
-                e.printStackTrace();
-                mStarted = false;
-                initTts();
+                restart("setLanguage", e);
             } catch (NullPointerException e) {
-                // TTS died; restart it.
-                Log.e("TextToSpeech.java - setLanguage", "NullPointerException");
-                e.printStackTrace();
-                mStarted = false;
-                initTts();
+                restart("setLanguage", e);
             } catch (IllegalStateException e) {
-                // TTS died; restart it.
-                Log.e("TextToSpeech.java - setLanguage", "IllegalStateException");
-                e.printStackTrace();
-                mStarted = false;
-                initTts();
-            } finally {
-                return result;
+                restart("setLanguage", e);
             }
+            return result;
         }
     }
 
@@ -1189,23 +1052,11 @@
                             mCachedParams[Engine.PARAM_POSITION_VARIANT + 1]);
                 }
             } catch (RemoteException e) {
-                // TTS died; restart it.
-                Log.e("TextToSpeech.java - getLanguage", "RemoteException");
-                e.printStackTrace();
-                mStarted = false;
-                initTts();
+                restart("getLanguage", e);
             } catch (NullPointerException e) {
-                // TTS died; restart it.
-                Log.e("TextToSpeech.java - getLanguage", "NullPointerException");
-                e.printStackTrace();
-                mStarted = false;
-                initTts();
+                restart("getLanguage", e);
             } catch (IllegalStateException e) {
-                // TTS died; restart it.
-                Log.e("TextToSpeech.java - getLanguage", "IllegalStateException");
-                e.printStackTrace();
-                mStarted = false;
-                initTts();
+                restart("getLanguage", e);
             }
             return null;
         }
@@ -1231,26 +1082,13 @@
                 result = mITts.isLanguageAvailable(loc.getISO3Language(),
                         loc.getISO3Country(), loc.getVariant(), mCachedParams);
             } catch (RemoteException e) {
-                // TTS died; restart it.
-                Log.e("TextToSpeech.java - isLanguageAvailable", "RemoteException");
-                e.printStackTrace();
-                mStarted = false;
-                initTts();
+                restart("isLanguageAvailable", e);
             } catch (NullPointerException e) {
-                // TTS died; restart it.
-                Log.e("TextToSpeech.java - isLanguageAvailable", "NullPointerException");
-                e.printStackTrace();
-                mStarted = false;
-                initTts();
+                restart("isLanguageAvailable", e);
             } catch (IllegalStateException e) {
-                // TTS died; restart it.
-                Log.e("TextToSpeech.java - isLanguageAvailable", "IllegalStateException");
-                e.printStackTrace();
-                mStarted = false;
-                initTts();
-            } finally {
-                return result;
+                restart("isLanguageAvailable", e);
             }
+            return result;
         }
     }
 
@@ -1291,27 +1129,15 @@
                 result = mITts.synthesizeToFile(mPackageName, text, mCachedParams, filename) ?
                         SUCCESS : ERROR;
             } catch (RemoteException e) {
-                // TTS died; restart it.
-                Log.e("TextToSpeech.java - synthesizeToFile", "RemoteException");
-                e.printStackTrace();
-                mStarted = false;
-                initTts();
+                restart("synthesizeToFile", e);
             } catch (NullPointerException e) {
-                // TTS died; restart it.
-                Log.e("TextToSpeech.java - synthesizeToFile", "NullPointerException");
-                e.printStackTrace();
-                mStarted = false;
-                initTts();
+                restart("synthesizeToFile", e);
             } catch (IllegalStateException e) {
-                // TTS died; restart it.
-                Log.e("TextToSpeech.java - synthesizeToFile", "IllegalStateException");
-                e.printStackTrace();
-                mStarted = false;
-                initTts();
+                restart("synthesizeToFile", e);
             } finally {
                 resetCachedParams();
-                return result;
             }
+            return result;
         }
     }
 
@@ -1364,26 +1190,13 @@
             try {
                 result = mITts.registerCallback(mPackageName, mITtscallback);
             } catch (RemoteException e) {
-                // TTS died; restart it.
-                Log.e("TextToSpeech.java - registerCallback", "RemoteException");
-                e.printStackTrace();
-                mStarted = false;
-                initTts();
+                restart("registerCallback", e);
             } catch (NullPointerException e) {
-                // TTS died; restart it.
-                Log.e("TextToSpeech.java - registerCallback", "NullPointerException");
-                e.printStackTrace();
-                mStarted = false;
-                initTts();
+                restart("registerCallback", e);
             } catch (IllegalStateException e) {
-                // TTS died; restart it.
-                Log.e("TextToSpeech.java - registerCallback", "IllegalStateException");
-                e.printStackTrace();
-                mStarted = false;
-                initTts();
-            } finally {
-                return result;
+                restart("registerCallback", e);
             }
+            return result;
         }
     }
 
@@ -1407,26 +1220,13 @@
                     mCachedParams[Engine.PARAM_POSITION_ENGINE + 1] = enginePackageName;
                 }
             } catch (RemoteException e) {
-                // TTS died; restart it.
-                Log.e("TextToSpeech.java - setEngineByPackageName", "RemoteException");
-                e.printStackTrace();
-                mStarted = false;
-                initTts();
+                restart("setEngineByPackageName", e);
             } catch (NullPointerException e) {
-                // TTS died; restart it.
-                Log.e("TextToSpeech.java - setEngineByPackageName", "NullPointerException");
-                e.printStackTrace();
-                mStarted = false;
-                initTts();
+                restart("setEngineByPackageName", e);
             } catch (IllegalStateException e) {
-                // TTS died; restart it.
-                Log.e("TextToSpeech.java - setEngineByPackageName", "IllegalStateException");
-                e.printStackTrace();
-                mStarted = false;
-                initTts();
-            } finally {
-                return result;
+                restart("setEngineByPackageName", e);
             }
+            return result;
         }
     }
 
@@ -1445,26 +1245,13 @@
             try {
                 engineName = mITts.getDefaultEngine();
             } catch (RemoteException e) {
-                // TTS died; restart it.
-                Log.e("TextToSpeech.java - setEngineByPackageName", "RemoteException");
-                e.printStackTrace();
-                mStarted = false;
-                initTts();
+                restart("getDefaultEngine", e);
             } catch (NullPointerException e) {
-                // TTS died; restart it.
-                Log.e("TextToSpeech.java - setEngineByPackageName", "NullPointerException");
-                e.printStackTrace();
-                mStarted = false;
-                initTts();
+                restart("getDefaultEngine", e);
             } catch (IllegalStateException e) {
-                // TTS died; restart it.
-                Log.e("TextToSpeech.java - setEngineByPackageName", "IllegalStateException");
-                e.printStackTrace();
-                mStarted = false;
-                initTts();
-            } finally {
-                return engineName;
+                restart("getDefaultEngine", e);
             }
+            return engineName;
         }
     }
 
@@ -1484,26 +1271,23 @@
             try {
                 defaultsEnforced = mITts.areDefaultsEnforced();
             } catch (RemoteException e) {
-                // TTS died; restart it.
-                Log.e("TextToSpeech.java - areDefaultsEnforced", "RemoteException");
-                e.printStackTrace();
-                mStarted = false;
-                initTts();
+                restart("areDefaultsEnforced", e);
             } catch (NullPointerException e) {
-                // TTS died; restart it.
-                Log.e("TextToSpeech.java - areDefaultsEnforced", "NullPointerException");
-                e.printStackTrace();
-                mStarted = false;
-                initTts();
+                restart("areDefaultsEnforced", e);
             } catch (IllegalStateException e) {
-                // TTS died; restart it.
-                Log.e("TextToSpeech.java - areDefaultsEnforced", "IllegalStateException");
-                e.printStackTrace();
-                mStarted = false;
-                initTts();
-            } finally {
-                return defaultsEnforced;
+                restart("areDefaultsEnforced", e);
             }
+            return defaultsEnforced;
         }
     }
+
+    /**
+     * Restarts the TTS after a failure.
+     */
+    private void restart(String method, Exception e) {
+        // TTS died; restart it.
+        Log.e(TAG, method, e);
+        mStarted = false;
+        initTts();
+    }
 }
diff --git a/core/java/android/text/SpannableStringBuilder.java b/core/java/android/text/SpannableStringBuilder.java
index 53fa7c2..ea5cdfe 100644
--- a/core/java/android/text/SpannableStringBuilder.java
+++ b/core/java/android/text/SpannableStringBuilder.java
@@ -1192,7 +1192,9 @@
      * CURSOR_AT_OR_BEFORE, or CURSOR_AT
      * @param p the Paint object that is requesting this information
      * @return the offset of the next position, or -1
+     * @deprecated This is an internal method, refrain from using it in your code
      */
+    @Deprecated
     public int getTextRunCursor(int contextStart, int contextEnd, int flags, int offset,
             int cursorOpt, Paint p) {
 
diff --git a/core/java/android/text/StaticLayout.java b/core/java/android/text/StaticLayout.java
index a826a97..9e48eff 100644
--- a/core/java/android/text/StaticLayout.java
+++ b/core/java/android/text/StaticLayout.java
@@ -235,6 +235,8 @@
                     } else {
                         MetricAffectingSpan[] spans =
                             spanned.getSpans(spanStart, spanEnd, MetricAffectingSpan.class);
+                        spans = TextUtils.removeEmptySpans(spans, spanned,
+                                MetricAffectingSpan.class);
                         measured.addStyleRun(paint, spans, spanLen, fm);
                     }
                 }
diff --git a/core/java/android/text/TextLine.java b/core/java/android/text/TextLine.java
index 90279d1..1b7f2f3 100644
--- a/core/java/android/text/TextLine.java
+++ b/core/java/android/text/TextLine.java
@@ -127,12 +127,12 @@
         boolean hasReplacement = false;
         if (text instanceof Spanned) {
             mSpanned = (Spanned) text;
-            hasReplacement = mSpanned.getSpans(start, limit,
-                    ReplacementSpan.class).length > 0;
+            ReplacementSpan[] spans = mSpanned.getSpans(start, limit, ReplacementSpan.class);
+            spans = TextUtils.removeEmptySpans(spans, mSpanned, ReplacementSpan.class);
+            hasReplacement = spans.length > 0;
         }
 
-        mCharsValid = hasReplacement || hasTabs ||
-            directions != Layout.DIRS_ALL_LEFT_TO_RIGHT;
+        mCharsValid = hasReplacement || hasTabs || directions != Layout.DIRS_ALL_LEFT_TO_RIGHT;
 
         if (mCharsValid) {
             if (mChars == null || mChars.length < mLen) {
@@ -147,10 +147,11 @@
                 // zero-width characters.
                 char[] chars = mChars;
                 for (int i = start, inext; i < limit; i = inext) {
-                    inext = mSpanned.nextSpanTransition(i, limit,
-                            ReplacementSpan.class);
-                    if (mSpanned.getSpans(i, inext, ReplacementSpan.class)
-                            .length > 0) { // transition into a span
+                    inext = mSpanned.nextSpanTransition(i, limit, ReplacementSpan.class);
+                    ReplacementSpan[] spans = mSpanned.getSpans(i, inext, ReplacementSpan.class);
+                    spans = TextUtils.removeEmptySpans(spans, mSpanned, ReplacementSpan.class);
+                    if (spans.length > 0) {
+                        // transition into a span
                         chars[i - start] = '\ufffc';
                         for (int j = i - start + 1, e = inext - start; j < e; ++j) {
                             chars[j] = '\ufeff'; // used as ZWNBS, marks positions to skip
@@ -197,7 +198,6 @@
             boolean runIsRtl = (runs[i+1] & Layout.RUN_RTL_FLAG) != 0;
 
             int segstart = runStart;
-            char[] chars = mChars;
             for (int j = mHasTabs ? runStart : runLimit; j <= runLimit; j++) {
                 int codept = 0;
                 Bitmap bm = null;
@@ -629,6 +629,7 @@
 
             MetricAffectingSpan[] spans = mSpanned.getSpans(mStart + spanStart,
                     mStart + spanLimit, MetricAffectingSpan.class);
+            spans = TextUtils.removeEmptySpans(spans, mSpanned, MetricAffectingSpan.class);
 
             if (spans.length > 0) {
                 ReplacementSpan replacement = null;
@@ -835,6 +836,7 @@
                 mlimit = inext < measureLimit ? inext : measureLimit;
                 MetricAffectingSpan[] spans = mSpanned.getSpans(mStart + i,
                         mStart + mlimit, MetricAffectingSpan.class);
+                spans = TextUtils.removeEmptySpans(spans, mSpanned, MetricAffectingSpan.class);
 
                 if (spans.length > 0) {
                     ReplacementSpan replacement = null;
@@ -868,6 +870,7 @@
 
                     CharacterStyle[] spans = mSpanned.getSpans(mStart + j,
                             mStart + jnext, CharacterStyle.class);
+                    spans = TextUtils.removeEmptySpans(spans, mSpanned, CharacterStyle.class);
 
                     wp.set(mPaint);
                     for (int k = 0; k < spans.length; k++) {
diff --git a/core/java/android/text/TextUtils.java b/core/java/android/text/TextUtils.java
index d5010c6..ee6342a 100644
--- a/core/java/android/text/TextUtils.java
+++ b/core/java/android/text/TextUtils.java
@@ -44,6 +44,7 @@
 import android.text.style.UnderlineSpan;
 import android.util.Printer;
 
+import java.lang.reflect.Array;
 import java.util.Iterator;
 import java.util.regex.Pattern;
 
@@ -54,7 +55,7 @@
 
     public static void getChars(CharSequence s, int start, int end,
                                 char[] dest, int destoff) {
-        Class c = s.getClass();
+        Class<? extends CharSequence> c = s.getClass();
 
         if (c == String.class)
             ((String) s).getChars(start, end, dest, destoff);
@@ -75,7 +76,7 @@
     }
 
     public static int indexOf(CharSequence s, char ch, int start) {
-        Class c = s.getClass();
+        Class<? extends CharSequence> c = s.getClass();
 
         if (c == String.class)
             return ((String) s).indexOf(ch, start);
@@ -84,7 +85,7 @@
     }
 
     public static int indexOf(CharSequence s, char ch, int start, int end) {
-        Class c = s.getClass();
+        Class<? extends CharSequence> c = s.getClass();
 
         if (s instanceof GetChars || c == StringBuffer.class ||
             c == StringBuilder.class || c == String.class) {
@@ -125,7 +126,7 @@
     }
 
     public static int lastIndexOf(CharSequence s, char ch, int last) {
-        Class c = s.getClass();
+        Class<? extends CharSequence> c = s.getClass();
 
         if (c == String.class)
             return ((String) s).lastIndexOf(ch, last);
@@ -142,7 +143,7 @@
 
         int end = last + 1;
 
-        Class c = s.getClass();
+        Class<? extends CharSequence> c = s.getClass();
 
         if (s instanceof GetChars || c == StringBuffer.class ||
             c == StringBuilder.class || c == String.class) {
@@ -499,6 +500,7 @@
             return new String(buf);
         }
 
+        @Override
         public String toString() {
             return subSequence(0, length()).toString();
         }
@@ -563,6 +565,8 @@
     public static final int TEXT_APPEARANCE_SPAN = 17;
     /** @hide */
     public static final int ANNOTATION = 18;
+    /** @hide */
+    public static final int CORRECTION_SPAN = 19;
 
     /**
      * Flatten a CharSequence and whatever styles can be copied across processes
@@ -621,7 +625,7 @@
          * Read and return a new CharSequence, possibly with styles,
          * from the parcel.
          */
-        public  CharSequence createFromParcel(Parcel p) {
+        public CharSequence createFromParcel(Parcel p) {
             int kind = p.readInt();
 
             if (kind == 1)
@@ -760,7 +764,7 @@
 
             if (where >= 0)
                 tb.setSpan(sources[i], where, where + sources[i].length(),
-                           Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
+                           Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
         }
 
         for (int i = 0; i < sources.length; i++) {
@@ -1114,7 +1118,6 @@
             int remaining = commaCount + 1;
 
             int ok = 0;
-            int okRemaining = remaining;
             String okFormat = "";
 
             int w = 0;
@@ -1146,7 +1149,6 @@
 
                     if (w + moreWid <= avail) {
                         ok = i + 1;
-                        okRemaining = remaining;
                         okFormat = format;
                     }
                 }
@@ -1179,6 +1181,7 @@
                         MetricAffectingSpan.class);
                 MetricAffectingSpan[] spans = sp.getSpans(
                         spanStart, spanEnd, MetricAffectingSpan.class);
+                spans = TextUtils.removeEmptySpans(spans, sp, MetricAffectingSpan.class);
                 width += mt.addStyleRun(paint, spans, spanEnd - spanStart, null);
             }
         }
@@ -1537,6 +1540,56 @@
         return false;
     }
 
+    /**
+     * Removes empty spans from the <code>spans</code> array.
+     *
+     * When parsing a Spanned using {@link Spanned#nextSpanTransition(int, int, Class)}, empty spans
+     * will (correctly) create span transitions, and calling getSpans on a slice of text bounded by
+     * one of these transitions will (correctly) include the empty overlapping span.
+     *
+     * However, these empty spans should not be taken into account when layouting or rendering the
+     * string and this method provides a way to filter getSpans' results accordingly.
+     *
+     * @param spans A list of spans retrieved using {@link Spanned#getSpans(int, int, Class)} from
+     * the <code>spanned</code>
+     * @param spanned The Spanned from which spans were extracted
+     * @return A subset of spans where empty spans ({@link Spanned#getSpanStart(Object)}  ==
+     * {@link Spanned#getSpanEnd(Object)} have been removed. The initial order is preserved
+     * @hide
+     */
+    @SuppressWarnings("unchecked")
+    public static <T> T[] removeEmptySpans(T[] spans, Spanned spanned, Class<T> klass) {
+        T[] copy = null;
+        int count = 0;
+
+        for (int i = 0; i < spans.length; i++) {
+            final T span = spans[i];
+            final int start = spanned.getSpanStart(span);
+            final int end = spanned.getSpanEnd(span);
+
+            if (start == end) {
+                if (copy == null) {
+                    copy = (T[]) Array.newInstance(klass, spans.length - 1);
+                    System.arraycopy(spans, 0, copy, 0, i);
+                    count = i;
+                }
+            } else {
+                if (copy != null) {
+                    copy[count] = span;
+                    count++;
+                }
+            }
+        }
+
+        if (copy != null) {
+            T[] result = (T[]) Array.newInstance(klass, count);
+            System.arraycopy(copy, 0, result, 0, count);
+            return result;
+        } else {
+            return spans;
+        }
+    }
+
     private static Object sLock = new Object();
     private static char[] sTemp = null;
 }
diff --git a/core/java/android/text/style/CorrectionSpan.aidl b/core/java/android/text/style/CorrectionSpan.aidl
new file mode 100644
index 0000000..82e3d04
--- /dev/null
+++ b/core/java/android/text/style/CorrectionSpan.aidl
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.text.style;
+
+parcelable CorrectionSpan;
diff --git a/core/java/android/text/style/CorrectionSpan.java b/core/java/android/text/style/CorrectionSpan.java
new file mode 100644
index 0000000..6142e6f
--- /dev/null
+++ b/core/java/android/text/style/CorrectionSpan.java
@@ -0,0 +1,161 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.text.style;
+
+import android.content.Context;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.text.ParcelableSpan;
+import android.text.TextUtils;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Locale;
+
+public class CorrectionSpan implements ParcelableSpan {
+
+    /**
+     * Flag for the default value.
+     */
+    public static final int FLAG_DEFAULT = 0x0000;
+    /**
+     * Flag for indicating that the input is verbatim. TextView refers to this flag to determine
+     * how it displays a word with CorrectionSpan.
+     */
+    public static final int FLAG_VERBATIM = 0x0001;
+
+    private static final int SUGGESTS_MAX_SIZE = 5;
+
+    /*
+     * TODO: Needs to check the validity and add a feature that TextView will change
+     * the current IME to the other IME which is specified in CorrectionSpan.
+     * An IME needs to set the span by specifying the target IME and Subtype of CorrectionSpan.
+     * And the current IME might want to specify any IME as the target IME including other IMEs.
+     */
+
+    private final int mFlags;
+    private final List<CharSequence> mSuggests = new ArrayList<CharSequence>();
+    private final String mLocaleString;
+    private final String mOriginalString;
+    /*
+     * TODO: If switching IME is required, needs to add parameters for ids of InputMethodInfo
+     * and InputMethodSubtype.
+     */
+
+    /**
+     * @param context Context for the application
+     * @param suggests Suggests for the string under the span
+     * @param flags Additional flags indicating how this span is handled in TextView
+     */
+    public CorrectionSpan(Context context, List<CharSequence> suggests, int flags) {
+        this(context, null, suggests, flags, null);
+    }
+
+    /**
+     * @param locale Locale of the suggestions
+     * @param suggests Suggests for the string under the span
+     * @param flags Additional flags indicating how this span is handled in TextView
+     */
+    public CorrectionSpan(Locale locale, List<CharSequence> suggests, int flags) {
+        this(null, locale, suggests, flags, null);
+    }
+
+    /**
+     * @param context Context for the application
+     * @param locale locale Locale of the suggestions
+     * @param suggests suggests Suggests for the string under the span
+     * @param flags Additional flags indicating how this span is handled in TextView
+     * @param originalString originalString for suggests
+     */
+    public CorrectionSpan(Context context, Locale locale, List<CharSequence> suggests, int flags,
+            String originalString) {
+        final int N = Math.min(SUGGESTS_MAX_SIZE, suggests.size());
+        for (int i = 0; i < N; ++i) {
+            mSuggests.add(suggests.get(i));
+        }
+        mFlags = flags;
+        if (context != null && locale == null) {
+            mLocaleString = context.getResources().getConfiguration().locale.toString();
+        } else {
+            mLocaleString = locale.toString();
+        }
+        mOriginalString = originalString;
+    }
+
+    public CorrectionSpan(Parcel src) {
+        src.readList(mSuggests, null);
+        mFlags = src.readInt();
+        mLocaleString = src.readString();
+        mOriginalString = src.readString();
+    }
+
+    /**
+     * @return suggestions
+     */
+    public List<CharSequence> getSuggests() {
+        return new ArrayList<CharSequence>(mSuggests);
+    }
+
+    /**
+     * @return locale of suggestions
+     */
+    public String getLocale() {
+        return mLocaleString;
+    }
+
+    /**
+     * @return original string of suggestions
+     */
+    public String getOriginalString() {
+        return mOriginalString;
+    }
+
+    public int getFlags() {
+        return mFlags;
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(Parcel dest, int flags) {
+        dest.writeList(mSuggests);
+        dest.writeInt(mFlags);
+        dest.writeString(mLocaleString);
+        dest.writeString(mOriginalString);
+    }
+
+    @Override
+    public int getSpanTypeId() {
+        return TextUtils.CORRECTION_SPAN;
+    }
+
+    public static final Parcelable.Creator<CorrectionSpan> CREATOR =
+            new Parcelable.Creator<CorrectionSpan>() {
+        @Override
+        public CorrectionSpan createFromParcel(Parcel source) {
+            return new CorrectionSpan(source);
+        }
+
+        @Override
+        public CorrectionSpan[] newArray(int size) {
+            return new CorrectionSpan[size];
+        }
+    };
+}
diff --git a/core/java/android/util/JsonReader.java b/core/java/android/util/JsonReader.java
index 8f44895..563c500 100644
--- a/core/java/android/util/JsonReader.java
+++ b/core/java/android/util/JsonReader.java
@@ -86,7 +86,11 @@
  *
  *   public List<Message> readJsonStream(InputStream in) throws IOException {
  *     JsonReader reader = new JsonReader(new InputStreamReader(in, "UTF-8"));
- *     return readMessagesArray(reader);
+ *     try {
+ *       return readMessagesArray(reader);
+ *     } finally {
+ *       reader.close();
+ *     }
  *   }
  *
  *   public List<Message> readMessagesArray(JsonReader reader) throws IOException {
diff --git a/core/java/android/util/LruCache.java b/core/java/android/util/LruCache.java
index a1501e6..5540000 100644
--- a/core/java/android/util/LruCache.java
+++ b/core/java/android/util/LruCache.java
@@ -139,8 +139,7 @@
      * Caches {@code value} for {@code key}. The value is moved to the head of
      * the queue.
      *
-     * @return the previous value mapped by {@code key}. Although that entry is
-     *     no longer cached, it has not been passed to {@link #entryEvicted}.
+     * @return the previous value mapped by {@code key}.
      */
     public final V put(K key, V value) {
         if (key == null || value == null) {
@@ -195,15 +194,14 @@
                 evictionCount++;
             }
 
-            entryEvicted(key, value);
+            entryRemoved(true, key, value, null);
         }
     }
 
     /**
      * Removes the entry for {@code key} if it exists.
      *
-     * @return the previous value mapped by {@code key}. Although that entry is
-     *     no longer cached, it has not been passed to {@link #entryEvicted}.
+     * @return the previous value mapped by {@code key}.
      */
     public final V remove(K key) {
         if (key == null) {
@@ -226,16 +224,6 @@
     }
 
     /**
-     * Calls {@link #entryRemoved}.
-     *
-     * @deprecated replaced by entryRemoved
-     */
-    @Deprecated
-    protected void entryEvicted(K key, V value) {
-        entryRemoved(true, key, value, null);
-    }
-
-    /**
      * Called for entries that have been evicted or removed. This method is
      * invoked when a value is evicted to make space, removed by a call to
      * {@link #remove}, or replaced by a call to {@link #put}. The default
@@ -291,7 +279,7 @@
     }
 
     /**
-     * Clear the cache, calling {@link #entryEvicted} on each removed entry.
+     * Clear the cache, calling {@link #entryRemoved} on each removed entry.
      */
     public final void evictAll() {
         trimToSize(-1); // -1 will evict 0-sized elements
@@ -316,7 +304,8 @@
     }
 
     /**
-     * Returns the number of times {@link #get} returned a value.
+     * Returns the number of times {@link #get} returned a value that was
+     * already present in the cache.
      */
     public synchronized final int hitCount() {
         return hitCount;
diff --git a/core/java/android/view/GLES20Canvas.java b/core/java/android/view/GLES20Canvas.java
index 9a6a274..8621de3 100644
--- a/core/java/android/view/GLES20Canvas.java
+++ b/core/java/android/view/GLES20Canvas.java
@@ -39,6 +39,12 @@
  * An implementation of Canvas on top of OpenGL ES 2.0.
  */
 class GLES20Canvas extends HardwareCanvas {
+    // Must match modifiers used in the JNI layer
+    private static final int MODIFIER_NONE = 0;
+    private static final int MODIFIER_SHADOW = 1;
+    private static final int MODIFIER_SHADER = 2;
+    private static final int MODIFIER_COLOR_FILTER = 4;
+
     private final boolean mOpaque;
     private int mRenderer;
 
@@ -245,11 +251,13 @@
     private static native void nDestroyDisplayList(int displayList);
 
     @Override
-    public boolean drawDisplayList(DisplayList displayList) {
-        return nDrawDisplayList(mRenderer, ((GLES20DisplayList) displayList).mNativeDisplayList);
+    public boolean drawDisplayList(DisplayList displayList, int width, int height, Rect dirty) {
+        return nDrawDisplayList(mRenderer,
+                ((GLES20DisplayList) displayList).mNativeDisplayList, width, height, dirty);
     }
 
-    private static native boolean nDrawDisplayList(int renderer, int displayList);
+    private static native boolean nDrawDisplayList(int renderer, int displayList,
+            int width, int height, Rect dirty);
 
     ///////////////////////////////////////////////////////////////////////////
     // Hardware layer
@@ -257,10 +265,10 @@
     
     void drawHardwareLayer(HardwareLayer layer, float x, float y, Paint paint) {
         final GLES20Layer glLayer = (GLES20Layer) layer;
-        boolean hasColorFilter = paint != null && setupColorFilter(paint);
+        int modifier = paint != null ? setupColorFilter(paint) : MODIFIER_NONE;
         final int nativePaint = paint == null ? 0 : paint.mNativePaint;
         nDrawLayer(mRenderer, glLayer.getLayer(), x, y, nativePaint);
-        if (hasColorFilter) nResetModifiers(mRenderer);
+        if (modifier != MODIFIER_NONE) nResetModifiers(mRenderer, modifier);
     }
 
     private static native void nDrawLayer(int renderer, int layer, float x, float y, int paint);
@@ -453,10 +461,10 @@
     public int saveLayer(float left, float top, float right, float bottom, Paint paint,
             int saveFlags) {
         if (left < right && top < bottom) {
-            boolean hasColorFilter = paint != null && setupColorFilter(paint);
+            int modifier = paint != null ? setupColorFilter(paint) : MODIFIER_NONE;
             final int nativePaint = paint == null ? 0 : paint.mNativePaint;
             int count = nSaveLayer(mRenderer, left, top, right, bottom, nativePaint, saveFlags);
-            if (hasColorFilter) nResetModifiers(mRenderer);
+            if (modifier != MODIFIER_NONE) nResetModifiers(mRenderer, modifier);
             return count;
         }
         return save(saveFlags);
@@ -525,10 +533,10 @@
     @Override
     public void drawArc(RectF oval, float startAngle, float sweepAngle, boolean useCenter,
             Paint paint) {
-        boolean hasModifier = setupModifiers(paint);
+        int modifiers = setupModifiers(paint);
         nDrawArc(mRenderer, oval.left, oval.top, oval.right, oval.bottom, startAngle, sweepAngle,
                 useCenter, paint.mNativePaint);
-        if (hasModifier) nResetModifiers(mRenderer);
+        if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers);
     }
 
     private static native void nDrawArc(int renderer, float left, float top,
@@ -543,11 +551,11 @@
     @Override
     public void drawPatch(Bitmap bitmap, byte[] chunks, RectF dst, Paint paint) {
         // Shaders are ignored when drawing patches
-        boolean hasColorFilter = paint != null && setupColorFilter(paint);
+        int modifier = paint != null ? setupColorFilter(paint) : MODIFIER_NONE;
         final int nativePaint = paint == null ? 0 : paint.mNativePaint;
         nDrawPatch(mRenderer, bitmap.mNativeBitmap, bitmap.mBuffer, chunks,
                 dst.left, dst.top, dst.right, dst.bottom, nativePaint);
-        if (hasColorFilter) nResetModifiers(mRenderer);
+        if (modifier != MODIFIER_NONE) nResetModifiers(mRenderer, modifier);
     }
 
     private static native void nDrawPatch(int renderer, int bitmap, byte[] buffer, byte[] chunks,
@@ -556,10 +564,10 @@
     @Override
     public void drawBitmap(Bitmap bitmap, float left, float top, Paint paint) {
         // Shaders are ignored when drawing bitmaps
-        boolean hasColorFilter = paint != null && setupColorFilter(paint);
+        int modifiers = paint != null ? setupModifiers(bitmap, paint) : MODIFIER_NONE;
         final int nativePaint = paint == null ? 0 : paint.mNativePaint;
         nDrawBitmap(mRenderer, bitmap.mNativeBitmap, bitmap.mBuffer, left, top, nativePaint);
-        if (hasColorFilter) nResetModifiers(mRenderer);
+        if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers);
     }
 
     private static native void nDrawBitmap(
@@ -568,11 +576,11 @@
     @Override
     public void drawBitmap(Bitmap bitmap, Matrix matrix, Paint paint) {
         // Shaders are ignored when drawing bitmaps
-        boolean hasColorFilter = paint != null && setupColorFilter(paint);
+        int modifiers = paint != null ? setupModifiers(bitmap, paint) : MODIFIER_NONE;
         final int nativePaint = paint == null ? 0 : paint.mNativePaint;
         nDrawBitmap(mRenderer, bitmap.mNativeBitmap, bitmap.mBuffer,
                 matrix.native_instance, nativePaint);
-        if (hasColorFilter) nResetModifiers(mRenderer);
+        if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers);
     }
 
     private static native void nDrawBitmap(int renderer, int bitmap, byte[] buff,
@@ -581,7 +589,7 @@
     @Override
     public void drawBitmap(Bitmap bitmap, Rect src, Rect dst, Paint paint) {
         // Shaders are ignored when drawing bitmaps
-        boolean hasColorFilter = paint != null && setupColorFilter(paint);
+        int modifiers = paint != null ? setupModifiers(bitmap, paint) : MODIFIER_NONE;
         final int nativePaint = paint == null ? 0 : paint.mNativePaint;
 
         int left, top, right, bottom;
@@ -598,17 +606,17 @@
 
         nDrawBitmap(mRenderer, bitmap.mNativeBitmap, bitmap.mBuffer, left, top, right, bottom,
                 dst.left, dst.top, dst.right, dst.bottom, nativePaint);
-        if (hasColorFilter) nResetModifiers(mRenderer);
+        if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers);
     }
 
     @Override
     public void drawBitmap(Bitmap bitmap, Rect src, RectF dst, Paint paint) {
         // Shaders are ignored when drawing bitmaps
-        boolean hasColorFilter = paint != null && setupColorFilter(paint);
+        int modifiers = paint != null ? setupModifiers(bitmap, paint) : MODIFIER_NONE;
         final int nativePaint = paint == null ? 0 : paint.mNativePaint;
         nDrawBitmap(mRenderer, bitmap.mNativeBitmap, bitmap.mBuffer, src.left, src.top, src.right,
                 src.bottom, dst.left, dst.top, dst.right, dst.bottom, nativePaint);
-        if (hasColorFilter) nResetModifiers(mRenderer);
+        if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers);
     }
 
     private static native void nDrawBitmap(int renderer, int bitmap, byte[] buffer,
@@ -619,13 +627,13 @@
     public void drawBitmap(int[] colors, int offset, int stride, float x, float y,
             int width, int height, boolean hasAlpha, Paint paint) {
         // Shaders are ignored when drawing bitmaps
-        boolean hasColorFilter = paint != null && setupColorFilter(paint);
+        int modifier = paint != null ? setupColorFilter(paint) : MODIFIER_NONE;
         final Bitmap.Config config = hasAlpha ? Bitmap.Config.ARGB_8888 : Bitmap.Config.RGB_565;
         final Bitmap b = Bitmap.createBitmap(colors, offset, stride, width, height, config);
         final int nativePaint = paint == null ? 0 : paint.mNativePaint;
         nDrawBitmap(mRenderer, b.mNativeBitmap, b.mBuffer, x, y, nativePaint);
         b.recycle();
-        if (hasColorFilter) nResetModifiers(mRenderer);
+        if (modifier != MODIFIER_NONE) nResetModifiers(mRenderer, modifier);
     }
 
     @Override
@@ -653,11 +661,11 @@
         colors = null;
         colorOffset = 0;
 
-        boolean hasColorFilter = paint != null && setupColorFilter(paint);
+        int modifiers = paint != null ? setupModifiers(bitmap, paint) : MODIFIER_NONE;
         final int nativePaint = paint == null ? 0 : paint.mNativePaint;        
         nDrawBitmapMesh(mRenderer, bitmap.mNativeBitmap, bitmap.mBuffer, meshWidth, meshHeight,
                 verts, vertOffset, colors, colorOffset, nativePaint);
-        if (hasColorFilter) nResetModifiers(mRenderer);
+        if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers);
     }
 
     private static native void nDrawBitmapMesh(int renderer, int bitmap, byte[] buffer,
@@ -666,9 +674,9 @@
 
     @Override
     public void drawCircle(float cx, float cy, float radius, Paint paint) {
-        boolean hasModifier = setupModifiers(paint);
+        int modifiers = setupModifiers(paint);
         nDrawCircle(mRenderer, cx, cy, radius, paint.mNativePaint);
-        if (hasModifier) nResetModifiers(mRenderer);        
+        if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers);        
     }
 
     private static native void nDrawCircle(int renderer, float cx, float cy,
@@ -700,9 +708,9 @@
         if ((offset | count) < 0 || offset + count > pts.length) {
             throw new IllegalArgumentException("The lines array must contain 4 elements per line.");
         }
-        boolean hasModifier = setupModifiers(paint);
+        int modifiers = setupModifiers(paint);
         nDrawLines(mRenderer, pts, offset, count, paint.mNativePaint);
-        if (hasModifier) nResetModifiers(mRenderer);
+        if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers);
     }
 
     private static native void nDrawLines(int renderer, float[] points,
@@ -715,9 +723,9 @@
 
     @Override
     public void drawOval(RectF oval, Paint paint) {
-        boolean hasModifier = setupModifiers(paint);
+        int modifiers = setupModifiers(paint);
         nDrawOval(mRenderer, oval.left, oval.top, oval.right, oval.bottom, paint.mNativePaint);
-        if (hasModifier) nResetModifiers(mRenderer); 
+        if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers); 
     }
 
     private static native void nDrawOval(int renderer, float left, float top,
@@ -732,7 +740,7 @@
 
     @Override
     public void drawPath(Path path, Paint paint) {
-        boolean hasModifier = setupModifiers(paint);
+        int modifiers = setupModifiers(paint);
         if (path.isSimplePath) {
             if (path.rects != null) {
                 nDrawRects(mRenderer, path.rects.mNativeRegion, paint.mNativePaint);
@@ -740,7 +748,7 @@
         } else {
             nDrawPath(mRenderer, path.mNativePath, paint.mNativePaint);
         }
-        if (hasModifier) nResetModifiers(mRenderer);
+        if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers);
     }
 
     private static native void nDrawPath(int renderer, int path, int paint);
@@ -765,20 +773,25 @@
     public void drawPoint(float x, float y, Paint paint) {
         mPoint[0] = x;
         mPoint[1] = y;
-        drawPoints(mPoint, 0, 1, paint);
-    }
-
-    @Override
-    public void drawPoints(float[] pts, int offset, int count, Paint paint) {
-        // TODO: Implement
+        drawPoints(mPoint, 0, 2, paint);
     }
 
     @Override
     public void drawPoints(float[] pts, Paint paint) {
-        drawPoints(pts, 0, pts.length / 2, paint);
+        drawPoints(pts, 0, pts.length, paint);
     }
 
     @Override
+    public void drawPoints(float[] pts, int offset, int count, Paint paint) {
+        int modifiers = setupModifiers(paint);
+        nDrawPoints(mRenderer, pts, offset, count, paint.mNativePaint);
+        if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers);
+    }
+
+    private static native void nDrawPoints(int renderer, float[] points,
+            int offset, int count, int paint);
+
+    @Override
     public void drawPosText(char[] text, int index, int count, float[] pos, Paint paint) {
         // TODO: Implement
     }
@@ -790,9 +803,9 @@
 
     @Override
     public void drawRect(float left, float top, float right, float bottom, Paint paint) {
-        boolean hasModifier = setupModifiers(paint);
+        int modifiers = setupModifiers(paint);
         nDrawRect(mRenderer, left, top, right, bottom, paint.mNativePaint);
-        if (hasModifier) nResetModifiers(mRenderer);
+        if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers);
     }
 
     private static native void nDrawRect(int renderer, float left, float top,
@@ -815,10 +828,10 @@
 
     @Override
     public void drawRoundRect(RectF rect, float rx, float ry, Paint paint) {
-        boolean hasModifier = setupModifiers(paint);
+        int modifiers = setupModifiers(paint);
         nDrawRoundRect(mRenderer, rect.left, rect.top, rect.right, rect.bottom,
                 rx, ry, paint.mNativePaint);
-        if (hasModifier) nResetModifiers(mRenderer);        
+        if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers);        
     }
 
     private static native void nDrawRoundRect(int renderer, float left, float top,
@@ -830,11 +843,11 @@
             throw new IndexOutOfBoundsException();
         }
 
-        boolean hasModifier = setupModifiers(paint);
+        int modifiers = setupModifiers(paint);
         try {
             nDrawText(mRenderer, text, index, count, x, y, paint.mBidiFlags, paint.mNativePaint);
         } finally {
-            if (hasModifier) nResetModifiers(mRenderer);
+            if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers);
         }
     }
     
@@ -843,7 +856,7 @@
 
     @Override
     public void drawText(CharSequence text, int start, int end, float x, float y, Paint paint) {
-        boolean hasModifier = setupModifiers(paint);
+        int modifiers = setupModifiers(paint);
         try {
             if (text instanceof String || text instanceof SpannedString ||
                     text instanceof SpannableString) {
@@ -860,7 +873,7 @@
                 TemporaryBuffer.recycle(buf);
             }
         } finally {
-            if (hasModifier) nResetModifiers(mRenderer);
+            if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers);
         }
     }
 
@@ -870,11 +883,11 @@
             throw new IndexOutOfBoundsException();
         }
 
-        boolean hasModifier = setupModifiers(paint);
+        int modifiers = setupModifiers(paint);
         try {
             nDrawText(mRenderer, text, start, end, x, y, paint.mBidiFlags, paint.mNativePaint);
         } finally {
-            if (hasModifier) nResetModifiers(mRenderer);
+            if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers);
         }
     }
 
@@ -883,12 +896,12 @@
 
     @Override
     public void drawText(String text, float x, float y, Paint paint) {
-        boolean hasModifier = setupModifiers(paint);
+        int modifiers = setupModifiers(paint);
         try {
             nDrawText(mRenderer, text, 0, text.length(), x, y, paint.mBidiFlags,
                     paint.mNativePaint);
         } finally {
-            if (hasModifier) nResetModifiers(mRenderer);
+            if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers);
         }
     }
 
@@ -913,12 +926,12 @@
             throw new IllegalArgumentException("Unknown direction: " + dir);
         }
 
-        boolean hasModifier = setupModifiers(paint);
+        int modifiers = setupModifiers(paint);
         try {
             nDrawTextRun(mRenderer, text, index, count, contextIndex, contextCount, x, y, dir,
                     paint.mNativePaint);
         } finally {
-            if (hasModifier) nResetModifiers(mRenderer);
+            if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers);
         }
     }
 
@@ -932,7 +945,7 @@
             throw new IndexOutOfBoundsException();
         }
 
-        boolean hasModifier = setupModifiers(paint);
+        int modifiers = setupModifiers(paint);
         try {
             int flags = dir == 0 ? 0 : 1;
             if (text instanceof String || text instanceof SpannedString ||
@@ -952,7 +965,7 @@
                 TemporaryBuffer.recycle(buf);
             }
         } finally {
-            if (hasModifier) nResetModifiers(mRenderer);
+            if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers);
         }
     }
 
@@ -966,43 +979,50 @@
         // TODO: Implement
     }
 
-    private boolean setupModifiers(Paint paint) {
-        boolean hasModifier = false;
+    private int setupModifiers(Bitmap b, Paint paint) {
+        if (b.getConfig() == Bitmap.Config.ALPHA_8) {
+            return setupModifiers(paint);
+        }
+        return MODIFIER_NONE;
+    }
+
+    private int setupModifiers(Paint paint) {
+        int modifiers = MODIFIER_NONE;
 
         if (paint.hasShadow) {
             nSetupShadow(mRenderer, paint.shadowRadius, paint.shadowDx, paint.shadowDy,
                     paint.shadowColor);
-            hasModifier = true;
+            modifiers |= MODIFIER_SHADOW;
         }
 
         final Shader shader = paint.getShader();
         if (shader != null) {
             nSetupShader(mRenderer, shader.native_shader);
-            hasModifier = true;
+            modifiers |= MODIFIER_SHADER;
         }
 
         final ColorFilter filter = paint.getColorFilter();
         if (filter != null) {
             nSetupColorFilter(mRenderer, filter.nativeColorFilter);
-            hasModifier = true;
+            modifiers |= MODIFIER_COLOR_FILTER;
         }
 
-        return hasModifier;
+        return modifiers;
     }
 
-    private boolean setupColorFilter(Paint paint) {
+    private int setupColorFilter(Paint paint) {
         final ColorFilter filter = paint.getColorFilter();
         if (filter != null) {
             nSetupColorFilter(mRenderer, filter.nativeColorFilter);
-            return true;
+            return MODIFIER_COLOR_FILTER;
         }
-        return false;        
+        return MODIFIER_NONE;        
     }
-    
+
     private static native void nSetupShader(int renderer, int shader);
     private static native void nSetupColorFilter(int renderer, int colorFilter);
     private static native void nSetupShadow(int renderer, float radius,
             float dx, float dy, int color);
 
-    private static native void nResetModifiers(int renderer);
+    private static native void nResetModifiers(int renderer, int modifiers);
 }
diff --git a/core/java/android/view/GLES20DisplayList.java b/core/java/android/view/GLES20DisplayList.java
index 262eb81..aeff31f 100644
--- a/core/java/android/view/GLES20DisplayList.java
+++ b/core/java/android/view/GLES20DisplayList.java
@@ -40,13 +40,6 @@
         hostView = new WeakReference<View>(view);
     }
 
-    public void invalidateView() {
-        View v = hostView.get();
-        if (v != null) {
-            v.invalidate();
-        }
-    }
-
     @Override
     HardwareCanvas start() {
         if (mStarted) {
diff --git a/core/java/android/view/HardwareCanvas.java b/core/java/android/view/HardwareCanvas.java
index e6fecc8..caa7b74 100644
--- a/core/java/android/view/HardwareCanvas.java
+++ b/core/java/android/view/HardwareCanvas.java
@@ -53,8 +53,15 @@
      * Draws the specified display list onto this canvas.
      * 
      * @param displayList The display list to replay.
+     * @param width The width of the display list.
+     * @param height The height of the display list.
+     * @param dirty The dirty region to redraw in the next pass, matters only
+     *        if this method returns true, can be null.
+     * 
+     * @return True if the content of the display list requires another
+     *         drawing pass (invalidate()), false otherwise
      */
-    abstract boolean drawDisplayList(DisplayList displayList);
+    abstract boolean drawDisplayList(DisplayList displayList, int width, int height, Rect dirty);
 
     /**
      * Draws the specified layer onto this canvas.
diff --git a/core/java/android/view/HardwareRenderer.java b/core/java/android/view/HardwareRenderer.java
index b53aa21..8584bf2 100644
--- a/core/java/android/view/HardwareRenderer.java
+++ b/core/java/android/view/HardwareRenderer.java
@@ -269,7 +269,7 @@
         static EGLDisplay sEglDisplay;
         static EGLConfig sEglConfig;
 
-        private static Thread sEglThread;        
+        private static Thread sEglThread;
 
         EGLSurface mEglSurface;
         
@@ -284,6 +284,8 @@
         final boolean mTranslucent;
 
         private boolean mDestroyed;
+        
+        private final Rect mRedrawClip = new Rect();
 
         GlRenderer(int glVersion, boolean translucent) {
             mGlVersion = glVersion;
@@ -606,8 +608,14 @@
 
                         DisplayList displayList = view.getDisplayList();
                         if (displayList != null) {
-                            if (canvas.drawDisplayList(displayList)) {
-                                view.invalidate();
+                            if (canvas.drawDisplayList(displayList, view.getWidth(),
+                                    view.getHeight(), mRedrawClip)) {
+                                if (mRedrawClip.isEmpty() || view.getParent() == null) {
+                                    view.invalidate();
+                                } else {
+                                    view.getParent().invalidateChild(view, mRedrawClip);
+                                }
+                                mRedrawClip.setEmpty();
                             }
                         } else {
                             // Shouldn't reach here
@@ -646,8 +654,8 @@
         private int checkCurrent() {
             // TODO: Don't check the current context when we have one per UI thread
             // TODO: Use a threadlocal flag to know whether the surface has changed
-            if (sEgl.eglGetCurrentContext() != sEglContext ||
-                    sEgl.eglGetCurrentSurface(EGL10.EGL_DRAW) != mEglSurface) {
+            if (!sEglContext.equals(sEgl.eglGetCurrentContext()) ||
+                    !mEglSurface.equals(sEgl.eglGetCurrentSurface(EGL10.EGL_DRAW))) {
                 if (!sEgl.eglMakeCurrent(sEglDisplay, mEglSurface, mEglSurface, sEglContext)) {
                     fallback(true);
                     Log.e(LOG_TAG, "eglMakeCurrent failed " +
diff --git a/core/java/android/view/InputDevice.java b/core/java/android/view/InputDevice.java
index def1161..98d4eb9 100755
--- a/core/java/android/view/InputDevice.java
+++ b/core/java/android/view/InputDevice.java
@@ -20,7 +20,9 @@
 import android.os.Parcelable;
 import android.os.RemoteException;
 import android.os.ServiceManager;
-import android.util.SparseArray;
+
+import java.util.ArrayList;
+import java.util.List;
 
 /**
  * Describes the capabilities of a particular input device.
@@ -43,8 +45,7 @@
     private int mSources;
     private int mKeyboardType;
 
-    private final SparseArray<MotionRange> mMotionRanges = new SparseArray<MotionRange>();
-    private int[] mMotionAxes;
+    private final ArrayList<MotionRange> mMotionRanges = new ArrayList<MotionRange>();
 
     /**
      * A mask for input source classes.
@@ -354,6 +355,11 @@
 
     /**
      * Gets information about the range of values for a particular {@link MotionEvent} axis.
+     * If the device supports multiple sources, the same axis may have different meanings
+     * for each source.  Returns information about the first axis found for any source.
+     * To obtain information about the axis for a specific source, use
+     * {@link #getMotionRange(int, int)}.
+     *
      * @param axis The axis constant.
      * @return The range of values, or null if the requested axis is not
      * supported by the device.
@@ -363,30 +369,55 @@
      * @see #getSupportedAxes()
      */
     public MotionRange getMotionRange(int axis) {
-        return mMotionRanges.get(axis);
+        final int numRanges = mMotionRanges.size();
+        for (int i = 0; i < numRanges; i++) {
+            final MotionRange range = mMotionRanges.get(i);
+            if (range.mAxis == axis) {
+                return range;
+            }
+        }
+        return null;
     }
 
     /**
-     * Gets the axis ids of all motion axes supported by this device.
-     * @return The axis ids of all motion axes supported by this device.
+     * Gets information about the range of values for a particular {@link MotionEvent} axis
+     * used by a particular source on the device.
+     * If the device supports multiple sources, the same axis may have different meanings
+     * for each source.
      *
-     * @see #getMotionRange(int)
+     * @param axis The axis constant.
+     * @param source The source for which to return information.
+     * @return The range of values, or null if the requested axis is not
+     * supported by the device.
+     *
+     * @see MotionEvent#AXIS_X
+     * @see MotionEvent#AXIS_Y
+     * @see #getSupportedAxes()
      */
-    public int[] getMotionAxes() {
-        synchronized (this) {
-            if (mMotionAxes == null) {
-                final int count = mMotionRanges.size();
-                mMotionAxes = new int[count];
-                for (int i = 0; i < count; i++) {
-                    mMotionAxes[i] = mMotionRanges.keyAt(i);
-                }
+    public MotionRange getMotionRange(int axis, int source) {
+        final int numRanges = mMotionRanges.size();
+        for (int i = 0; i < numRanges; i++) {
+            final MotionRange range = mMotionRanges.get(i);
+            if (range.mAxis == axis && range.mSource == source) {
+                return range;
             }
-            return mMotionAxes;
         }
+        return null;
     }
 
-    private void addMotionRange(int axis, float min, float max, float flat, float fuzz) {
-        mMotionRanges.append(axis, new MotionRange(min, max, flat, fuzz));
+    /**
+     * Gets the ranges for all axes supported by the device.
+     * @return The motion ranges for the device.
+     *
+     * @see #getMotionRange(int, int)
+     */
+    public List<MotionRange> getMotionRanges() {
+        return mMotionRanges;
+    }
+
+    private void addMotionRange(int axis, int source,
+            float min, float max, float flat, float fuzz) {
+        mMotionRanges.add(new MotionRange(axis, source, min, max, flat, fuzz));
     }
 
     /**
@@ -395,12 +426,16 @@
      * @see InputDevice#getMotionRange(int)
      */
     public static final class MotionRange {
+        private int mAxis;
+        private int mSource;
         private float mMin;
         private float mMax;
         private float mFlat;
         private float mFuzz;
 
-        private MotionRange(float min, float max, float flat, float fuzz) {
+        private MotionRange(int axis, int source, float min, float max, float flat, float fuzz) {
+            mAxis = axis;
+            mSource = source;
             mMin = min;
             mMax = max;
             mFlat = flat;
@@ -408,6 +443,22 @@
         }
 
         /**
+         * Gets the axis id.
+         * @return The axis id.
+         */
+        public int getAxis() {
+            return mAxis;
+        }
+
+        /**
+         * Gets the source for which the axis is defined.
+         * @return The source.
+         */
+        public int getSource() {
+            return mSource;
+        }
+
+        /**
          * Gets the inclusive minimum value for the axis.
          * @return The inclusive minimum value.
          */
@@ -480,7 +531,8 @@
             if (axis < 0) {
                 break;
             }
-            addMotionRange(axis, in.readFloat(), in.readFloat(), in.readFloat(), in.readFloat());
+            addMotionRange(axis, in.readInt(),
+                    in.readFloat(), in.readFloat(), in.readFloat(), in.readFloat());
         }
     }
 
@@ -491,11 +543,11 @@
         out.writeInt(mSources);
         out.writeInt(mKeyboardType);
 
-        final int numAxes = mMotionRanges.size();
-        for (int i = 0; i < numAxes; i++) {
-            int axis = mMotionRanges.keyAt(i);
-            MotionRange range = mMotionRanges.valueAt(i);
-            out.writeInt(axis);
+        final int numRanges = mMotionRanges.size();
+        for (int i = 0; i < numRanges; i++) {
+            MotionRange range = mMotionRanges.get(i);
+            out.writeInt(range.mAxis);
+            out.writeInt(range.mSource);
             out.writeFloat(range.mMin);
             out.writeFloat(range.mMax);
             out.writeFloat(range.mFlat);
@@ -528,7 +580,7 @@
         }
         description.append("\n");
 
-        description.append("  Sources: ").append(Integer.toHexString(mSources)).append(" (");
+        description.append("  Sources: 0x").append(Integer.toHexString(mSources)).append(" (");
         appendSourceDescriptionIfApplicable(description, SOURCE_KEYBOARD, "keyboard");
         appendSourceDescriptionIfApplicable(description, SOURCE_DPAD, "dpad");
         appendSourceDescriptionIfApplicable(description, SOURCE_TOUCHSCREEN, "touchscreen");
@@ -541,10 +593,10 @@
 
         final int numAxes = mMotionRanges.size();
         for (int i = 0; i < numAxes; i++) {
-            int axis = mMotionRanges.keyAt(i);
-            MotionRange range = mMotionRanges.valueAt(i);
-            description.append("    ").append(MotionEvent.axisToString(axis));
-            description.append(": min=").append(range.mMin);
+            MotionRange range = mMotionRanges.get(i);
+            description.append("    ").append(MotionEvent.axisToString(range.mAxis));
+            description.append(": source=0x").append(Integer.toHexString(range.mSource));
+            description.append(" min=").append(range.mMin);
             description.append(" max=").append(range.mMax);
             description.append(" flat=").append(range.mFlat);
             description.append(" fuzz=").append(range.mFuzz);
diff --git a/core/java/android/view/KeyEvent.java b/core/java/android/view/KeyEvent.java
index 81d5a6e..8070c6a 100755
--- a/core/java/android/view/KeyEvent.java
+++ b/core/java/android/view/KeyEvent.java
@@ -566,6 +566,19 @@
     public static final int KEYCODE_BUTTON_15       = 202;
     /** Key code constant: Generic Game Pad Button #16.*/
     public static final int KEYCODE_BUTTON_16       = 203;
+    /** Key code constant: Language Switch key.
+     * Toggles the current input language such as switching between English and Japanese on
+     * a QWERTY keyboard.  On some devices, the same function may be performed by
+     * pressing Shift+Spacebar. */
+    public static final int KEYCODE_LANGUAGE_SWITCH = 204;
+    /** Key code constant: Manner Mode key.
+     * Toggles silent or vibrate mode on and off to make the device behave more politely
+     * in certain settings such as on a crowded train.  On some devices, the key may only
+     * operate when long-pressed. */
+    public static final int KEYCODE_MANNER_MODE     = 205;
+    /** Key code constant: 3D Mode key.
+     * Toggles the display between 2D and 3D mode. */
+    public static final int KEYCODE_3D_MODE         = 206;
 
     private static final int LAST_KEYCODE           = KEYCODE_BUTTON_16;
 
@@ -791,6 +804,9 @@
         names.append(KEYCODE_BUTTON_14, "KEYCODE_BUTTON_14");
         names.append(KEYCODE_BUTTON_15, "KEYCODE_BUTTON_15");
         names.append(KEYCODE_BUTTON_16, "KEYCODE_BUTTON_16");
+        names.append(KEYCODE_LANGUAGE_SWITCH, "KEYCODE_LANGUAGE_SWITCH");
+        names.append(KEYCODE_MANNER_MODE, "KEYCODE_MANNER_MODE");
+        names.append(KEYCODE_3D_MODE, "KEYCODE_3D_MODE");
     };
 
     // Symbolic names of all metakeys in bit order from least significant to most significant.
diff --git a/core/java/android/view/MotionEvent.java b/core/java/android/view/MotionEvent.java
index f70f1fb..a17db5d 100644
--- a/core/java/android/view/MotionEvent.java
+++ b/core/java/android/view/MotionEvent.java
@@ -675,6 +675,87 @@
     public static final int AXIS_RTRIGGER = 18;
 
     /**
+     * Constant used to identify the Throttle axis of a motion event.
+     * <p>
+     * <ul>
+     * <li>For a joystick, reports the absolute position of the throttle control.
+     * The value is normalized to a range from 0.0 (fully open) to 1.0 (fully closed).
+     * </ul>
+     * </p>
+     *
+     * @see #getAxisValue(int, int)
+     * @see #getHistoricalAxisValue(int, int, int)
+     * @see MotionEvent.PointerCoords#getAxisValue(int)
+     * @see InputDevice#getMotionRange
+     */
+    public static final int AXIS_THROTTLE = 19;
+
+    /**
+     * Constant used to identify the Rudder axis of a motion event.
+     * <p>
+     * <ul>
+     * <li>For a joystick, reports the absolute position of the rudder control.
+     * The value is normalized to a range from -1.0 (turn left) to 1.0 (turn right).
+     * </ul>
+     * </p>
+     *
+     * @see #getAxisValue(int, int)
+     * @see #getHistoricalAxisValue(int, int, int)
+     * @see MotionEvent.PointerCoords#getAxisValue(int)
+     * @see InputDevice#getMotionRange
+     */
+    public static final int AXIS_RUDDER = 20;
+
+    /**
+     * Constant used to identify the Wheel axis of a motion event.
+     * <p>
+     * <ul>
+     * <li>For a joystick, reports the absolute position of the steering wheel control.
+     * The value is normalized to a range from -1.0 (turn left) to 1.0 (turn right).
+     * </ul>
+     * </p>
+     *
+     * @see #getAxisValue(int, int)
+     * @see #getHistoricalAxisValue(int, int, int)
+     * @see MotionEvent.PointerCoords#getAxisValue(int)
+     * @see InputDevice#getMotionRange
+     */
+    public static final int AXIS_WHEEL = 21;
+
+    /**
+     * Constant used to identify the Gas axis of a motion event.
+     * <p>
+     * <ul>
+     * <li>For a joystick, reports the absolute position of the gas (accelerator) control.
+     * The value is normalized to a range from 0.0 (no acceleration)
+     * to 1.0 (maximum acceleration).
+     * </ul>
+     * </p>
+     *
+     * @see #getAxisValue(int, int)
+     * @see #getHistoricalAxisValue(int, int, int)
+     * @see MotionEvent.PointerCoords#getAxisValue(int)
+     * @see InputDevice#getMotionRange
+     */
+    public static final int AXIS_GAS = 22;
+
+    /**
+     * Constant used to identify the Brake axis of a motion event.
+     * <p>
+     * <ul>
+     * <li>For a joystick, reports the absolute position of the brake control.
+     * The value is normalized to a range from 0.0 (no braking) to 1.0 (maximum braking).
+     * </ul>
+     * </p>
+     *
+     * @see #getAxisValue(int, int)
+     * @see #getHistoricalAxisValue(int, int, int)
+     * @see MotionEvent.PointerCoords#getAxisValue(int)
+     * @see InputDevice#getMotionRange
+     */
+    public static final int AXIS_BRAKE = 23;
+
+    /**
      * Constant used to identify the Generic 1 axis of a motion event.
      * The interpretation of a generic axis is device-specific.
      *
@@ -877,6 +958,11 @@
         names.append(AXIS_HAT_Y, "AXIS_HAT_Y");
         names.append(AXIS_LTRIGGER, "AXIS_LTRIGGER");
         names.append(AXIS_RTRIGGER, "AXIS_RTRIGGER");
+        names.append(AXIS_THROTTLE, "AXIS_THROTTLE");
+        names.append(AXIS_RUDDER, "AXIS_RUDDER");
+        names.append(AXIS_WHEEL, "AXIS_WHEEL");
+        names.append(AXIS_GAS, "AXIS_GAS");
+        names.append(AXIS_BRAKE, "AXIS_BRAKE");
         names.append(AXIS_GENERIC_1, "AXIS_GENERIC_1");
         names.append(AXIS_GENERIC_2, "AXIS_GENERIC_2");
         names.append(AXIS_GENERIC_3, "AXIS_GENERIC_3");
diff --git a/core/java/android/view/ScaleGestureDetector.java b/core/java/android/view/ScaleGestureDetector.java
index 0124151..d638e70 100644
--- a/core/java/android/view/ScaleGestureDetector.java
+++ b/core/java/android/view/ScaleGestureDetector.java
@@ -19,6 +19,7 @@
 import android.content.Context;
 import android.util.DisplayMetrics;
 import android.util.FloatMath;
+import android.util.Log;
 
 /**
  * Detects transformation gestures involving more than one pointer ("multitouch")
@@ -36,6 +37,8 @@
  * </ul>
  */
 public class ScaleGestureDetector {
+    private static final String TAG = "ScaleGestureDetector";
+
     /**
      * The listener for receiving notifications when gestures occur.
      * If you want to listen for all the different gestures then implement
@@ -153,6 +156,7 @@
     private float mRightSlopEdge;
     private float mBottomSlopEdge;
     private boolean mSloppyGesture;
+    private boolean mInvalidGesture;
 
     // Pointer IDs currently responsible for the two fingers controlling the gesture
     private int mActiveId0;
@@ -170,6 +174,12 @@
         final int action = event.getActionMasked();
         boolean handled = true;
 
+        if (action == MotionEvent.ACTION_DOWN) {
+            reset(); // Start fresh
+        }
+
+        if (mInvalidGesture) return false;
+
         if (!mGestureInProgress) {
             switch (action) {
             case MotionEvent.ACTION_DOWN: {
@@ -197,6 +207,11 @@
                 int index1 = event.getActionIndex();
                 int index0 = event.findPointerIndex(mActiveId0);
                 mActiveId1 = event.getPointerId(index1);
+                if (index0 < 0 || index0 == index1) {
+                    // Probably someone sending us a broken event stream.
+                    index0 = findNewActiveIndex(event, index0 == index1 ? -1 : mActiveId1, index0);
+                    mActiveId0 = event.getPointerId(index0);
+                }
                 mActive0MostRecent = false;
 
                 setContext(event);
@@ -315,6 +330,7 @@
                         final int index = event.findPointerIndex(actionId == mActiveId0 ?
                                 mActiveId1 : mActiveId0);
                         mActiveId0 = event.getPointerId(index);
+
                         mActive0MostRecent = true;
                         mActiveId1 = -1;
                         mFocusX = event.getX(index);
@@ -338,6 +354,18 @@
                     mActiveId1 = event.getPointerId(event.getActionIndex());
                     mActive0MostRecent = false;
 
+                    int index0 = event.findPointerIndex(mActiveId0);
+                    if (index0 < 0 || mActiveId0 == mActiveId1) {
+                        // Probably someone sending us a broken event stream.
+                        Log.e(TAG, "Got " + MotionEvent.actionToString(action) +
+                                " with bad state while a gesture was in progress. " +
+                                "Did you forget to pass an event to " +
+                                "ScaleGestureDetector#onTouchEvent?");
+                        index0 = findNewActiveIndex(event,
+                                mActiveId0 == mActiveId1 ? -1 : mActiveId1, index0);
+                        mActiveId0 = event.getPointerId(index0);
+                    }
+
                     setContext(event);
 
                     mGestureInProgress = mListener.onScaleBegin(this);
@@ -493,6 +521,15 @@
         final int currIndex0 = curr.findPointerIndex(mActiveId0);
         final int currIndex1 = curr.findPointerIndex(mActiveId1);
 
+        if (prevIndex0 < 0 || prevIndex1 < 0 || currIndex0 < 0 || currIndex1 < 0) {
+            mInvalidGesture = true;
+            Log.e(TAG, "Invalid MotionEvent stream detected.", new Throwable());
+            if (mGestureInProgress) {
+                mListener.onScaleEnd(this);
+            }
+            return;
+        }
+
         final float px0 = prev.getX(prevIndex0);
         final float py0 = prev.getY(prevIndex0);
         final float px1 = prev.getX(prevIndex1);
@@ -531,6 +568,7 @@
         mGestureInProgress = false;
         mActiveId0 = -1;
         mActiveId1 = -1;
+        mInvalidGesture = false;
     }
 
     /**
diff --git a/core/java/android/view/VelocityTracker.java b/core/java/android/view/VelocityTracker.java
index 4ab2881..fccef2b 100644
--- a/core/java/android/view/VelocityTracker.java
+++ b/core/java/android/view/VelocityTracker.java
@@ -16,8 +16,6 @@
 
 package android.view;
 
-import android.util.Config;
-import android.util.Log;
 import android.util.Poolable;
 import android.util.Pool;
 import android.util.Pools;
@@ -25,24 +23,15 @@
 
 /**
  * Helper for tracking the velocity of touch events, for implementing
- * flinging and other such gestures.  Use {@link #obtain} to retrieve a
- * new instance of the class when you are going to begin tracking, put
- * the motion events you receive into it with {@link #addMovement(MotionEvent)},
- * and when you want to determine the velocity call
- * {@link #computeCurrentVelocity(int)} and then {@link #getXVelocity()}
- * and {@link #getXVelocity()}.
+ * flinging and other such gestures.
+ *
+ * Use {@link #obtain} to retrieve a new instance of the class when you are going
+ * to begin tracking.  Put the motion events you receive into it with
+ * {@link #addMovement(MotionEvent)}.  When you want to determine the velocity call
+ * {@link #computeCurrentVelocity(int)} and then call {@link #getXVelocity(int)}
+ * and {@link #getXVelocity(int)} to retrieve the velocity for each pointer id.
  */
 public final class VelocityTracker implements Poolable<VelocityTracker> {
-    private static final String TAG = "VelocityTracker";
-    private static final boolean DEBUG = false;
-    private static final boolean localLOGV = DEBUG || Config.LOGV;
-
-    private static final int NUM_PAST = 10;
-    private static final int MAX_AGE_MILLISECONDS = 200;
-    
-    private static final int POINTER_POOL_CAPACITY = 20;
-    private static final int INVALID_POINTER = -1;
-
     private static final Pool<VelocityTracker> sPool = Pools.synchronizedPool(
             Pools.finitePool(new PoolableManager<VelocityTracker>() {
                 public VelocityTracker newInstance() {
@@ -56,31 +45,20 @@
                     element.clear();
                 }
             }, 2));
-    
-    private static Pointer sRecycledPointerListHead;
-    private static int sRecycledPointerCount;
-    
-    private static final class Pointer {
-        public Pointer next;
-        
-        public int id;
-        public float xVelocity;
-        public float yVelocity;
-        
-        public final float[] pastX = new float[NUM_PAST];
-        public final float[] pastY = new float[NUM_PAST];
-        public final long[] pastTime = new long[NUM_PAST]; // uses Long.MIN_VALUE as a sentinel
-        
-        public int generation;
-    }
-    
-    private Pointer mPointerListHead; // sorted by id in increasing order
-    private int mLastTouchIndex;
-    private int mGeneration;
-    private int mActivePointerId;
 
+    private static final int ACTIVE_POINTER_ID = -1;
+
+    private int mPtr;
     private VelocityTracker mNext;
 
+    private static native int nativeInitialize();
+    private static native void nativeDispose(int ptr);
+    private static native void nativeClear(int ptr);
+    private static native void nativeAddMovement(int ptr, MotionEvent event);
+    private static native void nativeComputeCurrentVelocity(int ptr, int units, float maxVelocity);
+    private static native float nativeGetXVelocity(int ptr, int id);
+    private static native float nativeGetYVelocity(int ptr, int id);
+
     /**
      * Retrieve a new VelocityTracker object to watch the velocity of a
      * motion.  Be sure to call {@link #recycle} when done.  You should
@@ -116,18 +94,26 @@
     }
 
     private VelocityTracker() {
-        clear();
+        mPtr = nativeInitialize();
     }
-    
+
+    @Override
+    protected void finalize() throws Throwable {
+        try {
+            if (mPtr != 0) {
+                nativeDispose(mPtr);
+                mPtr = 0;
+            }
+        } finally {
+            super.finalize();
+        }
+    }
+
     /**
      * Reset the velocity tracker back to its initial state.
      */
     public void clear() {
-        releasePointerList(mPointerListHead);
-        
-        mPointerListHead = null;
-        mLastTouchIndex = 0;
-        mActivePointerId = INVALID_POINTER;
+        nativeClear(mPtr);
     }
     
     /**
@@ -137,110 +123,13 @@
      * final {@link MotionEvent#ACTION_UP}.  You can, however, call this
      * for whichever events you desire.
      * 
-     * @param ev The MotionEvent you received and would like to track.
+     * @param event The MotionEvent you received and would like to track.
      */
-    public void addMovement(MotionEvent ev) {
-        final int historySize = ev.getHistorySize();
-        final int pointerCount = ev.getPointerCount();
-        final int lastTouchIndex = mLastTouchIndex;
-        final int nextTouchIndex = (lastTouchIndex + 1) % NUM_PAST;
-        final int finalTouchIndex = (nextTouchIndex + historySize) % NUM_PAST;
-        final int generation = mGeneration++;
-        
-        mLastTouchIndex = finalTouchIndex;
-
-        // Update pointer data.
-        Pointer previousPointer = null;
-        for (int i = 0; i < pointerCount; i++){
-            final int pointerId = ev.getPointerId(i);
-            
-            // Find the pointer data for this pointer id.
-            // This loop is optimized for the common case where pointer ids in the event
-            // are in sorted order.  However, we check for this case explicitly and
-            // perform a full linear scan from the start if needed.
-            Pointer nextPointer;
-            if (previousPointer == null || pointerId < previousPointer.id) {
-                previousPointer = null;
-                nextPointer = mPointerListHead;
-            } else {
-                nextPointer = previousPointer.next;
-            }
-            
-            final Pointer pointer;
-            for (;;) {
-                if (nextPointer != null) {
-                    final int nextPointerId = nextPointer.id;
-                    if (nextPointerId == pointerId) {
-                        pointer = nextPointer;
-                        break;
-                    }
-                    if (nextPointerId < pointerId) {
-                        nextPointer = nextPointer.next;
-                        continue;
-                    }
-                }
-                
-                // Pointer went down.  Add it to the list.
-                // Write a sentinel at the end of the pastTime trace so we will be able to
-                // tell when the trace started.
-                if (mActivePointerId == INVALID_POINTER) {
-                    // Congratulations! You're the new active pointer!
-                    mActivePointerId = pointerId;
-                }
-                pointer = obtainPointer();
-                pointer.id = pointerId;
-                pointer.pastTime[lastTouchIndex] = Long.MIN_VALUE;
-                pointer.next = nextPointer;
-                if (previousPointer == null) {
-                    mPointerListHead = pointer;
-                } else {
-                    previousPointer.next = pointer;
-                }
-                break;
-            }
-            
-            pointer.generation = generation;
-            previousPointer = pointer;
-            
-            final float[] pastX = pointer.pastX;
-            final float[] pastY = pointer.pastY;
-            final long[] pastTime = pointer.pastTime;
-            
-            for (int j = 0; j < historySize; j++) {
-                final int touchIndex = (nextTouchIndex + j) % NUM_PAST;
-                pastX[touchIndex] = ev.getHistoricalX(i, j);
-                pastY[touchIndex] = ev.getHistoricalY(i, j);
-                pastTime[touchIndex] = ev.getHistoricalEventTime(j);
-            }
-            pastX[finalTouchIndex] = ev.getX(i);
-            pastY[finalTouchIndex] = ev.getY(i);
-            pastTime[finalTouchIndex] = ev.getEventTime();
+    public void addMovement(MotionEvent event) {
+        if (event == null) {
+            throw new IllegalArgumentException("event must not be null");
         }
-        
-        // Find removed pointers.
-        previousPointer = null;
-        for (Pointer pointer = mPointerListHead; pointer != null; ) {
-            final Pointer nextPointer = pointer.next;
-            final int pointerId = pointer.id;
-            if (pointer.generation != generation) {
-                // Pointer went up.  Remove it from the list.
-                if (previousPointer == null) {
-                    mPointerListHead = nextPointer;
-                } else {
-                    previousPointer.next = nextPointer;
-                }
-                releasePointer(pointer);
-
-                if (pointerId == mActivePointerId) {
-                    // Pick a new active pointer. How is arbitrary.
-                    mActivePointerId = mPointerListHead != null ?
-                            mPointerListHead.id : INVALID_POINTER;
-                }
-            } else {
-                previousPointer = pointer;
-            }
-            pointer = nextPointer;
-        }
+        nativeAddMovement(mPtr, event);
     }
 
     /**
@@ -250,7 +139,7 @@
      * @see #computeCurrentVelocity(int, float) 
      */
     public void computeCurrentVelocity(int units) {
-        computeCurrentVelocity(units, Float.MAX_VALUE);
+        nativeComputeCurrentVelocity(mPtr, units, Float.MAX_VALUE);
     }
 
     /**
@@ -267,78 +156,7 @@
      * must be positive.
      */
     public void computeCurrentVelocity(int units, float maxVelocity) {
-        final int lastTouchIndex = mLastTouchIndex;
-        
-        for (Pointer pointer = mPointerListHead; pointer != null; pointer = pointer.next) {
-            final long[] pastTime = pointer.pastTime;
-            
-            // Search backwards in time for oldest acceptable time.
-            // Stop at the beginning of the trace as indicated by the sentinel time Long.MIN_VALUE.
-            int oldestTouchIndex = lastTouchIndex;
-            int numTouches = 1;
-            final long minTime = pastTime[lastTouchIndex] - MAX_AGE_MILLISECONDS;
-            while (numTouches < NUM_PAST) {
-                final int nextOldestTouchIndex = (oldestTouchIndex + NUM_PAST - 1) % NUM_PAST;
-                final long nextOldestTime = pastTime[nextOldestTouchIndex];
-                if (nextOldestTime < minTime) { // also handles end of trace sentinel
-                    break;
-                }
-                oldestTouchIndex = nextOldestTouchIndex;
-                numTouches += 1;
-            }
-            
-            // If we have a lot of samples, skip the last received sample since it is
-            // probably pretty noisy compared to the sum of all of the traces already acquired.
-            if (numTouches > 3) {
-                numTouches -= 1;
-            }
-            
-            // Kind-of stupid.
-            final float[] pastX = pointer.pastX;
-            final float[] pastY = pointer.pastY;
-            
-            final float oldestX = pastX[oldestTouchIndex];
-            final float oldestY = pastY[oldestTouchIndex];
-            final long oldestTime = pastTime[oldestTouchIndex];
-            
-            float accumX = 0;
-            float accumY = 0;
-            
-            for (int i = 1; i < numTouches; i++) {
-                final int touchIndex = (oldestTouchIndex + i) % NUM_PAST;
-                final int duration = (int)(pastTime[touchIndex] - oldestTime);
-                
-                if (duration == 0) continue;
-                
-                float delta = pastX[touchIndex] - oldestX;
-                float velocity = (delta / duration) * units; // pixels/frame.
-                accumX = (accumX == 0) ? velocity : (accumX + velocity) * .5f;
-            
-                delta = pastY[touchIndex] - oldestY;
-                velocity = (delta / duration) * units; // pixels/frame.
-                accumY = (accumY == 0) ? velocity : (accumY + velocity) * .5f;
-            }
-            
-            if (accumX < -maxVelocity) {
-                accumX = - maxVelocity;
-            } else if (accumX > maxVelocity) {
-                accumX = maxVelocity;
-            }
-            
-            if (accumY < -maxVelocity) {
-                accumY = - maxVelocity;
-            } else if (accumY > maxVelocity) {
-                accumY = maxVelocity;
-            }
-            
-            pointer.xVelocity = accumX;
-            pointer.yVelocity = accumY;
-            
-            if (localLOGV) {
-                Log.v(TAG, "Pointer " + pointer.id
-                    + ": Y velocity=" + accumX +" X velocity=" + accumY + " N=" + numTouches);
-            }
-        }
+        nativeComputeCurrentVelocity(mPtr, units, maxVelocity);
     }
     
     /**
@@ -348,8 +166,7 @@
      * @return The previously computed X velocity.
      */
     public float getXVelocity() {
-        Pointer pointer = getPointer(mActivePointerId);
-        return pointer != null ? pointer.xVelocity : 0;
+        return nativeGetXVelocity(mPtr, ACTIVE_POINTER_ID);
     }
     
     /**
@@ -359,8 +176,7 @@
      * @return The previously computed Y velocity.
      */
     public float getYVelocity() {
-        Pointer pointer = getPointer(mActivePointerId);
-        return pointer != null ? pointer.yVelocity : 0;
+        return nativeGetYVelocity(mPtr, ACTIVE_POINTER_ID);
     }
     
     /**
@@ -371,8 +187,7 @@
      * @return The previously computed X velocity.
      */
     public float getXVelocity(int id) {
-        Pointer pointer = getPointer(id);
-        return pointer != null ? pointer.xVelocity : 0;
+        return nativeGetXVelocity(mPtr, id);
     }
     
     /**
@@ -383,68 +198,6 @@
      * @return The previously computed Y velocity.
      */
     public float getYVelocity(int id) {
-        Pointer pointer = getPointer(id);
-        return pointer != null ? pointer.yVelocity : 0;
-    }
-    
-    private Pointer getPointer(int id) {
-        for (Pointer pointer = mPointerListHead; pointer != null; pointer = pointer.next) {
-            if (pointer.id == id) {
-                return pointer;
-            }
-        }
-        return null;
-    }
-    
-    private static Pointer obtainPointer() {
-        synchronized (sPool) {
-            if (sRecycledPointerCount != 0) {
-                Pointer element = sRecycledPointerListHead;
-                sRecycledPointerCount -= 1;
-                sRecycledPointerListHead = element.next;
-                element.next = null;
-                return element;
-            }
-        }
-        return new Pointer();
-    }
-    
-    private static void releasePointer(Pointer pointer) {
-        synchronized (sPool) {
-            if (sRecycledPointerCount < POINTER_POOL_CAPACITY) {
-                pointer.next = sRecycledPointerListHead;
-                sRecycledPointerCount += 1;
-                sRecycledPointerListHead = pointer;
-            }
-        }
-    }
-    
-    private static void releasePointerList(Pointer pointer) {
-        if (pointer != null) {
-            synchronized (sPool) {
-                int count = sRecycledPointerCount;
-                if (count >= POINTER_POOL_CAPACITY) {
-                    return;
-                }
-                
-                Pointer tail = pointer;
-                for (;;) {
-                    count += 1;
-                    if (count >= POINTER_POOL_CAPACITY) {
-                        break;
-                    }
-                    
-                    Pointer next = tail.next;
-                    if (next == null) {
-                        break;
-                    }
-                    tail = next;
-                }
-
-                tail.next = sRecycledPointerListHead;
-                sRecycledPointerCount = count;
-                sRecycledPointerListHead = pointer;
-            }
-        }
+        return nativeGetYVelocity(mPtr, id);
     }
 }
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 32c9e27..c729ccd 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -59,7 +59,6 @@
 import android.util.SparseArray;
 import android.util.TypedValue;
 import android.view.ContextMenu.ContextMenuInfo;
-import android.view.View.MeasureSpec;
 import android.view.accessibility.AccessibilityEvent;
 import android.view.accessibility.AccessibilityEventSource;
 import android.view.accessibility.AccessibilityManager;
@@ -4651,6 +4650,7 @@
      * @return True if the event was handled by the view, false otherwise.
      */
     public boolean dispatchGenericMotionEvent(MotionEvent event) {
+        //noinspection SimplifiableIfStatement
         if (mOnGenericMotionListener != null && (mViewFlags & ENABLED_MASK) == ENABLED
                 && mOnGenericMotionListener.onGenericMotion(this, event)) {
             return true;
@@ -5241,6 +5241,10 @@
         final int viewFlags = mViewFlags;
 
         if ((viewFlags & ENABLED_MASK) == DISABLED) {
+            if (event.getAction() == MotionEvent.ACTION_UP && (mPrivateFlags & PRESSED) != 0) {
+                mPrivateFlags &= ~PRESSED;
+                refreshDrawableState();
+            }
             // A disabled view that is clickable still consumes the touch
             // events, it just doesn't respond to them.
             return (((viewFlags & CLICKABLE) == CLICKABLE ||
@@ -9326,7 +9330,8 @@
         }
 
         final ScrollabilityCache scrollabilityCache = mScrollCache;
-        int length = scrollabilityCache.fadingEdgeLength;
+        final float fadeHeight = scrollabilityCache.fadingEdgeLength;        
+        int length = (int) fadeHeight;
 
         // clip the fade length if top and bottom fades overlap
         // overlapping fades produce odd-looking artifacts
@@ -9341,16 +9346,16 @@
 
         if (verticalEdges) {
             topFadeStrength = Math.max(0.0f, Math.min(1.0f, getTopFadingEdgeStrength()));
-            drawTop = topFadeStrength > 0.0f;
+            drawTop = topFadeStrength * fadeHeight > 1.0f;
             bottomFadeStrength = Math.max(0.0f, Math.min(1.0f, getBottomFadingEdgeStrength()));
-            drawBottom = bottomFadeStrength > 0.0f;
+            drawBottom = bottomFadeStrength * fadeHeight > 1.0f;
         }
 
         if (horizontalEdges) {
             leftFadeStrength = Math.max(0.0f, Math.min(1.0f, getLeftFadingEdgeStrength()));
-            drawLeft = leftFadeStrength > 0.0f;
+            drawLeft = leftFadeStrength * fadeHeight > 1.0f;
             rightFadeStrength = Math.max(0.0f, Math.min(1.0f, getRightFadingEdgeStrength()));
-            drawRight = rightFadeStrength > 0.0f;
+            drawRight = rightFadeStrength * fadeHeight > 1.0f;
         }
 
         saveCount = canvas.getSaveCount();
@@ -9388,7 +9393,6 @@
         final Paint p = scrollabilityCache.paint;
         final Matrix matrix = scrollabilityCache.matrix;
         final Shader fade = scrollabilityCache.shader;
-        final float fadeHeight = scrollabilityCache.fadingEdgeLength;
 
         if (drawTop) {
             matrix.setScale(1, fadeHeight * topFadeStrength);
@@ -9438,6 +9442,7 @@
      *
      * @return The known solid color background for this view, or 0 if the color may vary
      */
+    @ViewDebug.ExportedProperty(category = "drawing")
     public int getSolidColor() {
         return 0;
     }
@@ -11644,6 +11649,7 @@
      * @return true if scrolling was clamped to an over-scroll boundary along either
      *          axis, false otherwise.
      */
+    @SuppressWarnings({"UnusedParameters"})
     protected boolean overScrollBy(int deltaX, int deltaY,
             int scrollX, int scrollY,
             int scrollRangeX, int scrollRangeY,
diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java
index 3153ac5..8dc86ac 100644
--- a/core/java/android/view/ViewGroup.java
+++ b/core/java/android/view/ViewGroup.java
@@ -2585,7 +2585,7 @@
                     }
                 } else {
                     child.mPrivateFlags &= ~DIRTY_MASK;
-                    ((HardwareCanvas) canvas).drawDisplayList(displayList);
+                    ((HardwareCanvas) canvas).drawDisplayList(displayList, cr - cl, cb - ct, null);
                 }
             }
         } else if (cache != null) {
@@ -3680,7 +3680,7 @@
                     // flag coming from the child that initiated the invalidate
                     if (view != null) {
                         if ((view.mViewFlags & FADING_EDGE_MASK) != 0 &&
-                                view.getSolidColor() == 0 && !view.isOpaque()) {
+                                view.getSolidColor() == 0) {
                             opaqueFlag = DIRTY;
                         }
                         if ((view.mPrivateFlags & DIRTY_MASK) != DIRTY) {
@@ -4275,11 +4275,10 @@
      *         does not exist within the group
      */
     public View getChildAt(int index) {
-        try {
-            return mChildren[index];
-        } catch (IndexOutOfBoundsException ex) {
+        if (index < 0 || index >= mChildrenCount) {
             return null;
         }
+        return mChildren[index];
     }
 
     /**
diff --git a/core/java/android/view/ViewRoot.java b/core/java/android/view/ViewRoot.java
index 5468230..c86c9a5 100644
--- a/core/java/android/view/ViewRoot.java
+++ b/core/java/android/view/ViewRoot.java
@@ -498,15 +498,21 @@
         mAttachInfo.mHardwareAccelerationRequested = false;
 
         // Try to enable hardware acceleration if requested
-        if (attrs != null &&
-                (attrs.flags & WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED) != 0) {
+        final boolean hardwareAccelerated = 
+                (attrs.flags & WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED) != 0;
+
+        if (hardwareAccelerated) {
             // Only enable hardware acceleration if we are not in the system process
             // The window manager creates ViewRoots to display animated preview windows
             // of launching apps and we don't want those to be hardware accelerated
-            if (!HardwareRenderer.sRendererDisabled) {
+
+            final boolean systemHwAccelerated =
+                (attrs.flags & WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED_SYSTEM) != 0;
+
+            if (!HardwareRenderer.sRendererDisabled || systemHwAccelerated) {
                 // Don't enable hardware acceleration when we're not on the main thread
-                if (Looper.getMainLooper() != Looper.myLooper()) {
-                    Log.w(HardwareRenderer.LOG_TAG, "Attempting to initialize hardware " 
+                if (!systemHwAccelerated && Looper.getMainLooper() != Looper.myLooper()) {
+                    Log.w(HardwareRenderer.LOG_TAG, "Attempting to initialize hardware "
                             + "acceleration outside of the main thread, aborting");
                     return;
                 }
@@ -1169,10 +1175,11 @@
                         }
                     }
                     mSurfaceHolder.mSurfaceLock.lock();
-                    // Make surface invalid.
-                    //mSurfaceHolder.mSurface.copyFrom(mSurface);
-                    mSurfaceHolder.mSurface = new Surface();
-                    mSurfaceHolder.mSurfaceLock.unlock();
+                    try {
+                        mSurfaceHolder.mSurface = new Surface();
+                    } finally {
+                        mSurfaceHolder.mSurfaceLock.unlock();
+                    }
                 }
             }
 
@@ -1606,13 +1613,9 @@
                 return;
             } catch (IllegalArgumentException e) {
                 Log.e(TAG, "IllegalArgumentException locking surface", e);
-                try {
-                    if (!sWindowSession.outOfMemory(mWindow)) {
-                        Slog.w(TAG, "No processes killed for memory; killing self");
-                        Process.killProcess(Process.myPid());
-                    }
-                } catch (RemoteException ex) {
-                }
+                // Don't assume this is due to out of memory, it could be
+                // something else, and if it is something else then we could
+                // kill stuff (or ourself) for no reason.
                 mLayoutRequested = true;    // ask wm for a new surface next time.
                 return;
             }
diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java
index ca932e9..8a18aaf 100644
--- a/core/java/android/view/WindowManager.java
+++ b/core/java/android/view/WindowManager.java
@@ -665,6 +665,17 @@
          * XML attribute is set to true on an activity or on the application.</p>
          */
         public static final int FLAG_HARDWARE_ACCELERATED = 0x01000000;
+        
+        /**
+         * Like {@link #FLAG_HARDWARE_ACCELERATED} except for trusted system windows
+         * that need hardware acceleration (e.g. LockScreen), where hardware acceleration
+         * is generally disabled. This flag must be specified in addition to 
+         * {@link #FLAG_HARDWARE_ACCELERATED} to enable hardware acceleration for system
+         * windows.
+         * 
+         * @hide
+         */
+        public static final int FLAG_HARDWARE_ACCELERATED_SYSTEM = 0x02000000;
 
         // ----- HIDDEN FLAGS.
         // These start at the high bit and go down.
diff --git a/core/java/android/view/accessibility/AccessibilityEvent.java b/core/java/android/view/accessibility/AccessibilityEvent.java
index fc61700..9af19b8 100644
--- a/core/java/android/view/accessibility/AccessibilityEvent.java
+++ b/core/java/android/view/accessibility/AccessibilityEvent.java
@@ -159,7 +159,12 @@
      *
      * @see #getBeforeText()
      * @see #getText()
+     * </br>
+     * Note: This constant is no longer needed since there
+     *       is no limit on the length of text that is contained
+     *       in an accessibility event anymore.
      */
+    @Deprecated
     public static final int MAX_TEXT_LENGTH = 500;
 
     /**
diff --git a/core/java/android/view/inputmethod/BaseInputConnection.java b/core/java/android/view/inputmethod/BaseInputConnection.java
index e644045..b95e7c9 100644
--- a/core/java/android/view/inputmethod/BaseInputConnection.java
+++ b/core/java/android/view/inputmethod/BaseInputConnection.java
@@ -20,6 +20,7 @@
 import android.content.res.TypedArray;
 import android.os.Bundle;
 import android.os.Handler;
+import android.os.IBinder;
 import android.os.SystemClock;
 import android.text.Editable;
 import android.text.NoCopySpan;
@@ -29,6 +30,7 @@
 import android.text.Spanned;
 import android.text.TextUtils;
 import android.text.method.MetaKeyKeyListener;
+import android.text.style.CorrectionSpan;
 import android.util.Log;
 import android.util.LogPrinter;
 import android.view.KeyCharacterMap;
@@ -190,6 +192,15 @@
     }
 
     /**
+     * Default implementation does nothing and returns false.
+     */
+    @Override
+    public boolean setCorrectionSpan(IBinder token, CorrectionSpan correctionSpan, int start,
+            int end, int flags) {
+        return false;
+    }
+
+    /**
      * The default implementation performs the deletion around the current
      * selection position of the editable text.
      */
diff --git a/core/java/android/view/inputmethod/InputConnection.java b/core/java/android/view/inputmethod/InputConnection.java
index ea9e402..a8a5346 100644
--- a/core/java/android/view/inputmethod/InputConnection.java
+++ b/core/java/android/view/inputmethod/InputConnection.java
@@ -17,6 +17,8 @@
 package android.view.inputmethod;
 
 import android.os.Bundle;
+import android.os.IBinder;
+import android.text.style.CorrectionSpan;
 import android.view.KeyCharacterMap;
 import android.view.KeyEvent;
 
@@ -353,4 +355,10 @@
      * valid.
      */
     public boolean performPrivateCommand(String action, Bundle data);
+
+    /**
+     * Add a correction span.
+     */
+    public boolean setCorrectionSpan(IBinder token, CorrectionSpan correctionSpan, int start,
+            int end, int flags);
 }
diff --git a/core/java/android/view/inputmethod/InputConnectionWrapper.java b/core/java/android/view/inputmethod/InputConnectionWrapper.java
index 4d9d51e..fee88d9 100644
--- a/core/java/android/view/inputmethod/InputConnectionWrapper.java
+++ b/core/java/android/view/inputmethod/InputConnectionWrapper.java
@@ -17,6 +17,8 @@
 package android.view.inputmethod;
 
 import android.os.Bundle;
+import android.os.IBinder;
+import android.text.style.CorrectionSpan;
 import android.view.KeyEvent;
 
 /**
@@ -126,4 +128,9 @@
     public boolean performPrivateCommand(String action, Bundle data) {
         return mTarget.performPrivateCommand(action, data);
     }
+
+    public boolean setCorrectionSpan(IBinder token, CorrectionSpan correctionSpan, int start,
+            int end, int flags) {
+        return mTarget.setCorrectionSpan(token, correctionSpan, start, end, flags);
+    }
 }
diff --git a/core/java/android/webkit/BrowserFrame.java b/core/java/android/webkit/BrowserFrame.java
index ab4bfe1..6306274 100644
--- a/core/java/android/webkit/BrowserFrame.java
+++ b/core/java/android/webkit/BrowserFrame.java
@@ -1043,13 +1043,16 @@
     // These ids need to be in sync with enum rawResId in PlatformBridge.h
     private static final int NODOMAIN = 1;
     private static final int LOADERROR = 2;
-    private static final int DRAWABLEDIR = 3;
+    /* package */ static final int DRAWABLEDIR = 3;
     private static final int FILE_UPLOAD_LABEL = 4;
     private static final int RESET_LABEL = 5;
     private static final int SUBMIT_LABEL = 6;
     private static final int FILE_UPLOAD_NO_FILE_CHOSEN = 7;
 
-    String getRawResFilename(int id) {
+    private String getRawResFilename(int id) {
+        return getRawResFilename(id, mContext);
+    }
+    /* package */ static String getRawResFilename(int id, Context context) {
         int resid;
         switch (id) {
             case NODOMAIN:
@@ -1066,19 +1069,19 @@
                 break;
 
             case FILE_UPLOAD_LABEL:
-                return mContext.getResources().getString(
+                return context.getResources().getString(
                         com.android.internal.R.string.upload_file);
 
             case RESET_LABEL:
-                return mContext.getResources().getString(
+                return context.getResources().getString(
                         com.android.internal.R.string.reset);
 
             case SUBMIT_LABEL:
-                return mContext.getResources().getString(
+                return context.getResources().getString(
                         com.android.internal.R.string.submit);
 
             case FILE_UPLOAD_NO_FILE_CHOSEN:
-                return mContext.getResources().getString(
+                return context.getResources().getString(
                         com.android.internal.R.string.no_file_chosen);
 
             default:
@@ -1086,7 +1089,7 @@
                 return "";
         }
         TypedValue value = new TypedValue();
-        mContext.getResources().getValue(resid, value, true);
+        context.getResources().getValue(resid, value, true);
         if (id == DRAWABLEDIR) {
             String path = value.string.toString();
             int index = path.lastIndexOf('/');
@@ -1237,11 +1240,17 @@
         }
     }
 
-
     /*package*/ SearchBox getSearchBox() {
         return mSearchBox;
     }
 
+    /**
+     * Called by JNI when processing the X-Auto-Login header.
+     */
+    private void autoLogin(String realm, String account, String args) {
+        mCallbackProxy.onReceivedLoginRequest(realm, account, args);
+    }
+
     //==========================================================================
     // native functions
     //==========================================================================
diff --git a/core/java/android/webkit/CallbackProxy.java b/core/java/android/webkit/CallbackProxy.java
index c66d701..23fd12d 100644
--- a/core/java/android/webkit/CallbackProxy.java
+++ b/core/java/android/webkit/CallbackProxy.java
@@ -117,6 +117,7 @@
     private static final int AUTH_CREDENTIALS                    = 137;
     private static final int SET_INSTALLABLE_WEBAPP              = 138;
     private static final int NOTIFY_SEARCHBOX_LISTENERS          = 139;
+    private static final int AUTO_LOGIN                          = 140;
 
     // Message triggered by the client to resume execution
     private static final int NOTIFY                              = 200;
@@ -770,7 +771,7 @@
                             (WebHistoryItem) msg.obj, msg.arg1);
                 }
                 break;
-            case AUTH_CREDENTIALS:
+            case AUTH_CREDENTIALS: {
                 String host = msg.getData().getString("host");
                 String realm = msg.getData().getString("realm");
                 username = msg.getData().getString("username");
@@ -778,6 +779,7 @@
                 mWebView.setHttpAuthUsernamePassword(
                         host, realm, username, password);
                 break;
+            }
             case SET_INSTALLABLE_WEBAPP:
                 if (mWebChromeClient != null) {
                     mWebChromeClient.setInstallableWebApp();
@@ -789,6 +791,17 @@
                 @SuppressWarnings("unchecked")
                 List<String> suggestions = (List<String>) msg.obj;
                 searchBox.handleSuggestions(msg.getData().getString("query"), suggestions);
+                break;
+            case AUTO_LOGIN: {
+                if (mWebViewClient != null) {
+                    String realm = msg.getData().getString("realm");
+                    String account = msg.getData().getString("account");
+                    String args = msg.getData().getString("args");
+                    mWebViewClient.onReceivedLoginRequest(mWebView, realm,
+                            account, args);
+                }
+                break;
+            }
         }
     }
 
@@ -1051,6 +1064,20 @@
         sendMessage(msg);
     }
 
+    void onReceivedLoginRequest(String realm, String account, String args) {
+        // Do an unsynchronized quick check to avoid posting if no callback has
+        // been set.
+        if (mWebViewClient == null) {
+            return;
+        }
+        Message msg = obtainMessage(AUTO_LOGIN);
+        Bundle bundle = msg.getData();
+        bundle.putString("realm", realm);
+        bundle.putString("account", account);
+        bundle.putString("args", args);
+        sendMessage(msg);
+    }
+
     //--------------------------------------------------------------------------
     // DownloadListener functions.
     //--------------------------------------------------------------------------
diff --git a/core/java/android/webkit/DebugFlags.java b/core/java/android/webkit/DebugFlags.java
index 2dac7e9..3cb5e24 100644
--- a/core/java/android/webkit/DebugFlags.java
+++ b/core/java/android/webkit/DebugFlags.java
@@ -31,7 +31,7 @@
     public static final boolean CACHE_MANAGER = false;
     public static final boolean CALLBACK_PROXY = false;
     public static final boolean COOKIE_MANAGER = false;
-    public static final boolean COOKIE_SYNC_MANAGER = true;
+    public static final boolean COOKIE_SYNC_MANAGER = false;
     public static final boolean FRAME_LOADER = false;
     public static final boolean J_WEB_CORE_JAVA_BRIDGE = false;// HIGHLY VERBOSE
     public static final boolean LOAD_LISTENER = false;
@@ -41,7 +41,7 @@
     public static final boolean URL_UTIL = false;
     public static final boolean WEB_BACK_FORWARD_LIST = false;
     public static final boolean WEB_SETTINGS = false;
-    public static final boolean WEB_SYNC_MANAGER = true;
+    public static final boolean WEB_SYNC_MANAGER = false;
     public static final boolean WEB_TEXT_VIEW = false;
     public static final boolean WEB_VIEW = false;
     public static final boolean WEB_VIEW_CORE = false;
diff --git a/core/java/android/webkit/HTML5VideoFullScreen.java b/core/java/android/webkit/HTML5VideoFullScreen.java
new file mode 100644
index 0000000..0510f8b
--- /dev/null
+++ b/core/java/android/webkit/HTML5VideoFullScreen.java
@@ -0,0 +1,324 @@
+
+package android.webkit;
+
+import android.content.Context;
+import android.media.MediaPlayer;
+import android.media.Metadata;
+import android.util.Log;
+import android.view.Gravity;
+import android.view.MotionEvent;
+import android.view.SurfaceHolder;
+import android.view.SurfaceView;
+import android.view.View;
+import android.view.ViewGroup;
+import android.webkit.HTML5VideoView;
+import android.webkit.HTML5VideoViewProxy;
+import android.widget.FrameLayout;
+import android.widget.MediaController;
+import android.widget.MediaController.MediaPlayerControl;
+
+
+/**
+ * @hide This is only used by the browser
+ */
+public class HTML5VideoFullScreen extends HTML5VideoView
+    implements MediaPlayerControl, MediaPlayer.OnPreparedListener,
+    View.OnTouchListener {
+
+    // Add this sub-class to handle the resizing when rotating screen.
+    private class VideoSurfaceView extends SurfaceView {
+
+        public VideoSurfaceView(Context context) {
+            super(context);
+        }
+
+        @Override
+        protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+            int width = getDefaultSize(mVideoWidth, widthMeasureSpec);
+            int height = getDefaultSize(mVideoHeight, heightMeasureSpec);
+            if (mVideoWidth > 0 && mVideoHeight > 0) {
+                if ( mVideoWidth * height  > width * mVideoHeight ) {
+                    height = width * mVideoHeight / mVideoWidth;
+                } else if ( mVideoWidth * height  < width * mVideoHeight ) {
+                    width = height * mVideoWidth / mVideoHeight;
+                }
+            }
+            setMeasuredDimension(width, height);
+        }
+    }
+
+    // This view will contain the video.
+    private VideoSurfaceView mVideoSurfaceView;
+
+    // We need the full screen state to decide which surface to render to and
+    // when to create the MediaPlayer accordingly.
+    static final int FULLSCREEN_OFF               = 0;
+    static final int FULLSCREEN_SURFACECREATING   = 1;
+    static final int FULLSCREEN_SURFACECREATED    = 2;
+
+    private int mFullScreenMode;
+    // The Media Controller only used for full screen mode
+    private MediaController mMediaController;
+
+    // SurfaceHolder for full screen
+    private SurfaceHolder mSurfaceHolder = null;
+
+    // Data only for MediaController
+    private boolean mCanSeekBack;
+    private boolean mCanSeekForward;
+    private boolean mCanPause;
+    private int mCurrentBufferPercentage;
+
+    // The progress view.
+    private static View mProgressView;
+    // The container for the progress view and video view
+    private static FrameLayout mLayout;
+
+    // The video size will be ready when prepared. Used to make sure the aspect
+    // ratio is correct.
+    private int mVideoWidth;
+    private int mVideoHeight;
+
+    SurfaceHolder.Callback mSHCallback = new SurfaceHolder.Callback()
+    {
+        public void surfaceChanged(SurfaceHolder holder, int format,
+                                    int w, int h)
+        {
+            if (mPlayer != null && mMediaController != null
+                    && mCurrentState == STATE_PREPARED) {
+                if (mMediaController.isShowing()) {
+                    // ensure the controller will get repositioned later
+                    mMediaController.hide();
+                }
+                mMediaController.show();
+            }
+        }
+
+        public void surfaceCreated(SurfaceHolder holder)
+        {
+            mSurfaceHolder = holder;
+            mFullScreenMode = FULLSCREEN_SURFACECREATED;
+
+            prepareForFullScreen();
+        }
+
+        public void surfaceDestroyed(SurfaceHolder holder)
+        {
+            // after we return from this we can't use the surface any more
+            mSurfaceHolder = null;
+            // The current Video View will be destroy when we play a new video.
+        }
+    };
+
+    private SurfaceView getSurfaceView() {
+        return mVideoSurfaceView;
+    }
+
+    @Override
+    public void start() {
+        if (getAutostart()) {
+            super.start();
+        }
+    }
+
+    HTML5VideoFullScreen(Context context, int videoLayerId, int position,
+            boolean autoStart) {
+        mVideoSurfaceView = new VideoSurfaceView(context);
+        mFullScreenMode = FULLSCREEN_OFF;
+        mVideoWidth = 0;
+        mVideoHeight = 0;
+        init(videoLayerId, position, autoStart);
+    }
+
+    private void setMediaController(MediaController m) {
+        mMediaController  = m;
+        attachMediaController();
+    }
+
+    private void attachMediaController() {
+        if (mPlayer != null && mMediaController != null) {
+            mMediaController.setMediaPlayer(this);
+            mMediaController.setAnchorView(mVideoSurfaceView);
+            //Will be enabled when prepared
+            mMediaController.setEnabled(false);
+        }
+    }
+
+    @Override
+    public void decideDisplayMode() {
+        mPlayer.setDisplay(mSurfaceHolder);
+    }
+
+    private void prepareForFullScreen() {
+        // So in full screen, we reset the MediaPlayer
+        mPlayer.reset();
+        setMediaController(new MediaController(mProxy.getContext()));
+
+        prepareDataAndDisplayMode(mProxy);
+    }
+
+
+    private void toggleMediaControlsVisiblity() {
+        if (mMediaController.isShowing()) {
+            mMediaController.hide();
+        } else {
+            mMediaController.show();
+        }
+    }
+
+    @Override
+    public void onPrepared(MediaPlayer mp) {
+        super.onPrepared(mp);
+
+        mVideoSurfaceView.setOnTouchListener(this);
+        // Get the capabilities of the player for this stream
+        Metadata data = mp.getMetadata(MediaPlayer.METADATA_ALL,
+                MediaPlayer.BYPASS_METADATA_FILTER);
+        if (data != null) {
+            mCanPause = !data.has(Metadata.PAUSE_AVAILABLE)
+                    || data.getBoolean(Metadata.PAUSE_AVAILABLE);
+            mCanSeekBack = !data.has(Metadata.SEEK_BACKWARD_AVAILABLE)
+                    || data.getBoolean(Metadata.SEEK_BACKWARD_AVAILABLE);
+            mCanSeekForward = !data.has(Metadata.SEEK_FORWARD_AVAILABLE)
+                    || data.getBoolean(Metadata.SEEK_FORWARD_AVAILABLE);
+        } else {
+            mCanPause = mCanSeekBack = mCanSeekForward = true;
+        }
+
+        // mMediaController status depends on the Metadata result, so put it
+        // after reading the MetaData
+        if (mMediaController != null) {
+            mMediaController.setEnabled(true);
+            // If paused , should show the controller for ever!
+            if (getAutostart())
+                mMediaController.show();
+            else
+                mMediaController.show(0);
+        }
+
+        if (mProgressView != null) {
+            mProgressView.setVisibility(View.GONE);
+            mLayout.removeView(mProgressView);
+            mProgressView = null;
+        }
+
+        mVideoWidth = mp.getVideoWidth();
+        mVideoHeight = mp.getVideoHeight();
+        // This will trigger the onMeasure to get the display size right.
+        mVideoSurfaceView.getHolder().setFixedSize(mVideoWidth, mVideoHeight);
+    }
+
+
+    private final WebChromeClient.CustomViewCallback mCallback =
+        new WebChromeClient.CustomViewCallback() {
+            public void onCustomViewHidden() {
+                // It listens to SurfaceHolder.Callback.SurfaceDestroyed event
+                // which happens when the video view is detached from its parent
+                // view. This happens in the WebChromeClient before this method
+                // is invoked.
+                pauseAndDispatch(mProxy);
+
+                mLayout.removeView(getSurfaceView());
+
+                if (mProgressView != null) {
+                    mLayout.removeView(mProgressView);
+                    mProgressView = null;
+                }
+                mLayout = null;
+                // Re enable plugin views.
+                mProxy.getWebView().getViewManager().showAll();
+
+                mProxy = null;
+            }
+        };
+
+    @Override
+    public void enterFullScreenVideoState(int layerId,
+            HTML5VideoViewProxy proxy, WebView webView) {
+        mFullScreenMode = FULLSCREEN_SURFACECREATING;
+        mCurrentBufferPercentage = 0;
+        mPlayer.setOnBufferingUpdateListener(mBufferingUpdateListener);
+        mProxy = proxy;
+
+        mVideoSurfaceView.getHolder().addCallback(mSHCallback);
+        mVideoSurfaceView.getHolder().setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
+        mVideoSurfaceView.setFocusable(true);
+        mVideoSurfaceView.setFocusableInTouchMode(true);
+        mVideoSurfaceView.requestFocus();
+
+        // Create a FrameLayout that will contain the VideoView and the
+        // progress view (if any).
+        mLayout = new FrameLayout(mProxy.getContext());
+        FrameLayout.LayoutParams layoutParams = new FrameLayout.LayoutParams(
+                            ViewGroup.LayoutParams.WRAP_CONTENT,
+                            ViewGroup.LayoutParams.WRAP_CONTENT,
+                            Gravity.CENTER);
+
+        mLayout.addView(getSurfaceView(), layoutParams);
+
+        mLayout.setVisibility(View.VISIBLE);
+
+        WebChromeClient client = webView.getWebChromeClient();
+        client.onShowCustomView(mLayout, mCallback);
+        // Plugins like Flash will draw over the video so hide
+        // them while we're playing.
+        mProxy.getWebView().getViewManager().hideAll();
+
+        mProgressView = client.getVideoLoadingProgressView();
+        if (mProgressView != null) {
+            mLayout.addView(mProgressView, layoutParams);
+            mProgressView.setVisibility(View.VISIBLE);
+        }
+
+    }
+
+    /**
+     * @return true when we are in full screen mode, even the surface not fully
+     * created.
+     */
+    public boolean isFullScreenMode() {
+        return true;
+    }
+
+    // MediaController FUNCTIONS:
+    @Override
+    public boolean canPause() {
+        return mCanPause;
+    }
+
+    @Override
+    public boolean canSeekBackward() {
+        return mCanSeekBack;
+    }
+
+    @Override
+    public boolean canSeekForward() {
+        return mCanSeekForward;
+    }
+
+    @Override
+    public int getBufferPercentage() {
+        if (mPlayer != null) {
+            return mCurrentBufferPercentage;
+        }
+    return 0;
+    }
+
+    // Other listeners functions:
+    private MediaPlayer.OnBufferingUpdateListener mBufferingUpdateListener =
+        new MediaPlayer.OnBufferingUpdateListener() {
+        public void onBufferingUpdate(MediaPlayer mp, int percent) {
+            mCurrentBufferPercentage = percent;
+        }
+    };
+
+    @Override
+    public boolean onTouch(View v, MotionEvent event) {
+        if (mFullScreenMode >= FULLSCREEN_SURFACECREATED
+                && mMediaController != null) {
+            toggleMediaControlsVisiblity();
+        }
+        return false;
+    }
+
+}
diff --git a/core/java/android/webkit/HTML5VideoInline.java b/core/java/android/webkit/HTML5VideoInline.java
new file mode 100644
index 0000000..25921bc
--- /dev/null
+++ b/core/java/android/webkit/HTML5VideoInline.java
@@ -0,0 +1,86 @@
+
+package android.webkit;
+
+import android.graphics.SurfaceTexture;
+import android.media.MediaPlayer;
+import android.webkit.HTML5VideoView;
+import android.webkit.HTML5VideoViewProxy;
+import android.opengl.GLES20;
+
+/**
+ * @hide This is only used by the browser
+ */
+public class HTML5VideoInline extends HTML5VideoView{
+
+    // Due to the fact that SurfaceTexture consume a lot of memory, we make it
+    // as static. m_textureNames is the texture bound with this SurfaceTexture.
+    private static SurfaceTexture mSurfaceTexture = null;
+    private static int[] mTextureNames;
+
+    // Video control FUNCTIONS:
+    @Override
+    public void start() {
+        if (!getPauseDuringPreparing()) {
+            super.start();
+        }
+    }
+
+    HTML5VideoInline(int videoLayerId, int position,
+            boolean autoStart) {
+        init(videoLayerId, position, autoStart);
+    }
+
+    @Override
+    public void decideDisplayMode() {
+        mPlayer.setTexture(getSurfaceTextureInstance());
+    }
+
+    // Normally called immediately after setVideoURI. But for full screen,
+    // this should be after surface holder created
+    @Override
+    public void prepareDataAndDisplayMode(HTML5VideoViewProxy proxy) {
+        super.prepareDataAndDisplayMode(proxy);
+        setFrameAvailableListener(proxy);
+    }
+
+    // Pause the play and update the play/pause button
+    @Override
+    public void pauseAndDispatch(HTML5VideoViewProxy proxy) {
+        super.pauseAndDispatch(proxy);
+    }
+
+    // Inline Video specific FUNCTIONS:
+
+    @Override
+    public SurfaceTexture getSurfaceTexture() {
+        return mSurfaceTexture;
+    }
+
+    @Override
+    public void deleteSurfaceTexture() {
+        mSurfaceTexture = null;
+        return;
+    }
+
+    // SurfaceTexture is a singleton here , too
+    private SurfaceTexture getSurfaceTextureInstance() {
+        // Create the surface texture.
+        if (mSurfaceTexture == null)
+        {
+            mTextureNames = new int[1];
+            GLES20.glGenTextures(1, mTextureNames, 0);
+            mSurfaceTexture = new SurfaceTexture(mTextureNames[0]);
+        }
+        return mSurfaceTexture;
+    }
+
+    @Override
+    public int getTextureName() {
+        return mTextureNames[0];
+    }
+
+    private void setFrameAvailableListener(SurfaceTexture.OnFrameAvailableListener l) {
+        mSurfaceTexture.setOnFrameAvailableListener(l);
+    }
+
+}
diff --git a/core/java/android/webkit/HTML5VideoView.java b/core/java/android/webkit/HTML5VideoView.java
new file mode 100644
index 0000000..8ea73b5
--- /dev/null
+++ b/core/java/android/webkit/HTML5VideoView.java
@@ -0,0 +1,295 @@
+
+package android.webkit;
+
+import android.graphics.SurfaceTexture;
+import android.media.MediaPlayer;
+import android.util.Log;
+import android.view.SurfaceView;
+import android.webkit.HTML5VideoViewProxy;
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Timer;
+import java.util.TimerTask;
+
+/**
+ * @hide This is only used by the browser
+ */
+public class HTML5VideoView implements MediaPlayer.OnPreparedListener{
+
+    protected static final String LOGTAG = "HTML5VideoView";
+
+    protected static final String COOKIE = "Cookie";
+    protected static final String HIDE_URL_LOGS = "x-hide-urls-from-log";
+
+    // For handling the seekTo before prepared, we need to know whether or not
+    // the video is prepared. Therefore, we differentiate the state between
+    // prepared and not prepared.
+    // When the video is not prepared, we will have to save the seekTo time,
+    // and use it when prepared to play.
+    // NOTE: these values are in sync with VideoLayerAndroid.h in webkit side.
+    // Please keep them in sync when changed.
+    static final int STATE_INITIALIZED        = 0;
+    static final int STATE_NOTPREPARED        = 1;
+    static final int STATE_PREPARED           = 2;
+    static final int STATE_PLAYING            = 3;
+    protected int mCurrentState;
+
+    protected HTML5VideoViewProxy mProxy;
+
+    // Save the seek time when not prepared. This can happen when switching
+    // video besides initial load.
+    protected int mSaveSeekTime;
+
+    // This is used to find the VideoLayer on the native side.
+    protected int mVideoLayerId;
+
+    // Every video will have one MediaPlayer. Given the fact we only have one
+    // SurfaceTexture, there is only one MediaPlayer in action. Every time we
+    // switch videos, a new instance of MediaPlayer will be created in reset().
+    // Switching between inline and full screen will also create a new instance.
+    protected MediaPlayer mPlayer;
+
+    // This will be set up every time we create the Video View object.
+    // Set to true only when switching into full screen while playing
+    protected boolean mAutostart;
+
+    // We need to save such info.
+    protected String mUri;
+    protected Map<String, String> mHeaders;
+
+    // The timer for timeupate events.
+    // See http://www.whatwg.org/specs/web-apps/current-work/#event-media-timeupdate
+    protected static Timer mTimer;
+
+    // The spec says the timer should fire every 250 ms or less.
+    private static final int TIMEUPDATE_PERIOD = 250;  // ms
+
+    protected boolean mPauseDuringPreparing;
+    // common Video control FUNCTIONS:
+    public void start() {
+        if (mCurrentState == STATE_PREPARED) {
+            // When replaying the same video, there is no onPrepared call.
+            // Therefore, the timer should be set up here.
+            if (mTimer == null)
+            {
+                mTimer = new Timer();
+                mTimer.schedule(new TimeupdateTask(mProxy), TIMEUPDATE_PERIOD,
+                        TIMEUPDATE_PERIOD);
+            }
+            mPlayer.start();
+        }
+    }
+
+    public void pause() {
+        if (mCurrentState == STATE_PREPARED && mPlayer.isPlaying()) {
+            mPlayer.pause();
+        } else if (mCurrentState == STATE_NOTPREPARED) {
+            mPauseDuringPreparing = true;
+        }
+        // Delete the Timer to stop it since there is no stop call.
+        if (mTimer != null) {
+            mTimer.purge();
+            mTimer.cancel();
+            mTimer = null;
+        }
+    }
+
+    public int getDuration() {
+        if (mCurrentState == STATE_PREPARED) {
+            return mPlayer.getDuration();
+        } else {
+            return -1;
+        }
+    }
+
+    public int getCurrentPosition() {
+        if (mCurrentState == STATE_PREPARED) {
+            return mPlayer.getCurrentPosition();
+        }
+        return 0;
+    }
+
+    public void seekTo(int pos) {
+        if (mCurrentState == STATE_PREPARED)
+            mPlayer.seekTo(pos);
+        else
+            mSaveSeekTime = pos;
+    }
+
+    public boolean isPlaying() {
+        return mPlayer.isPlaying();
+    }
+
+    public void release() {
+        mPlayer.release();
+    }
+
+    public void stopPlayback() {
+        if (mCurrentState == STATE_PREPARED) {
+            mPlayer.stop();
+        }
+    }
+
+    public boolean getAutostart() {
+        return mAutostart;
+    }
+
+    public boolean getPauseDuringPreparing() {
+        return mPauseDuringPreparing;
+    }
+
+    // Every time we start a new Video, we create a VideoView and a MediaPlayer
+    public void init(int videoLayerId, int position, boolean autoStart) {
+        mPlayer = new MediaPlayer();
+        mCurrentState = STATE_INITIALIZED;
+        mProxy = null;
+        mVideoLayerId = videoLayerId;
+        mSaveSeekTime = position;
+        mAutostart = autoStart;
+        mTimer = null;
+        mPauseDuringPreparing = false;
+    }
+
+    protected HTML5VideoView() {
+    }
+
+    protected static Map<String, String> generateHeaders(String url,
+            HTML5VideoViewProxy proxy) {
+        boolean isPrivate = proxy.getWebView().isPrivateBrowsingEnabled();
+        String cookieValue = CookieManager.getInstance().getCookie(url, isPrivate);
+        Map<String, String> headers = new HashMap<String, String>();
+        if (cookieValue != null) {
+            headers.put(COOKIE, cookieValue);
+        }
+        if (isPrivate) {
+            headers.put(HIDE_URL_LOGS, "true");
+        }
+
+        return headers;
+    }
+
+    public void setVideoURI(String uri, HTML5VideoViewProxy proxy) {
+        // When switching players, surface texture will be reused.
+        mUri = uri;
+        mHeaders = generateHeaders(uri, proxy);
+    }
+
+    // Listeners setup FUNCTIONS:
+    public void setOnCompletionListener(HTML5VideoViewProxy proxy) {
+        mPlayer.setOnCompletionListener(proxy);
+    }
+
+    public void setOnErrorListener(HTML5VideoViewProxy proxy) {
+        mPlayer.setOnErrorListener(proxy);
+    }
+
+    public void setOnPreparedListener(HTML5VideoViewProxy proxy) {
+        mProxy = proxy;
+        mPlayer.setOnPreparedListener(this);
+    }
+
+    // Normally called immediately after setVideoURI. But for full screen,
+    // this should be after surface holder created
+    public void prepareDataAndDisplayMode(HTML5VideoViewProxy proxy) {
+        // SurfaceTexture will be created lazily here for inline mode
+        decideDisplayMode();
+
+        setOnCompletionListener(proxy);
+        setOnPreparedListener(proxy);
+        setOnErrorListener(proxy);
+
+        // When there is exception, we could just bail out silently.
+        // No Video will be played though. Write the stack for debug
+        try {
+            mPlayer.setDataSource(mUri, mHeaders);
+            mPlayer.prepareAsync();
+        } catch (IllegalArgumentException e) {
+            e.printStackTrace();
+        } catch (IllegalStateException e) {
+            e.printStackTrace();
+        } catch (IOException e) {
+            e.printStackTrace();
+        }
+        mCurrentState = STATE_NOTPREPARED;
+    }
+
+
+    // Common code
+    public int getVideoLayerId() {
+        return mVideoLayerId;
+    }
+
+
+    public int getCurrentState() {
+        if (mPlayer.isPlaying()) {
+            return STATE_PLAYING;
+        } else {
+            return mCurrentState;
+        }
+    }
+
+    private static final class TimeupdateTask extends TimerTask {
+        private HTML5VideoViewProxy mProxy;
+
+        public TimeupdateTask(HTML5VideoViewProxy proxy) {
+            mProxy = proxy;
+        }
+
+        @Override
+        public void run() {
+            mProxy.onTimeupdate();
+        }
+    }
+
+    @Override
+    public void onPrepared(MediaPlayer mp) {
+        mCurrentState = STATE_PREPARED;
+        seekTo(mSaveSeekTime);
+        if (mProxy != null) {
+            mProxy.onPrepared(mp);
+        }
+        if (mPauseDuringPreparing) {
+            pauseAndDispatch(mProxy);
+            mPauseDuringPreparing = false;
+        }
+    }
+
+    // Pause the play and update the play/pause button
+    public void pauseAndDispatch(HTML5VideoViewProxy proxy) {
+        pause();
+        if (proxy != null) {
+            proxy.dispatchOnPaused();
+        }
+    }
+
+    // Below are functions that are different implementation on inline and full-
+    // screen mode. Some are specific to one type, but currently are called
+    // directly from the proxy.
+    public void enterFullScreenVideoState(int layerId,
+            HTML5VideoViewProxy proxy, WebView webView) {
+    }
+
+    public boolean isFullScreenMode() {
+        return false;
+    }
+
+    public void decideDisplayMode() {
+    }
+
+    public boolean getReadyToUseSurfTex() {
+        return false;
+    }
+
+    public SurfaceTexture getSurfaceTexture() {
+        return null;
+    }
+
+    public void deleteSurfaceTexture() {
+    }
+
+    public int getTextureName() {
+        return 0;
+    }
+
+}
diff --git a/core/java/android/webkit/HTML5VideoViewProxy.java b/core/java/android/webkit/HTML5VideoViewProxy.java
index 85763da..094566f 100644
--- a/core/java/android/webkit/HTML5VideoViewProxy.java
+++ b/core/java/android/webkit/HTML5VideoViewProxy.java
@@ -19,30 +19,18 @@
 import android.content.Context;
 import android.graphics.Bitmap;
 import android.graphics.BitmapFactory;
+import android.graphics.SurfaceTexture;
 import android.media.MediaPlayer;
-import android.media.MediaPlayer.OnPreparedListener;
-import android.media.MediaPlayer.OnCompletionListener;
-import android.media.MediaPlayer.OnErrorListener;
 import android.net.http.EventHandler;
 import android.net.http.Headers;
 import android.net.http.RequestHandle;
 import android.net.http.RequestQueue;
 import android.net.http.SslCertificate;
 import android.net.http.SslError;
-import android.net.Uri;
-import android.os.Bundle;
 import android.os.Handler;
 import android.os.Looper;
 import android.os.Message;
 import android.util.Log;
-import android.view.MotionEvent;
-import android.view.Gravity;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.AbsoluteLayout;
-import android.widget.FrameLayout;
-import android.widget.MediaController;
-import android.widget.VideoView;
 
 import java.io.ByteArrayOutputStream;
 import java.io.IOException;
@@ -50,8 +38,6 @@
 import java.net.URL;
 import java.util.HashMap;
 import java.util.Map;
-import java.util.Timer;
-import java.util.TimerTask;
 
 /**
  * <p>Proxy for HTML5 video views.
@@ -59,7 +45,8 @@
 class HTML5VideoViewProxy extends Handler
                           implements MediaPlayer.OnPreparedListener,
                           MediaPlayer.OnCompletionListener,
-                          MediaPlayer.OnErrorListener {
+                          MediaPlayer.OnErrorListener,
+                          SurfaceTexture.OnFrameAvailableListener {
     // Logging tag.
     private static final String LOGTAG = "HTML5VideoViewProxy";
 
@@ -76,9 +63,6 @@
     private static final int POSTER_FETCHED    = 202;
     private static final int PAUSED            = 203;
 
-    private static final String COOKIE = "Cookie";
-    private static final String HIDE_URL_LOGS = "x-hide-urls-from-log";
-
     // Timer thread -> UI thread
     private static final int TIMEUPDATE = 300;
 
@@ -101,152 +85,160 @@
         private static HTML5VideoViewProxy mCurrentProxy;
         // The VideoView instance. This is a singleton for now, at least until
         // http://b/issue?id=1973663 is fixed.
-        private static VideoView mVideoView;
-        // The progress view.
-        private static View mProgressView;
-        // The container for the progress view and video view
-        private static FrameLayout mLayout;
-        // The timer for timeupate events.
-        // See http://www.whatwg.org/specs/web-apps/current-work/#event-media-timeupdate
-        private static Timer mTimer;
-        private static final class TimeupdateTask extends TimerTask {
-            private HTML5VideoViewProxy mProxy;
+        private static HTML5VideoView mHTML5VideoView;
 
-            public TimeupdateTask(HTML5VideoViewProxy proxy) {
-                mProxy = proxy;
-            }
+        private static boolean isVideoSelfEnded = false;
+        // By using the baseLayer and the current video Layer ID, we can
+        // identify the exact layer on the UI thread to use the SurfaceTexture.
+        private static int mBaseLayer = 0;
 
-            public void run() {
-                mProxy.onTimeupdate();
+        // Every time webView setBaseLayer, this will be called.
+        // When we found the Video layer, then we set the Surface Texture to it.
+        // Otherwise, we may want to delete the Surface Texture to save memory.
+        public static void setBaseLayer(int layer) {
+            // Don't do this for full screen mode.
+            if (mHTML5VideoView != null
+                    && !mHTML5VideoView.isFullScreenMode()) {
+                mBaseLayer = layer;
+                SurfaceTexture surfTexture = mHTML5VideoView.getSurfaceTexture();
+                int textureName = mHTML5VideoView.getTextureName();
+
+                int currentVideoLayerId = mHTML5VideoView.getVideoLayerId();
+                if (layer != 0 && surfTexture != null && currentVideoLayerId != -1) {
+                    int playerState = mHTML5VideoView.getCurrentState();
+                    boolean foundInTree = nativeSendSurfaceTexture(surfTexture,
+                            layer, currentVideoLayerId, textureName,
+                            playerState);
+                    if (playerState == HTML5VideoView.STATE_PREPARED
+                            && !foundInTree) {
+                        mHTML5VideoView.pauseAndDispatch(mCurrentProxy);
+                        mHTML5VideoView.deleteSurfaceTexture();
+                    }
+                }
             }
         }
-        // The spec says the timer should fire every 250 ms or less.
-        private static final int TIMEUPDATE_PERIOD = 250;  // ms
-        static boolean isVideoSelfEnded = false;
 
-        private static final WebChromeClient.CustomViewCallback mCallback =
-            new WebChromeClient.CustomViewCallback() {
-                public void onCustomViewHidden() {
-                    // At this point the videoview is pretty much destroyed.
-                    // It listens to SurfaceHolder.Callback.SurfaceDestroyed event
-                    // which happens when the video view is detached from its parent
-                    // view. This happens in the WebChromeClient before this method
-                    // is invoked.
-                    mTimer.cancel();
-                    mTimer = null;
-                    if (mVideoView.isPlaying()) {
-                        mVideoView.stopPlayback();
+        // When a WebView is paused, we also want to pause the video in it.
+        public static void pauseAndDispatch() {
+            if (mHTML5VideoView != null) {
+                mHTML5VideoView.pauseAndDispatch(mCurrentProxy);
+                // When switching out, clean the video content on the old page
+                // by telling the layer not readyToUseSurfTex.
+                setBaseLayer(mBaseLayer);
+            }
+        }
+
+        public static void enterFullScreenVideo(int layerId, String url,
+                HTML5VideoViewProxy proxy, WebView webView) {
+                // Save the inline video info and inherit it in the full screen
+                int savePosition = 0;
+                boolean savedIsPlaying = false;
+                if (mHTML5VideoView != null) {
+                    // If we are playing the same video, then it is better to
+                    // save the current position.
+                    if (layerId == mHTML5VideoView.getVideoLayerId()) {
+                        savePosition = mHTML5VideoView.getCurrentPosition();
+                        savedIsPlaying = mHTML5VideoView.isPlaying();
                     }
-                    if (isVideoSelfEnded)
-                        mCurrentProxy.dispatchOnEnded();
-                    else
-                        mCurrentProxy.dispatchOnPaused();
-
-                    // Re enable plugin views.
-                    mCurrentProxy.getWebView().getViewManager().showAll();
-
-                    isVideoSelfEnded = false;
-                    mCurrentProxy = null;
-                    mLayout.removeView(mVideoView);
-                    mVideoView = null;
-                    if (mProgressView != null) {
-                        mLayout.removeView(mProgressView);
-                        mProgressView = null;
-                    }
-                    mLayout = null;
+                    mHTML5VideoView.pauseAndDispatch(mCurrentProxy);
+                    mHTML5VideoView.release();
                 }
-            };
+                mHTML5VideoView = new HTML5VideoFullScreen(proxy.getContext(),
+                        layerId, savePosition, savedIsPlaying);
+                mCurrentProxy = proxy;
 
+                mHTML5VideoView.setVideoURI(url, mCurrentProxy);
+
+                mHTML5VideoView.enterFullScreenVideoState(layerId, proxy, webView);
+        }
+
+        // This is on the UI thread.
+        // When native tell Java to play, we need to check whether or not it is
+        // still the same video by using videoLayerId and treat it differently.
         public static void play(String url, int time, HTML5VideoViewProxy proxy,
-                WebChromeClient client) {
-            if (mCurrentProxy == proxy) {
-                if (!mVideoView.isPlaying()) {
-                    mVideoView.start();
+                WebChromeClient client, int videoLayerId) {
+            int currentVideoLayerId = -1;
+            boolean backFromFullScreenMode = false;
+
+            if (mHTML5VideoView != null) {
+                currentVideoLayerId = mHTML5VideoView.getVideoLayerId();
+                if (mHTML5VideoView instanceof HTML5VideoFullScreen) {
+                    backFromFullScreenMode = true;
                 }
-                return;
             }
 
-            if (mCurrentProxy != null) {
-                // Some other video is already playing. Notify the caller that its playback ended.
+            if (backFromFullScreenMode
+                ||  currentVideoLayerId != videoLayerId
+                || mHTML5VideoView.getSurfaceTexture() == null) {
+                // Here, we handle the case when switching to a new video,
+                // either inside a WebView or across WebViews
+                // For switching videos within a WebView or across the WebView,
+                // we need to pause the old one and re-create a new media player
+                // inside the HTML5VideoView.
+                if (mHTML5VideoView != null) {
+                    mHTML5VideoView.pauseAndDispatch(mCurrentProxy);
+                    // release the media player to avoid finalize error
+                    mHTML5VideoView.release();
+                }
+                mCurrentProxy = proxy;
+                mHTML5VideoView = new HTML5VideoInline(videoLayerId, time, false);
+
+                mHTML5VideoView.setVideoURI(url, mCurrentProxy);
+                mHTML5VideoView.prepareDataAndDisplayMode(proxy);
+            } else if (mCurrentProxy == proxy) {
+                // Here, we handle the case when we keep playing with one video
+                if (!mHTML5VideoView.isPlaying()) {
+                    mHTML5VideoView.seekTo(time);
+                    mHTML5VideoView.start();
+                }
+            } else if (mCurrentProxy != null) {
+                // Some other video is already playing. Notify the caller that
+                // its playback ended.
                 proxy.dispatchOnEnded();
-                return;
             }
-
-            mCurrentProxy = proxy;
-            // Create a FrameLayout that will contain the VideoView and the
-            // progress view (if any).
-            mLayout = new FrameLayout(proxy.getContext());
-            FrameLayout.LayoutParams layoutParams = new FrameLayout.LayoutParams(
-                    ViewGroup.LayoutParams.WRAP_CONTENT,
-                    ViewGroup.LayoutParams.WRAP_CONTENT,
-                    Gravity.CENTER);
-            mVideoView = new VideoView(proxy.getContext());
-            mVideoView.setWillNotDraw(false);
-            mVideoView.setMediaController(new MediaController(proxy.getContext()));
-
-            boolean isPrivate = mCurrentProxy.getWebView().isPrivateBrowsingEnabled();
-            String cookieValue = CookieManager.getInstance().getCookie(url, isPrivate);
-            Map<String, String> headers = new HashMap<String, String>();
-            if (cookieValue != null) {
-                headers.put(COOKIE, cookieValue);
-            }
-            if (isPrivate) {
-                headers.put(HIDE_URL_LOGS, "true");
-            }
-
-            mVideoView.setVideoURI(Uri.parse(url), headers);
-            mVideoView.setOnCompletionListener(proxy);
-            mVideoView.setOnPreparedListener(proxy);
-            mVideoView.setOnErrorListener(proxy);
-            mVideoView.seekTo(time);
-            mLayout.addView(mVideoView, layoutParams);
-            mProgressView = client.getVideoLoadingProgressView();
-            if (mProgressView != null) {
-                mLayout.addView(mProgressView, layoutParams);
-                mProgressView.setVisibility(View.VISIBLE);
-            }
-            mLayout.setVisibility(View.VISIBLE);
-            mTimer = new Timer();
-            mVideoView.start();
-            client.onShowCustomView(mLayout, mCallback);
-            // Plugins like Flash will draw over the video so hide
-            // them while we're playing.
-            mCurrentProxy.getWebView().getViewManager().hideAll();
         }
 
         public static boolean isPlaying(HTML5VideoViewProxy proxy) {
-            return (mCurrentProxy == proxy && mVideoView != null && mVideoView.isPlaying());
+            return (mCurrentProxy == proxy && mHTML5VideoView != null
+                    && mHTML5VideoView.isPlaying());
         }
 
         public static int getCurrentPosition() {
             int currentPosMs = 0;
-            if (mVideoView != null) {
-                currentPosMs = mVideoView.getCurrentPosition();
+            if (mHTML5VideoView != null) {
+                currentPosMs = mHTML5VideoView.getCurrentPosition();
             }
             return currentPosMs;
         }
 
         public static void seek(int time, HTML5VideoViewProxy proxy) {
-            if (mCurrentProxy == proxy && time >= 0 && mVideoView != null) {
-                mVideoView.seekTo(time);
+            if (mCurrentProxy == proxy && time >= 0 && mHTML5VideoView != null) {
+                mHTML5VideoView.seekTo(time);
             }
         }
 
         public static void pause(HTML5VideoViewProxy proxy) {
-            if (mCurrentProxy == proxy && mVideoView != null) {
-                mVideoView.pause();
-                mTimer.purge();
+            if (mCurrentProxy == proxy && mHTML5VideoView != null) {
+                mHTML5VideoView.pause();
             }
         }
 
         public static void onPrepared() {
-            if (mProgressView == null || mLayout == null) {
-                return;
+            // The VideoView will decide whether to really kick off to play.
+            mHTML5VideoView.start();
+            if (mBaseLayer != 0) {
+                setBaseLayer(mBaseLayer);
             }
-            mTimer.schedule(new TimeupdateTask(mCurrentProxy), TIMEUPDATE_PERIOD, TIMEUPDATE_PERIOD);
-            mProgressView.setVisibility(View.GONE);
-            mLayout.removeView(mProgressView);
-            mProgressView = null;
+        }
+
+        public static void end() {
+            if (mCurrentProxy != null) {
+                if (isVideoSelfEnded)
+                    mCurrentProxy.dispatchOnEnded();
+                else
+                    mCurrentProxy.dispatchOnPaused();
+            }
+            isVideoSelfEnded = false;
         }
     }
 
@@ -292,6 +284,14 @@
         sendMessage(obtainMessage(TIMEUPDATE));
     }
 
+    // When there is a frame ready from surface texture, we should tell WebView
+    // to refresh.
+    @Override
+    public void onFrameAvailable(SurfaceTexture surfaceTexture) {
+        // TODO: This should support partial invalidation too.
+        mWebView.invalidate();
+    }
+
     // Handler for the messages from WebCore or Timer thread to the UI thread.
     @Override
     public void handleMessage(Message msg) {
@@ -300,8 +300,9 @@
             case PLAY: {
                 String url = (String) msg.obj;
                 WebChromeClient client = mWebView.getWebChromeClient();
+                int videoLayerID = msg.arg1;
                 if (client != null) {
-                    VideoPlayer.play(url, mSeekPosition, this, client);
+                    VideoPlayer.play(url, mSeekPosition, this, client, videoLayerID);
                 }
                 break;
             }
@@ -318,6 +319,8 @@
             case ENDED:
                 if (msg.arg1 == 1)
                     VideoPlayer.isVideoSelfEnded = true;
+                VideoPlayer.end();
+                break;
             case ERROR: {
                 WebChromeClient client = mWebView.getWebChromeClient();
                 if (client != null) {
@@ -500,6 +503,10 @@
         super(Looper.getMainLooper());
         // Save the WebView object.
         mWebView = webView;
+        // Pass Proxy into webview, such that every time we have a setBaseLayer
+        // call, we tell this Proxy to call the native to update the layer tree
+        // for the Video Layer's surface texture info
+        mWebView.setHTML5VideoViewProxy(this);
         // Save the native ptr
         mNativePointer = nativePtr;
         // create the message handler for this thread
@@ -565,7 +572,7 @@
      * Play a video stream.
      * @param url is the URL of the video stream.
      */
-    public void play(String url, int position) {
+    public void play(String url, int position, int videoLayerID) {
         if (url == null) {
             return;
         }
@@ -573,8 +580,8 @@
         if (position > 0) {
             seek(position);
         }
-
         Message message = obtainMessage(PLAY);
+        message.arg1 = videoLayerID;
         message.obj = url;
         sendMessage(message);
     }
@@ -628,6 +635,19 @@
         mPosterDownloader.start();
     }
 
+    // These three function are called from UI thread only by WebView.
+    public void setBaseLayer(int layer) {
+        VideoPlayer.setBaseLayer(layer);
+    }
+
+    public void pauseAndDispatch() {
+        VideoPlayer.pauseAndDispatch();
+    }
+
+    public void enterFullScreenVideo(int layerId, String url) {
+        VideoPlayer.enterFullScreenVideo(layerId, url, this, mWebView);
+    }
+
     /**
      * The factory for HTML5VideoViewProxy instances.
      * @param webViewCore is the WebViewCore that is requesting the proxy.
@@ -647,4 +667,7 @@
     private native void nativeOnPaused(int nativePointer);
     private native void nativeOnPosterFetched(Bitmap poster, int nativePointer);
     private native void nativeOnTimeupdate(int position, int nativePointer);
+    private native static boolean nativeSendSurfaceTexture(SurfaceTexture texture,
+            int baseLayer, int videoLayerId, int textureName,
+            int playerState);
 }
diff --git a/core/java/android/webkit/WebTextView.java b/core/java/android/webkit/WebTextView.java
index 47c69be..7f4f103 100644
--- a/core/java/android/webkit/WebTextView.java
+++ b/core/java/android/webkit/WebTextView.java
@@ -26,14 +26,15 @@
 import android.graphics.PixelFormat;
 import android.graphics.Rect;
 import android.graphics.drawable.Drawable;
+import android.os.Bundle;
 import android.os.Handler;
 import android.os.Message;
+import android.os.ResultReceiver;
 import android.text.BoringLayout.Metrics;
 import android.text.DynamicLayout;
 import android.text.Editable;
 import android.text.InputFilter;
 import android.text.Layout;
-import android.text.Layout.Alignment;
 import android.text.Selection;
 import android.text.Spannable;
 import android.text.TextPaint;
@@ -50,8 +51,8 @@
 import android.view.ViewConfiguration;
 import android.view.ViewGroup;
 import android.view.inputmethod.EditorInfo;
-import android.view.inputmethod.InputMethodManager;
 import android.view.inputmethod.InputConnection;
+import android.view.inputmethod.InputMethodManager;
 import android.widget.AbsoluteLayout.LayoutParams;
 import android.widget.AdapterView;
 import android.widget.ArrayAdapter;
@@ -136,6 +137,23 @@
     // Used to determine whether onFocusChanged was called as a result of
     // calling remove().
     private boolean mInsideRemove;
+    private class MyResultReceiver extends ResultReceiver {
+        @Override
+        protected void onReceiveResult(int resultCode, Bundle resultData) {
+            if (resultCode == InputMethodManager.RESULT_SHOWN
+                    && mWebView != null) {
+                mWebView.revealSelection();
+            }
+        }
+
+        /**
+         * @param handler
+         */
+        public MyResultReceiver(Handler handler) {
+            super(handler);
+        }
+    }
+    private MyResultReceiver mReceiver;
 
     // Types used with setType.  Keep in sync with CachedInput.h
     private static final int NORMAL_TEXT_FIELD = 0;
@@ -184,7 +202,7 @@
                 }
             }
         };
-
+        mReceiver = new MyResultReceiver(mHandler);
     }
 
     public void setAutoFillable(int queryId) {
@@ -362,6 +380,8 @@
         }
     }
 
+    /* package */ ResultReceiver getResultReceiver() { return mReceiver; }
+
     /**
      *  Determine whether this WebTextView currently represents the node
      *  represented by ptr.
@@ -415,7 +435,7 @@
             }
             CharSequence text = getText();
             // Copy from the existing Layout.
-            mLayout = new WebTextViewLayout(text, text, getPaint(), w,
+            mLayout = new WebTextViewLayout(text, text, getPaint(), mLayout.getWidth(),
                     mLayout.getAlignment(), mLayout.getSpacingMultiplier(),
                     mLayout.getSpacingAdd(), false, null, ellipsisWidth,
                     lineHeight);
@@ -495,7 +515,6 @@
             int candEnd = EditableInputConnection.getComposingSpanEnd(sp);
             imm.updateSelection(this, selStart, selEnd, candStart, candEnd);
         }
-        updateCursorControllerPositions();
     }
 
     @Override
diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java
index 975f815..056650c 100644
--- a/core/java/android/webkit/WebView.java
+++ b/core/java/android/webkit/WebView.java
@@ -27,6 +27,7 @@
 import android.content.IntentFilter;
 import android.content.pm.PackageInfo;
 import android.content.pm.PackageManager;
+import android.content.res.AssetManager;
 import android.content.res.Configuration;
 import android.database.DataSetObserver;
 import android.graphics.Bitmap;
@@ -43,6 +44,7 @@
 import android.graphics.Rect;
 import android.graphics.RectF;
 import android.graphics.Region;
+import android.graphics.SurfaceTexture;
 import android.graphics.Shader;
 import android.graphics.drawable.Drawable;
 import android.net.Proxy;
@@ -351,7 +353,8 @@
 
     private ZoomManager mZoomManager;
 
-    private Rect mGLRectViewport = new Rect();
+    private final Rect mGLRectViewport = new Rect();
+    private final Rect mViewRectViewport = new Rect();
     private boolean mGLViewportEmpty = false;
 
     /**
@@ -496,15 +499,6 @@
     // default is not set, the UI will continue handle them.
     private boolean mDeferTouchProcess;
 
-    // Currently, multi-touch events are sent to WebKit first then back to
-    // WebView while single-touch events are handled in WebView first.
-    // So there is a chance that a single-touch move event is handled in WebView
-    // before multi-touch events are finished.
-    // if mIsHandlingMultiTouch is true, which means multi-touch event handling
-    // is not finished, then any single-touch move event will be skipped.
-    // FIXME: send single-touch events to WebKit first then back to WebView.
-    private boolean mIsHandlingMultiTouch = false;
-
     // to avoid interfering with the current touch events, track them
     // separately. Currently no snapping or fling in the deferred process mode
     private int mDeferTouchMode = TOUCH_DONE_MODE;
@@ -616,6 +610,10 @@
     private int mTouchHighlightX;
     private int mTouchHighlightY;
 
+    // Basically this proxy is used to tell the Video to update layer tree at
+    // SetBaseLayer time and to pause when WebView paused.
+    private HTML5VideoViewProxy mHTML5VideoViewProxy;
+
     /*
      * Private message ids
      */
@@ -674,6 +672,7 @@
 
     static final int SELECT_AT                          = 135;
     static final int SCREEN_ON                          = 136;
+    static final int ENTER_FULLSCREEN_VIDEO             = 137;
 
     private static final int FIRST_PACKAGE_MSG_ID = SCROLL_TO_MSG_ID;
     private static final int LAST_PACKAGE_MSG_ID = SET_TOUCH_HIGHLIGHT_RECTS;
@@ -728,7 +727,8 @@
         "SET_AUTOFILLABLE", //               = 133;
         "AUTOFILL_COMPLETE", //              = 134;
         "SELECT_AT", //                      = 135;
-        "SCREEN_ON" //                       = 136;
+        "SCREEN_ON", //                      = 136;
+        "ENTER_FULLSCREEN_VIDEO" //          = 137;
     };
 
     // If the site doesn't use the viewport meta tag to specify the viewport,
@@ -847,6 +847,9 @@
     private Rect mScrollingLayerBounds = new Rect();
     private boolean mSentAutoScrollMessage = false;
 
+    // used for serializing asynchronously handled touch events.
+    private final TouchEventQueue mTouchEventQueue = new TouchEventQueue();
+
     // Used to notify listeners of a new picture.
     private PictureListener mPictureListener;
     /**
@@ -1128,10 +1131,13 @@
             protected Set<String> doInBackground(Void... unused) {
                 Set<String> installedPackages = new HashSet<String>();
                 PackageManager pm = mContext.getPackageManager();
-                List<PackageInfo> packages = pm.getInstalledPackages(0);
-                for (PackageInfo p : packages) {
-                    if (sGoogleApps.contains(p.packageName)) {
-                        installedPackages.add(p.packageName);
+                for (String name : sGoogleApps) {
+                    try {
+                        PackageInfo pInfo = pm.getPackageInfo(name,
+                                PackageManager.GET_ACTIVITIES | PackageManager.GET_SERVICES);
+                        installedPackages.add(name);
+                    } catch(PackageManager.NameNotFoundException e) {
+                        // package not found
                     }
                 }
                 return installedPackages;
@@ -1182,6 +1188,7 @@
         // Initially use a size of two, since the user is likely to only hold
         // down two keys at a time (shift + another key)
         mKeysPressed = new Vector<Integer>(2);
+        mHTML5VideoViewProxy = null ;
     }
 
     /**
@@ -1349,10 +1356,10 @@
         return mTitleBar != null ? mTitleBar.getHeight() : 0;
     }
 
-    /*
+    /**
      * Return the amount of the titlebarview (if any) that is visible
      *
-     * @hide
+     * @deprecated This method is now obsolete.
      */
     public int getVisibleTitleHeight() {
         // need to restrict mScrollY due to over scroll
@@ -1656,6 +1663,7 @@
 
         mDrawHistory = true;
         mHistoryPicture = p;
+
         mScrollX = sx;
         mScrollY = sy;
         mZoomManager.restoreZoomState(b);
@@ -2095,7 +2103,7 @@
     public void clearView() {
         mContentWidth = 0;
         mContentHeight = 0;
-        setBaseLayer(0, null, false);
+        setBaseLayer(0, null, false, false);
         mWebViewCore.sendMessage(EventHub.CLEAR_CONTENT);
     }
 
@@ -2890,6 +2898,11 @@
         if (!mIsPaused) {
             mIsPaused = true;
             mWebViewCore.sendMessage(EventHub.ON_PAUSE);
+            // We want to pause the current playing video when switching out
+            // from the current WebView/tab.
+            if (mHTML5VideoViewProxy != null) {
+                mHTML5VideoViewProxy.pauseAndDispatch();
+            }
         }
     }
 
@@ -3001,7 +3014,8 @@
     }
 
     /**
-     * Start an ActionMode for finding text in this WebView.
+     * Start an ActionMode for finding text in this WebView.  Only works if this
+     *              WebView is attached to the view system.
      * @param text If non-null, will be the initial text to search for.
      *             Otherwise, the last String searched for in this WebView will
      *             be used to start.
@@ -3011,7 +3025,7 @@
      */
     public boolean showFindDialog(String text, boolean showIme) {
         FindActionModeCallback callback = new FindActionModeCallback(mContext);
-        if (startActionMode(callback) == null) {
+        if (getParent() == null || startActionMode(callback) == null) {
             // Could not start the action mode, so end Find on page
             return false;
         }
@@ -4017,14 +4031,14 @@
         }
     }
 
-    void setBaseLayer(int layer, Rect invalRect, boolean showVisualIndciator) {
+    void setBaseLayer(int layer, Region invalRegion, boolean showVisualIndicator,
+            boolean isPictureAfterFirstLayout) {
         if (mNativeClass == 0)
             return;
-        if (invalRect == null) {
-            Rect rect = new Rect(0, 0, mContentWidth, mContentHeight);
-            nativeSetBaseLayer(layer, rect, showVisualIndciator);
-        } else {
-            nativeSetBaseLayer(layer, invalRect, showVisualIndciator);
+        nativeSetBaseLayer(layer, invalRegion, showVisualIndicator,
+                isPictureAfterFirstLayout);
+        if (mHTML5VideoViewProxy != null) {
+            mHTML5VideoViewProxy.setBaseLayer(layer);
         }
     }
 
@@ -4098,7 +4112,7 @@
         }
         if (animateZoom) {
             mZoomManager.animateZoom(canvas);
-        } else {
+        } else if (!canvas.isHardwareAccelerated()) {
             canvas.scale(mZoomManager.getScale(), mZoomManager.getScale());
         }
 
@@ -4108,8 +4122,11 @@
         if (mNativeClass != 0 && nativeEvaluateLayersAnimations()) {
             UIAnimationsRunning = true;
             // If we have unfinished (or unstarted) animations,
-            // we ask for a repaint.
-            invalidate();
+            // we ask for a repaint. We only need to do this in software
+            // rendering (with hardware rendering we already have a different
+            // method of requesting a repaint)
+            if (!canvas.isHardwareAccelerated())
+                invalidate();
         }
 
         // decide which adornments to draw
@@ -4135,7 +4152,7 @@
 
         if (canvas.isHardwareAccelerated()) {
             int functor = nativeGetDrawGLFunction(mGLViewportEmpty ? null : mGLRectViewport,
-                    getScale(), extras);
+                    mGLViewportEmpty ? null : mViewRectViewport, getScale(), extras);
             ((HardwareCanvas) canvas).callDrawGLFunction(functor);
         } else {
             DrawFilter df = null;
@@ -4265,7 +4282,7 @@
         if (isTextView) {
             rebuildWebTextView();
             if (inEditingMode()) {
-                imm.showSoftInput(mWebTextView, 0);
+                imm.showSoftInput(mWebTextView, 0, mWebTextView.getResultReceiver());
                 if (zoom) {
                     didUpdateWebTextViewDimensions(INTERSECTS_SCREEN);
                 }
@@ -5036,6 +5053,9 @@
      * @hide pending API Council approval.
      */
     public SearchBox getSearchBox() {
+        if ((mWebViewCore == null) || (mWebViewCore.getBrowserFrame() == null)) {
+            return null;
+        }
         return mWebViewCore.getBrowserFrame().getSearchBox();
     }
 
@@ -5062,6 +5082,8 @@
         }
 
         addAccessibilityApisToJavaScript();
+
+        mTouchEventQueue.reset();
     }
 
     @Override
@@ -5234,6 +5256,7 @@
             // Then need to invert the Y axis, just for GL
             View rootView = getRootView();
             int rootViewHeight = rootView.getHeight();
+            mViewRectViewport.set(mGLRectViewport);
             int savedWebViewBottom = mGLRectViewport.bottom;
             mGLRectViewport.bottom = rootViewHeight - mGLRectViewport.top - getVisibleTitleHeight();
             mGLRectViewport.top = rootViewHeight - savedWebViewBottom;
@@ -5241,7 +5264,8 @@
         } else {
             mGLViewportEmpty = true;
         }
-        nativeUpdateDrawGLFunction(mGLViewportEmpty ? null : mGLRectViewport);
+        nativeUpdateDrawGLFunction(mGLViewportEmpty ? null : mGLRectViewport,
+                mGLViewportEmpty ? null : mViewRectViewport);
     }
 
     /**
@@ -5351,7 +5375,8 @@
     private boolean shouldForwardTouchEvent() {
         return mFullScreenHolder != null || (mForwardTouchEvents
                 && !mSelectingText
-                && mPreventDefault != PREVENT_DEFAULT_IGNORE);
+                && mPreventDefault != PREVENT_DEFAULT_IGNORE
+                && mPreventDefault != PREVENT_DEFAULT_NO);
     }
 
     private boolean inFullScreenMode() {
@@ -5413,34 +5438,17 @@
                 + " numPointers=" + ev.getPointerCount());
         }
 
-        int action = ev.getActionMasked();
-        if (ev.getPointerCount() > 1) {  // Multi-touch
-            mIsHandlingMultiTouch = true;
-
-            // If WebKit already showed no interests in this sequence of events,
-            // WebView handles them directly.
-            if (mPreventDefault == PREVENT_DEFAULT_NO) {
-                handleMultiTouchInWebView(ev);
-            } else {
-                passMultiTouchToWebKit(ev);
-            }
-            return true;
+        // If WebKit wasn't interested in this multitouch gesture, enqueue
+        // the event for handling directly rather than making the round trip
+        // to WebKit and back.
+        if (ev.getPointerCount() > 1 && mPreventDefault != PREVENT_DEFAULT_NO) {
+            passMultiTouchToWebKit(ev, mTouchEventQueue.nextTouchSequence());
         } else {
-            final ScaleGestureDetector detector = mZoomManager.getMultiTouchGestureDetector();
-            if (detector != null) {
-                // ScaleGestureDetector needs a consistent event stream to operate properly.
-                // It won't take any action with fewer than two pointers, but it needs to
-                // update internal bookkeeping state.
-                detector.onTouchEvent(ev);
-            }
+            mTouchEventQueue.enqueueTouchEvent(ev);
         }
 
-        // Skip ACTION_MOVE for single touch if it's still handling multi-touch.
-        if (mIsHandlingMultiTouch && action == MotionEvent.ACTION_MOVE) {
-            return false;
-        }
-
-        return handleTouchEventCommon(ev, action, Math.round(ev.getX()), Math.round(ev.getY()));
+        // Since all events are handled asynchronously, we always want the gesture stream.
+        return true;
     }
 
     /*
@@ -5451,7 +5459,6 @@
     private boolean handleTouchEventCommon(MotionEvent ev, int action, int x, int y) {
         long eventTime = ev.getEventTime();
 
-
         // Due to the touch screen edge effect, a touch closer to the edge
         // always snapped to the edge. As getViewWidth() can be different from
         // getWidth() due to the scrollbar, adjusting the point to match
@@ -5468,7 +5475,6 @@
             case MotionEvent.ACTION_DOWN: {
                 mPreventDefault = PREVENT_DEFAULT_NO;
                 mConfirmMove = false;
-                mIsHandlingMultiTouch = false;
                 mInitialHitTestResult = null;
                 if (!mScroller.isFinished()) {
                     // stop the current scroll animation, but if this is
@@ -5556,10 +5562,13 @@
                         ted.mIds[0] = ev.getPointerId(0);
                         ted.mPoints = new Point[1];
                         ted.mPoints[0] = new Point(contentX, contentY);
+                        ted.mPointsInView = new Point[1];
+                        ted.mPointsInView[0] = new Point(x, y);
                         ted.mMetaState = ev.getMetaState();
                         ted.mReprocess = mDeferTouchProcess;
                         ted.mNativeLayer = nativeScrollableLayer(
                                 contentX, contentY, ted.mNativeLayerRect, null);
+                        ted.mSequence = mTouchEventQueue.nextTouchSequence();
                         mWebViewCore.sendMessage(EventHub.TOUCH_EVENT, ted);
                         if (mDeferTouchProcess) {
                             // still needs to set them for compute deltaX/Y
@@ -5602,10 +5611,13 @@
                     ted.mIds[0] = ev.getPointerId(0);
                     ted.mPoints = new Point[1];
                     ted.mPoints[0] = new Point(contentX, contentY);
+                    ted.mPointsInView = new Point[1];
+                    ted.mPointsInView[0] = new Point(x, y);
                     ted.mMetaState = ev.getMetaState();
                     ted.mReprocess = mDeferTouchProcess;
                     ted.mNativeLayer = mScrollingLayer;
                     ted.mNativeLayerRect.set(mScrollingLayerRect);
+                    ted.mSequence = mTouchEventQueue.nextTouchSequence();
                     mWebViewCore.sendMessage(EventHub.TOUCH_EVENT, ted);
                     mLastSentTouchTime = eventTime;
                     if (mDeferTouchProcess) {
@@ -5783,10 +5795,13 @@
                     ted.mAction = action;
                     ted.mPoints = new Point[1];
                     ted.mPoints[0] = new Point(contentX, contentY);
+                    ted.mPointsInView = new Point[1];
+                    ted.mPointsInView[0] = new Point(x, y);
                     ted.mMetaState = ev.getMetaState();
                     ted.mReprocess = mDeferTouchProcess;
                     ted.mNativeLayer = mScrollingLayer;
                     ted.mNativeLayerRect.set(mScrollingLayerRect);
+                    ted.mSequence = mTouchEventQueue.nextTouchSequence();
                     mWebViewCore.sendMessage(EventHub.TOUCH_EVENT, ted);
                 }
                 mLastTouchUpTime = eventTime;
@@ -5804,11 +5819,14 @@
                             ted.mAction = WebViewCore.ACTION_DOUBLETAP;
                             ted.mPoints = new Point[1];
                             ted.mPoints[0] = new Point(contentX, contentY);
+                            ted.mPointsInView = new Point[1];
+                            ted.mPointsInView[0] = new Point(x, y);
                             ted.mMetaState = ev.getMetaState();
                             ted.mReprocess = mDeferTouchProcess;
                             ted.mNativeLayer = nativeScrollableLayer(
                                     contentX, contentY,
                                     ted.mNativeLayerRect, null);
+                            ted.mSequence = mTouchEventQueue.nextTouchSequence();
                             mWebViewCore.sendMessage(EventHub.TOUCH_EVENT, ted);
                         } else if (mPreventDefault != PREVENT_DEFAULT_YES){
                             mZoomManager.handleDoubleTap(mLastTouchX, mLastTouchY);
@@ -5933,28 +5951,34 @@
         return true;
     }
 
-    private void passMultiTouchToWebKit(MotionEvent ev) {
+    private void passMultiTouchToWebKit(MotionEvent ev, long sequence) {
         TouchEventData ted = new TouchEventData();
         ted.mAction = ev.getActionMasked();
         final int count = ev.getPointerCount();
         ted.mIds = new int[count];
         ted.mPoints = new Point[count];
+        ted.mPointsInView = new Point[count];
         for (int c = 0; c < count; c++) {
             ted.mIds[c] = ev.getPointerId(c);
             int x = viewToContentX((int) ev.getX(c) + mScrollX);
             int y = viewToContentY((int) ev.getY(c) + mScrollY);
             ted.mPoints[c] = new Point(x, y);
+            ted.mPointsInView[c] = new Point((int) ev.getX(c), (int) ev.getY(c));
+        }
+        if (ted.mAction == MotionEvent.ACTION_POINTER_DOWN
+            || ted.mAction == MotionEvent.ACTION_POINTER_UP) {
+            ted.mActionIndex = ev.getActionIndex();
         }
         ted.mMetaState = ev.getMetaState();
         ted.mReprocess = true;
         ted.mMotionEvent = MotionEvent.obtain(ev);
+        ted.mSequence = sequence;
         mWebViewCore.sendMessage(EventHub.TOUCH_EVENT, ted);
         cancelLongPress();
         mPrivateHandler.removeMessages(SWITCH_TO_LONGPRESS);
-        mPreventDefault = PREVENT_DEFAULT_IGNORE;
     }
 
-    private void handleMultiTouchInWebView(MotionEvent ev) {
+    void handleMultiTouchInWebView(MotionEvent ev) {
         if (DebugFlags.WEB_VIEW) {
             Log.v(LOGTAG, "multi-touch: " + ev + " at " + ev.getEventTime()
                 + " mTouchMode=" + mTouchMode
@@ -5972,24 +5996,26 @@
         float x = ev.getX();
         float y = ev.getY();
 
-        detector.onTouchEvent(ev);
+        if (mPreventDefault != PREVENT_DEFAULT_YES) {
+            detector.onTouchEvent(ev);
 
-        if (detector.isInProgress()) {
-            if (DebugFlags.WEB_VIEW) {
-                Log.v(LOGTAG, "detector is in progress");
-            }
-            mLastTouchTime = ev.getEventTime();
-            x = detector.getFocusX();
-            y = detector.getFocusY();
+            if (detector.isInProgress()) {
+                if (DebugFlags.WEB_VIEW) {
+                    Log.v(LOGTAG, "detector is in progress");
+                }
+                mLastTouchTime = ev.getEventTime();
+                x = detector.getFocusX();
+                y = detector.getFocusY();
 
-            cancelLongPress();
-            mPrivateHandler.removeMessages(SWITCH_TO_LONGPRESS);
-            if (!mZoomManager.supportsPanDuringZoom()) {
-                return;
-            }
-            mTouchMode = TOUCH_DRAG_MODE;
-            if (mVelocityTracker == null) {
-                mVelocityTracker = VelocityTracker.obtain();
+                cancelLongPress();
+                mPrivateHandler.removeMessages(SWITCH_TO_LONGPRESS);
+                if (!mZoomManager.supportsPanDuringZoom()) {
+                    return;
+                }
+                mTouchMode = TOUCH_DRAG_MODE;
+                if (mVelocityTracker == null) {
+                    mVelocityTracker = VelocityTracker.obtain();
+                }
             }
         }
 
@@ -5997,11 +6023,10 @@
         if (action == MotionEvent.ACTION_POINTER_DOWN) {
             cancelTouch();
             action = MotionEvent.ACTION_DOWN;
-        } else if (action == MotionEvent.ACTION_POINTER_UP) {
+        } else if (action == MotionEvent.ACTION_POINTER_UP && ev.getPointerCount() == 2) {
             // set mLastTouchX/Y to the remaining point
             mLastTouchX = Math.round(x);
             mLastTouchY = Math.round(y);
-            mIsHandlingMultiTouch = false;
         } else if (action == MotionEvent.ACTION_MOVE) {
             // negative x or y indicate it is on the edge, skip it.
             if (x < 0 || y < 0) {
@@ -6016,15 +6041,21 @@
         if (shouldForwardTouchEvent()) {
             if (removeEvents) {
                 mWebViewCore.removeMessages(EventHub.TOUCH_EVENT);
+                mTouchEventQueue.ignoreCurrentlyMissingEvents();
             }
             TouchEventData ted = new TouchEventData();
             ted.mIds = new int[1];
             ted.mIds[0] = 0;
             ted.mPoints = new Point[1];
             ted.mPoints[0] = new Point(x, y);
+            ted.mPointsInView = new Point[1];
+            int viewX = contentToViewX(x) - mScrollX;
+            int viewY = contentToViewY(y) - mScrollY;
+            ted.mPointsInView[0] = new Point(viewX, viewY);
             ted.mAction = MotionEvent.ACTION_CANCEL;
             ted.mNativeLayer = nativeScrollableLayer(
                     x, y, ted.mNativeLayerRect, null);
+            ted.mSequence = mTouchEventQueue.nextTouchSequence();
             mWebViewCore.sendMessage(EventHub.TOUCH_EVENT, ted);
             mPreventDefault = PREVENT_DEFAULT_IGNORE;
         }
@@ -7102,6 +7133,374 @@
         return mWebViewCore;
     }
 
+    /**
+     * Used only by TouchEventQueue to store pending touch events.
+     */
+    private static class QueuedTouch {
+        long mSequence;
+        MotionEvent mEvent; // Optional
+        TouchEventData mTed; // Optional
+
+        QueuedTouch mNext;
+
+        public QueuedTouch set(TouchEventData ted) {
+            mSequence = ted.mSequence;
+            mTed = ted;
+            mEvent = null;
+            mNext = null;
+            return this;
+        }
+
+        public QueuedTouch set(MotionEvent ev, long sequence) {
+            mEvent = MotionEvent.obtain(ev);
+            mSequence = sequence;
+            mTed = null;
+            mNext = null;
+            return this;
+        }
+
+        public QueuedTouch add(QueuedTouch other) {
+            if (other.mSequence < mSequence) {
+                other.mNext = this;
+                return other;
+            }
+
+            QueuedTouch insertAt = this;
+            while (insertAt.mNext != null && insertAt.mNext.mSequence < other.mSequence) {
+                insertAt = insertAt.mNext;
+            }
+            other.mNext = insertAt.mNext;
+            insertAt.mNext = other;
+            return this;
+        }
+    }
+
+    /**
+     * WebView handles touch events asynchronously since some events must be passed to WebKit
+     * for potentially slower processing. TouchEventQueue serializes touch events regardless
+     * of which path they take to ensure that no events are ever processed out of order
+     * by WebView.
+     */
+    private class TouchEventQueue {
+        private long mNextTouchSequence = Long.MIN_VALUE + 1;
+        private long mLastHandledTouchSequence = Long.MIN_VALUE;
+        private long mIgnoreUntilSequence = Long.MIN_VALUE + 1;
+        private QueuedTouch mTouchEventQueue;
+        private QueuedTouch mQueuedTouchRecycleBin;
+        private int mQueuedTouchRecycleCount;
+        private long mLastEventTime = Long.MAX_VALUE;
+        private static final int MAX_RECYCLED_QUEUED_TOUCH = 15;
+
+        // milliseconds until we abandon hope of getting all of a previous gesture
+        private static final int QUEUED_GESTURE_TIMEOUT = 1000;
+
+        private QueuedTouch obtainQueuedTouch() {
+            if (mQueuedTouchRecycleBin != null) {
+                QueuedTouch result = mQueuedTouchRecycleBin;
+                mQueuedTouchRecycleBin = result.mNext;
+                mQueuedTouchRecycleCount--;
+                return result;
+            }
+            return new QueuedTouch();
+        }
+
+        /**
+         * Allow events with any currently missing sequence numbers to be skipped in processing.
+         */
+        public void ignoreCurrentlyMissingEvents() {
+            mIgnoreUntilSequence = mNextTouchSequence;
+        }
+
+        private void recycleQueuedTouch(QueuedTouch qd) {
+            if (mQueuedTouchRecycleCount < MAX_RECYCLED_QUEUED_TOUCH) {
+                qd.mNext = mQueuedTouchRecycleBin;
+                mQueuedTouchRecycleBin = qd;
+                mQueuedTouchRecycleCount++;
+            }
+        }
+
+        /**
+         * Reset the touch event queue. This will dump any pending events
+         * and reset the sequence numbering.
+         */
+        public void reset() {
+            mNextTouchSequence = Long.MIN_VALUE + 1;
+            mLastHandledTouchSequence = Long.MIN_VALUE;
+            mIgnoreUntilSequence = Long.MIN_VALUE + 1;
+            while (mTouchEventQueue != null) {
+                QueuedTouch recycleMe = mTouchEventQueue;
+                mTouchEventQueue = mTouchEventQueue.mNext;
+                recycleQueuedTouch(recycleMe);
+            }
+        }
+
+        /**
+         * Return the next valid sequence number for tagging incoming touch events.
+         * @return The next touch event sequence number
+         */
+        public long nextTouchSequence() {
+            return mNextTouchSequence++;
+        }
+
+        /**
+         * Enqueue a touch event in the form of TouchEventData.
+         * The sequence number will be read from the mSequence field of the argument.
+         *
+         * If the touch event's sequence number is the next in line to be processed, it will
+         * be handled before this method returns. Any subsequent events that have already
+         * been queued will also be processed in their proper order.
+         *
+         * @param ted Touch data to be processed in order.
+         */
+        public void enqueueTouchEvent(TouchEventData ted) {
+            if (ted.mSequence < mLastHandledTouchSequence) {
+                // Stale event and we already moved on; drop it. (Should not be common.)
+                Log.w(LOGTAG, "Stale touch event " + MotionEvent.actionToString(ted.mAction) +
+                        " received from webcore; ignoring");
+                return;
+            }
+
+            if (dropStaleGestures(ted.mMotionEvent, ted.mSequence)) {
+                return;
+            }
+
+            if (mLastHandledTouchSequence + 1 == ted.mSequence) {
+                handleQueuedTouchEventData(ted);
+
+                mLastHandledTouchSequence++;
+
+                // Do we have any more? Run them if so.
+                QueuedTouch qd = mTouchEventQueue;
+                while (qd != null && qd.mSequence == mLastHandledTouchSequence + 1) {
+                    handleQueuedTouch(qd);
+                    QueuedTouch recycleMe = qd;
+                    qd = qd.mNext;
+                    recycleQueuedTouch(recycleMe);
+                    mLastHandledTouchSequence++;
+                }
+                mTouchEventQueue = qd;
+            } else {
+                QueuedTouch qd = obtainQueuedTouch().set(ted);
+                mTouchEventQueue = mTouchEventQueue == null ? qd : mTouchEventQueue.add(qd);
+            }
+        }
+
+        /**
+         * Enqueue a touch event in the form of a MotionEvent from the framework.
+         *
+         * If the touch event's sequence number is the next in line to be processed, it will
+         * be handled before this method returns. Any subsequent events that have already
+         * been queued will also be processed in their proper order.
+         *
+         * @param ev MotionEvent to be processed in order
+         */
+        public void enqueueTouchEvent(MotionEvent ev) {
+            final long sequence = nextTouchSequence();
+
+            if (dropStaleGestures(ev, sequence)) {
+                return;
+            }
+
+            if (mLastHandledTouchSequence + 1 == sequence) {
+                handleQueuedMotionEvent(ev);
+
+                mLastHandledTouchSequence++;
+
+                // Do we have any more? Run them if so.
+                QueuedTouch qd = mTouchEventQueue;
+                while (qd != null && qd.mSequence == mLastHandledTouchSequence + 1) {
+                    handleQueuedTouch(qd);
+                    QueuedTouch recycleMe = qd;
+                    qd = qd.mNext;
+                    recycleQueuedTouch(recycleMe);
+                    mLastHandledTouchSequence++;
+                }
+                mTouchEventQueue = qd;
+            } else {
+                QueuedTouch qd = obtainQueuedTouch().set(ev, sequence);
+                mTouchEventQueue = mTouchEventQueue == null ? qd : mTouchEventQueue.add(qd);
+            }
+        }
+
+        private boolean dropStaleGestures(MotionEvent ev, long sequence) {
+            if (ev != null && ev.getAction() == MotionEvent.ACTION_MOVE && !mConfirmMove) {
+                // This is to make sure that we don't attempt to process a tap
+                // or long press when webkit takes too long to get back to us.
+                // The movement will be properly confirmed when we process the
+                // enqueued event later.
+                final int dx = Math.round(ev.getX()) - mLastTouchX;
+                final int dy = Math.round(ev.getY()) - mLastTouchY;
+                if (dx * dx + dy * dy > mTouchSlopSquare) {
+                    mPrivateHandler.removeMessages(SWITCH_TO_SHORTPRESS);
+                    mPrivateHandler.removeMessages(SWITCH_TO_LONGPRESS);
+                }
+            }
+
+            if (mTouchEventQueue == null) {
+                return sequence <= mLastHandledTouchSequence;
+            }
+
+            // If we have a new down event and it's been a while since the last event
+            // we saw, just reset and keep going.
+            if (ev != null && ev.getAction() == MotionEvent.ACTION_DOWN) {
+                long eventTime = ev.getEventTime();
+                long lastHandledEventTime = mLastEventTime;
+                if (eventTime > lastHandledEventTime + QUEUED_GESTURE_TIMEOUT) {
+                    Log.w(LOGTAG, "Got ACTION_DOWN but still waiting on stale event. " +
+                            "Ignoring previous queued events.");
+                    QueuedTouch qd = mTouchEventQueue;
+                    while (qd != null && qd.mSequence < sequence) {
+                        QueuedTouch recycleMe = qd;
+                        qd = qd.mNext;
+                        recycleQueuedTouch(recycleMe);
+                    }
+                    mTouchEventQueue = qd;
+                    mLastHandledTouchSequence = sequence - 1;
+                }
+            }
+
+            if (mIgnoreUntilSequence - 1 > mLastHandledTouchSequence) {
+                QueuedTouch qd = mTouchEventQueue;
+                while (qd != null && qd.mSequence < mIgnoreUntilSequence) {
+                    QueuedTouch recycleMe = qd;
+                    qd = qd.mNext;
+                    recycleQueuedTouch(recycleMe);
+                }
+                mTouchEventQueue = qd;
+                mLastHandledTouchSequence = mIgnoreUntilSequence - 1;
+            }
+
+            return sequence <= mLastHandledTouchSequence;
+        }
+
+        private void handleQueuedTouch(QueuedTouch qt) {
+            if (qt.mTed != null) {
+                handleQueuedTouchEventData(qt.mTed);
+            } else {
+                handleQueuedMotionEvent(qt.mEvent);
+                qt.mEvent.recycle();
+            }
+        }
+
+        private void handleQueuedMotionEvent(MotionEvent ev) {
+            mLastEventTime = ev.getEventTime();
+            int action = ev.getActionMasked();
+            if (ev.getPointerCount() > 1) {  // Multi-touch
+                handleMultiTouchInWebView(ev);
+            } else {
+                final ScaleGestureDetector detector = mZoomManager.getMultiTouchGestureDetector();
+                if (detector != null && mPreventDefault != PREVENT_DEFAULT_YES) {
+                    // ScaleGestureDetector needs a consistent event stream to operate properly.
+                    // It won't take any action with fewer than two pointers, but it needs to
+                    // update internal bookkeeping state.
+                    detector.onTouchEvent(ev);
+                }
+
+                handleTouchEventCommon(ev, action, Math.round(ev.getX()), Math.round(ev.getY()));
+            }
+        }
+
+        private void handleQueuedTouchEventData(TouchEventData ted) {
+            if (ted.mMotionEvent != null) {
+                mLastEventTime = ted.mMotionEvent.getEventTime();
+            }
+            if (!ted.mReprocess) {
+                if (ted.mAction == MotionEvent.ACTION_DOWN
+                        && mPreventDefault == PREVENT_DEFAULT_MAYBE_YES) {
+                    // if prevent default is called from WebCore, UI
+                    // will not handle the rest of the touch events any
+                    // more.
+                    mPreventDefault = ted.mNativeResult ? PREVENT_DEFAULT_YES
+                            : PREVENT_DEFAULT_NO_FROM_TOUCH_DOWN;
+                } else if (ted.mAction == MotionEvent.ACTION_MOVE
+                        && mPreventDefault == PREVENT_DEFAULT_NO_FROM_TOUCH_DOWN) {
+                    // the return for the first ACTION_MOVE will decide
+                    // whether UI will handle touch or not. Currently no
+                    // support for alternating prevent default
+                    mPreventDefault = ted.mNativeResult ? PREVENT_DEFAULT_YES
+                            : PREVENT_DEFAULT_NO;
+                }
+                if (mPreventDefault == PREVENT_DEFAULT_YES) {
+                    mTouchHighlightRegion.setEmpty();
+                }
+            } else {
+                if (ted.mPoints.length > 1) {  // multi-touch
+                    if (!ted.mNativeResult && mPreventDefault != PREVENT_DEFAULT_YES) {
+                        mPreventDefault = PREVENT_DEFAULT_NO;
+                        handleMultiTouchInWebView(ted.mMotionEvent);
+                    } else {
+                        mPreventDefault = PREVENT_DEFAULT_YES;
+                    }
+                    return;
+                }
+
+                // prevent default is not called in WebCore, so the
+                // message needs to be reprocessed in UI
+                if (!ted.mNativeResult) {
+                    // Following is for single touch.
+                    switch (ted.mAction) {
+                        case MotionEvent.ACTION_DOWN:
+                            mLastDeferTouchX = ted.mPointsInView[0].x;
+                            mLastDeferTouchY = ted.mPointsInView[0].y;
+                            mDeferTouchMode = TOUCH_INIT_MODE;
+                            break;
+                        case MotionEvent.ACTION_MOVE: {
+                            // no snapping in defer process
+                            int x = ted.mPointsInView[0].x;
+                            int y = ted.mPointsInView[0].y;
+
+                            if (mDeferTouchMode != TOUCH_DRAG_MODE) {
+                                mDeferTouchMode = TOUCH_DRAG_MODE;
+                                mLastDeferTouchX = x;
+                                mLastDeferTouchY = y;
+                                startScrollingLayer(x, y);
+                                startDrag();
+                            }
+                            int deltaX = pinLocX((int) (mScrollX
+                                    + mLastDeferTouchX - x))
+                                    - mScrollX;
+                            int deltaY = pinLocY((int) (mScrollY
+                                    + mLastDeferTouchY - y))
+                                    - mScrollY;
+                            doDrag(deltaX, deltaY);
+                            if (deltaX != 0) mLastDeferTouchX = x;
+                            if (deltaY != 0) mLastDeferTouchY = y;
+                            break;
+                        }
+                        case MotionEvent.ACTION_UP:
+                        case MotionEvent.ACTION_CANCEL:
+                            if (mDeferTouchMode == TOUCH_DRAG_MODE) {
+                                // no fling in defer process
+                                mScroller.springBack(mScrollX, mScrollY, 0,
+                                        computeMaxScrollX(), 0,
+                                        computeMaxScrollY());
+                                invalidate();
+                                WebViewCore.resumePriority();
+                                WebViewCore.resumeUpdatePicture(mWebViewCore);
+                            }
+                            mDeferTouchMode = TOUCH_DONE_MODE;
+                            break;
+                        case WebViewCore.ACTION_DOUBLETAP:
+                            // doDoubleTap() needs mLastTouchX/Y as anchor
+                            mLastDeferTouchX = ted.mPointsInView[0].x;
+                            mLastDeferTouchY = ted.mPointsInView[0].y;
+                            mZoomManager.handleDoubleTap(mLastTouchX, mLastTouchY);
+                            mDeferTouchMode = TOUCH_DONE_MODE;
+                            break;
+                        case WebViewCore.ACTION_LONGPRESS:
+                            HitTestResult hitTest = getHitTestResult();
+                            if (hitTest != null && hitTest.mType
+                                    != HitTestResult.UNKNOWN_TYPE) {
+                                performLongClick();
+                            }
+                            mDeferTouchMode = TOUCH_DONE_MODE;
+                            break;
+                    }
+                }
+            }
+        }
+    }
+
     //-------------------------------------------------------------------------
     // Methods can be called from a separate thread, like WebViewCore
     // If it needs to call the View system, it has to send message.
@@ -7208,6 +7607,8 @@
                         ted.mPoints = new Point[1];
                         ted.mPoints[0] = new Point(viewToContentX(mLastTouchX + mScrollX),
                                                    viewToContentY(mLastTouchY + mScrollY));
+                        ted.mPointsInView = new Point[1];
+                        ted.mPointsInView[0] = new Point(mLastTouchX, mLastTouchY);
                         // metaState for long press is tricky. Should it be the
                         // state when the press started or when the press was
                         // released? Or some intermediary key state? For
@@ -7217,6 +7618,7 @@
                         ted.mNativeLayer = nativeScrollableLayer(
                                 ted.mPoints[0].x, ted.mPoints[0].y,
                                 ted.mNativeLayerRect, null);
+                        ted.mSequence = mTouchEventQueue.nextTouchSequence();
                         mWebViewCore.sendMessage(EventHub.TOUCH_EVENT, ted);
                     } else if (mPreventDefault != PREVENT_DEFAULT_YES) {
                         mTouchMode = TOUCH_DONE_MODE;
@@ -7262,11 +7664,12 @@
                 case NEW_PICTURE_MSG_ID: {
                     // called for new content
                     final WebViewCore.DrawData draw = (WebViewCore.DrawData) msg.obj;
-                    setBaseLayer(draw.mBaseLayer, draw.mInvalRegion.getBounds(),
-                            getSettings().getShowVisualIndicator());
-                    final Point viewSize = draw.mViewSize;
                     WebViewCore.ViewState viewState = draw.mViewState;
                     boolean isPictureAfterFirstLayout = viewState != null;
+                    setBaseLayer(draw.mBaseLayer, draw.mInvalRegion,
+                            getSettings().getShowVisualIndicator(),
+                            isPictureAfterFirstLayout);
+                    final Point viewSize = draw.mViewSize;
                     if (isPictureAfterFirstLayout) {
                         // Reset the last sent data here since dealing with new page.
                         mLastWidthSent = 0;
@@ -7325,7 +7728,10 @@
                 }
                 case WEBCORE_INITIALIZED_MSG_ID:
                     // nativeCreate sets mNativeClass to a non-zero value
-                    nativeCreate(msg.arg1);
+                    String drawableDir = BrowserFrame.getRawResFilename(
+                            BrowserFrame.DRAWABLEDIR, mContext);
+                    AssetManager am = mContext.getAssets();
+                    nativeCreate(msg.arg1, drawableDir, am);
                     break;
                 case UPDATE_TEXTFIELD_TEXT_MSG_ID:
                     // Make sure that the textfield is currently focused
@@ -7431,106 +7837,13 @@
                     if (inFullScreenMode()) {
                         break;
                     }
-                    if (msg.obj == null) {
-                        if (msg.arg1 == MotionEvent.ACTION_DOWN
-                                && mPreventDefault == PREVENT_DEFAULT_MAYBE_YES) {
-                            // if prevent default is called from WebCore, UI
-                            // will not handle the rest of the touch events any
-                            // more.
-                            mPreventDefault = msg.arg2 == 1 ? PREVENT_DEFAULT_YES
-                                    : PREVENT_DEFAULT_NO_FROM_TOUCH_DOWN;
-                        } else if (msg.arg1 == MotionEvent.ACTION_MOVE
-                                && mPreventDefault == PREVENT_DEFAULT_NO_FROM_TOUCH_DOWN) {
-                            // the return for the first ACTION_MOVE will decide
-                            // whether UI will handle touch or not. Currently no
-                            // support for alternating prevent default
-                            mPreventDefault = msg.arg2 == 1 ? PREVENT_DEFAULT_YES
-                                    : PREVENT_DEFAULT_NO;
-                        }
-                        if (mPreventDefault == PREVENT_DEFAULT_YES) {
-                            mTouchHighlightRegion.setEmpty();
-                        }
-                    } else {
-                        TouchEventData ted = (TouchEventData) msg.obj;
+                    TouchEventData ted = (TouchEventData) msg.obj;
 
-                        if (ted.mPoints.length > 1) {  // multi-touch
-                            if (ted.mAction == MotionEvent.ACTION_POINTER_UP) {
-                                mIsHandlingMultiTouch = false;
-                            }
-                            if (msg.arg2 == 0) {
-                                mPreventDefault = PREVENT_DEFAULT_NO;
-                                handleMultiTouchInWebView(ted.mMotionEvent);
-                            } else {
-                                mPreventDefault = PREVENT_DEFAULT_YES;
-                            }
-                            break;
-                        }
+                    // WebCore is responding to us; remove pending timeout.
+                    // It will be re-posted when needed.
+                    removeMessages(PREVENT_DEFAULT_TIMEOUT);
 
-                        // prevent default is not called in WebCore, so the
-                        // message needs to be reprocessed in UI
-                        if (msg.arg2 == 0) {
-                            // Following is for single touch.
-                            switch (ted.mAction) {
-                                case MotionEvent.ACTION_DOWN:
-                                    mLastDeferTouchX = contentToViewX(ted.mPoints[0].x)
-                                            - mScrollX;
-                                    mLastDeferTouchY = contentToViewY(ted.mPoints[0].y)
-                                            - mScrollY;
-                                    mDeferTouchMode = TOUCH_INIT_MODE;
-                                    break;
-                                case MotionEvent.ACTION_MOVE: {
-                                    // no snapping in defer process
-                                    int x = contentToViewX(ted.mPoints[0].x) - mScrollX;
-                                    int y = contentToViewY(ted.mPoints[0].y) - mScrollY;
-                                    if (mDeferTouchMode != TOUCH_DRAG_MODE) {
-                                        mDeferTouchMode = TOUCH_DRAG_MODE;
-                                        mLastDeferTouchX = x;
-                                        mLastDeferTouchY = y;
-                                        startScrollingLayer(x, y);
-                                        startDrag();
-                                    }
-                                    int deltaX = pinLocX((int) (mScrollX
-                                            + mLastDeferTouchX - x))
-                                            - mScrollX;
-                                    int deltaY = pinLocY((int) (mScrollY
-                                            + mLastDeferTouchY - y))
-                                            - mScrollY;
-                                    doDrag(deltaX, deltaY);
-                                    if (deltaX != 0) mLastDeferTouchX = x;
-                                    if (deltaY != 0) mLastDeferTouchY = y;
-                                    break;
-                                }
-                                case MotionEvent.ACTION_UP:
-                                case MotionEvent.ACTION_CANCEL:
-                                    if (mDeferTouchMode == TOUCH_DRAG_MODE) {
-                                        // no fling in defer process
-                                        mScroller.springBack(mScrollX, mScrollY, 0,
-                                                computeMaxScrollX(), 0,
-                                                computeMaxScrollY());
-                                        invalidate();
-                                        WebViewCore.resumePriority();
-                                        WebViewCore.resumeUpdatePicture(mWebViewCore);
-                                    }
-                                    mDeferTouchMode = TOUCH_DONE_MODE;
-                                    break;
-                                case WebViewCore.ACTION_DOUBLETAP:
-                                    // doDoubleTap() needs mLastTouchX/Y as anchor
-                                    mLastTouchX = contentToViewX(ted.mPoints[0].x) - mScrollX;
-                                    mLastTouchY = contentToViewY(ted.mPoints[0].y) - mScrollY;
-                                    mZoomManager.handleDoubleTap(mLastTouchX, mLastTouchY);
-                                    mDeferTouchMode = TOUCH_DONE_MODE;
-                                    break;
-                                case WebViewCore.ACTION_LONGPRESS:
-                                    HitTestResult hitTest = getHitTestResult();
-                                    if (hitTest != null && hitTest.mType
-                                            != HitTestResult.UNKNOWN_TYPE) {
-                                        performLongClick();
-                                    }
-                                    mDeferTouchMode = TOUCH_DONE_MODE;
-                                    break;
-                            }
-                        }
-                    }
+                    mTouchEventQueue.enqueueTouchEvent(ted);
                     break;
 
                 case REQUEST_KEYBOARD:
@@ -7572,6 +7885,15 @@
                     setKeepScreenOn(msg.arg1 == 1);
                     break;
 
+                case ENTER_FULLSCREEN_VIDEO:
+                    int layerId = msg.arg1;
+
+                    String url = (String) msg.obj;
+                    if (mHTML5VideoViewProxy != null) {
+                        mHTML5VideoViewProxy.enterFullScreenVideo(layerId, url);
+                    }
+                    break;
+
                 case SHOW_FULLSCREEN: {
                     View view = (View) msg.obj;
                     int npp = msg.arg1;
@@ -8250,6 +8572,15 @@
     }
 
     /**
+     * Enable the communication b/t the webView and VideoViewProxy
+     *
+     * @hide only used by the Browser
+     */
+    public void setHTML5VideoViewProxy(HTML5VideoViewProxy proxy) {
+        mHTML5VideoViewProxy = proxy;
+    }
+
+    /**
      * Enable expanded tiles bound for smoother scrolling.
      *
      * @hide only used by the Browser
@@ -8291,7 +8622,7 @@
     private native Rect nativeCacheHitNodeBounds();
     private native int nativeCacheHitNodePointer();
     /* package */ native void nativeClearCursor();
-    private native void     nativeCreate(int ptr);
+    private native void     nativeCreate(int ptr, String drawableDir, AssetManager am);
     private native int      nativeCursorFramePointer();
     private native Rect     nativeCursorNodeBounds();
     private native int nativeCursorNodePointer();
@@ -8318,8 +8649,9 @@
             boolean splitIfNeeded);
     private native void     nativeDumpDisplayTree(String urlOrNull);
     private native boolean  nativeEvaluateLayersAnimations();
-    private native int      nativeGetDrawGLFunction(Rect rect, float scale, int extras);
-    private native void     nativeUpdateDrawGLFunction(Rect rect);
+    private native int      nativeGetDrawGLFunction(Rect rect, Rect viewRect,
+            float scale, int extras);
+    private native void     nativeUpdateDrawGLFunction(Rect rect, Rect viewRect);
     private native boolean  nativeDrawGL(Rect rect, float scale, int extras);
     private native void     nativeExtendSelection(int x, int y);
     private native int      nativeFindAll(String findLower, String findUpper,
@@ -8395,8 +8727,8 @@
     private native void     nativeSetFindIsEmpty();
     private native void     nativeSetFindIsUp(boolean isUp);
     private native void     nativeSetHeightCanMeasure(boolean measure);
-    private native void     nativeSetBaseLayer(int layer, Rect invalRect,
-            boolean showVisualIndicator);
+    private native void     nativeSetBaseLayer(int layer, Region invalRegion,
+            boolean showVisualIndicator, boolean isPictureAfterFirstLayout);
     private native void     nativeShowCursorTimed();
     private native void     nativeReplaceBaseContent(int content);
     private native void     nativeCopyBaseContentToPicture(Picture pict);
diff --git a/core/java/android/webkit/WebViewClient.java b/core/java/android/webkit/WebViewClient.java
index db605de..65026a5 100644
--- a/core/java/android/webkit/WebViewClient.java
+++ b/core/java/android/webkit/WebViewClient.java
@@ -256,4 +256,18 @@
      */
     public void onScaleChanged(WebView view, float oldScale, float newScale) {
     }
+
+    /**
+     * Notify the host application that a request to automatically log in the
+     * user has been processed.
+     * @param view The WebView requesting the login.
+     * @param realm The account realm used to look up accounts.
+     * @param account An optional account. If not null, the account should be
+     *                checked against accounts on the device. If it is a valid
+     *                account, it should be used to log in the user.
+     * @param args Authenticator specific arguments used to log in the user.
+     */
+    public void onReceivedLoginRequest(WebView view, String realm,
+            String account, String args) {
+    }
 }
diff --git a/core/java/android/webkit/WebViewCore.java b/core/java/android/webkit/WebViewCore.java
index c18c9e4..0271695 100644
--- a/core/java/android/webkit/WebViewCore.java
+++ b/core/java/android/webkit/WebViewCore.java
@@ -480,6 +480,17 @@
         mCallbackProxy.setInstallableWebApp();
     }
 
+    /**
+     * Notify the webview that we want to display the video layer fullscreen.
+     */
+    protected void enterFullscreenForVideoLayer(int layerId, String url) {
+        if (mWebView == null) return;
+        Message message = Message.obtain(mWebView.mPrivateHandler,
+                       WebView.ENTER_FULLSCREEN_VIDEO, layerId, 0);
+        message.obj = url;
+        message.sendToTarget();
+    }
+
     //-------------------------------------------------------------------------
     // JNI methods
     //-------------------------------------------------------------------------
@@ -563,7 +574,7 @@
             int framePtr, int nodePtr, int x, int y);
 
     private native boolean nativeHandleTouchEvent(int action, int[] idArray,
-            int[] xArray, int[] yArray, int count, int metaState);
+            int[] xArray, int[] yArray, int count, int actionIndex, int metaState);
 
     private native void nativeUpdateFrameCache();
 
@@ -820,11 +831,15 @@
         int mAction;
         int[] mIds;  // Ids of the touch points
         Point[] mPoints;
+        Point[] mPointsInView;  // the point coordinates in view axis.
+        int mActionIndex;  // Associated pointer index for ACTION_POINTER_DOWN/UP
         int mMetaState;
         boolean mReprocess;
         MotionEvent mMotionEvent;
         int mNativeLayer;
         Rect mNativeLayerRect = new Rect();
+        long mSequence;
+        boolean mNativeResult;
     }
 
     static class GeolocationPermissionsData {
@@ -1332,13 +1347,14 @@
                                 nativeScrollLayer(ted.mNativeLayer,
                                         ted.mNativeLayerRect);
                             }
+                            ted.mNativeResult = nativeHandleTouchEvent(ted.mAction, ted.mIds,
+                                    xArray, yArray, count, ted.mActionIndex, ted.mMetaState);
                             Message.obtain(
                                     mWebView.mPrivateHandler,
                                     WebView.PREVENT_TOUCH_ID,
                                     ted.mAction,
-                                    nativeHandleTouchEvent(ted.mAction, ted.mIds,
-                                        xArray, yArray, count, ted.mMetaState) ? 1 : 0,
-                                    ted.mReprocess ? ted : null).sendToTarget();
+                                    ted.mNativeResult ? 1 : 0,
+                                    ted).sendToTarget();
                             break;
                         }
 
diff --git a/core/java/android/webkit/ZoomManager.java b/core/java/android/webkit/ZoomManager.java
index 28f64a9..f2a1ec3 100644
--- a/core/java/android/webkit/ZoomManager.java
+++ b/core/java/android/webkit/ZoomManager.java
@@ -23,6 +23,7 @@
 import android.graphics.Rect;
 import android.os.Bundle;
 import android.os.SystemClock;
+import android.util.FloatMath;
 import android.util.Log;
 import android.view.ScaleGestureDetector;
 import android.view.View;
@@ -112,6 +113,22 @@
     private float mZoomCenterY;
 
     /*
+     * Similar to mZoomCenterX(Y), these track the focus point of the scale
+     * gesture. The difference is these get updated every time when onScale is
+     * invoked no matter if a zooming really happens.
+     */
+    private float mFocusX;
+    private float mFocusY;
+
+    /*
+     * mFocusMovementQueue keeps track of the previous focus point movement
+     * has been through. Comparing to the difference of the gesture's previous
+     * span and current span, it determines if the gesture is for panning or
+     * zooming or both.
+     */
+    private FocusMovementQueue mFocusMovementQueue;
+
+    /*
      * These values represent the point around which the screen should be
      * centered after zooming. In other words it is used to determine the center
      * point of the visible document after the page has finished zooming. This
@@ -169,7 +186,7 @@
     private int mInitialScrollY;
     private long mZoomStart;
 
-    private static final int ZOOM_ANIMATION_LENGTH = 500;
+    private static final int ZOOM_ANIMATION_LENGTH = 175;
 
     // whether support multi-touch
     private boolean mSupportMultiTouch;
@@ -196,6 +213,8 @@
          * viewport size is.
          */
         setZoomOverviewWidth(WebView.DEFAULT_VIEWPORT_WIDTH);
+
+        mFocusMovementQueue = new FocusMovementQueue();
     }
 
     /**
@@ -336,6 +355,10 @@
         return scale;
     }
 
+    public final boolean isScaleOverLimits(float scale) {
+        return scale <= mMinZoomScale || scale >= mMaxZoomScale;
+    }
+
     public final boolean isZoomScaleFixed() {
         return mMinZoomScale >= mMaxZoomScale;
     }
@@ -481,7 +504,7 @@
     }
 
     public boolean isFixedLengthAnimationInProgress() {
-        return mZoomScale != 0;
+        return mZoomScale != 0 || mInHWAcceleratedZoom;
     }
 
     public void refreshZoomScale(boolean reflowText) {
@@ -507,7 +530,7 @@
             mTextWrapScale = scale;
         }
 
-        if (exceedsMinScaleIncrement(scale, mActualScale) || force) {
+        if (scale != mActualScale || force) {
             float oldScale = mActualScale;
             float oldInvScale = mInvActualScale;
 
@@ -714,21 +737,91 @@
         return mScaleDetector;
     }
 
+    private class FocusMovementQueue {
+        private static final int QUEUE_CAPACITY = 5;
+        private float[] mQueue;
+        private float mSum;
+        private int mSize;
+        private int mIndex;
+
+        FocusMovementQueue() {
+            mQueue = new float[QUEUE_CAPACITY];
+            mSize = 0;
+            mSum = 0;
+            mIndex = 0;
+        }
+
+        private void clear() {
+            mSize = 0;
+            mSum = 0;
+            mIndex = 0;
+            for (int i = 0; i < QUEUE_CAPACITY; ++i) {
+                mQueue[i] = 0;
+            }
+        }
+
+        private void add(float focusDelta) {
+            mSum += focusDelta;
+            if (mSize < QUEUE_CAPACITY) {  // fill up the queue.
+                mSize++;
+            } else {  // circulate the queue.
+                mSum -= mQueue[mIndex];
+            }
+            mQueue[mIndex] = focusDelta;
+            mIndex = (mIndex + 1) % QUEUE_CAPACITY;
+        }
+
+        private float getSum() {
+            return mSum;
+        }
+    }
+
     private class ScaleDetectorListener implements ScaleGestureDetector.OnScaleGestureListener {
+        private float mAccumulatedSpan;
 
         public boolean onScaleBegin(ScaleGestureDetector detector) {
             mInitialZoomOverview = false;
             dismissZoomPicker();
+            mFocusMovementQueue.clear();
             mWebView.mViewManager.startZoom();
             mWebView.onPinchToZoomAnimationStart();
+            mAccumulatedSpan = 0;
             return true;
         }
 
-        public boolean onScale(ScaleGestureDetector detector) {
+            // If the user moves the fingers but keeps the same distance between them,
+            // we should do panning only.
+        public boolean isPanningOnly(ScaleGestureDetector detector) {
+            float prevFocusX = mFocusX;
+            float prevFocusY = mFocusY;
+            mFocusX = detector.getFocusX();
+            mFocusY = detector.getFocusY();
+            float focusDelta = (prevFocusX == 0 && prevFocusY == 0) ? 0 :
+                    FloatMath.sqrt((mFocusX - prevFocusX) * (mFocusX - prevFocusX)
+                                   + (mFocusY - prevFocusY) * (mFocusY - prevFocusY));
+            mFocusMovementQueue.add(focusDelta);
+            float deltaSpan = detector.getCurrentSpan() - detector.getPreviousSpan() +
+                    mAccumulatedSpan;
+            final boolean result = mFocusMovementQueue.getSum() > Math.abs(deltaSpan);
+            if (result) {
+                mAccumulatedSpan += deltaSpan;
+            } else {
+                mAccumulatedSpan = 0;
+            }
+            return result;
+        }
+
+        public boolean handleScale(ScaleGestureDetector detector) {
+            float scale = detector.getScaleFactor() * mActualScale;
+
+            // if scale is limited by any reason, don't zoom but do ask
+            // the detector to update the event.
+            boolean isScaleLimited =
+                    isScaleOverLimits(scale) || scale < getZoomOverviewScale();
+
             // Prevent scaling beyond overview scale.
-            float scale = Math.max(
-                    computeScaleWithLimits(detector.getScaleFactor() * mActualScale),
-                    getZoomOverviewScale());
+            scale = Math.max(computeScaleWithLimits(scale), getZoomOverviewScale());
+
             if (mPinchToZoomAnimating || willScaleTriggerZoom(scale)) {
                 mPinchToZoomAnimating = true;
                 // limit the scale change per step
@@ -740,13 +833,21 @@
                 scale = computeScaleWithLimits(scale);
                 // if the scale change is too small, regard it as jitter and skip it.
                 if (Math.abs(scale - mActualScale) < MINIMUM_SCALE_WITHOUT_JITTER) {
-                    return false;
+                    return isScaleLimited;
                 }
                 setZoomCenter(detector.getFocusX(), detector.getFocusY());
                 setZoomScale(scale, false);
                 mWebView.invalidate();
                 return true;
             }
+            return isScaleLimited;
+        }
+
+        public boolean onScale(ScaleGestureDetector detector) {
+            if (isPanningOnly(detector) || handleScale(detector)) {
+                mFocusMovementQueue.clear();
+                return true;
+            }
             return false;
         }
 
@@ -960,14 +1061,15 @@
         final Point viewSize = drawData.mViewSize;
         updateZoomRange(viewState, viewSize.x, drawData.mMinPrefWidth);
         setupZoomOverviewWidth(drawData, mWebView.getViewWidth());
+        final float overviewScale = getZoomOverviewScale();
         if (!mMinZoomScaleFixed) {
-            mMinZoomScale = getZoomOverviewScale();
+            mMinZoomScale = (mInitialScale > 0) ?
+                    Math.min(mInitialScale, overviewScale) : overviewScale;
             mMaxZoomScale = Math.max(mMaxZoomScale, mMinZoomScale);
         }
 
         if (!mWebView.drawHistory()) {
             float scale;
-            final float overviewScale = getZoomOverviewScale();
             WebSettings settings = mWebView.getSettings();
 
             if (mInitialScale > 0) {
diff --git a/core/java/android/widget/AbsListView.java b/core/java/android/widget/AbsListView.java
index eca39fc..6cb5c35 100644
--- a/core/java/android/widget/AbsListView.java
+++ b/core/java/android/widget/AbsListView.java
@@ -4529,8 +4529,9 @@
      * Otherwise resurrects the selection and returns true if resurrected.
      */
     boolean resurrectSelectionIfNeeded() {
-        if (mSelectedPosition < 0) {
-            return resurrectSelection();
+        if (mSelectedPosition < 0 && resurrectSelection()) {
+            updateSelectorState();
+            return true;
         }
         return false;
     }
@@ -5226,6 +5227,7 @@
      *
      * @return The cache color hint
      */
+    @ViewDebug.ExportedProperty(category = "drawing")
     public int getCacheColorHint() {
         return mCacheColorHint;
     }
diff --git a/core/java/android/widget/AbsSeekBar.java b/core/java/android/widget/AbsSeekBar.java
index 0da73a4..2621e64 100644
--- a/core/java/android/widget/AbsSeekBar.java
+++ b/core/java/android/widget/AbsSeekBar.java
@@ -201,7 +201,8 @@
     }
     
     @Override
-    void onProgressRefresh(float scale, boolean fromUser) { 
+    void onProgressRefresh(float scale, boolean fromUser) {
+        super.onProgressRefresh(scale, fromUser);
         Drawable thumb = mThumb;
         if (thumb != null) {
             setThumbPos(getWidth(), thumb, scale, Integer.MIN_VALUE);
diff --git a/core/java/android/widget/CalendarView.java b/core/java/android/widget/CalendarView.java
index 13a407f..f8c76f2 100644
--- a/core/java/android/widget/CalendarView.java
+++ b/core/java/android/widget/CalendarView.java
@@ -1066,7 +1066,10 @@
         public boolean onTouch(View v, MotionEvent event) {
             if (mListView.isEnabled() && mGestureDetector.onTouchEvent(event)) {
                 WeekView weekView = (WeekView) v;
-                weekView.getDayFromLocation(event.getX(), mTempDate);
+                // if we cannot find a day for the given location we are done
+                if (!weekView.getDayFromLocation(event.getX(), mTempDate)) {
+                    return true;
+                }
                 // it is possible that the touched day is outside the valid range
                 // we draw whole weeks but range end can fall not on the week end
                 if (mTempDate.before(mMinDate) || mTempDate.after(mMaxDate)) {
@@ -1271,21 +1274,23 @@
 
         /**
          * Calculates the day that the given x position is in, accounting for
-         * week number. Returns a Time referencing that day or null if
+         * week number.
          *
-         * @param x The x position of the touch eventy
+         * @param x The x position of the touch event.
+         * @return True if a day was found for the given location.
          */
-        public void getDayFromLocation(float x, Calendar outCalendar) {
+        public boolean getDayFromLocation(float x, Calendar outCalendar) {
             int dayStart = mShowWeekNumber ? mWidth / mNumCells : 0;
             if (x < dayStart || x > mWidth) {
                 outCalendar.clear();
-                return;
+                return false;
             }
             // Selection is (x - start) / (pixels/day) == (x -s) * day / pixels
             int dayPosition = (int) ((x - dayStart) * mDaysPerWeek
                     / (mWidth - dayStart));
             outCalendar.setTimeInMillis(mFirstDay.getTimeInMillis());
             outCalendar.add(Calendar.DAY_OF_MONTH, dayPosition);
+            return true;
         }
 
         @Override
diff --git a/core/java/android/widget/DatePicker.java b/core/java/android/widget/DatePicker.java
index 1d442db..7210e21 100644
--- a/core/java/android/widget/DatePicker.java
+++ b/core/java/android/widget/DatePicker.java
@@ -410,73 +410,27 @@
     }
 
     /**
-     * Reorders the spinners according to the date format in the current
-     * {@link Locale}.
+     * Reorders the spinners according to the date format that is
+     * explicitly set by the user and if no such is set fall back
+     * to the current locale's default format.
      */
     private void reorderSpinners() {
-        java.text.DateFormat format;
-        String order;
-
-        /*
-         * If the user is in a locale where the medium date format is still
-         * numeric (Japanese and Czech, for example), respect the date format
-         * order setting. Otherwise, use the order that the locale says is
-         * appropriate for a spelled-out date.
-         */
-
-        if (getShortMonths()[0].startsWith("1")) {
-            format = DateFormat.getDateFormat(getContext());
-        } else {
-            format = DateFormat.getMediumDateFormat(getContext());
-        }
-
-        if (format instanceof SimpleDateFormat) {
-            order = ((SimpleDateFormat) format).toPattern();
-        } else {
-            // Shouldn't happen, but just in case.
-            order = new String(DateFormat.getDateFormatOrder(getContext()));
-        }
-
-        /*
-         * Remove the 3 spinners from their parent and then add them back in the
-         * required order.
-         */
-        LinearLayout parent = mSpinners;
-        parent.removeAllViews();
-
-        boolean quoted = false;
-        boolean didDay = false, didMonth = false, didYear = false;
-
-        for (int i = 0; i < order.length(); i++) {
-            char c = order.charAt(i);
-
-            if (c == '\'') {
-                quoted = !quoted;
+        mSpinners.removeAllViews();
+        char[] order = DateFormat.getDateFormatOrder(getContext());
+        for (int i = 0; i < order.length; i++) {
+            switch (order[i]) {
+                case DateFormat.DATE:
+                    mSpinners.addView(mDaySpinner);
+                    break;
+                case DateFormat.MONTH:
+                    mSpinners.addView(mMonthSpinner);
+                    break;
+                case DateFormat.YEAR:
+                    mSpinners.addView(mYearSpinner);
+                    break;
+                default:
+                    throw new IllegalArgumentException();
             }
-
-            if (!quoted) {
-                if (c == DateFormat.DATE && !didDay) {
-                    parent.addView(mDaySpinner);
-                    didDay = true;
-                } else if ((c == DateFormat.MONTH || c == 'L') && !didMonth) {
-                    parent.addView(mMonthSpinner);
-                    didMonth = true;
-                } else if (c == DateFormat.YEAR && !didYear) {
-                    parent.addView(mYearSpinner);
-                    didYear = true;
-                }
-            }
-        }
-
-        // Shouldn't happen, but just in case.
-        if (!didMonth) {
-            parent.addView(mMonthSpinner);
-        }
-        if (!didDay) {
-            parent.addView(mDaySpinner);
-        }
-        if (!didYear) {
-            parent.addView(mYearSpinner);
         }
     }
 
diff --git a/core/java/android/widget/FastScroller.java b/core/java/android/widget/FastScroller.java
index 200c870..fb57ce0 100644
--- a/core/java/android/widget/FastScroller.java
+++ b/core/java/android/widget/FastScroller.java
@@ -564,6 +564,9 @@
             }
         } else {
             int index = (int) (position * count);
+            // Don't overflow
+            if (index > count - 1) index = count - 1;
+
             if (mList instanceof ExpandableListView) {
                 ExpandableListView expList = (ExpandableListView) mList;
                 expList.setSelectionFromTop(expList.getFlatListPosition(
diff --git a/core/java/android/widget/HorizontalScrollView.java b/core/java/android/widget/HorizontalScrollView.java
index d92588cb..17b3bda 100644
--- a/core/java/android/widget/HorizontalScrollView.java
+++ b/core/java/android/widget/HorizontalScrollView.java
@@ -477,8 +477,7 @@
                 break;
             case MotionEvent.ACTION_POINTER_DOWN: {
                 final int index = ev.getActionIndex();
-                final float x = ev.getX(index);
-                mLastMotionX = x;
+                mLastMotionX = ev.getX(index);
                 mActivePointerId = ev.getPointerId(index);
                 break;
             }
@@ -1446,6 +1445,7 @@
         super.setOverScrollMode(mode);
     }
 
+    @SuppressWarnings({"SuspiciousNameCombination"})
     @Override
     public void draw(Canvas canvas) {
         super.draw(canvas);
diff --git a/core/java/android/widget/ListView.java b/core/java/android/widget/ListView.java
index 2802144..af954c9 100644
--- a/core/java/android/widget/ListView.java
+++ b/core/java/android/widget/ListView.java
@@ -3015,8 +3015,23 @@
 
     @Override
     public boolean isOpaque() {
-        return (mCachingActive && mIsCacheColorOpaque && mDividerIsOpaque &&
+        boolean retValue = (mCachingActive && mIsCacheColorOpaque && mDividerIsOpaque &&
                 hasOpaqueScrollbars()) || super.isOpaque();
+        if (retValue) {
+            // only return true if the list items cover the entire area of the view
+            final int listTop = mListPadding != null ? mListPadding.top : mPaddingTop;
+            View first = getChildAt(0);
+            if (first == null || first.getTop() > listTop) {
+                return false;
+            }
+            final int listBottom = getHeight() -
+                    (mListPadding != null ? mListPadding.bottom : mPaddingBottom);
+            View last = getChildAt(getChildCount() - 1);
+            if (last == null || last.getBottom() < listBottom) {
+                return false;
+            }
+        }
+        return retValue;
     }
 
     @Override
diff --git a/core/java/android/widget/PopupWindow.java b/core/java/android/widget/PopupWindow.java
index 9002b1d..72b70bc 100644
--- a/core/java/android/widget/PopupWindow.java
+++ b/core/java/android/widget/PopupWindow.java
@@ -1039,7 +1039,7 @@
      *
      * @return true if the popup is translated upwards to fit on screen
      */
-    boolean findDropDownPosition(View anchor, WindowManager.LayoutParams p,
+    private boolean findDropDownPosition(View anchor, WindowManager.LayoutParams p,
             int xoff, int yoff) {
 
         anchor.getLocationInWindow(mDrawingLocation);
diff --git a/core/java/android/widget/ProgressBar.java b/core/java/android/widget/ProgressBar.java
index cf72ec4..8db34d9 100644
--- a/core/java/android/widget/ProgressBar.java
+++ b/core/java/android/widget/ProgressBar.java
@@ -16,6 +16,8 @@
 
 package android.widget;
 
+import com.android.internal.R;
+
 import android.content.Context;
 import android.content.res.TypedArray;
 import android.graphics.Bitmap;
@@ -41,6 +43,8 @@
 import android.view.RemotableViewMethod;
 import android.view.View;
 import android.view.ViewDebug;
+import android.view.accessibility.AccessibilityEvent;
+import android.view.accessibility.AccessibilityManager;
 import android.view.animation.AlphaAnimation;
 import android.view.animation.Animation;
 import android.view.animation.AnimationUtils;
@@ -49,8 +53,6 @@
 import android.view.animation.Transformation;
 import android.widget.RemoteViews.RemoteView;
 
-import com.android.internal.R;
-
 
 /**
  * <p>
@@ -125,6 +127,7 @@
 public class ProgressBar extends View {
     private static final int MAX_LEVEL = 10000;
     private static final int ANIMATION_RESOLUTION = 200;
+    private static final int TIMEOUT_SEND_ACCESSIBILITY_EVENT = 200;
 
     int mMinWidth;
     int mMaxWidth;
@@ -156,6 +159,8 @@
 
     private int mAnimationResolution;
 
+    private AccessibilityEventSender mAccessibilityEventSender;
+
     /**
      * Create a new progress bar with range 0...100 and initial progress of 0.
      * @param context the application environment
@@ -542,8 +547,11 @@
             onProgressRefresh(scale, fromUser);
         }
     }
-    
-    void onProgressRefresh(float scale, boolean fromUser) {        
+
+    void onProgressRefresh(float scale, boolean fromUser) {
+        if (AccessibilityManager.getInstance(mContext).isEnabled()) {
+            scheduleAccessibilityEventSender();
+        }
     }
 
     private synchronized void refreshProgress(int id, int progress, boolean fromUser) {
@@ -1007,8 +1015,48 @@
         if (mIndeterminate) {
             stopAnimation();
         }
+        if(mRefreshProgressRunnable != null) {
+            removeCallbacks(mRefreshProgressRunnable);
+        }
+        if (mAccessibilityEventSender != null) {
+            removeCallbacks(mAccessibilityEventSender);
+        }
         // This should come after stopAnimation(), otherwise an invalidate message remains in the
         // queue, which can prevent the entire view hierarchy from being GC'ed during a rotation
         super.onDetachedFromWindow();
     }
+
+    @Override
+    public boolean dispatchPopulateAccessibilityEvent(AccessibilityEvent event) {
+        if (!super.dispatchPopulateAccessibilityEvent(event)) {
+            event.setItemCount(mMax);
+            event.setCurrentItemIndex(mProgress);
+        }
+        return true;
+    }
+
+    /**
+     * Schedule a command for sending an accessibility event.
+     * </br>
+     * Note: A command is used to ensure that accessibility events
+     *       are sent at most one in a given time frame to save
+     *       system resources while the progress changes quickly.
+     */
+    private void scheduleAccessibilityEventSender() {
+        if (mAccessibilityEventSender == null) {
+            mAccessibilityEventSender = new AccessibilityEventSender();
+        } else {
+            removeCallbacks(mAccessibilityEventSender);
+        }
+        postDelayed(mAccessibilityEventSender, TIMEOUT_SEND_ACCESSIBILITY_EVENT);
+    }
+
+    /**
+     * Command for sending an accessibility event.
+     */
+    private class AccessibilityEventSender implements Runnable {
+        public void run() {
+            sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_SELECTED);
+        }
+    }
 }
diff --git a/core/java/android/widget/RemoteViewsAdapter.java b/core/java/android/widget/RemoteViewsAdapter.java
index 2d2165b..1c0a2bb 100644
--- a/core/java/android/widget/RemoteViewsAdapter.java
+++ b/core/java/android/widget/RemoteViewsAdapter.java
@@ -889,7 +889,7 @@
             boolean isConnected = mServiceConnection.isConnected();
             boolean hasNewItems = false;
 
-            if (!isConnected) {
+            if (!isInCache && !isConnected) {
                 // Requesting bind service will trigger a super.notifyDataSetChanged(), which will
                 // in turn trigger another request to getView()
                 requestBindService();
diff --git a/core/java/android/widget/SearchView.java b/core/java/android/widget/SearchView.java
index 2d164fd..9933d68 100644
--- a/core/java/android/widget/SearchView.java
+++ b/core/java/android/widget/SearchView.java
@@ -54,18 +54,16 @@
 import java.util.WeakHashMap;
 
 /**
- * Provides the user interface elements for the user to enter a search query and submit a
+ * A widget that provides a user interface for the user to enter a search query and submit a
  * request to a search provider. Shows a list of query suggestions or results, if
- * available and allows the user to pick a suggestion or result to launch into.
+ * available, and allows the user to pick a suggestion or result to launch into.
  *
- * <p>
- * <b>XML attributes</b>
- * <p>
- * See {@link android.R.styleable#SearchView SearchView Attributes},
- * {@link android.R.styleable#View View Attributes}
+ * <p>For more information, see the <a href="{@docRoot}guide/topics/search/index.html">Search</a>
+ * documentation.<p>
  *
  * @attr ref android.R.styleable#SearchView_iconifiedByDefault
  * @attr ref android.R.styleable#SearchView_maxWidth
+ * @attr ref android.R.styleable#SearchView_queryHint
  */
 public class SearchView extends LinearLayout {
 
@@ -83,6 +81,7 @@
     private CursorAdapter mSuggestionsAdapter;
     private View mSearchButton;
     private View mSubmitButton;
+    private View mSearchPlate;
     private View mSubmitArea;
     private ImageView mCloseButton;
     private View mSearchEditFrame;
@@ -190,6 +189,7 @@
         mQueryTextView.setSearchView(this);
 
         mSearchEditFrame = findViewById(R.id.search_edit_frame);
+        mSearchPlate = findViewById(R.id.search_plate);
         mSubmitArea = findViewById(R.id.submit_area);
         mSubmitButton = findViewById(R.id.search_go_btn);
         mCloseButton = (ImageView) findViewById(R.id.search_close_btn);
@@ -258,6 +258,7 @@
         mSearchable = searchable;
         if (mSearchable != null) {
             updateSearchAutoComplete();
+            updateQueryHint();
         }
         // Cache the voice search capability
         mVoiceButtonEnabled = hasVoiceSearch();
@@ -384,6 +385,8 @@
      * in the SearchableInfo.
      *
      * @param hint the hint text to display
+     *
+     * @attr ref android.R.styleable#SearchView_queryHint
      */
     public void setQueryHint(CharSequence hint) {
         mQueryHint = hint;
@@ -399,6 +402,8 @@
      * <p>The default value is true.</p>
      *
      * @param iconified whether the search field should be iconified by default
+     *
+     * @attr ref android.R.styleable#SearchView_iconifiedByDefault
      */
     public void setIconifiedByDefault(boolean iconified) {
         if (mIconifiedByDefault == iconified) return;
@@ -575,19 +580,19 @@
     }
 
     private void updateSubmitButton(boolean hasText) {
-        mSubmitButton.setVisibility(
-                isSubmitAreaEnabled() ? (hasText ? VISIBLE : INVISIBLE) : GONE);
+        int visibility = GONE;
+        if (isSubmitAreaEnabled() && hasFocus() && (hasText || !mVoiceButtonEnabled)) {
+            visibility = VISIBLE;
+        }
+        mSubmitButton.setVisibility(visibility);
     }
 
     private void updateSubmitArea() {
         int visibility = GONE;
-        if (isSubmitAreaEnabled()) {
-            if (mSubmitButton.getVisibility() == VISIBLE
-                    || mVoiceButton.getVisibility() == VISIBLE) {
-                visibility = VISIBLE;
-            } else {
-                visibility = INVISIBLE;
-            }
+        if (isSubmitAreaEnabled()
+                && (mSubmitButton.getVisibility() == VISIBLE
+                        || mVoiceButton.getVisibility() == VISIBLE)) {
+            visibility = VISIBLE;
         }
         mSubmitArea.setVisibility(visibility);
     }
@@ -601,6 +606,11 @@
         mCloseButton.getDrawable().setState(hasText ? ENABLED_STATE_SET : EMPTY_STATE_SET);
     }
 
+    private void updateFocusedState(boolean focused) {
+        mSearchPlate.getBackground().setState(focused ? FOCUSED_STATE_SET : EMPTY_STATE_SET);
+        mSubmitArea.getBackground().setState(focused ? FOCUSED_STATE_SET : EMPTY_STATE_SET);
+    }
+
     private void setImeVisibility(boolean visible) {
         InputMethodManager imm = (InputMethodManager)
                 getContext().getSystemService(Context.INPUT_METHOD_SERVICE);
@@ -851,16 +861,11 @@
      * Update the visibility of the voice button.  There are actually two voice search modes,
      * either of which will activate the button.
      * @param empty whether the search query text field is empty. If it is, then the other
-     * criteria apply to make the voice button visible. Otherwise the voice button will not
-     * be visible - i.e., if the user has typed a query, remove the voice button.
+     * criteria apply to make the voice button visible.
      */
     private void updateVoiceButton(boolean empty) {
-        // If the voice button is to be visible, show it
-        // Else, make it gone if the submit button is enabled, otherwise invisible to
-        // avoid losing the real-estate
-        int visibility = mSubmitButtonEnabled ? GONE : INVISIBLE;
-
-        if (mVoiceButtonEnabled && !isIconified() && empty) {
+        int visibility = GONE;
+        if (mVoiceButtonEnabled && !isIconified() && (empty || !mSubmitButtonEnabled)) {
             visibility = VISIBLE;
             mSubmitButton.setVisibility(GONE);
         }
@@ -958,7 +963,8 @@
     }
 
     void onTextFocusChanged() {
-        updateCloseButton();
+        updateViewsVisibility(isIconified());
+        updateFocusedState(mQueryTextView.hasFocus());
     }
 
     private boolean onItemClicked(int position, int actionKey, String actionMsg) {
diff --git a/core/java/android/widget/StackView.java b/core/java/android/widget/StackView.java
index bab469b..21c61bd 100644
--- a/core/java/android/widget/StackView.java
+++ b/core/java/android/widget/StackView.java
@@ -531,6 +531,8 @@
 
     @Override
     protected void dispatchDraw(Canvas canvas) {
+        boolean expandClipRegion = false;
+
         canvas.getClipBounds(stackInvalidateRect);
         final int childCount = getChildCount();
         for (int i = 0; i < childCount; i++) {
@@ -540,12 +542,22 @@
                     child.getAlpha() == 0f || child.getVisibility() != VISIBLE) {
                 lp.resetInvalidateRect();
             }
-            stackInvalidateRect.union(lp.getInvalidateRect());
+            Rect childInvalidateRect = lp.getInvalidateRect();
+            if (!childInvalidateRect.isEmpty()) {
+                expandClipRegion = true;
+                stackInvalidateRect.union(childInvalidateRect);
+            }
         }
-        canvas.save(Canvas.CLIP_SAVE_FLAG);
-        canvas.clipRect(stackInvalidateRect, Region.Op.UNION);
-        super.dispatchDraw(canvas);
-        canvas.restore();
+
+        // We only expand the clip bounds if necessary.
+        if (expandClipRegion) {
+            canvas.save(Canvas.CLIP_SAVE_FLAG);
+            canvas.clipRect(stackInvalidateRect, Region.Op.UNION);
+            super.dispatchDraw(canvas);
+            canvas.restore();
+        } else {
+            super.dispatchDraw(canvas);
+        }
     }
 
     private void onLayout() {
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index 09c1ac5..222bc84 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -43,6 +43,7 @@
 import android.net.Uri;
 import android.os.Bundle;
 import android.os.Handler;
+import android.os.IBinder;
 import android.os.Message;
 import android.os.Parcel;
 import android.os.Parcelable;
@@ -81,6 +82,7 @@
 import android.text.method.TimeKeyListener;
 import android.text.method.TransformationMethod;
 import android.text.style.ClickableSpan;
+import android.text.style.CorrectionSpan;
 import android.text.style.ParagraphStyle;
 import android.text.style.URLSpan;
 import android.text.style.UpdateAppearance;
@@ -126,6 +128,7 @@
 import java.io.IOException;
 import java.lang.ref.WeakReference;
 import java.util.ArrayList;
+import java.util.HashSet;
 
 /**
  * Displays text to the user and optionally allows them to edit it.  A TextView
@@ -4210,6 +4213,12 @@
 
     @Override
     protected void onDraw(Canvas canvas) {
+        if (mPreDrawState == PREDRAW_DONE) {
+            final ViewTreeObserver observer = getViewTreeObserver();
+            observer.removeOnPreDrawListener(this);
+            mPreDrawState = PREDRAW_NOT_REGISTERED;
+        }
+
         if (mCurrentAlpha <= ViewConfiguration.ALPHA_THRESHOLD_INT) return;
 
         restartMarqueeIfNeeded();
@@ -4281,12 +4290,6 @@
             }
         }
 
-        if (mPreDrawState == PREDRAW_DONE) {
-            final ViewTreeObserver observer = getViewTreeObserver();
-            observer.removeOnPreDrawListener(this);
-            mPreDrawState = PREDRAW_NOT_REGISTERED;
-        }
-
         int color = mCurTextColor;
 
         if (mLayout == null) {
@@ -4498,8 +4501,6 @@
         */
 
         canvas.restore();
-
-        updateCursorControllerPositions();
     }
 
     private void updateCursorsPositions() {
@@ -4551,23 +4552,6 @@
         if (translate) canvas.translate(0, -cursorOffsetVertical);
     }
 
-    /**
-     * Update the positions of the CursorControllers.  Needed by WebTextView,
-     * which does not draw.
-     * @hide
-     */
-    protected void updateCursorControllerPositions() {
-        // No need to create the controllers if they were not already
-        if (mInsertionPointCursorController != null &&
-                mInsertionPointCursorController.isShowing()) {
-            mInsertionPointCursorController.updatePosition();
-        }
-        if (mSelectionModifierCursorController != null &&
-                mSelectionModifierCursorController.isShowing()) {
-            mSelectionModifierCursorController.updatePosition();
-        }
-    }
-
     @Override
     public void getFocusedRect(Rect r) {
         if (mLayout == null) {
@@ -5246,6 +5230,7 @@
      * @param text The auto complete text the user has selected.
      */
     public void onCommitCompletion(CompletionInfo text) {
+        // intentionally empty
     }
 
     /**
@@ -5432,6 +5417,7 @@
      * of edit operations through a call to link {@link #beginBatchEdit()}.
      */
     public void onBeginBatchEdit() {
+        // intentionally empty
     }
     
     /**
@@ -5439,6 +5425,7 @@
      * of edit operations through a call to link {@link #endBatchEdit}.
      */
     public void onEndBatchEdit() {
+        // intentionally empty
     }
     
     /**
@@ -6285,15 +6272,15 @@
         }
 
         if (isFocused()) {
-            // This offsets because getInterestingRect() is in terms of
-            // viewport coordinates, but requestRectangleOnScreen()
-            // is in terms of content coordinates.
+            // This offsets because getInterestingRect() is in terms of viewport coordinates, but
+            // requestRectangleOnScreen() is in terms of content coordinates.
 
-            Rect r = new Rect(x, top, x + 1, bottom);
-            getInterestingRect(r, line);
-            r.offset(mScrollX, mScrollY);
+            if (mTempRect == null) mTempRect = new Rect();
+            mTempRect.set(x, top, x + 1, bottom);
+            getInterestingRect(mTempRect, line);
+            mTempRect.offset(mScrollX, mScrollY);
 
-            if (requestRectangleOnScreen(r)) {
+            if (requestRectangleOnScreen(mTempRect)) {
                 changed = true;
             }
         }
@@ -6766,25 +6753,22 @@
     }
 
     /**
-     * This method is called when the text is changed, in case any
-     * subclasses would like to know.
+     * This method is called when the text is changed, in case any subclasses
+     * would like to know.
      *
-     * @param text The text the TextView is displaying.
-     * @param start The offset of the start of the range of the text
-     *              that was modified.
-     * @param before The offset of the former end of the range of the
-     *               text that was modified.  If text was simply inserted,
-     *               this will be the same as <code>start</code>.
-     *               If text was replaced with new text or deleted, the
-     *               length of the old text was <code>before-start</code>.
-     * @param after The offset of the end of the range of the text
-     *              that was modified.  If text was simply deleted,
-     *              this will be the same as <code>start</code>.
-     *              If text was replaced with new text or inserted,
-     *              the length of the new text is <code>after-start</code>.
+     * Within <code>text</code>, the <code>lengthAfter</code> characters
+     * beginning at <code>start</code> have just replaced old text that had
+     * length <code>lengthBefore</code>. It is an error to attempt to make
+     * changes to <code>text</code> from this callback.
+     *
+     * @param text The text the TextView is displaying
+     * @param start The offset of the start of the range of the text that was
+     * modified
+     * @param lengthBefore The length of the former text that has been replaced
+     * @param lengthAfter The length of the replacement modified text
      */
-    protected void onTextChanged(CharSequence text,
-                                 int start, int before, int after) {
+    protected void onTextChanged(CharSequence text, int start, int lengthBefore, int lengthAfter) {
+        // intentionally empty
     }
 
     /**
@@ -6795,6 +6779,7 @@
      * @param selEnd The new selection end location.
      */
     protected void onSelectionChanged(int selStart, int selEnd) {
+        // intentionally empty
     }
     
     /**
@@ -7336,9 +7321,6 @@
                 && mText instanceof Spannable && mLayout != null) {
             boolean handled = false;
 
-            final int oldScrollX = mScrollX;
-            final int oldScrollY = mScrollY;
-
             if (mMovement != null) {
                 handled |= mMovement.onTouchEvent(this, (Spannable) mText, event);
             }
@@ -7355,33 +7337,20 @@
                 }
             }
 
-            if (isTextEditable() || mTextIsSelectable) {
-                if (mScrollX != oldScrollX || mScrollY != oldScrollY) {
-                    // Hide insertion anchor while scrolling. Leave selection.
-                    hideInsertionPointCursorController();
-                    // No need to create the controller, since there is nothing to update.
-                    if (mSelectionModifierCursorController != null &&
-                            mSelectionModifierCursorController.isShowing()) {
-                        mSelectionModifierCursorController.updatePosition();
-                    }
+            if ((isTextEditable() || mTextIsSelectable) && touchIsFinished) {
+                // Show the IME, except when selecting in read-only text.
+                if (!mTextIsSelectable) {
+                    final InputMethodManager imm = InputMethodManager.peekInstance();
+                    handled |= imm != null && imm.showSoftInput(this, 0);
                 }
 
-                if (touchIsFinished) {
-                    // Show the IME, except when selecting in read-only text.
-                    if (!mTextIsSelectable) {
-                        final InputMethodManager imm = InputMethodManager.peekInstance();
-                        handled |= imm != null && imm.showSoftInput(this, 0);
-                    }
-
-
-                    boolean selectAllGotFocus = mSelectAllOnFocus && didTouchFocusSelect();
-                    if (!selectAllGotFocus && hasSelection()) {
-                        startSelectionActionMode();
-                    } else {
-                        stopSelectionActionMode();
-                        if (hasInsertionController() && !selectAllGotFocus && mText.length() > 0) {
-                            getInsertionController().show();
-                        }
+                boolean selectAllGotFocus = mSelectAllOnFocus && didTouchFocusSelect();
+                if (!selectAllGotFocus && hasSelection()) {
+                    startSelectionActionMode();
+                } else {
+                    stopSelectionActionMode();
+                    if (hasInsertionController() && !selectAllGotFocus && mText.length() > 0) {
+                        getInsertionController().show();
                     }
                 }
             }
@@ -7929,9 +7898,6 @@
                 text = getHint();
             }
             if (!TextUtils.isEmpty(text)) {
-                if (text.length() > AccessibilityEvent.MAX_TEXT_LENGTH) {
-                    text = text.subSequence(0, AccessibilityEvent.MAX_TEXT_LENGTH + 1);
-                }
                 event.getText().add(text);
             }
         } else {
@@ -8196,7 +8162,7 @@
             final int offset = getOffset(mLastDownPositionX, mLastDownPositionY);
             stopSelectionActionMode();
             Selection.setSelection((Spannable)mText, offset);
-            getInsertionController().show(0);
+            getInsertionController().showWithPaste();
             handled = true;
         }
 
@@ -8373,6 +8339,19 @@
         sLastCutOrCopyTime = SystemClock.uptimeMillis();
     }
 
+    public boolean setCorrectionSpan(IBinder token, CorrectionSpan span, int start, int end,
+            int flags) {
+        if (getWindowToken() != token || !(mText instanceof Spannable)) return false;
+        Spannable spannable = (Spannable)mText;
+        CorrectionSpan[] spans = spannable.getSpans(start, end, CorrectionSpan.class);
+        final int N = spans.length;
+        for (int i = 0; i < N; ++i) {
+            spannable.removeSpan(spans[i]);
+        }
+        spannable.setSpan(span, start, end, flags);
+        return true;
+    }
+
     /**
      * An ActionMode Callback class that is used to provide actions while in text selection mode.
      *
@@ -8469,55 +8448,6 @@
         }
     }
 
-    /**
-     * A CursorController instance can be used to control a cursor in the text.
-     * It is not used outside of {@link TextView}.
-     * @hide
-     */
-    private interface CursorController extends ViewTreeObserver.OnTouchModeChangeListener {
-        /**
-         * Makes the cursor controller visible on screen. Will be drawn by {@link #draw(Canvas)}.
-         * See also {@link #hide()}.
-         */
-        public void show();
-
-        /**
-         * Hide the cursor controller from screen.
-         * See also {@link #show()}.
-         */
-        public void hide();
-
-        /**
-         * @return true if the CursorController is currently visible
-         */
-        public boolean isShowing();
-
-        /**
-         * Update the controller's position.
-         */
-        public void updatePosition(HandleView handle, int x, int y);
-
-        public void updateOffset(HandleView handle, int offset);
-
-        public void updatePosition();
-
-        public int getCurrentOffset(HandleView handle);
-
-        /**
-         * This method is called by {@link #onTouchEvent(MotionEvent)} and gives the controller
-         * a chance to become active and/or visible.
-         * @param event The touch event
-         */
-        public boolean onTouchEvent(MotionEvent event);
-
-        /**
-         * Called when the view is detached from window. Perform house keeping task, such as
-         * stopping Runnable thread that would otherwise keep a reference on the context, thus
-         * preventing the activity to be recycled.
-         */
-        public void onDetached();
-    }
-
     private class PastePopupMenu implements OnClickListener {
         private final PopupWindow mContainer;
         private int mPositionX;
@@ -8653,27 +8583,43 @@
         }
     }
 
-    private class HandleView extends View implements ViewTreeObserver.OnScrollChangedListener {
-        private Drawable mDrawable;
-        private final ScrollingPopupWindow mContainer;
-        private int mPositionX;
-        private int mPositionY;
-        private final CursorController mController;
+    private abstract class HandleView extends View implements ViewTreeObserver.OnPreDrawListener {
+        protected Drawable mDrawable;
+        private final PopupWindow mContainer;
+        // Position with respect to the parent TextView
+        private int mPositionX, mPositionY;
         private boolean mIsDragging;
-        private float mTouchToWindowOffsetX;
-        private float mTouchToWindowOffsetY;
-        private float mHotspotX;
+        // Offset from touch position to mPosition
+        private float mTouchToWindowOffsetX, mTouchToWindowOffsetY;
+        protected float mHotspotX;
         // Offsets the hotspot point up, so that cursor is not hidden by the finger when moving up
         private float mTouchOffsetY;
         // Where the touch position should be on the handle to ensure a maximum cursor visibility
         private float mIdealVerticalOffset;
-        private int mLastParentX;
-        private int mLastParentY;
-        private float mDownPositionX, mDownPositionY;
+        // Parent's (TextView) position in window
+        private int mLastParentX, mLastParentY;
+        // PopupWindow container absolute position with respect to the enclosing window
         private int mContainerPositionX, mContainerPositionY;
-        private long mTouchTimer;
-        private boolean mIsInsertionHandle = false;
-        private PastePopupMenu mPastePopupWindow;
+        // Visible or not (scrolled off screen), whether or not this handle should be visible
+        private boolean mIsActive = false;
+
+        public HandleView() {
+            super(TextView.this.mContext);
+            mContainer = new PopupWindow(TextView.this.mContext, null,
+                    com.android.internal.R.attr.textSelectHandleWindowStyle);
+            mContainer.setSplitTouchEnabled(true);
+            mContainer.setClippingEnabled(false);
+            mContainer.setWindowLayoutType(WindowManager.LayoutParams.TYPE_APPLICATION_SUB_PANEL);
+            mContainer.setContentView(this);
+
+            initDrawable();
+
+            final int handleHeight = mDrawable.getIntrinsicHeight();
+            mTouchOffsetY = -0.3f * handleHeight;
+            mIdealVerticalOffset = 0.7f * handleHeight;
+        }
+
+        protected abstract void initDrawable();
 
         // Touch-up filter: number of previous positions remembered
         private static final int HISTORY_SIZE = 5;
@@ -8684,12 +8630,12 @@
         private int mPreviousOffsetIndex = 0;
         private int mNumberPreviousOffsets = 0;
 
-        public void startTouchUpFilter(int offset) {
+        private void startTouchUpFilter(int offset) {
             mNumberPreviousOffsets = 0;
             addPositionToTouchUpFilter(offset);
         }
 
-        public void addPositionToTouchUpFilter(int offset) {
+        private void addPositionToTouchUpFilter(int offset) {
             if (mNumberPreviousOffsets > 0 &&
                     mPreviousOffsets[mPreviousOffsetIndex] == offset) {
                 // Make sure only actual changes of position are recorded.
@@ -8702,7 +8648,7 @@
             mNumberPreviousOffsets++;
         }
 
-        public void filterOnTouchUp() {
+        private void filterOnTouchUp() {
             final long now = SystemClock.uptimeMillis();
             int i = 0;
             int index = mPreviousOffsetIndex;
@@ -8714,98 +8660,46 @@
 
             if (i > 0 && i < iMax &&
                     (now - mPreviousOffsetsTimes[index]) > TOUCH_UP_FILTER_DELAY_BEFORE) {
-                mController.updateOffset(this, mPreviousOffsets[index]);
+                updateOffset(mPreviousOffsets[index]);
             }
         }
 
-        public static final int LEFT = 0;
-        public static final int CENTER = 1;
-        public static final int RIGHT = 2;
-
-        public HandleView(CursorController controller, int pos) {
-            super(TextView.this.mContext);
-            mController = controller;
-            mContainer = new ScrollingPopupWindow(TextView.this.mContext, null,
-                    com.android.internal.R.attr.textSelectHandleWindowStyle);
-            mContainer.setSplitTouchEnabled(true);
-            mContainer.setClippingEnabled(false);
-            mContainer.setWindowLayoutType(WindowManager.LayoutParams.TYPE_APPLICATION_SUB_PANEL);
-
-            setOrientation(pos);
-        }
-
-        public void setOrientation(int pos) {
-            int handleWidth;
-            switch (pos) {
-                case LEFT: {
-                    if (mSelectHandleLeft == null) {
-                        mSelectHandleLeft = mContext.getResources().getDrawable(
-                                mTextSelectHandleLeftRes);
-                    }
-                    mDrawable = mSelectHandleLeft;
-                    handleWidth = mDrawable.getIntrinsicWidth();
-                    mHotspotX = handleWidth * 3.0f / 4.0f;
-                    break;
-                }
-
-                case RIGHT: {
-                    if (mSelectHandleRight == null) {
-                        mSelectHandleRight = mContext.getResources().getDrawable(
-                                mTextSelectHandleRightRes);
-                    }
-                    mDrawable = mSelectHandleRight;
-                    handleWidth = mDrawable.getIntrinsicWidth();
-                    mHotspotX = handleWidth / 4.0f;
-                    break;
-                }
-
-                case CENTER:
-                default: {
-                    if (mSelectHandleCenter == null) {
-                        mSelectHandleCenter = mContext.getResources().getDrawable(
-                                mTextSelectHandleRes);
-                    }
-                    mDrawable = mSelectHandleCenter;
-                    handleWidth = mDrawable.getIntrinsicWidth();
-                    mHotspotX = handleWidth / 2.0f;
-                    mIsInsertionHandle = true;
-                    break;
-                }
-            }
-
-            final int handleHeight = mDrawable.getIntrinsicHeight();
-
-            mTouchOffsetY = -0.3f * handleHeight;
-            mIdealVerticalOffset = 0.7f * handleHeight;
-            invalidate();
-        }
-
         @Override
         protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
-            setMeasuredDimension(mDrawable.getIntrinsicWidth(),
-                    mDrawable.getIntrinsicHeight());
+            setMeasuredDimension(mDrawable.getIntrinsicWidth(), mDrawable.getIntrinsicHeight());
         }
 
         public void show() {
-            if (!isPositionVisible()) {
-                hide();
-                return;
-            }
-            mContainer.setContentView(this);
-            mContainerPositionX = mPositionX;
-            mContainerPositionY = mPositionY - TextView.this.getHeight();
-            mContainer.showAsDropDown(TextView.this, mContainerPositionX, mContainerPositionY);
+            updateContainerPosition();
+            if (isShowing()) {
+                mContainer.update(mContainerPositionX, mContainerPositionY,
+                        mRight - mLeft, mBottom - mTop);
 
-            // Hide paste view when handle is moved on screen.
-            hidePastePopupWindow();
+                hideAssociatedPopupWindow();
+            } else {
+                mContainer.showAtLocation(TextView.this, 0,
+                        mContainerPositionX, mContainerPositionY);
+
+                mIsActive = true;
+
+                ViewTreeObserver vto = TextView.this.getViewTreeObserver();
+                vto.addOnPreDrawListener(this);
+            }
+        }
+
+        protected void dismiss() {
+            mIsDragging = false;
+            mContainer.dismiss();
+            hideAssociatedPopupWindow();
         }
 
         public void hide() {
-            mIsDragging = false;
-            mContainer.dismiss();
-            hidePastePopupWindow();
+            dismiss();
+
+            mIsActive = false;
+
             ViewTreeObserver vto = TextView.this.getViewTreeObserver();
-            vto.removeOnScrollChangedListener(this);
+            vto.removeOnPreDrawListener(this);
         }
 
         public boolean isShowing() {
@@ -8829,9 +8723,7 @@
 
             final TextView hostView = TextView.this;
 
-            if (mTempRect == null) {
-                mTempRect = new Rect();
-            }
+            if (mTempRect == null) mTempRect = new Rect();
             final Rect clip = mTempRect;
             clip.left = compoundPaddingLeft;
             clip.top = extendedPaddingTop;
@@ -8856,44 +8748,83 @@
         private void moveTo(int x, int y) {
             mPositionX = x - TextView.this.mScrollX;
             mPositionY = y - TextView.this.mScrollY;
-            if (isPositionVisible()) {
-                int[] coords = null;
-                if (mContainer.isShowing()) {
-                    final int containerPositionX = mPositionX;
-                    final int containerPositionY = mPositionY - TextView.this.getHeight();
 
-                    if (containerPositionX != mContainerPositionX || 
-                        containerPositionY != mContainerPositionY) {
-                        mContainerPositionX = containerPositionX;
-                        mContainerPositionY = containerPositionY;
+            if (mIsDragging) {
+                TextView.this.getLocationInWindow(mTempCoords);
+                if (mTempCoords[0] != mLastParentX || mTempCoords[1] != mLastParentY) {
+                    mTouchToWindowOffsetX += mTempCoords[0] - mLastParentX;
+                    mTouchToWindowOffsetY += mTempCoords[1] - mLastParentY;
+                    mLastParentX = mTempCoords[0];
+                    mLastParentY = mTempCoords[1];
+                }
 
-                        mContainer.update(TextView.this, mContainerPositionX, mContainerPositionY,
-                                mRight - mLeft, mBottom - mTop);
+                hideAssociatedPopupWindow();
+            }
+        }
 
-                        // Hide paste popup window as soon as a scroll occurs.
-                        hidePastePopupWindow();
+        public abstract int getCurrentCursorOffset();
+
+        public abstract void updateOffset(int offset);
+
+        public abstract void updatePosition(int x, int y);
+
+        protected void positionAtCursorOffset(int offset) {
+            addPositionToTouchUpFilter(offset);
+            final int width = mDrawable.getIntrinsicWidth();
+            final int height = mDrawable.getIntrinsicHeight();
+            final int line = mLayout.getLineForOffset(offset);
+            final int lineBottom = mLayout.getLineBottom(line);
+
+            final Rect bounds = sCursorControllerTempRect;
+            bounds.left = (int) (mLayout.getPrimaryHorizontal(offset) - 0.5f - mHotspotX) +
+                    TextView.this.mScrollX;
+            bounds.top = lineBottom + TextView.this.mScrollY;
+
+            bounds.right = bounds.left + width;
+            bounds.bottom = bounds.top + height;
+
+            convertFromViewportToContentCoordinates(bounds);
+            moveTo(bounds.left, bounds.top);
+        }
+
+        /**
+         * Updates the global container's position.
+         * @return whether or not the position has actually changed
+         */
+        private boolean updateContainerPosition() {
+            positionAtCursorOffset(getCurrentCursorOffset());
+            TextView.this.getLocationInWindow(mTempCoords);
+            final int containerPositionX = mTempCoords[0] + mPositionX;
+            final int containerPositionY = mTempCoords[1] + mPositionY;
+
+            if (containerPositionX != mContainerPositionX ||
+                containerPositionY != mContainerPositionY) {
+                mContainerPositionX = containerPositionX;
+                mContainerPositionY = containerPositionY;
+                return true;
+            }
+            return false;
+        }
+
+        public boolean onPreDraw() {
+            if (updateContainerPosition()) {
+                if (isPositionVisible()) {
+                    mContainer.update(mContainerPositionX, mContainerPositionY,
+                            mRight - mLeft, mBottom - mTop);
+
+                    if (mIsActive && !isShowing()) {
+                        show();
                     }
                 } else {
-                    show();
+                    if (isShowing()) {
+                        dismiss();
+                    }
                 }
 
-                if (mIsDragging) {
-                    if (coords == null) {
-                        coords = mTempCoords;
-                        TextView.this.getLocationInWindow(coords);
-                    }
-                    if (coords[0] != mLastParentX || coords[1] != mLastParentY) {
-                        mTouchToWindowOffsetX += coords[0] - mLastParentX;
-                        mTouchToWindowOffsetY += coords[1] - mLastParentY;
-                        mLastParentX = coords[0];
-                        mLastParentY = coords[1];
-                    }
-                    // Hide paste popup window as soon as the handle is dragged.
-                    hidePastePopupWindow();
-                }
-            } else {
-                hide();
+                // Hide paste popup as soon as the view is scrolled or moved
+                hideAssociatedPopupWindow();
             }
+            return true;
         }
 
         @Override
@@ -8906,20 +8837,15 @@
         public boolean onTouchEvent(MotionEvent ev) {
             switch (ev.getActionMasked()) {
                 case MotionEvent.ACTION_DOWN: {
-                    startTouchUpFilter(mController.getCurrentOffset(this));
-                    mDownPositionX = ev.getRawX();
-                    mDownPositionY = ev.getRawY();
-                    mTouchToWindowOffsetX = mDownPositionX - mPositionX;
-                    mTouchToWindowOffsetY = mDownPositionY - mPositionY;
+                    startTouchUpFilter(getCurrentCursorOffset());
+                    mTouchToWindowOffsetX = ev.getRawX() - mPositionX;
+                    mTouchToWindowOffsetY = ev.getRawY() - mPositionY;
 
                     final int[] coords = mTempCoords;
                     TextView.this.getLocationInWindow(coords);
                     mLastParentX = coords[0];
                     mLastParentY = coords[1];
                     mIsDragging = true;
-                    if (mIsInsertionHandle) {
-                        mTouchTimer = SystemClock.uptimeMillis();
-                    }
                     break;
                 }
 
@@ -8943,27 +8869,11 @@
                     final float newPosX = rawX - mTouchToWindowOffsetX + mHotspotX;
                     final float newPosY = rawY - mTouchToWindowOffsetY + mTouchOffsetY;
 
-                    mController.updatePosition(this, Math.round(newPosX), Math.round(newPosY));
+                    updatePosition(Math.round(newPosX), Math.round(newPosY));
                     break;
                 }
 
                 case MotionEvent.ACTION_UP:
-                    if (mIsInsertionHandle) {
-                        long delay = SystemClock.uptimeMillis() - mTouchTimer;
-                        if (delay < ViewConfiguration.getTapTimeout()) {
-                            final float deltaX = mDownPositionX - ev.getRawX();
-                            final float deltaY = mDownPositionY - ev.getRawY();
-                            final float distanceSquared = deltaX * deltaX + deltaY * deltaY;
-                            if (distanceSquared < mSquaredTouchSlopDistance) {
-                                if (mPastePopupWindow != null && mPastePopupWindow.isShowing()) {
-                                    // Tapping on the handle dismisses the displayed paste view,
-                                    mPastePopupWindow.hide();
-                                } else {
-                                    ((InsertionPointCursorController) mController).show(0);
-                                }
-                            }
-                        }
-                    }
                     filterOnTouchUp();
                     mIsDragging = false;
                     break;
@@ -8979,104 +8889,40 @@
             return mIsDragging;
         }
 
-        void positionAtCursor(final int offset) {
-            addPositionToTouchUpFilter(offset);
-            final int width = mDrawable.getIntrinsicWidth();
-            final int height = mDrawable.getIntrinsicHeight();
-            final int line = mLayout.getLineForOffset(offset);
-            final int lineBottom = mLayout.getLineBottom(line);
-
-            final Rect bounds = sCursorControllerTempRect;
-            bounds.left = (int) (mLayout.getPrimaryHorizontal(offset) - 0.5f - mHotspotX) +
-                    TextView.this.mScrollX;
-            bounds.top = lineBottom + TextView.this.mScrollY;
-
-            bounds.right = bounds.left + width;
-            bounds.bottom = bounds.top + height;
-
-            convertFromViewportToContentCoordinates(bounds);
-            moveTo(bounds.left, bounds.top);
+        void hideAssociatedPopupWindow() {
+            // No associated popup window by default
         }
-
-        void showPastePopupWindow() {
-            if (mIsInsertionHandle) {
-                if (mPastePopupWindow == null) {
-                    // Lazy initialisation: create when actually shown only.
-                    mPastePopupWindow = new PastePopupMenu();
-                }
-                mPastePopupWindow.show();
-            }
-        }
-
-        void hidePastePopupWindow() {
-            if (mPastePopupWindow != null) {
-                mPastePopupWindow.hide();
-            }
-        }
-
-        /**
-         * A popup window, attached to a view, and that listens to scroll events in its anchors'
-         * view hierarchy, so that it is automatically moved on such events.
-         */
-        private class ScrollingPopupWindow extends PopupWindow {
-
-            private int[] mDrawingLocations = new int[2];
-
-            public ScrollingPopupWindow(Context context, AttributeSet attrs, int defStyle) {
-                super(context, attrs, defStyle);
-            }
-
-            @Override
-            public boolean findDropDownPosition(View anchor, WindowManager.LayoutParams p,
-                    int xoff, int yoff) {
-                anchor.getLocationInWindow(mDrawingLocations);
-                p.x = mDrawingLocations[0] + xoff;
-                p.y = mDrawingLocations[1] + anchor.getHeight() + yoff;
-
-                // Hide paste popup as soon as the view is scrolled.
-                hidePastePopupWindow();
-
-                if (!isPositionVisible()) {
-                    dismiss();
-                    onHandleBecomeInvisible();
-                }
-
-                return false;
-            }
-        }
-
-        public void onScrollChanged() {
-            if (isPositionVisible()) {
-                show();
-                ViewTreeObserver vto = TextView.this.getViewTreeObserver();
-                vto.removeOnScrollChangedListener(this);
-            }
-        }
-
-        public void onHandleBecomeInvisible() {
-            ViewTreeObserver vto = TextView.this.getViewTreeObserver();
-            vto.addOnScrollChangedListener(this);
+        
+        public void onDetached() {
+            // Should be overriden to clean possible Runnable
         }
     }
 
-    private class InsertionPointCursorController implements CursorController {
+    private class InsertionHandleView extends HandleView {
         private static final int DELAY_BEFORE_FADE_OUT = 4000;
-        private static final int DELAY_BEFORE_PASTE = 2000;
-        private static final int RECENT_CUT_COPY_DURATION = 15 * 1000;
+        private static final int RECENT_CUT_COPY_DURATION = 15 * 1000; // seconds
 
-        // The cursor controller image. Lazily created.
-        private HandleView mHandle;
+        // Used to detect taps on the insertion handle, which will affect the PastePopupMenu
+        private long mTouchTimer;
+        private float mDownPositionX, mDownPositionY;
+        private PastePopupMenu mPastePopupWindow;
         private Runnable mHider;
         private Runnable mPastePopupShower;
 
+        public InsertionHandleView() {
+            super();
+        }
+
+        @Override
         public void show() {
-            show(DELAY_BEFORE_PASTE);
+            super.show();
+            hideDelayed();
+            removePastePopupCallback();
         }
 
         public void show(int delayBeforePaste) {
-            updatePosition();
-            hideDelayed();
-            removePastePopupCallback();
+            show();
+
             final long durationSinceCutOrCopy = SystemClock.uptimeMillis() - sLastCutOrCopyTime;
             if (durationSinceCutOrCopy < RECENT_CUT_COPY_DURATION) {
                 delayBeforePaste = 0;
@@ -9085,7 +8931,7 @@
                 if (mPastePopupShower == null) {
                     mPastePopupShower = new Runnable() {
                         public void run() {
-                            getHandle().showPastePopupWindow();
+                            showAssociatedPopupWindow();
                         }
                     };
                 }
@@ -9093,24 +8939,15 @@
             }
         }
 
-        private void removePastePopupCallback() {
-            if (mPastePopupShower != null) {
-                removeCallbacks(mPastePopupShower);
-            }
+        @Override
+        protected void dismiss() {
+            super.dismiss();
+            onDetached();
         }
 
-        private void removeHiderCallback() {
-            if (mHider != null) {
-                removeCallbacks(mHider);
-            }
-        }
-
+        @Override
         public void hide() {
-            if (mHandle != null) {
-                mHandle.hide();
-            }
-            removeHiderCallback();
-            removePastePopupCallback();
+            super.hide();
         }
 
         private void hideDelayed() {
@@ -9125,41 +8962,244 @@
             postDelayed(mHider, DELAY_BEFORE_FADE_OUT);
         }
 
-        public boolean isShowing() {
-            return mHandle != null && mHandle.isShowing();
+        private void removePastePopupCallback() {
+            if (mPastePopupShower != null) {
+                removeCallbacks(mPastePopupShower);
+            }
         }
 
-        public void updatePosition(HandleView handle, int x, int y) {
-            final int previousOffset = getSelectionStart();
+        private void removeHiderCallback() {
+            if (mHider != null) {
+                removeCallbacks(mHider);
+            }
+        }
+
+        @Override
+        protected void initDrawable() {
+            if (mSelectHandleCenter == null) {
+                mSelectHandleCenter = mContext.getResources().getDrawable(
+                        mTextSelectHandleRes);
+            }
+            mDrawable = mSelectHandleCenter;
+            mHotspotX = mDrawable.getIntrinsicWidth() / 2.0f;
+        }
+
+        @Override
+        public boolean onTouchEvent(MotionEvent ev) {
+            final boolean result = super.onTouchEvent(ev);
+
+            switch (ev.getActionMasked()) {
+                case MotionEvent.ACTION_DOWN:
+                    mDownPositionX = ev.getRawX();
+                    mDownPositionY = ev.getRawY();
+                    mTouchTimer = SystemClock.uptimeMillis();
+                    break;
+
+                case MotionEvent.ACTION_UP:
+                    long delay = SystemClock.uptimeMillis() - mTouchTimer;
+                    if (delay < ViewConfiguration.getTapTimeout()) {
+                        final float deltaX = mDownPositionX - ev.getRawX();
+                        final float deltaY = mDownPositionY - ev.getRawY();
+                        final float distanceSquared = deltaX * deltaX + deltaY * deltaY;
+                        if (distanceSquared < mSquaredTouchSlopDistance) {
+                            if (mPastePopupWindow != null && mPastePopupWindow.isShowing()) {
+                                // Tapping on the handle dismisses the displayed paste view,
+                                mPastePopupWindow.hide();
+                            } else {
+                                show(0);
+                            }
+                        }
+                    }
+                    break;
+
+                default:
+                    break;
+            }
+
+            return result;
+        }
+
+        @Override
+        public int getCurrentCursorOffset() {
+            return TextView.this.getSelectionStart();
+        }
+
+        @Override
+        public void updateOffset(int offset) {
+            Selection.setSelection((Spannable) mText, offset);
+            positionAtCursorOffset(offset);
+        }
+
+        @Override
+        public void updatePosition(int x, int y) {
+            final int previousOffset = getCurrentCursorOffset();
             final int newOffset = getOffset(x, y);
 
             if (newOffset != previousOffset) {
-                updateOffset(handle, newOffset);
+                updateOffset(newOffset);
                 removePastePopupCallback();
             }
             hideDelayed();
         }
 
-        public void updateOffset(HandleView handle, int offset) {
-            Selection.setSelection((Spannable) mText, offset);
-            updatePosition();
-        }
-
-        public void updatePosition() {
-            final int offset = getSelectionStart();
-
-            if (offset < 0) {
-                // Should never happen, safety check.
-                Log.w(LOG_TAG, "Update cursor controller position called with no cursor");
-                hide();
-                return;
+        void showAssociatedPopupWindow() {
+            if (mPastePopupWindow == null) {
+                // Lazy initialisation: create when actually shown only.
+                mPastePopupWindow = new PastePopupMenu();
             }
-
-            getHandle().positionAtCursor(offset);
+            mPastePopupWindow.show();
         }
 
-        public int getCurrentOffset(HandleView handle) {
-            return getSelectionStart();
+        @Override
+        void hideAssociatedPopupWindow() {
+            if (mPastePopupWindow != null) {
+                mPastePopupWindow.hide();
+            }
+        }
+
+        @Override
+        public void onDetached() {
+            removeHiderCallback();
+            removePastePopupCallback();
+        }
+    }
+
+    private class SelectionStartHandleView extends HandleView {
+        public SelectionStartHandleView() {
+            super();
+        }
+
+        @Override
+        protected void initDrawable() {
+            if (mSelectHandleLeft == null) {
+                mSelectHandleLeft = mContext.getResources().getDrawable(
+                        mTextSelectHandleLeftRes);
+            }
+            mDrawable = mSelectHandleLeft;
+            mHotspotX = mDrawable.getIntrinsicWidth() * 3.0f / 4.0f;
+        }
+
+        @Override
+        public int getCurrentCursorOffset() {
+            return TextView.this.getSelectionStart();
+        }
+
+        @Override
+        public void updateOffset(int offset) {
+            Selection.setSelection((Spannable) mText, offset, getSelectionEnd());
+            positionAtCursorOffset(offset);
+        }
+
+        @Override
+        public void updatePosition(int x, int y) {
+            final int selectionStart = getSelectionStart();
+            final int selectionEnd = getSelectionEnd();
+
+            int offset = getOffset(x, y);
+
+            // No need to redraw when the offset is unchanged
+            if (offset == selectionStart) return;
+            // Handles can not cross and selection is at least one character
+            if (offset >= selectionEnd) offset = selectionEnd - 1;
+
+            Selection.setSelection((Spannable) mText, offset, selectionEnd);
+            positionAtCursorOffset(offset);
+        }
+    }
+
+    private class SelectionEndHandleView extends HandleView {
+        public SelectionEndHandleView() {
+            super();
+        }
+
+        @Override
+        protected void initDrawable() {
+            if (mSelectHandleRight == null) {
+                mSelectHandleRight = mContext.getResources().getDrawable(
+                        mTextSelectHandleRightRes);
+            }
+            mDrawable = mSelectHandleRight;
+            mHotspotX = mDrawable.getIntrinsicWidth() / 4.0f;
+        }
+
+        @Override
+        public int getCurrentCursorOffset() {
+            return TextView.this.getSelectionEnd();
+        }
+
+        @Override
+        public void updateOffset(int offset) {
+            Selection.setSelection((Spannable) mText, getSelectionStart(), offset);
+            positionAtCursorOffset(offset);
+        }
+
+        @Override
+        public void updatePosition(int x, int y) {
+            final int selectionStart = getSelectionStart();
+            final int selectionEnd = getSelectionEnd();
+
+            int offset = getOffset(x, y);
+
+            // No need to redraw when the offset is unchanged
+            if (offset == selectionEnd) return;
+            // Handles can not cross and selection is at least one character
+            if (offset <= selectionStart) offset = selectionStart + 1;
+
+            Selection.setSelection((Spannable) mText, selectionStart, offset);
+            positionAtCursorOffset(offset);
+        }
+    }
+
+    /**
+     * A CursorController instance can be used to control a cursor in the text.
+     * It is not used outside of {@link TextView}.
+     * @hide
+     */
+    private interface CursorController extends ViewTreeObserver.OnTouchModeChangeListener {
+        /**
+         * Makes the cursor controller visible on screen. Will be drawn by {@link #draw(Canvas)}.
+         * See also {@link #hide()}.
+         */
+        public void show();
+
+        /**
+         * Hide the cursor controller from screen.
+         * See also {@link #show()}.
+         */
+        public void hide();
+
+        /**
+         * This method is called by {@link #onTouchEvent(MotionEvent)} and gives the controller
+         * a chance to become active and/or visible.
+         * @param event The touch event
+         */
+        public boolean onTouchEvent(MotionEvent event);
+
+        /**
+         * Called when the view is detached from window. Perform house keeping task, such as
+         * stopping Runnable thread that would otherwise keep a reference on the context, thus
+         * preventing the activity from being recycled.
+         */
+        public void onDetached();
+    }
+
+    private class InsertionPointCursorController implements CursorController {
+        private static final int DELAY_BEFORE_PASTE = 2000;
+
+        private InsertionHandleView mHandle;
+
+        public void show() {
+            ((InsertionHandleView) getHandle()).show(DELAY_BEFORE_PASTE);
+        }
+
+        public void showWithPaste() {
+            ((InsertionHandleView) getHandle()).show(0);
+        }
+
+        public void hide() {
+            if (mHandle != null) {
+                mHandle.hide();
+            }
         }
 
         public boolean onTouchEvent(MotionEvent ev) {
@@ -9174,30 +9214,27 @@
 
         private HandleView getHandle() {
             if (mHandle == null) {
-                mHandle = new HandleView(this, HandleView.CENTER);
+                mHandle = new InsertionHandleView();
             }
             return mHandle;
         }
 
         @Override
         public void onDetached() {
-            removeHiderCallback();
-            removePastePopupCallback();
+            if (mHandle != null) mHandle.onDetached();
         }
     }
 
     private class SelectionModifierCursorController implements CursorController {
-        // The cursor controller images, lazily created when shown.
-        private HandleView mStartHandle, mEndHandle;
+        // The cursor controller handles, lazily created when shown.
+        private SelectionStartHandleView mStartHandle;
+        private SelectionEndHandleView mEndHandle;
         // The offsets of that last touch down event. Remembered to start selection there.
         private int mMinTouchOffset, mMaxTouchOffset;
-        // Whether selection anchors are active
-        private boolean mIsShowing;
 
         // Double tap detection
         private long mPreviousTapUpTime = 0;
-        private int mPreviousTapPositionX;
-        private int mPreviousTapPositionY;
+        private int mPreviousTapPositionX, mPreviousTapPositionY;
 
         SelectionModifierCursorController() {
             resetTouchOffsets();
@@ -9209,11 +9246,8 @@
             }
 
             // Lazy object creation has to be done before updatePosition() is called.
-            if (mStartHandle == null) mStartHandle = new HandleView(this, HandleView.LEFT);
-            if (mEndHandle == null) mEndHandle = new HandleView(this, HandleView.RIGHT);
-
-            mIsShowing = true;
-            updatePosition();
+            if (mStartHandle == null) mStartHandle = new SelectionStartHandleView();
+            if (mEndHandle == null) mEndHandle = new SelectionEndHandleView();
 
             mStartHandle.show();
             mEndHandle.show();
@@ -9224,82 +9258,6 @@
         public void hide() {
             if (mStartHandle != null) mStartHandle.hide();
             if (mEndHandle != null) mEndHandle.hide();
-            mIsShowing = false;
-        }
-
-        public boolean isShowing() {
-            return mIsShowing;
-        }
-
-        public void updatePosition(HandleView handle, int x, int y) {
-            int selectionStart = getSelectionStart();
-            int selectionEnd = getSelectionEnd();
-
-            int offset = getOffset(x, y);
-
-            // Handle the case where start and end are swapped, making sure start <= end
-            if (handle == mStartHandle) {
-                if (selectionStart == offset || offset > selectionEnd) {
-                    return; // no change, no need to redraw;
-                }
-                // If the user "closes" the selection entirely they were probably trying to
-                // select a single character. Help them out.
-                if (offset == selectionEnd) {
-                    offset = selectionEnd - 1;
-                }
-                selectionStart = offset;
-            } else {
-                if (selectionEnd == offset || offset < selectionStart) {
-                    return; // no change, no need to redraw;
-                }
-                // If the user "closes" the selection entirely they were probably trying to
-                // select a single character. Help them out.
-                if (offset == selectionStart) {
-                    offset = selectionStart + 1;
-                }
-                selectionEnd = offset;
-            }
-
-            Selection.setSelection((Spannable) mText, selectionStart, selectionEnd);
-            updatePosition();
-        }
-
-        public void updateOffset(HandleView handle, int offset) {
-            int start = getSelectionStart();
-            int end = getSelectionEnd();
-
-            if (mStartHandle == handle) {
-                start = offset;
-            } else {
-                end = offset;
-            }
-
-            Selection.setSelection((Spannable) mText, start, end);
-            updatePosition();
-        }
-
-        public void updatePosition() {
-            if (!isShowing()) {
-                return;
-            }
-
-            final int selectionStart = getSelectionStart();
-            final int selectionEnd = getSelectionEnd();
-
-            if ((selectionStart < 0) || (selectionEnd < 0)) {
-                // Should never happen, safety check.
-                Log.w(LOG_TAG, "Update selection controller position called with no cursor");
-                hide();
-                return;
-            }
-
-            // The handles have been created since the controller isShowing().
-            mStartHandle.positionAtCursor(selectionStart);
-            mEndHandle.positionAtCursor(selectionEnd);
-        }
-
-        public int getCurrentOffset(HandleView handle) {
-            return mStartHandle == handle ? getSelectionStart() : getSelectionEnd();
         }
 
         public boolean onTouchEvent(MotionEvent event) {
@@ -9390,7 +9348,10 @@
         }
 
         @Override
-        public void onDetached() {}
+        public void onDetached() {
+            if (mStartHandle != null) mStartHandle.onDetached();
+            if (mEndHandle != null) mEndHandle.onDetached();
+        }
     }
 
     private void hideInsertionPointCursorController() {
diff --git a/core/java/com/android/internal/app/ActionBarImpl.java b/core/java/com/android/internal/app/ActionBarImpl.java
index 8f1354b..b712fdb 100644
--- a/core/java/com/android/internal/app/ActionBarImpl.java
+++ b/core/java/com/android/internal/app/ActionBarImpl.java
@@ -889,23 +889,24 @@
         return mTabs.get(index);
     }
 
-    /**
-     * This fragment is added when we're keeping a back stack in a tab switch
-     * transaction. We use it to change the selected tab in the action bar view
-     * when we back out.
-     */
-    private class SwitchSelectedTabViewFragment extends Fragment {
-        private int mSelectedTabIndex;
 
-        public SwitchSelectedTabViewFragment(int oldSelectedTab) {
-            mSelectedTabIndex = oldSelectedTab;
-        }
+    @Override
+    public void setIcon(int resId) {
+        mActionView.setIcon(mContext.getResources().getDrawable(resId));
+    }
 
-        @Override
-        public void onDetach() {
-            if (mSelectedTabIndex >= 0 && mSelectedTabIndex < getTabCount()) {
-                mActionView.setTabSelected(mSelectedTabIndex);
-            }
-        }
+    @Override
+    public void setIcon(Drawable icon) {
+        mActionView.setIcon(icon);
+    }
+
+    @Override
+    public void setLogo(int resId) {
+        mActionView.setLogo(mContext.getResources().getDrawable(resId));
+    }
+
+    @Override
+    public void setLogo(Drawable logo) {
+        mActionView.setLogo(logo);
     }
 }
diff --git a/core/java/com/android/internal/app/IMediaContainerService.aidl b/core/java/com/android/internal/app/IMediaContainerService.aidl
index aee1626..dd22e25 100755
--- a/core/java/com/android/internal/app/IMediaContainerService.aidl
+++ b/core/java/com/android/internal/app/IMediaContainerService.aidl
@@ -27,8 +27,9 @@
                 String key, String resFileName);
     boolean copyResource(in Uri packageURI,
                 in ParcelFileDescriptor outStream);
-    PackageInfoLite getMinimalPackageInfo(in Uri fileUri, int flags);
-    boolean checkFreeStorage(boolean external, in Uri fileUri);
+    PackageInfoLite getMinimalPackageInfo(in Uri fileUri, in int flags, in long threshold);
+    boolean checkInternalFreeStorage(in Uri fileUri, in long threshold);
+    boolean checkExternalFreeStorage(in Uri fileUri);
     ObbInfo getObbInfo(in String filename);
     long calculateDirectorySize(in String directory);
 }
diff --git a/core/java/com/android/internal/app/LocalePicker.java b/core/java/com/android/internal/app/LocalePicker.java
index e32c62d..52cb679 100644
--- a/core/java/com/android/internal/app/LocalePicker.java
+++ b/core/java/com/android/internal/app/LocalePicker.java
@@ -88,7 +88,7 @@
     public static ArrayAdapter<LocaleInfo> constructAdapter(Context context,
             int layoutId, int fieldId) {
         final Resources resources = context.getResources();
-        final String[] locales = context.getAssets().getLocales();
+        final String[] locales = Resources.getSystem().getAssets().getLocales();
         final String[] specialLocaleCodes = resources.getStringArray(R.array.special_locale_codes);
         final String[] specialLocaleNames = resources.getStringArray(R.array.special_locale_names);
         Arrays.sort(locales);
diff --git a/core/java/com/android/internal/app/ResolverActivity.java b/core/java/com/android/internal/app/ResolverActivity.java
index fb2a72b..2e56996 100644
--- a/core/java/com/android/internal/app/ResolverActivity.java
+++ b/core/java/com/android/internal/app/ResolverActivity.java
@@ -68,7 +68,7 @@
 
     protected void onCreate(Bundle savedInstanceState, Intent intent,
             CharSequence title, Intent[] initialIntents, List<ResolveInfo> rList,
-            boolean alwaysUseOption, boolean alwaysChoose) {
+            boolean alwaysUseOption) {
         super.onCreate(savedInstanceState);
         mPm = getPackageManager();
         intent.setComponent(null);
@@ -91,7 +91,7 @@
         }
         mAdapter = new ResolveListAdapter(this, intent, initialIntents, rList);
         int count = mAdapter.getCount();
-        if (count > 1 || (count == 1 && alwaysChoose)) {
+        if (count > 1) {
             ap.mAdapter = mAdapter;
         } else if (count == 1) {
             startActivity(mAdapter.intentForPosition(0));
@@ -104,12 +104,6 @@
         setupAlert();
     }
 
-    protected void onCreate(Bundle savedInstanceState, Intent intent,
-            CharSequence title, Intent[] initialIntents, List<ResolveInfo> rList,
-            boolean alwaysUseOption) {
-        onCreate(savedInstanceState, intent, title, initialIntents, rList, alwaysUseOption, false);
-      }
-
     public void onClick(DialogInterface dialog, int which) {
         ResolveInfo ri = mAdapter.resolveInfoForPosition(which);
         Intent intent = mAdapter.intentForPosition(which);
diff --git a/core/java/com/android/internal/content/PackageHelper.java b/core/java/com/android/internal/content/PackageHelper.java
index d6c43f9..b57046c 100644
--- a/core/java/com/android/internal/content/PackageHelper.java
+++ b/core/java/com/android/internal/content/PackageHelper.java
@@ -56,18 +56,13 @@
         return null;
     }
 
-    public static String createSdDir(long sizeBytes, String cid,
+    public static String createSdDir(int sizeMb, String cid,
             String sdEncKey, int uid) {
         // Create mount point via MountService
         IMountService mountService = getMountService();
-        int sizeMb = (int) (sizeBytes >> 20);
-        if ((sizeBytes - (sizeMb * 1024 * 1024)) > 0) {
-            sizeMb++;
-        }
-        // Add buffer size
-        sizeMb++;
+
         if (localLOGV)
-            Log.i(TAG, "Size of container " + sizeMb + " MB " + sizeBytes + " bytes");
+            Log.i(TAG, "Size of container " + sizeMb + " MB");
 
         try {
             int rc = mountService.createSecureContainer(
diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java
index 1cca21d..d86504d 100644
--- a/core/java/com/android/internal/os/BatteryStatsImpl.java
+++ b/core/java/com/android/internal/os/BatteryStatsImpl.java
@@ -1581,7 +1581,7 @@
             
             // Update discharge amounts.
             if (mOnBatteryInternal) {
-                updateDischargeScreenLevels(false, true);
+                updateDischargeScreenLevelsLocked(false, true);
             }
         }
     }
@@ -1602,7 +1602,7 @@
             
             // Update discharge amounts.
             if (mOnBatteryInternal) {
-                updateDischargeScreenLevels(true, false);
+                updateDischargeScreenLevelsLocked(true, false);
             }
         }
     }
@@ -4030,7 +4030,7 @@
         clearHistoryLocked();
     }
 
-    void updateDischargeScreenLevels(boolean oldScreenOn, boolean newScreenOn) {
+    void updateDischargeScreenLevelsLocked(boolean oldScreenOn, boolean newScreenOn) {
         if (oldScreenOn) {
             int diff = mDischargeScreenOnUnplugLevel - mDischargeCurrentLevel;
             if (diff > 0) {
@@ -4055,69 +4055,73 @@
     
     void setOnBattery(boolean onBattery, int oldStatus, int level) {
         synchronized(this) {
-            boolean doWrite = false;
-            Message m = mHandler.obtainMessage(MSG_REPORT_POWER_CHANGE);
-            m.arg1 = onBattery ? 1 : 0;
-            mHandler.sendMessage(m);
-            mOnBattery = mOnBatteryInternal = onBattery;
+            setOnBatteryLocked(onBattery, oldStatus, level);
+        }
+    }
 
-            long uptime = SystemClock.uptimeMillis() * 1000;
-            long mSecRealtime = SystemClock.elapsedRealtime();
-            long realtime = mSecRealtime * 1000;
-            if (onBattery) {
-                // We will reset our status if we are unplugging after the
-                // battery was last full, or the level is at 100, or
-                // we have gone through a significant charge (from a very low
-                // level to a now very high level).
-                if (oldStatus == BatteryManager.BATTERY_STATUS_FULL
-                        || level >= 90
-                        || (mDischargeCurrentLevel < 20 && level >= 80)) {
-                    doWrite = true;
-                    resetAllStatsLocked();
-                    mDischargeStartLevel = level;
-                }
-                updateKernelWakelocksLocked();
-                mHistoryCur.batteryLevel = (byte)level;
-                mHistoryCur.states &= ~HistoryItem.STATE_BATTERY_PLUGGED_FLAG;
-                if (DEBUG_HISTORY) Slog.v(TAG, "Battery unplugged to: "
-                        + Integer.toHexString(mHistoryCur.states));
-                addHistoryRecordLocked(mSecRealtime);
-                mTrackBatteryUptimeStart = uptime;
-                mTrackBatteryRealtimeStart = realtime;
-                mUnpluggedBatteryUptime = getBatteryUptimeLocked(uptime);
-                mUnpluggedBatteryRealtime = getBatteryRealtimeLocked(realtime);
-                mDischargeCurrentLevel = mDischargeUnplugLevel = level;
-                if (mScreenOn) {
-                    mDischargeScreenOnUnplugLevel = level;
-                    mDischargeScreenOffUnplugLevel = 0;
-                } else {
-                    mDischargeScreenOnUnplugLevel = 0;
-                    mDischargeScreenOffUnplugLevel = level;
-                }
-                mDischargeAmountScreenOn = 0;
-                mDischargeAmountScreenOff = 0;
-                doUnplugLocked(mUnpluggedBatteryUptime, mUnpluggedBatteryRealtime);
-            } else {
-                updateKernelWakelocksLocked();
-                mHistoryCur.batteryLevel = (byte)level;
-                mHistoryCur.states |= HistoryItem.STATE_BATTERY_PLUGGED_FLAG;
-                if (DEBUG_HISTORY) Slog.v(TAG, "Battery plugged to: "
-                        + Integer.toHexString(mHistoryCur.states));
-                addHistoryRecordLocked(mSecRealtime);
-                mTrackBatteryPastUptime += uptime - mTrackBatteryUptimeStart;
-                mTrackBatteryPastRealtime += realtime - mTrackBatteryRealtimeStart;
-                mDischargeCurrentLevel = level;
-                if (level < mDischargeUnplugLevel) {
-                    mLowDischargeAmountSinceCharge += mDischargeUnplugLevel-level-1;
-                    mHighDischargeAmountSinceCharge += mDischargeUnplugLevel-level;
-                }
-                updateDischargeScreenLevels(mScreenOn, mScreenOn);
-                doPlugLocked(getBatteryUptimeLocked(uptime), getBatteryRealtimeLocked(realtime));
+    void setOnBatteryLocked(boolean onBattery, int oldStatus, int level) {
+        boolean doWrite = false;
+        Message m = mHandler.obtainMessage(MSG_REPORT_POWER_CHANGE);
+        m.arg1 = onBattery ? 1 : 0;
+        mHandler.sendMessage(m);
+        mOnBattery = mOnBatteryInternal = onBattery;
+
+        long uptime = SystemClock.uptimeMillis() * 1000;
+        long mSecRealtime = SystemClock.elapsedRealtime();
+        long realtime = mSecRealtime * 1000;
+        if (onBattery) {
+            // We will reset our status if we are unplugging after the
+            // battery was last full, or the level is at 100, or
+            // we have gone through a significant charge (from a very low
+            // level to a now very high level).
+            if (oldStatus == BatteryManager.BATTERY_STATUS_FULL
+                    || level >= 90
+                    || (mDischargeCurrentLevel < 20 && level >= 80)) {
+                doWrite = true;
+                resetAllStatsLocked();
+                mDischargeStartLevel = level;
             }
-            if (doWrite || (mLastWriteTime + (60 * 1000)) < mSecRealtime) {
-                if (mFile != null) {
-                    writeAsyncLocked();
-                }
+            updateKernelWakelocksLocked();
+            mHistoryCur.batteryLevel = (byte)level;
+            mHistoryCur.states &= ~HistoryItem.STATE_BATTERY_PLUGGED_FLAG;
+            if (DEBUG_HISTORY) Slog.v(TAG, "Battery unplugged to: "
+                    + Integer.toHexString(mHistoryCur.states));
+            addHistoryRecordLocked(mSecRealtime);
+            mTrackBatteryUptimeStart = uptime;
+            mTrackBatteryRealtimeStart = realtime;
+            mUnpluggedBatteryUptime = getBatteryUptimeLocked(uptime);
+            mUnpluggedBatteryRealtime = getBatteryRealtimeLocked(realtime);
+            mDischargeCurrentLevel = mDischargeUnplugLevel = level;
+            if (mScreenOn) {
+                mDischargeScreenOnUnplugLevel = level;
+                mDischargeScreenOffUnplugLevel = 0;
+            } else {
+                mDischargeScreenOnUnplugLevel = 0;
+                mDischargeScreenOffUnplugLevel = level;
+            }
+            mDischargeAmountScreenOn = 0;
+            mDischargeAmountScreenOff = 0;
+            doUnplugLocked(mUnpluggedBatteryUptime, mUnpluggedBatteryRealtime);
+        } else {
+            updateKernelWakelocksLocked();
+            mHistoryCur.batteryLevel = (byte)level;
+            mHistoryCur.states |= HistoryItem.STATE_BATTERY_PLUGGED_FLAG;
+            if (DEBUG_HISTORY) Slog.v(TAG, "Battery plugged to: "
+                    + Integer.toHexString(mHistoryCur.states));
+            addHistoryRecordLocked(mSecRealtime);
+            mTrackBatteryPastUptime += uptime - mTrackBatteryUptimeStart;
+            mTrackBatteryPastRealtime += realtime - mTrackBatteryRealtimeStart;
+            mDischargeCurrentLevel = level;
+            if (level < mDischargeUnplugLevel) {
+                mLowDischargeAmountSinceCharge += mDischargeUnplugLevel-level-1;
+                mHighDischargeAmountSinceCharge += mDischargeUnplugLevel-level;
+            }
+            updateDischargeScreenLevelsLocked(mScreenOn, mScreenOn);
+            doPlugLocked(getBatteryUptimeLocked(uptime), getBatteryRealtimeLocked(realtime));
+        }
+        if (doWrite || (mLastWriteTime + (60 * 1000)) < mSecRealtime) {
+            if (mFile != null) {
+                writeAsyncLocked();
             }
         }
     }
@@ -4127,71 +4131,73 @@
 
     public void setBatteryState(int status, int health, int plugType, int level,
             int temp, int volt) {
-        boolean onBattery = plugType == BATTERY_PLUGGED_NONE;
-        int oldStatus = mHistoryCur.batteryStatus;
-        if (!mHaveBatteryLevel) {
-            mHaveBatteryLevel = true;
-            // We start out assuming that the device is plugged in (not
-            // on battery).  If our first report is now that we are indeed
-            // plugged in, then twiddle our state to correctly reflect that
-            // since we won't be going through the full setOnBattery().
-            if (onBattery == mOnBattery) {
-                if (onBattery) {
-                    mHistoryCur.states &= ~HistoryItem.STATE_BATTERY_PLUGGED_FLAG;
-                } else {
-                    mHistoryCur.states |= HistoryItem.STATE_BATTERY_PLUGGED_FLAG;
+        synchronized(this) {
+            boolean onBattery = plugType == BATTERY_PLUGGED_NONE;
+            int oldStatus = mHistoryCur.batteryStatus;
+            if (!mHaveBatteryLevel) {
+                mHaveBatteryLevel = true;
+                // We start out assuming that the device is plugged in (not
+                // on battery).  If our first report is now that we are indeed
+                // plugged in, then twiddle our state to correctly reflect that
+                // since we won't be going through the full setOnBattery().
+                if (onBattery == mOnBattery) {
+                    if (onBattery) {
+                        mHistoryCur.states &= ~HistoryItem.STATE_BATTERY_PLUGGED_FLAG;
+                    } else {
+                        mHistoryCur.states |= HistoryItem.STATE_BATTERY_PLUGGED_FLAG;
+                    }
+                }
+                oldStatus = status;
+            }
+            if (onBattery) {
+                mDischargeCurrentLevel = level;
+                mRecordingHistory = true;
+            }
+            if (onBattery != mOnBattery) {
+                mHistoryCur.batteryLevel = (byte)level;
+                mHistoryCur.batteryStatus = (byte)status;
+                mHistoryCur.batteryHealth = (byte)health;
+                mHistoryCur.batteryPlugType = (byte)plugType;
+                mHistoryCur.batteryTemperature = (char)temp;
+                mHistoryCur.batteryVoltage = (char)volt;
+                setOnBatteryLocked(onBattery, oldStatus, level);
+            } else {
+                boolean changed = false;
+                if (mHistoryCur.batteryLevel != level) {
+                    mHistoryCur.batteryLevel = (byte)level;
+                    changed = true;
+                }
+                if (mHistoryCur.batteryStatus != status) {
+                    mHistoryCur.batteryStatus = (byte)status;
+                    changed = true;
+                }
+                if (mHistoryCur.batteryHealth != health) {
+                    mHistoryCur.batteryHealth = (byte)health;
+                    changed = true;
+                }
+                if (mHistoryCur.batteryPlugType != plugType) {
+                    mHistoryCur.batteryPlugType = (byte)plugType;
+                    changed = true;
+                }
+                if (temp >= (mHistoryCur.batteryTemperature+10)
+                        || temp <= (mHistoryCur.batteryTemperature-10)) {
+                    mHistoryCur.batteryTemperature = (char)temp;
+                    changed = true;
+                }
+                if (volt > (mHistoryCur.batteryVoltage+20)
+                        || volt < (mHistoryCur.batteryVoltage-20)) {
+                    mHistoryCur.batteryVoltage = (char)volt;
+                    changed = true;
+                }
+                if (changed) {
+                    addHistoryRecordLocked(SystemClock.elapsedRealtime());
                 }
             }
-            oldStatus = status;
-        }
-        if (onBattery) {
-            mDischargeCurrentLevel = level;
-            mRecordingHistory = true;
-        }
-        if (onBattery != mOnBattery) {
-            mHistoryCur.batteryLevel = (byte)level;
-            mHistoryCur.batteryStatus = (byte)status;
-            mHistoryCur.batteryHealth = (byte)health;
-            mHistoryCur.batteryPlugType = (byte)plugType;
-            mHistoryCur.batteryTemperature = (char)temp;
-            mHistoryCur.batteryVoltage = (char)volt;
-            setOnBattery(onBattery, oldStatus, level);
-        } else {
-            boolean changed = false;
-            if (mHistoryCur.batteryLevel != level) {
-                mHistoryCur.batteryLevel = (byte)level;
-                changed = true;
+            if (!onBattery && status == BatteryManager.BATTERY_STATUS_FULL) {
+                // We don't record history while we are plugged in and fully charged.
+                // The next time we are unplugged, history will be cleared.
+                mRecordingHistory = false;
             }
-            if (mHistoryCur.batteryStatus != status) {
-                mHistoryCur.batteryStatus = (byte)status;
-                changed = true;
-            }
-            if (mHistoryCur.batteryHealth != health) {
-                mHistoryCur.batteryHealth = (byte)health;
-                changed = true;
-            }
-            if (mHistoryCur.batteryPlugType != plugType) {
-                mHistoryCur.batteryPlugType = (byte)plugType;
-                changed = true;
-            }
-            if (temp >= (mHistoryCur.batteryTemperature+10)
-                    || temp <= (mHistoryCur.batteryTemperature-10)) {
-                mHistoryCur.batteryTemperature = (char)temp;
-                changed = true;
-            }
-            if (volt > (mHistoryCur.batteryVoltage+20)
-                    || volt < (mHistoryCur.batteryVoltage-20)) {
-                mHistoryCur.batteryVoltage = (char)volt;
-                changed = true;
-            }
-            if (changed) {
-                addHistoryRecordLocked(SystemClock.elapsedRealtime());
-            }
-        }
-        if (!onBattery && status == BatteryManager.BATTERY_STATUS_FULL) {
-            // We don't record history while we are plugged in and fully charged.
-            // The next time we are unplugged, history will be cleared.
-            mRecordingHistory = false;
         }
     }
 
diff --git a/core/java/com/android/internal/os/ZygoteInit.java b/core/java/com/android/internal/os/ZygoteInit.java
index dea53bf..32ddc22 100644
--- a/core/java/com/android/internal/os/ZygoteInit.java
+++ b/core/java/com/android/internal/os/ZygoteInit.java
@@ -31,7 +31,6 @@
 
 import dalvik.system.VMRuntime;
 import dalvik.system.Zygote;
-import dalvik.system.SamplingProfiler;
 
 import java.io.BufferedReader;
 import java.io.FileDescriptor;
@@ -99,25 +98,6 @@
     private static final boolean PRELOAD_RESOURCES = true;
 
     /**
-     * List of methods we "warm up" in the register map cache.  These were
-     * chosen because they appeared on the stack in GCs in multiple
-     * applications.
-     *
-     * This is in a VM-ready format, to minimize string processing.  If a
-     * class is not already loaded, or a method is not found, the entry
-     * will be skipped.
-     *
-     * This doesn't really merit a separately-generated input file at this
-     * time.  The list is fairly short, and the consequences of failure
-     * are minor.
-     */
-    private static final String[] REGISTER_MAP_METHODS = {
-        // (currently not doing any)
-        //"Landroid/app/Activity;.setContentView:(I)V",
-    };
-
-
-    /**
      * Invokes a static "main(argv[]) method on class "className".
      * Converts various failing exceptions into RuntimeExceptions, with
      * the assumption that they will then cause the VM instance to exit.
@@ -338,45 +318,6 @@
     }
 
     /**
-     * Pre-caches register maps for methods that are commonly used.
-     */
-    private static void cacheRegisterMaps() {
-        String failed = null;
-        int failure;
-        long startTime = System.nanoTime();
-
-        failure = 0;
-
-        for (int i = 0; i < REGISTER_MAP_METHODS.length; i++) {
-            String str = REGISTER_MAP_METHODS[i];
-
-            if (!Debug.cacheRegisterMap(str)) {
-                if (failed == null)
-                    failed = str;
-                failure++;
-            }
-        }
-
-        long delta = System.nanoTime() - startTime;
-
-        if (failure == REGISTER_MAP_METHODS.length) {
-            if (REGISTER_MAP_METHODS.length > 0) {
-                Log.i(TAG,
-                    "Register map caching failed (precise GC not enabled?)");
-            }
-            return;
-        }
-
-        Log.i(TAG, "Register map cache: found " +
-            (REGISTER_MAP_METHODS.length - failure) + " of " +
-            REGISTER_MAP_METHODS.length + " methods in " +
-            (delta / 1000000L) + "ms");
-        if (failure > 0) {
-            Log.i(TAG, "  First failure: " + failed);
-        }
-    }
-
-    /**
      * Load in commonly used resources, so they can be shared across
      * processes.
      *
@@ -564,7 +505,6 @@
             EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_START,
                 SystemClock.uptimeMillis());
             preloadClasses();
-            //cacheRegisterMaps();
             preloadResources();
             EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_END,
                 SystemClock.uptimeMillis());
diff --git a/core/java/com/android/internal/util/AsyncChannel.java b/core/java/com/android/internal/util/AsyncChannel.java
index 101dd91..4d656c0c 100644
--- a/core/java/com/android/internal/util/AsyncChannel.java
+++ b/core/java/com/android/internal/util/AsyncChannel.java
@@ -135,6 +135,8 @@
      * channel is forcibly disconnected by the system or as a reply to CMD_CHANNEL_DISCONNECT.
      *
      * msg.arg1 == 0 : STATUS_SUCCESSFUL
+     *             1 : STATUS_BINDING_UNSUCCESSFUL
+     *             2 : STATUS_SEND_UNSUCCESSFUL
      *               : All other values signify failure and the channel state is indeterminate
      * msg.obj  == the AsyncChannel
      * msg.replyTo = messenger disconnecting or null if it was never connected.
@@ -147,6 +149,9 @@
     /** Error attempting to bind on a connect */
     public static final int STATUS_BINDING_UNSUCCESSFUL = 1;
 
+    /** Error attempting to send a message */
+    public static final int STATUS_SEND_UNSUCCESSFUL = 2;
+
     /** Service connection */
     private AsyncChannelConnection mConnection;
 
@@ -345,11 +350,7 @@
             mSrcContext.unbindService(mConnection);
         }
         if (mSrcHandler != null) {
-            Message msg = mSrcHandler.obtainMessage(CMD_CHANNEL_DISCONNECTED);
-            msg.arg1 = STATUS_SUCCESSFUL;
-            msg.obj = this;
-            msg.replyTo = mDstMessenger;
-            mSrcHandler.sendMessage(msg);
+            replyDisconnected(STATUS_SUCCESSFUL);
         }
     }
 
@@ -363,7 +364,7 @@
         try {
             mDstMessenger.send(msg);
         } catch (RemoteException e) {
-            log("TODO: handle sendMessage RemoteException" + e);
+            replyDisconnected(STATUS_SEND_UNSUCCESSFUL);
         }
     }
 
@@ -712,6 +713,7 @@
 
     /**
      * Reply to the src handler that we're half connected.
+     * see: CMD_CHANNEL_HALF_CONNECTED for message contents
      *
      * @param status to be stored in msg.arg1
      */
@@ -724,6 +726,21 @@
     }
 
     /**
+     * Reply to the src handler that we are disconnected
+     * see: CMD_CHANNEL_DISCONNECTED for message contents
+     *
+     * @param status to be stored in msg.arg1
+     */
+    private void replyDisconnected(int status) {
+        Message msg = mSrcHandler.obtainMessage(CMD_CHANNEL_DISCONNECTED);
+        msg.arg1 = status;
+        msg.obj = this;
+        msg.replyTo = mDstMessenger;
+        mSrcHandler.sendMessage(msg);
+    }
+
+
+    /**
      * ServiceConnection to receive call backs.
      */
     class AsyncChannelConnection implements ServiceConnection {
@@ -736,11 +753,7 @@
         }
 
         public void onServiceDisconnected(ComponentName className) {
-            Message msg = mSrcHandler.obtainMessage(CMD_CHANNEL_DISCONNECTED);
-            msg.arg1 = STATUS_SUCCESSFUL;
-            msg.obj = AsyncChannel.this;
-            msg.replyTo = mDstMessenger;
-            mSrcHandler.sendMessage(msg);
+            replyDisconnected(STATUS_SUCCESSFUL);
         }
     }
 
diff --git a/core/java/com/android/internal/view/IInputConnectionWrapper.java b/core/java/com/android/internal/view/IInputConnectionWrapper.java
index b5df812..8719fde 100644
--- a/core/java/com/android/internal/view/IInputConnectionWrapper.java
+++ b/core/java/com/android/internal/view/IInputConnectionWrapper.java
@@ -18,9 +18,11 @@
 
 import android.os.Bundle;
 import android.os.Handler;
+import android.os.IBinder;
 import android.os.Looper;
 import android.os.Message;
 import android.os.RemoteException;
+import android.text.style.CorrectionSpan;
 import android.util.Log;
 import android.view.KeyEvent;
 import android.view.inputmethod.CompletionInfo;
@@ -45,6 +47,7 @@
     private static final int DO_PERFORM_EDITOR_ACTION = 58;
     private static final int DO_PERFORM_CONTEXT_MENU_ACTION = 59;
     private static final int DO_SET_COMPOSING_TEXT = 60;
+    private static final int DO_SET_SECURE_CORRECTION_SPAN = 61;
     private static final int DO_SET_COMPOSING_REGION = 63;
     private static final int DO_FINISH_COMPOSING_TEXT = 65;
     private static final int DO_SEND_KEY_EVENT = 70;
@@ -174,7 +177,14 @@
     public void performPrivateCommand(String action, Bundle data) {
         dispatchMessage(obtainMessageOO(DO_PERFORM_PRIVATE_COMMAND, action, data));
     }
-    
+
+    @Override
+    public void setCorrectionSpan(IBinder token, CorrectionSpan correctionSpan, int start,
+            int end, int flags) {
+        dispatchMessage(obtainMessageOOIII(DO_SET_SECURE_CORRECTION_SPAN, token, correctionSpan,
+                start, end, flags));
+    }
+
     void dispatchMessage(Message msg) {
         // If we are calling this from the main thread, then we can call
         // right through.  Otherwise, we need to send the message to the
@@ -420,6 +430,17 @@
                         (Bundle)args.arg2);
                 return;
             }
+            case DO_SET_SECURE_CORRECTION_SPAN: {
+                InputConnection ic = mInputConnection.get();
+                if (ic == null || !isActive()) {
+                    Log.w(TAG, "setCorrectionSpan on inactive InputConnection");
+                    return;
+                }
+                SomeArgs args = (SomeArgs)msg.obj;
+                ic.setCorrectionSpan((IBinder)args.arg1, (CorrectionSpan)args.arg2, msg.arg1,
+                        msg.arg2, args.seq);
+                return;
+            }
         }
         Log.w(TAG, "Unhandled message code: " + msg.what);
     }
@@ -469,4 +490,12 @@
         args.arg2 = arg2;
         return mH.obtainMessage(what, 0, 0, args);
     }
+
+    Message obtainMessageOOIII(int what, Object arg1, Object arg2, int arg3, int arg4, int arg5) {
+        SomeArgs args = new SomeArgs();
+        args.arg1 = arg1;
+        args.arg2 = arg2;
+        args.seq = arg5;
+        return mH.obtainMessage(what, arg3, arg4, args);
+    }
 }
diff --git a/core/java/com/android/internal/view/IInputContext.aidl b/core/java/com/android/internal/view/IInputContext.aidl
index e00dd4e..eb20d61 100644
--- a/core/java/com/android/internal/view/IInputContext.aidl
+++ b/core/java/com/android/internal/view/IInputContext.aidl
@@ -17,6 +17,7 @@
 package com.android.internal.view;
 
 import android.os.Bundle;
+import android.text.style.CorrectionSpan;
 import android.view.KeyEvent;
 import android.view.inputmethod.CompletionInfo;
 import android.view.inputmethod.CorrectionInfo;
@@ -72,4 +73,7 @@
     void setComposingRegion(int start, int end);
 
     void getSelectedText(int flags, int seq, IInputContextCallback callback);
+
+    void setCorrectionSpan(in IBinder token, in CorrectionSpan correctionSpan, int start,
+            int end, int flags);
 }
diff --git a/core/java/com/android/internal/view/InputConnectionWrapper.java b/core/java/com/android/internal/view/InputConnectionWrapper.java
index b13118a..efe315f 100644
--- a/core/java/com/android/internal/view/InputConnectionWrapper.java
+++ b/core/java/com/android/internal/view/InputConnectionWrapper.java
@@ -17,8 +17,10 @@
 package com.android.internal.view;
 
 import android.os.Bundle;
+import android.os.IBinder;
 import android.os.RemoteException;
 import android.os.SystemClock;
+import android.text.style.CorrectionSpan;
 import android.util.Log;
 import android.view.KeyEvent;
 import android.view.inputmethod.CompletionInfo;
@@ -413,4 +415,14 @@
             return false;
         }
     }
+    @Override
+    public boolean setCorrectionSpan(IBinder token, CorrectionSpan correctionSpan, int start,
+            int end, int flags) {
+        try {
+            mIInputContext.setCorrectionSpan(token, correctionSpan, start, end, flags);
+            return true;
+        } catch (RemoteException e) {
+            return false;
+        }
+    }
 }
diff --git a/core/java/com/android/internal/widget/ActionBarView.java b/core/java/com/android/internal/widget/ActionBarView.java
index e3a66c5..2d9a9f2 100644
--- a/core/java/com/android/internal/widget/ActionBarView.java
+++ b/core/java/com/android/internal/widget/ActionBarView.java
@@ -43,6 +43,7 @@
 import android.view.ViewParent;
 import android.view.Window;
 import android.widget.AdapterView;
+import android.widget.FrameLayout;
 import android.widget.HorizontalScrollView;
 import android.widget.ImageView;
 import android.widget.LinearLayout;
@@ -385,7 +386,7 @@
 
             if ((flagsChanged & ActionBar.DISPLAY_HOME_AS_UP) != 0) {
                 mHomeAsUpView.setVisibility((options & ActionBar.DISPLAY_HOME_AS_UP) != 0
-                        ? VISIBLE : INVISIBLE);
+                        ? VISIBLE : GONE);
             }
 
             if ((flagsChanged & ActionBar.DISPLAY_USE_LOGO) != 0) {
@@ -415,6 +416,21 @@
         }
     }
 
+    public void setIcon(Drawable icon) {
+        mIcon = icon;
+        if (icon != null &&
+                ((mDisplayOptions & ActionBar.DISPLAY_USE_LOGO) == 0 || mLogo == null)) {
+            mIconView.setImageDrawable(icon);
+        }
+    }
+
+    public void setLogo(Drawable logo) {
+        mLogo = logo;
+        if (logo != null && (mDisplayOptions & ActionBar.DISPLAY_USE_LOGO) != 0) {
+            mIconView.setImageDrawable(logo);
+        }
+    }
+
     public void setNavigationMode(int mode) {
         final int oldMode = mNavigationMode;
         if (mode != oldMode) {
@@ -461,6 +477,7 @@
     private void ensureTabsExist() {
         if (mTabScrollView == null) {
             mTabScrollView = new HorizontalScrollView(getContext());
+            mTabScrollView.setHorizontalFadingEdgeEnabled(true);
             mTabLayout = new LinearLayout(getContext(), null,
                     com.android.internal.R.attr.actionBarTabBarStyle);
             mTabScrollView.addView(mTabLayout);
@@ -957,4 +974,60 @@
             }
         }
     }
+
+    private static class HomeView extends FrameLayout {
+        private View mUpView;
+        private View mIconView;
+
+        public HomeView(Context context) {
+            this(context, null);
+        }
+
+        public HomeView(Context context, AttributeSet attrs) {
+            super(context, attrs);
+        }
+
+        @Override
+        protected void onFinishInflate() {
+            mUpView = findViewById(com.android.internal.R.id.up);
+            mIconView = (ImageView) findViewById(com.android.internal.R.id.home);
+        }
+
+        @Override
+        protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+            measureChildWithMargins(mUpView, widthMeasureSpec, 0, heightMeasureSpec, 0);
+            final LayoutParams upLp = (LayoutParams) mUpView.getLayoutParams();
+            int width = upLp.leftMargin + mUpView.getMeasuredWidth() + upLp.rightMargin;
+            int height = upLp.topMargin + mUpView.getMeasuredHeight() + upLp.bottomMargin;
+            measureChildWithMargins(mIconView, widthMeasureSpec, width, heightMeasureSpec, 0);
+            final LayoutParams iconLp = (LayoutParams) mIconView.getLayoutParams();
+            width += iconLp.leftMargin + mIconView.getMeasuredWidth() + iconLp.rightMargin;
+            height = Math.max(height,
+                    iconLp.topMargin + mIconView.getMeasuredHeight() + iconLp.bottomMargin);
+            setMeasuredDimension(width, height);
+        }
+
+        @Override
+        protected void onLayout(boolean changed, int l, int t, int r, int b) {
+            final int vCenter = (b - t) / 2;
+            int width = r - l;
+            if (mUpView.getVisibility() != GONE) {
+                final LayoutParams upLp = (LayoutParams) mUpView.getLayoutParams();
+                final int upHeight = mUpView.getMeasuredHeight();
+                final int upWidth = mUpView.getMeasuredWidth();
+                final int upTop = t + vCenter - upHeight / 2;
+                mUpView.layout(l, upTop, l + upWidth, upTop + upHeight);
+                final int upOffset = upLp.leftMargin + upWidth + upLp.rightMargin;
+                width -= upOffset;
+                l += upOffset;
+            }
+            final LayoutParams iconLp = (LayoutParams) mIconView.getLayoutParams();
+            final int iconHeight = mIconView.getMeasuredHeight();
+            final int iconWidth = mIconView.getMeasuredWidth();
+            final int hCenter = (r - l) / 2;
+            final int iconLeft = l + iconLp.leftMargin + hCenter - iconWidth / 2;
+            final int iconTop = t + iconLp.topMargin + vCenter - iconHeight / 2;
+            mIconView.layout(iconLeft, iconTop, iconLeft + iconWidth, iconTop + iconHeight);
+        }
+    }
 }
diff --git a/core/java/com/android/internal/widget/EditableInputConnection.java b/core/java/com/android/internal/widget/EditableInputConnection.java
index 9f9f020..ea82bc7 100644
--- a/core/java/com/android/internal/widget/EditableInputConnection.java
+++ b/core/java/com/android/internal/widget/EditableInputConnection.java
@@ -17,8 +17,10 @@
 package com.android.internal.widget;
 
 import android.os.Bundle;
+import android.os.IBinder;
 import android.text.Editable;
 import android.text.method.KeyListener;
+import android.text.style.CorrectionSpan;
 import android.util.Log;
 import android.view.inputmethod.BaseInputConnection;
 import android.view.inputmethod.CompletionInfo;
@@ -144,4 +146,13 @@
 
         return success;
     }
+
+    @Override
+    public boolean setCorrectionSpan(IBinder token, CorrectionSpan correctionSpan, int start,
+            int end, int flags) {
+        mTextView.beginBatchEdit();
+        boolean retval = mTextView.setCorrectionSpan(token, correctionSpan, start, end, flags);
+        mTextView.endBatchEdit();
+        return retval;
+    }
 }
diff --git a/core/java/com/android/internal/widget/PointerLocationView.java b/core/java/com/android/internal/widget/PointerLocationView.java
index 5ac903d..076a1cb 100644
--- a/core/java/com/android/internal/widget/PointerLocationView.java
+++ b/core/java/com/android/internal/widget/PointerLocationView.java
@@ -23,6 +23,7 @@
 import android.graphics.Paint.FontMetricsInt;
 import android.util.Log;
 import android.view.InputDevice;
+import android.view.KeyEvent;
 import android.view.MotionEvent;
 import android.view.VelocityTracker;
 import android.view.View;
@@ -97,7 +98,8 @@
     
     public PointerLocationView(Context c) {
         super(c);
-        setFocusable(true);
+        setFocusableInTouchMode(true);
+
         mVC = ViewConfiguration.get(c);
         mTextPaint = new Paint();
         mTextPaint.setAntiAlias(true);
@@ -505,22 +507,69 @@
     @Override
     public boolean onTouchEvent(MotionEvent event) {
         addPointerEvent(event);
+
+        if (event.getAction() == MotionEvent.ACTION_DOWN && !isFocused()) {
+            requestFocus();
+        }
         return true;
     }
 
     @Override
     public boolean onGenericMotionEvent(MotionEvent event) {
-        if ((event.getSource() & InputDevice.SOURCE_CLASS_POINTER) != 0) {
+        final int source = event.getSource();
+        if ((source & InputDevice.SOURCE_CLASS_POINTER) != 0) {
             addPointerEvent(event);
+        } else if ((source & InputDevice.SOURCE_CLASS_JOYSTICK) != 0) {
+            Log.i(TAG, "Joystick: " + event);
+        } else if ((source & InputDevice.SOURCE_CLASS_POSITION) != 0) {
+            Log.i(TAG, "Position: " + event);
+        } else {
+            Log.i(TAG, "Generic: " + event);
+        }
+        return true;
+    }
+
+    @Override
+    public boolean onKeyDown(int keyCode, KeyEvent event) {
+        if (shouldLogKey(keyCode)) {
+            final int repeatCount = event.getRepeatCount();
+            if (repeatCount == 0) {
+                Log.i(TAG, "Key Down: " + event);
+            } else {
+                Log.i(TAG, "Key Repeat #" + repeatCount + ": " + event);
+            }
             return true;
         }
-        return super.onGenericMotionEvent(event);
+        return super.onKeyDown(keyCode, event);
+    }
+
+    @Override
+    public boolean onKeyUp(int keyCode, KeyEvent event) {
+        if (shouldLogKey(keyCode)) {
+            Log.i(TAG, "Key Up: " + event);
+            return true;
+        }
+        return super.onKeyUp(keyCode, event);
+    }
+
+    private static boolean shouldLogKey(int keyCode) {
+        switch (keyCode) {
+            case KeyEvent.KEYCODE_DPAD_UP:
+            case KeyEvent.KEYCODE_DPAD_DOWN:
+            case KeyEvent.KEYCODE_DPAD_LEFT:
+            case KeyEvent.KEYCODE_DPAD_RIGHT:
+            case KeyEvent.KEYCODE_DPAD_CENTER:
+                return true;
+            default:
+                return KeyEvent.isGamepadButton(keyCode)
+                    || KeyEvent.isModifierKey(keyCode);
+        }
     }
 
     @Override
     public boolean onTrackballEvent(MotionEvent event) {
         Log.i(TAG, "Trackball: " + event);
-        return super.onTrackballEvent(event);
+        return true;
     }
     
     // HACK
diff --git a/core/java/com/android/internal/widget/WaveView.java b/core/java/com/android/internal/widget/WaveView.java
index d6f2e1a..288865f 100644
--- a/core/java/com/android/internal/widget/WaveView.java
+++ b/core/java/com/android/internal/widget/WaveView.java
@@ -40,7 +40,7 @@
 public class WaveView extends View implements ValueAnimator.AnimatorUpdateListener {
     private static final String TAG = "WaveView";
     private static final boolean DBG = false;
-    private static final int WAVE_COUNT = 5; // default wave count
+    private static final int WAVE_COUNT = 20; // default wave count
     private static final long VIBRATE_SHORT = 20;  // msec
     private static final long VIBRATE_LONG = 20;  // msec
 
diff --git a/core/java/com/google/android/mms/pdu/PduParser.java b/core/java/com/google/android/mms/pdu/PduParser.java
old mode 100644
new mode 100755
index 8edfe52..3f185aa
--- a/core/java/com/google/android/mms/pdu/PduParser.java
+++ b/core/java/com/google/android/mms/pdu/PduParser.java
@@ -29,6 +29,8 @@
 import java.util.Arrays;
 import java.util.HashMap;
 
+import android.content.res.Resources;
+
 public class PduParser {
     /**
      *  The next are WAP values defined in WSP specification.
@@ -1557,43 +1559,55 @@
                          * Attachment = <Octet 129>
                          * Inline = <Octet 130>
                          */
-                        int len = parseValueLength(pduDataStream);
-                        pduDataStream.mark(1);
-                        int thisStartPos = pduDataStream.available();
-                        int thisEndPos = 0;
-                        int value = pduDataStream.read();
 
-                        if (value == PduPart.P_DISPOSITION_FROM_DATA ) {
-                            part.setContentDisposition(PduPart.DISPOSITION_FROM_DATA);
-                        } else if (value == PduPart.P_DISPOSITION_ATTACHMENT) {
-                            part.setContentDisposition(PduPart.DISPOSITION_ATTACHMENT);
-                        } else if (value == PduPart.P_DISPOSITION_INLINE) {
-                            part.setContentDisposition(PduPart.DISPOSITION_INLINE);
-                        } else {
-                            pduDataStream.reset();
-                            /* Token-text */
-                            part.setContentDisposition(parseWapString(pduDataStream, TYPE_TEXT_STRING));
-                        }
+                        /*
+                         * some carrier mmsc servers do not support content_disposition
+                         * field correctly
+                         */
+                        boolean contentDisposition = Resources.getSystem().getBoolean(com
+                                .android.internal.R.bool.config_mms_content_disposition_support);
 
-                        /* get filename parameter and skip other parameters */
-                        thisEndPos = pduDataStream.available();
-                        if (thisStartPos - thisEndPos < len) {
-                            value = pduDataStream.read();
-                            if (value == PduPart.P_FILENAME) { //filename is text-string
-                                part.setFilename(parseWapString(pduDataStream, TYPE_TEXT_STRING));
+                        if (contentDisposition) {
+                            int len = parseValueLength(pduDataStream);
+                            pduDataStream.mark(1);
+                            int thisStartPos = pduDataStream.available();
+                            int thisEndPos = 0;
+                            int value = pduDataStream.read();
+
+                            if (value == PduPart.P_DISPOSITION_FROM_DATA ) {
+                                part.setContentDisposition(PduPart.DISPOSITION_FROM_DATA);
+                            } else if (value == PduPart.P_DISPOSITION_ATTACHMENT) {
+                                part.setContentDisposition(PduPart.DISPOSITION_ATTACHMENT);
+                            } else if (value == PduPart.P_DISPOSITION_INLINE) {
+                                part.setContentDisposition(PduPart.DISPOSITION_INLINE);
+                            } else {
+                                pduDataStream.reset();
+                                /* Token-text */
+                                part.setContentDisposition(parseWapString(pduDataStream
+                                        , TYPE_TEXT_STRING));
                             }
 
-                            /* skip other parameters */
+                            /* get filename parameter and skip other parameters */
                             thisEndPos = pduDataStream.available();
                             if (thisStartPos - thisEndPos < len) {
-                                int last = len - (thisStartPos - thisEndPos);
-                                byte[] temp = new byte[last];
-                                pduDataStream.read(temp, 0, last);
-                            }
-                        }
+                                value = pduDataStream.read();
+                                if (value == PduPart.P_FILENAME) { //filename is text-string
+                                    part.setFilename(parseWapString(pduDataStream
+                                            , TYPE_TEXT_STRING));
+                                }
 
-                        tempPos = pduDataStream.available();
-                        lastLen = length - (startPos - tempPos);
+                                /* skip other parameters */
+                                thisEndPos = pduDataStream.available();
+                                if (thisStartPos - thisEndPos < len) {
+                                    int last = len - (thisStartPos - thisEndPos);
+                                    byte[] temp = new byte[last];
+                                    pduDataStream.read(temp, 0, last);
+                                }
+                            }
+
+                            tempPos = pduDataStream.available();
+                            lastLen = length - (startPos - tempPos);
+                        }
                         break;
                     default:
                         if (LOCAL_LOGV) {
diff --git a/core/java/com/google/android/mms/util/PduCache.java b/core/java/com/google/android/mms/util/PduCache.java
index 7c3fad7..866ca1e 100644
--- a/core/java/com/google/android/mms/util/PduCache.java
+++ b/core/java/com/google/android/mms/util/PduCache.java
@@ -235,7 +235,7 @@
     }
 
     private void removeFromMessageBoxes(Uri key, PduCacheEntry entry) {
-        HashSet<Uri> msgBox = mThreads.get(entry.getMessageBox());
+        HashSet<Uri> msgBox = mThreads.get(Long.valueOf(entry.getMessageBox()));
         if (msgBox != null) {
             msgBox.remove(key);
         }
diff --git a/core/jni/Android.mk b/core/jni/Android.mk
index a5d700b..66d8a36 100644
--- a/core/jni/Android.mk
+++ b/core/jni/Android.mk
@@ -54,6 +54,7 @@
 	android_view_KeyCharacterMap.cpp \
 	android_view_GLES20Canvas.cpp \
 	android_view_MotionEvent.cpp \
+	android_view_VelocityTracker.cpp \
 	android_text_AndroidCharacter.cpp \
 	android_text_AndroidBidi.cpp \
 	android_os_Debug.cpp \
@@ -127,6 +128,7 @@
 	android_hardware_Camera.cpp \
 	android_hardware_SensorManager.cpp \
 	android_hardware_UsbDevice.cpp \
+	android_hardware_UsbDeviceConnection.cpp \
 	android_hardware_UsbRequest.cpp \
 	android_debug_JNITest.cpp \
 	android_util_FileObserver.cpp \
diff --git a/core/jni/AndroidRuntime.cpp b/core/jni/AndroidRuntime.cpp
index 878af3d..e4eb692 100644
--- a/core/jni/AndroidRuntime.cpp
+++ b/core/jni/AndroidRuntime.cpp
@@ -78,6 +78,7 @@
 extern int register_android_hardware_Camera(JNIEnv *env);
 extern int register_android_hardware_SensorManager(JNIEnv *env);
 extern int register_android_hardware_UsbDevice(JNIEnv *env);
+extern int register_android_hardware_UsbDeviceConnection(JNIEnv *env);
 extern int register_android_hardware_UsbRequest(JNIEnv *env);
 
 extern int register_android_media_AudioRecord(JNIEnv *env);
@@ -169,6 +170,7 @@
 extern int register_android_view_InputQueue(JNIEnv* env);
 extern int register_android_view_KeyEvent(JNIEnv* env);
 extern int register_android_view_MotionEvent(JNIEnv* env);
+extern int register_android_view_VelocityTracker(JNIEnv* env);
 extern int register_android_content_res_ObbScanner(JNIEnv* env);
 extern int register_android_content_res_Configuration(JNIEnv* env);
 extern int register_android_animation_PropertyValuesHolder(JNIEnv *env);
@@ -1274,6 +1276,7 @@
     REG_JNI(register_android_hardware_Camera),
     REG_JNI(register_android_hardware_SensorManager),
     REG_JNI(register_android_hardware_UsbDevice),
+    REG_JNI(register_android_hardware_UsbDeviceConnection),
     REG_JNI(register_android_hardware_UsbRequest),
     REG_JNI(register_android_media_AudioRecord),
     REG_JNI(register_android_media_AudioSystem),
@@ -1300,6 +1303,7 @@
     REG_JNI(register_android_view_InputQueue),
     REG_JNI(register_android_view_KeyEvent),
     REG_JNI(register_android_view_MotionEvent),
+    REG_JNI(register_android_view_VelocityTracker),
 
     REG_JNI(register_android_content_res_ObbScanner),
     REG_JNI(register_android_content_res_Configuration),
diff --git a/core/jni/android/graphics/Bitmap.cpp b/core/jni/android/graphics/Bitmap.cpp
index 8064836..05a46a8 100644
--- a/core/jni/android/graphics/Bitmap.cpp
+++ b/core/jni/android/graphics/Bitmap.cpp
@@ -100,6 +100,8 @@
         dst = (char*)dst + dstBitmap.rowBytes();

     }

 

+    dstBitmap.notifyPixelsChanged();

+

     env->ReleaseIntArrayElements(srcColors, const_cast<jint*>(array),

                                  JNI_ABORT);

     return true;

@@ -524,6 +526,7 @@
     }

 

     proc(bitmap->getAddr(x, y), &color, 1, x, y);

+    bitmap->notifyPixelsChanged();

 }

 

 static void Bitmap_setPixels(JNIEnv* env, jobject, const SkBitmap* bitmap,

diff --git a/core/jni/android/graphics/BitmapRegionDecoder.cpp b/core/jni/android/graphics/BitmapRegionDecoder.cpp
index f89967b..ee3e209 100644
--- a/core/jni/android/graphics/BitmapRegionDecoder.cpp
+++ b/core/jni/android/graphics/BitmapRegionDecoder.cpp
@@ -91,7 +91,7 @@
         return nullObjectReturn("decoder->buildTileIndex returned false");
     }
 
-    SkBitmapRegionDecoder *bm = new SkBitmapRegionDecoder(decoder, width, height);
+    SkBitmapRegionDecoder *bm = new SkBitmapRegionDecoder(decoder, stream, width, height);
 
     return GraphicsJNI::createBitmapRegionDecoder(env, bm);
 }
diff --git a/core/jni/android/graphics/NinePatchPeeker.h b/core/jni/android/graphics/NinePatchPeeker.h
index 1f37b8b..8567e23 100644
--- a/core/jni/android/graphics/NinePatchPeeker.h
+++ b/core/jni/android/graphics/NinePatchPeeker.h
@@ -14,6 +14,9 @@
  * limitations under the License.
  */
 
+#ifndef NinePatchPeeker_h
+#define NinePatchPeeker_h
+
 #include "SkImageDecoder.h"
 #include <utils/ResourceTypes.h>
 
@@ -40,3 +43,4 @@
     virtual bool peek(const char tag[], const void* data, size_t length);
 };
 
+#endif // NinePatchPeeker_h
diff --git a/core/jni/android/graphics/Shader.cpp b/core/jni/android/graphics/Shader.cpp
index 0ea8225..7fdad10 100644
--- a/core/jni/android/graphics/Shader.cpp
+++ b/core/jni/android/graphics/Shader.cpp
@@ -119,7 +119,7 @@
     const jint* colorValues = env->GetIntArrayElements(colorArray, NULL);
 
     SkAutoSTMalloc<8, SkScalar> storage(posArray ? count : 0);
-    SkScalar*                   pos = NULL;
+    SkScalar* pos = NULL;
 
     if (posArray) {
         AutoJavaFloatArray autoPos(env, posArray, count);
@@ -164,7 +164,11 @@
         }
     } else {
         storedPositions[0] = 0.0f;
-        storedPositions[1] = 1.0f;
+        const jfloat step = 1.0f / (count - 1);
+        for (size_t i = 1; i < count - 1; i++) {
+            storedPositions[i] = step * i;
+        }
+        storedPositions[count - 1] = 1.0f;
     }
 
     SkiaShader* skiaShader = new SkiaLinearGradientShader(storedBounds, storedColors,
@@ -289,7 +293,11 @@
         }
     } else {
         storedPositions[0] = 0.0f;
-        storedPositions[1] = 1.0f;
+        const jfloat step = 1.0f / (count - 1);
+        for (size_t i = 1; i < count - 1; i++) {
+            storedPositions[i] = step * i;
+        }
+        storedPositions[count - 1] = 1.0f;
     }
 
     SkiaShader* skiaShader = new SkiaCircularGradientShader(x, y, radius, storedColors,
@@ -384,7 +392,11 @@
         }
     } else {
         storedPositions[0] = 0.0f;
-        storedPositions[1] = 1.0f;
+        const jfloat step = 1.0f / (count - 1);
+        for (size_t i = 1; i < count - 1; i++) {
+            storedPositions[i] = step * i;
+        }
+        storedPositions[count - 1] = 1.0f;
     }
 
     SkiaShader* skiaShader = new SkiaSweepGradientShader(x, y, storedColors, storedPositions, count,
diff --git a/core/jni/android/graphics/SurfaceTexture.cpp b/core/jni/android/graphics/SurfaceTexture.cpp
index 88de94f..2f70190 100644
--- a/core/jni/android/graphics/SurfaceTexture.cpp
+++ b/core/jni/android/graphics/SurfaceTexture.cpp
@@ -19,6 +19,7 @@
 #include <stdio.h>
 
 #include <gui/SurfaceTexture.h>
+#include <gui/SurfaceTextureClient.h>
 
 #include <android_runtime/AndroidRuntime.h>
 
@@ -64,6 +65,15 @@
     return surfaceTexture;
 }
 
+sp<ANativeWindow> android_SurfaceTexture_getNativeWindow(
+        JNIEnv* env, jobject thiz)
+{
+    sp<SurfaceTexture> surfaceTexture(SurfaceTexture_getSurfaceTexture(env, thiz));
+    sp<SurfaceTextureClient> surfaceTextureClient(surfaceTexture != NULL ?
+            new SurfaceTextureClient(surfaceTexture) : NULL);
+    return surfaceTextureClient;
+}
+
 // ----------------------------------------------------------------------------
 
 class JNISurfaceTextureContext : public SurfaceTexture::FrameAvailableListener
@@ -161,6 +171,12 @@
     env->ReleaseFloatArrayElements(jmtx, mtx, 0);
 }
 
+static jlong SurfaceTexture_getTimestamp(JNIEnv* env, jobject thiz)
+{
+    sp<SurfaceTexture> surfaceTexture(SurfaceTexture_getSurfaceTexture(env, thiz));
+    return surfaceTexture->getTimestamp();
+}
+
 // ----------------------------------------------------------------------------
 
 const char* const kSurfaceTextureClassPathName = "android/graphics/SurfaceTexture";
@@ -168,9 +184,10 @@
 static JNINativeMethod gSurfaceTextureMethods[] = {
     {"nativeClassInit",          "()V",   (void*)SurfaceTexture_classInit },
     {"nativeInit",               "(ILjava/lang/Object;)V", (void*)SurfaceTexture_init },
-    {"nativeFinalize",            "()V",  (void*)SurfaceTexture_finalize },
+    {"nativeFinalize",           "()V",   (void*)SurfaceTexture_finalize },
     {"nativeUpdateTexImage",     "()V",   (void*)SurfaceTexture_updateTexImage },
     {"nativeGetTransformMatrix", "([F)V", (void*)SurfaceTexture_getTransformMatrix },
+    {"nativeGetTimestamp",       "()J",   (void*)SurfaceTexture_getTimestamp }
 };
 
 int register_android_graphics_SurfaceTexture(JNIEnv* env)
diff --git a/core/jni/android_app_NativeActivity.cpp b/core/jni/android_app_NativeActivity.cpp
index 56f2646..b1ea90b 100644
--- a/core/jni/android_app_NativeActivity.cpp
+++ b/core/jni/android_app_NativeActivity.cpp
@@ -42,8 +42,6 @@
 {
 
 static struct {
-    jclass clazz;
-
     jmethodID dispatchUnhandledKeyEvent;
     jmethodID preDispatchKeyEvent;
     jmethodID finish;
@@ -1054,8 +1052,7 @@
 
 #define FIND_CLASS(var, className) \
         var = env->FindClass(className); \
-        LOG_FATAL_IF(! var, "Unable to find class %s", className); \
-        var = jclass(env->NewGlobalRef(var));
+        LOG_FATAL_IF(! var, "Unable to find class %s", className);
 
 #define GET_METHOD_ID(var, clazz, methodName, fieldDescriptor) \
         var = env->GetMethodID(clazz, methodName, fieldDescriptor); \
@@ -1064,30 +1061,30 @@
 int register_android_app_NativeActivity(JNIEnv* env)
 {
     //LOGD("register_android_app_NativeActivity");
+    jclass clazz;
+    FIND_CLASS(clazz, kNativeActivityPathName);
 
-    FIND_CLASS(gNativeActivityClassInfo.clazz, kNativeActivityPathName);
-    
     GET_METHOD_ID(gNativeActivityClassInfo.dispatchUnhandledKeyEvent,
-            gNativeActivityClassInfo.clazz,
+            clazz,
             "dispatchUnhandledKeyEvent", "(Landroid/view/KeyEvent;)Z");
     GET_METHOD_ID(gNativeActivityClassInfo.preDispatchKeyEvent,
-            gNativeActivityClassInfo.clazz,
+            clazz,
             "preDispatchKeyEvent", "(Landroid/view/KeyEvent;I)V");
 
     GET_METHOD_ID(gNativeActivityClassInfo.finish,
-            gNativeActivityClassInfo.clazz,
+            clazz,
             "finish", "()V");
     GET_METHOD_ID(gNativeActivityClassInfo.setWindowFlags,
-            gNativeActivityClassInfo.clazz,
+            clazz,
             "setWindowFlags", "(II)V");
     GET_METHOD_ID(gNativeActivityClassInfo.setWindowFormat,
-            gNativeActivityClassInfo.clazz,
+            clazz,
             "setWindowFormat", "(I)V");
     GET_METHOD_ID(gNativeActivityClassInfo.showIme,
-            gNativeActivityClassInfo.clazz,
+            clazz,
             "showIme", "(I)V");
     GET_METHOD_ID(gNativeActivityClassInfo.hideIme,
-            gNativeActivityClassInfo.clazz,
+            clazz,
             "hideIme", "(I)V");
 
     return AndroidRuntime::registerNativeMethods(
diff --git a/core/jni/android_content_res_Configuration.cpp b/core/jni/android_content_res_Configuration.cpp
index 28a43ab..95b18ea 100644
--- a/core/jni/android_content_res_Configuration.cpp
+++ b/core/jni/android_content_res_Configuration.cpp
@@ -26,8 +26,6 @@
 namespace android {
 
 static struct {
-    jclass clazz;
-
     jfieldID mcc;
     jfieldID mnc;
     jfieldID locale;
@@ -75,8 +73,7 @@
 
 #define FIND_CLASS(var, className) \
         var = env->FindClass(className); \
-        LOG_FATAL_IF(! var, "Unable to find class " className); \
-        var = jclass(env->NewGlobalRef(var));
+        LOG_FATAL_IF(! var, "Unable to find class " className);
 
 #define GET_FIELD_ID(var, clazz, fieldName, fieldDescriptor) \
         var = env->GetFieldID(clazz, fieldName, fieldDescriptor); \
@@ -84,31 +81,32 @@
 
 int register_android_content_res_Configuration(JNIEnv* env)
 {
-    FIND_CLASS(gConfigurationClassInfo.clazz, "android/content/res/Configuration");
+    jclass clazz;
+    FIND_CLASS(clazz, "android/content/res/Configuration");
 
-    GET_FIELD_ID(gConfigurationClassInfo.mcc, gConfigurationClassInfo.clazz,
+    GET_FIELD_ID(gConfigurationClassInfo.mcc, clazz,
             "mcc", "I");
-    GET_FIELD_ID(gConfigurationClassInfo.mnc, gConfigurationClassInfo.clazz,
+    GET_FIELD_ID(gConfigurationClassInfo.mnc, clazz,
             "mnc", "I");
-    GET_FIELD_ID(gConfigurationClassInfo.locale, gConfigurationClassInfo.clazz,
+    GET_FIELD_ID(gConfigurationClassInfo.locale, clazz,
             "locale", "Ljava/util/Locale;");
-    GET_FIELD_ID(gConfigurationClassInfo.screenLayout, gConfigurationClassInfo.clazz,
+    GET_FIELD_ID(gConfigurationClassInfo.screenLayout, clazz,
             "screenLayout", "I");
-    GET_FIELD_ID(gConfigurationClassInfo.touchscreen, gConfigurationClassInfo.clazz,
+    GET_FIELD_ID(gConfigurationClassInfo.touchscreen, clazz,
             "touchscreen", "I");
-    GET_FIELD_ID(gConfigurationClassInfo.keyboard, gConfigurationClassInfo.clazz,
+    GET_FIELD_ID(gConfigurationClassInfo.keyboard, clazz,
             "keyboard", "I");
-    GET_FIELD_ID(gConfigurationClassInfo.keyboardHidden, gConfigurationClassInfo.clazz,
+    GET_FIELD_ID(gConfigurationClassInfo.keyboardHidden, clazz,
             "keyboardHidden", "I");
-    GET_FIELD_ID(gConfigurationClassInfo.hardKeyboardHidden, gConfigurationClassInfo.clazz,
+    GET_FIELD_ID(gConfigurationClassInfo.hardKeyboardHidden, clazz,
             "hardKeyboardHidden", "I");
-    GET_FIELD_ID(gConfigurationClassInfo.navigation, gConfigurationClassInfo.clazz,
+    GET_FIELD_ID(gConfigurationClassInfo.navigation, clazz,
             "navigation", "I");
-    GET_FIELD_ID(gConfigurationClassInfo.navigationHidden, gConfigurationClassInfo.clazz,
+    GET_FIELD_ID(gConfigurationClassInfo.navigationHidden, clazz,
             "navigationHidden", "I");
-    GET_FIELD_ID(gConfigurationClassInfo.orientation, gConfigurationClassInfo.clazz,
+    GET_FIELD_ID(gConfigurationClassInfo.orientation, clazz,
             "orientation", "I");
-    GET_FIELD_ID(gConfigurationClassInfo.uiMode, gConfigurationClassInfo.clazz,
+    GET_FIELD_ID(gConfigurationClassInfo.uiMode, clazz,
             "uiMode", "I");
 
     return AndroidRuntime::registerNativeMethods(env, "android/content/res/Configuration", gMethods,
diff --git a/core/jni/android_content_res_ObbScanner.cpp b/core/jni/android_content_res_ObbScanner.cpp
index 3fd7985..4759e27 100644
--- a/core/jni/android_content_res_ObbScanner.cpp
+++ b/core/jni/android_content_res_ObbScanner.cpp
@@ -91,8 +91,7 @@
 
 #define FIND_CLASS(var, className) \
         var = env->FindClass(className); \
-        LOG_FATAL_IF(! var, "Unable to find class " className); \
-        var = jclass(env->NewGlobalRef(var));
+        LOG_FATAL_IF(! var, "Unable to find class " className);
 
 #define GET_FIELD_ID(var, clazz, fieldName, fieldDescriptor) \
         var = env->GetFieldID(clazz, fieldName, fieldDescriptor); \
@@ -100,15 +99,16 @@
 
 int register_android_content_res_ObbScanner(JNIEnv* env)
 {
-    FIND_CLASS(gObbInfoClassInfo.clazz, "android/content/res/ObbInfo");
+    jclass clazz;
+    FIND_CLASS(clazz, "android/content/res/ObbInfo");
 
-    GET_FIELD_ID(gObbInfoClassInfo.packageName, gObbInfoClassInfo.clazz,
+    GET_FIELD_ID(gObbInfoClassInfo.packageName, clazz,
             "packageName", "Ljava/lang/String;");
-    GET_FIELD_ID(gObbInfoClassInfo.version, gObbInfoClassInfo.clazz,
+    GET_FIELD_ID(gObbInfoClassInfo.version, clazz,
             "version", "I");
-    GET_FIELD_ID(gObbInfoClassInfo.flags, gObbInfoClassInfo.clazz,
+    GET_FIELD_ID(gObbInfoClassInfo.flags, clazz,
             "flags", "I");
-    GET_FIELD_ID(gObbInfoClassInfo.salt, gObbInfoClassInfo.clazz,
+    GET_FIELD_ID(gObbInfoClassInfo.salt, clazz,
             "salt", "[B");
 
     return AndroidRuntime::registerNativeMethods(env, "android/content/res/ObbScanner", gMethods,
@@ -116,4 +116,3 @@
 }
 
 }; // namespace android
-
diff --git a/core/jni/android_database_SQLiteDatabase.cpp b/core/jni/android_database_SQLiteDatabase.cpp
index a5878a9..e0c900e 100644
--- a/core/jni/android_database_SQLiteDatabase.cpp
+++ b/core/jni/android_database_SQLiteDatabase.cpp
@@ -64,7 +64,7 @@
 
 static jfieldID offset_db_handle;
 static jmethodID method_custom_function_callback;
-static jclass string_class = NULL;
+static jclass string_class;
 static jint sSqliteSoftHeapLimit = 0;
 
 static char *createStr(const char *path, short extra) {
@@ -406,8 +406,6 @@
     jobject function = (jobject)sqlite3_user_data(context);
 
     // pack up the arguments into a string array
-    if (!string_class)
-        string_class = (jclass)env->NewGlobalRef(env->FindClass("java/lang/String"));
     jobjectArray strArray = env->NewObjectArray(argc, string_class, NULL);
     if (!strArray)
         goto done;
@@ -425,6 +423,7 @@
     }
 
     env->CallVoidMethod(function, method_custom_function_callback, strArray);
+    env->DeleteLocalRef(strArray);
 
 done:
     if (env->ExceptionCheck()) {
@@ -489,6 +488,12 @@
         return -1;
     }
 
+    string_class = (jclass)env->NewGlobalRef(env->FindClass("java/lang/String"));
+    if (string_class == NULL) {
+        LOGE("Can't find java/lang/String\n");
+        return -1;
+    }
+
     offset_db_handle = env->GetFieldID(clazz, "mNativeHandle", "I");
     if (offset_db_handle == NULL) {
         LOGE("Can't find SQLiteDatabase.mNativeHandle\n");
diff --git a/core/jni/android_hardware_UsbDevice.cpp b/core/jni/android_hardware_UsbDevice.cpp
index b01820c..c2950ea 100644
--- a/core/jni/android_hardware_UsbDevice.cpp
+++ b/core/jni/android_hardware_UsbDevice.cpp
@@ -24,190 +24,8 @@
 
 #include <usbhost/usbhost.h>
 
-#include <stdio.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <fcntl.h>
-
 using namespace android;
 
-static jfieldID field_context;
-
-struct usb_device* get_device_from_object(JNIEnv* env, jobject javaDevice)
-{
-    return (struct usb_device*)env->GetIntField(javaDevice, field_context);
-}
-
-// in android_hardware_UsbEndpoint.cpp
-extern struct usb_endpoint* get_endpoint_from_object(JNIEnv* env, jobject javaEndpoint);
-
-static jboolean
-android_hardware_UsbDevice_open(JNIEnv *env, jobject thiz, jstring deviceName,
-        jobject fileDescriptor)
-{
-    int fd = getParcelFileDescriptorFD(env, fileDescriptor);
-    // duplicate the file descriptor, since ParcelFileDescriptor will eventually close its copy
-    fd = dup(fd);
-    if (fd < 0)
-        return false;
-
-    const char *deviceNameStr = env->GetStringUTFChars(deviceName, NULL);
-    struct usb_device* device = usb_device_new(deviceNameStr, fd);
-    if (device) {
-        env->SetIntField(thiz, field_context, (int)device);
-    } else {
-        LOGE("usb_device_open failed for %s", deviceNameStr);
-        close(fd);
-    }
-
-    env->ReleaseStringUTFChars(deviceName, deviceNameStr);
-    return (device != NULL);
-}
-
-static void
-android_hardware_UsbDevice_close(JNIEnv *env, jobject thiz)
-{
-    LOGD("close\n");
-    struct usb_device* device = get_device_from_object(env, thiz);
-    if (device) {
-        usb_device_close(device);
-        env->SetIntField(thiz, field_context, 0);
-    }
-}
-
-static jint
-android_hardware_UsbDevice_get_fd(JNIEnv *env, jobject thiz)
-{
-    struct usb_device* device = get_device_from_object(env, thiz);
-    if (!device) {
-        LOGE("device is closed in native_get_fd");
-        return -1;
-    }
-    return usb_device_get_fd(device);
-}
-
-static jboolean
-android_hardware_UsbDevice_claim_interface(JNIEnv *env, jobject thiz, int interfaceID, jboolean force)
-{
-    struct usb_device* device = get_device_from_object(env, thiz);
-    if (!device) {
-        LOGE("device is closed in native_claim_interface");
-        return -1;
-    }
-
-    int ret = usb_device_claim_interface(device, interfaceID);
-    if (ret && force && errno == EBUSY) {
-        // disconnect kernel driver and try again
-        usb_device_connect_kernel_driver(device, interfaceID, false);
-        ret = usb_device_claim_interface(device, interfaceID);
-    }
-    return ret == 0;
-}
-
-static jint
-android_hardware_UsbDevice_release_interface(JNIEnv *env, jobject thiz, int interfaceID)
-{
-    struct usb_device* device = get_device_from_object(env, thiz);
-    if (!device) {
-        LOGE("device is closed in native_release_interface");
-        return -1;
-    }
-    int ret = usb_device_release_interface(device, interfaceID);
-    if (ret == 0) {
-        // allow kernel to reconnect its driver
-        usb_device_connect_kernel_driver(device, interfaceID, true);
-    }
-    return ret;
-}
-
-static jint
-android_hardware_UsbDevice_control_request(JNIEnv *env, jobject thiz,
-        jint requestType, jint request, jint value, jint index,
-        jbyteArray buffer, jint length, jint timeout)
-{
-    struct usb_device* device = get_device_from_object(env, thiz);
-    if (!device) {
-        LOGE("device is closed in native_control_request");
-        return -1;
-    }
-
-    jbyte* bufferBytes = NULL;
-    if (buffer) {
-        if (env->GetArrayLength(buffer) < length) {
-            env->ThrowNew(env->FindClass("java/lang/ArrayIndexOutOfBoundsException"), NULL);
-            return -1;
-        }
-        bufferBytes = env->GetByteArrayElements(buffer, 0);
-    }
-
-    jint result = usb_device_control_transfer(device, requestType, request,
-            value, index, bufferBytes, length, timeout);
-
-    if (bufferBytes)
-        env->ReleaseByteArrayElements(buffer, bufferBytes, 0);
-
-    return result;
-}
-
-static jint
-android_hardware_UsbDevice_bulk_request(JNIEnv *env, jobject thiz,
-        jint endpoint, jbyteArray buffer, jint length, jint timeout)
-{
-    struct usb_device* device = get_device_from_object(env, thiz);
-    if (!device) {
-        LOGE("device is closed in native_control_request");
-        return -1;
-    }
-
-    jbyte* bufferBytes = NULL;
-    if (buffer) {
-        if (env->GetArrayLength(buffer) < length) {
-            env->ThrowNew(env->FindClass("java/lang/ArrayIndexOutOfBoundsException"), NULL);
-            return -1;
-        }
-        bufferBytes = env->GetByteArrayElements(buffer, 0);
-    }
-
-    jint result = usb_device_bulk_transfer(device, endpoint, bufferBytes, length, timeout);
-
-    if (bufferBytes)
-        env->ReleaseByteArrayElements(buffer, bufferBytes, 0);
-
-    return result;
-}
-
-static jobject
-android_hardware_UsbDevice_request_wait(JNIEnv *env, jobject thiz)
-{
-    struct usb_device* device = get_device_from_object(env, thiz);
-    if (!device) {
-        LOGE("device is closed in native_request_wait");
-        return NULL;
-    }
-
-    struct usb_request* request = usb_request_wait(device);
-    if (request)
-        return (jobject)request->client_data;
-    else
-        return NULL;
-}
-
-static jstring
-android_hardware_UsbDevice_get_serial(JNIEnv *env, jobject thiz)
-{
-    struct usb_device* device = get_device_from_object(env, thiz);
-    if (!device) {
-        LOGE("device is closed in native_request_wait");
-        return NULL;
-    }
-    char* serial = usb_device_get_serial(device);
-    if (!serial)
-        return NULL;
-    jstring result = env->NewStringUTF(serial);
-    free(serial);
-    return result;
-}
-
 static jint
 android_hardware_UsbDevice_get_device_id(JNIEnv *env, jobject clazz, jstring name)
 {
@@ -227,21 +45,6 @@
 }
 
 static JNINativeMethod method_table[] = {
-    {"native_open",             "(Ljava/lang/String;Ljava/io/FileDescriptor;)Z",
-                                        (void *)android_hardware_UsbDevice_open},
-    {"native_close",            "()V",  (void *)android_hardware_UsbDevice_close},
-    {"native_get_fd",           "()I",  (void *)android_hardware_UsbDevice_get_fd},
-    {"native_claim_interface",  "(IZ)Z",(void *)android_hardware_UsbDevice_claim_interface},
-    {"native_release_interface","(I)Z", (void *)android_hardware_UsbDevice_release_interface},
-    {"native_control_request",  "(IIII[BII)I",
-                                        (void *)android_hardware_UsbDevice_control_request},
-    {"native_bulk_request",     "(I[BII)I",
-                                        (void *)android_hardware_UsbDevice_bulk_request},
-    {"native_request_wait",             "()Landroid/hardware/usb/UsbRequest;",
-                                        (void *)android_hardware_UsbDevice_request_wait},
-    { "native_get_serial",      "()Ljava/lang/String;",
-                                        (void*)android_hardware_UsbDevice_get_serial },
-
     // static methods
     { "native_get_device_id", "(Ljava/lang/String;)I",
                                         (void*)android_hardware_UsbDevice_get_device_id },
@@ -256,11 +59,6 @@
         LOGE("Can't find android/hardware/usb/UsbDevice");
         return -1;
     }
-    field_context = env->GetFieldID(clazz, "mNativeContext", "I");
-    if (field_context == NULL) {
-        LOGE("Can't find UsbDevice.mNativeContext");
-        return -1;
-    }
 
     return AndroidRuntime::registerNativeMethods(env, "android/hardware/usb/UsbDevice",
             method_table, NELEM(method_table));
diff --git a/core/jni/android_hardware_UsbDeviceConnection.cpp b/core/jni/android_hardware_UsbDeviceConnection.cpp
new file mode 100644
index 0000000..ec36a38
--- /dev/null
+++ b/core/jni/android_hardware_UsbDeviceConnection.cpp
@@ -0,0 +1,242 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "UsbDeviceConnectionJNI"
+
+#include "utils/Log.h"
+
+#include "jni.h"
+#include "JNIHelp.h"
+#include "android_runtime/AndroidRuntime.h"
+
+#include <usbhost/usbhost.h>
+
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+
+using namespace android;
+
+static jfieldID field_context;
+
+struct usb_device* get_device_from_object(JNIEnv* env, jobject connection)
+{
+    return (struct usb_device*)env->GetIntField(connection, field_context);
+}
+
+static jboolean
+android_hardware_UsbDeviceConnection_open(JNIEnv *env, jobject thiz, jstring deviceName,
+        jobject fileDescriptor)
+{
+    int fd = getParcelFileDescriptorFD(env, fileDescriptor);
+    // duplicate the file descriptor, since ParcelFileDescriptor will eventually close its copy
+    fd = dup(fd);
+    if (fd < 0)
+        return false;
+
+    const char *deviceNameStr = env->GetStringUTFChars(deviceName, NULL);
+    struct usb_device* device = usb_device_new(deviceNameStr, fd);
+    if (device) {
+        env->SetIntField(thiz, field_context, (int)device);
+    } else {
+        LOGE("usb_device_open failed for %s", deviceNameStr);
+        close(fd);
+    }
+
+    env->ReleaseStringUTFChars(deviceName, deviceNameStr);
+    return (device != NULL);
+}
+
+static void
+android_hardware_UsbDeviceConnection_close(JNIEnv *env, jobject thiz)
+{
+    LOGD("close\n");
+    struct usb_device* device = get_device_from_object(env, thiz);
+    if (device) {
+        usb_device_close(device);
+        env->SetIntField(thiz, field_context, 0);
+    }
+}
+
+static jint
+android_hardware_UsbDeviceConnection_get_fd(JNIEnv *env, jobject thiz)
+{
+    struct usb_device* device = get_device_from_object(env, thiz);
+    if (!device) {
+        LOGE("device is closed in native_get_fd");
+        return -1;
+    }
+    return usb_device_get_fd(device);
+}
+
+static jboolean
+android_hardware_UsbDeviceConnection_claim_interface(JNIEnv *env, jobject thiz,
+        int interfaceID, jboolean force)
+{
+    struct usb_device* device = get_device_from_object(env, thiz);
+    if (!device) {
+        LOGE("device is closed in native_claim_interface");
+        return -1;
+    }
+
+    int ret = usb_device_claim_interface(device, interfaceID);
+    if (ret && force && errno == EBUSY) {
+        // disconnect kernel driver and try again
+        usb_device_connect_kernel_driver(device, interfaceID, false);
+        ret = usb_device_claim_interface(device, interfaceID);
+    }
+    return ret == 0;
+}
+
+static jint
+android_hardware_UsbDeviceConnection_release_interface(JNIEnv *env, jobject thiz, int interfaceID)
+{
+    struct usb_device* device = get_device_from_object(env, thiz);
+    if (!device) {
+        LOGE("device is closed in native_release_interface");
+        return -1;
+    }
+    int ret = usb_device_release_interface(device, interfaceID);
+    if (ret == 0) {
+        // allow kernel to reconnect its driver
+        usb_device_connect_kernel_driver(device, interfaceID, true);
+    }
+    return ret;
+}
+
+static jint
+android_hardware_UsbDeviceConnection_control_request(JNIEnv *env, jobject thiz,
+        jint requestType, jint request, jint value, jint index,
+        jbyteArray buffer, jint length, jint timeout)
+{
+    struct usb_device* device = get_device_from_object(env, thiz);
+    if (!device) {
+        LOGE("device is closed in native_control_request");
+        return -1;
+    }
+
+    jbyte* bufferBytes = NULL;
+    if (buffer) {
+        if (env->GetArrayLength(buffer) < length) {
+            env->ThrowNew(env->FindClass("java/lang/ArrayIndexOutOfBoundsException"), NULL);
+            return -1;
+        }
+        bufferBytes = env->GetByteArrayElements(buffer, 0);
+    }
+
+    jint result = usb_device_control_transfer(device, requestType, request,
+            value, index, bufferBytes, length, timeout);
+
+    if (bufferBytes)
+        env->ReleaseByteArrayElements(buffer, bufferBytes, 0);
+
+    return result;
+}
+
+static jint
+android_hardware_UsbDeviceConnection_bulk_request(JNIEnv *env, jobject thiz,
+        jint endpoint, jbyteArray buffer, jint length, jint timeout)
+{
+    struct usb_device* device = get_device_from_object(env, thiz);
+    if (!device) {
+        LOGE("device is closed in native_control_request");
+        return -1;
+    }
+
+    jbyte* bufferBytes = NULL;
+    if (buffer) {
+        if (env->GetArrayLength(buffer) < length) {
+            env->ThrowNew(env->FindClass("java/lang/ArrayIndexOutOfBoundsException"), NULL);
+            return -1;
+        }
+        bufferBytes = env->GetByteArrayElements(buffer, 0);
+    }
+
+    jint result = usb_device_bulk_transfer(device, endpoint, bufferBytes, length, timeout);
+
+    if (bufferBytes)
+        env->ReleaseByteArrayElements(buffer, bufferBytes, 0);
+
+    return result;
+}
+
+static jobject
+android_hardware_UsbDeviceConnection_request_wait(JNIEnv *env, jobject thiz)
+{
+    struct usb_device* device = get_device_from_object(env, thiz);
+    if (!device) {
+        LOGE("device is closed in native_request_wait");
+        return NULL;
+    }
+
+    struct usb_request* request = usb_request_wait(device);
+    if (request)
+        return (jobject)request->client_data;
+    else
+        return NULL;
+}
+
+static jstring
+android_hardware_UsbDeviceConnection_get_serial(JNIEnv *env, jobject thiz)
+{
+    struct usb_device* device = get_device_from_object(env, thiz);
+    if (!device) {
+        LOGE("device is closed in native_request_wait");
+        return NULL;
+    }
+    char* serial = usb_device_get_serial(device);
+    if (!serial)
+        return NULL;
+    jstring result = env->NewStringUTF(serial);
+    free(serial);
+    return result;
+}
+
+static JNINativeMethod method_table[] = {
+    {"native_open",             "(Ljava/lang/String;Ljava/io/FileDescriptor;)Z",
+                                        (void *)android_hardware_UsbDeviceConnection_open},
+    {"native_close",            "()V",  (void *)android_hardware_UsbDeviceConnection_close},
+    {"native_get_fd",           "()I",  (void *)android_hardware_UsbDeviceConnection_get_fd},
+    {"native_claim_interface",  "(IZ)Z",(void *)android_hardware_UsbDeviceConnection_claim_interface},
+    {"native_release_interface","(I)Z", (void *)android_hardware_UsbDeviceConnection_release_interface},
+    {"native_control_request",  "(IIII[BII)I",
+                                        (void *)android_hardware_UsbDeviceConnection_control_request},
+    {"native_bulk_request",     "(I[BII)I",
+                                        (void *)android_hardware_UsbDeviceConnection_bulk_request},
+    {"native_request_wait",             "()Landroid/hardware/usb/UsbRequest;",
+                                        (void *)android_hardware_UsbDeviceConnection_request_wait},
+    { "native_get_serial",      "()Ljava/lang/String;",
+                                        (void*)android_hardware_UsbDeviceConnection_get_serial },
+};
+
+int register_android_hardware_UsbDeviceConnection(JNIEnv *env)
+{
+    jclass clazz = env->FindClass("android/hardware/usb/UsbDeviceConnection");
+    if (clazz == NULL) {
+        LOGE("Can't find android/hardware/usb/UsbDeviceConnection");
+        return -1;
+    }
+    field_context = env->GetFieldID(clazz, "mNativeContext", "I");
+    if (field_context == NULL) {
+        LOGE("Can't find UsbDeviceConnection.mNativeContext");
+        return -1;
+    }
+
+    return AndroidRuntime::registerNativeMethods(env, "android/hardware/usb/UsbDeviceConnection",
+            method_table, NELEM(method_table));
+}
+
diff --git a/core/jni/android_hardware_UsbRequest.cpp b/core/jni/android_hardware_UsbRequest.cpp
index b497adb..6bd67d1 100644
--- a/core/jni/android_hardware_UsbRequest.cpp
+++ b/core/jni/android_hardware_UsbRequest.cpp
@@ -35,8 +35,8 @@
     return (struct usb_request*)env->GetIntField(java_request, field_context);
 }
 
-// in android_hardware_UsbDevice.cpp
-extern struct usb_device* get_device_from_object(JNIEnv* env, jobject java_device);
+// in android_hardware_UsbDeviceConnection.cpp
+extern struct usb_device* get_device_from_object(JNIEnv* env, jobject connection);
 
 static jboolean
 android_hardware_UsbRequest_init(JNIEnv *env, jobject thiz, jobject java_device,
@@ -107,7 +107,7 @@
         }
         return false;
     } else {
-        // save a reference to ourselves so UsbDevice.waitRequest() can find us
+        // save a reference to ourselves so UsbDeviceConnection.waitRequest() can find us
         request->client_data = (void *)env->NewGlobalRef(thiz);
         return true;
     }
@@ -155,7 +155,7 @@
         request->buffer = NULL;
         return false;
     } else {
-        // save a reference to ourselves so UsbDevice.waitRequest() can find us
+        // save a reference to ourselves so UsbDeviceConnection.waitRequest() can find us
         // we also need this to make sure our native buffer is not deallocated
         // while IO is active
         request->client_data = (void *)env->NewGlobalRef(thiz);
@@ -187,7 +187,7 @@
 }
 
 static JNINativeMethod method_table[] = {
-    {"native_init",             "(Landroid/hardware/usb/UsbDevice;IIII)Z",
+    {"native_init",             "(Landroid/hardware/usb/UsbDeviceConnection;IIII)Z",
                                             (void *)android_hardware_UsbRequest_init},
     {"native_close",            "()V",      (void *)android_hardware_UsbRequest_close},
     {"native_queue_array",      "([BIZ)Z",  (void *)android_hardware_UsbRequest_queue_array},
diff --git a/core/jni/android_media_AudioRecord.cpp b/core/jni/android_media_AudioRecord.cpp
index f78f83c..b6619ab 100644
--- a/core/jni/android_media_AudioRecord.cpp
+++ b/core/jni/android_media_AudioRecord.cpp
@@ -315,7 +315,11 @@
     }
 
     // get the pointer to where we'll record the audio
-    recordBuff = (jbyte *)env->GetPrimitiveArrayCritical(javaAudioData, NULL);
+    // NOTE: We may use GetPrimitiveArrayCritical() when the JNI implementation changes in such
+    // a way that it becomes much more efficient. When doing so, we will have to prevent the
+    // AudioSystem callback to be called while in critical section (in case of media server
+    // process crash for instance)
+    recordBuff = (jbyte *)env->GetByteArrayElements(javaAudioData, NULL);
 
     if (recordBuff == NULL) {
         LOGE("Error retrieving destination for recorded audio data, can't record");
@@ -327,7 +331,7 @@
     ssize_t readSize = lpRecorder->read(recordBuff + offsetInBytes, 
                                         sizeInBytes > (jint)recorderBuffSize ? 
                                             (jint)recorderBuffSize : sizeInBytes );
-    env->ReleasePrimitiveArrayCritical(javaAudioData, recordBuff, 0);
+    env->ReleaseByteArrayElements(javaAudioData, recordBuff, 0);
 
     return (jint) readSize;
 }
diff --git a/core/jni/android_media_AudioTrack.cpp b/core/jni/android_media_AudioTrack.cpp
index 8409adc..44d2a52 100644
--- a/core/jni/android_media_AudioTrack.cpp
+++ b/core/jni/android_media_AudioTrack.cpp
@@ -530,8 +530,12 @@
     }
 
     // get the pointer for the audio data from the java array
+    // NOTE: We may use GetPrimitiveArrayCritical() when the JNI implementation changes in such
+    // a way that it becomes much more efficient. When doing so, we will have to prevent the
+    // AudioSystem callback to be called while in critical section (in case of media server
+    // process crash for instance)
     if (javaAudioData) {
-        cAudioData = (jbyte *)env->GetPrimitiveArrayCritical(javaAudioData, NULL);
+        cAudioData = (jbyte *)env->GetByteArrayElements(javaAudioData, NULL);
         if (cAudioData == NULL) {
             LOGE("Error retrieving source of audio data to play, can't play");
             return 0; // out of memory or no data to load
@@ -543,7 +547,7 @@
 
     jint written = writeToTrack(lpTrack, javaAudioFormat, cAudioData, offsetInBytes, sizeInBytes);
 
-    env->ReleasePrimitiveArrayCritical(javaAudioData, cAudioData, 0);
+    env->ReleaseByteArrayElements(javaAudioData, cAudioData, 0);
 
     //LOGV("write wrote %d (tried %d) bytes in the native AudioTrack with offset %d",
     //     (int)written, (int)(sizeInBytes), (int)offsetInBytes);
diff --git a/core/jni/android_os_MessageQueue.cpp b/core/jni/android_os_MessageQueue.cpp
index d2e5462..12a77d5 100644
--- a/core/jni/android_os_MessageQueue.cpp
+++ b/core/jni/android_os_MessageQueue.cpp
@@ -27,8 +27,6 @@
 // ----------------------------------------------------------------------------
 
 static struct {
-    jclass clazz;
-
     jfieldID mPtr;   // native object attached to the DVM MessageQueue
 } gMessageQueueClassInfo;
 
@@ -135,8 +133,7 @@
 
 #define FIND_CLASS(var, className) \
         var = env->FindClass(className); \
-        LOG_FATAL_IF(! var, "Unable to find class " className); \
-        var = jclass(env->NewGlobalRef(var));
+        LOG_FATAL_IF(! var, "Unable to find class " className);
 
 #define GET_FIELD_ID(var, clazz, fieldName, fieldDescriptor) \
         var = env->GetFieldID(clazz, fieldName, fieldDescriptor); \
@@ -147,9 +144,10 @@
             gMessageQueueMethods, NELEM(gMessageQueueMethods));
     LOG_FATAL_IF(res < 0, "Unable to register native methods.");
 
-    FIND_CLASS(gMessageQueueClassInfo.clazz, "android/os/MessageQueue");
+    jclass clazz;
+    FIND_CLASS(clazz, "android/os/MessageQueue");
 
-    GET_FIELD_ID(gMessageQueueClassInfo.mPtr, gMessageQueueClassInfo.clazz,
+    GET_FIELD_ID(gMessageQueueClassInfo.mPtr, clazz,
             "mPtr", "I");
     
     return 0;
diff --git a/core/jni/android_os_Power.cpp b/core/jni/android_os_Power.cpp
index a46c2dd..5cfb9b1 100644
--- a/core/jni/android_os_Power.cpp
+++ b/core/jni/android_os_Power.cpp
@@ -20,7 +20,7 @@
 #include "android_runtime/AndroidRuntime.h"
 #include <utils/misc.h>
 #include <hardware_legacy/power.h>
-#include <sys/reboot.h>
+#include <cutils/android_reboot.h>
 
 namespace android
 {
@@ -77,25 +77,26 @@
 
 static void android_os_Power_shutdown(JNIEnv *env, jobject clazz)
 {
-    sync();
 #ifdef HAVE_ANDROID_OS
-    reboot(RB_POWER_OFF);
+    android_reboot(ANDROID_RB_POWEROFF, 0, 0);
+#else
+    sync();
 #endif
 }
 
 static void android_os_Power_reboot(JNIEnv *env, jobject clazz, jstring reason)
 {
-    sync();
 #ifdef HAVE_ANDROID_OS
     if (reason == NULL) {
-        reboot(RB_AUTOBOOT);
+        android_reboot(ANDROID_RB_RESTART, 0, 0);
     } else {
         const char *chars = env->GetStringUTFChars(reason, NULL);
-        __reboot(LINUX_REBOOT_MAGIC1, LINUX_REBOOT_MAGIC2,
-                 LINUX_REBOOT_CMD_RESTART2, (char*) chars);
+        android_reboot(ANDROID_RB_RESTART2, 0, (char *) chars);
         env->ReleaseStringUTFChars(reason, chars);  // In case it fails.
     }
     jniThrowIOException(env, errno);
+#else
+    sync();
 #endif
 }
 
diff --git a/core/jni/android_os_SystemProperties.cpp b/core/jni/android_os_SystemProperties.cpp
index 406884b..3c4d2bf 100644
--- a/core/jni/android_os_SystemProperties.cpp
+++ b/core/jni/android_os_SystemProperties.cpp
@@ -164,7 +164,7 @@
 
     if (keyJ == NULL) {
         jniThrowException(env, "java/lang/NullPointerException",
-                                "key must not be null.");
+                          "key must not be null.");
         return ;
     }
     key = env->GetStringUTFChars(keyJ, NULL);
@@ -174,15 +174,20 @@
     } else {
         val = env->GetStringUTFChars(valJ, NULL);
     }
-    
+
     err = property_set(key, val);
-    
+
     env->ReleaseStringUTFChars(keyJ, key);
-    
+
     if (valJ != NULL) {
-    	env->ReleaseStringUTFChars(valJ, val);
+        env->ReleaseStringUTFChars(valJ, val);
     }
-} 
+
+    if (err < 0) {
+        jniThrowException(env, "java/lang/RuntimeException",
+                          "failed to set system property");
+    }
+}
 
 static JNINativeMethod method_table[] = {
     { "native_get", "(Ljava/lang/String;)Ljava/lang/String;",
diff --git a/core/jni/android_util_Binder.cpp b/core/jni/android_util_Binder.cpp
index 5deed1e..09a5fd41 100644
--- a/core/jni/android_util_Binder.cpp
+++ b/core/jni/android_util_Binder.cpp
@@ -44,6 +44,13 @@
 //#undef LOGV
 //#define LOGV(...) fprintf(stderr, __VA_ARGS__)
 
+#define DEBUG_DEATH 0
+#if DEBUG_DEATH
+#define LOGDEATH LOGD
+#else
+#define LOGDEATH LOGV
+#endif
+
 using namespace android;
 
 // ----------------------------------------------------------------------------
@@ -363,6 +370,7 @@
     Mutex mLock;
 
 public:
+    DeathRecipientList();
     ~DeathRecipientList();
 
     void add(const sp<JavaDeathRecipient>& recipient);
@@ -380,6 +388,7 @@
     {
         // These objects manage their own lifetimes so are responsible for final bookkeeping.
         // The list holds a strong reference to this object.
+        LOGDEATH("Adding JDR %p to DRL %p", this, list.get());
         list->add(this);
 
         android_atomic_inc(&gNumDeathRefs);
@@ -390,7 +399,7 @@
     {
         JNIEnv* env = javavm_to_jnienv(mVM);
 
-        LOGV("Receiving binderDied() on JavaDeathRecipient %p\n", this);
+        LOGDEATH("Receiving binderDied() on JavaDeathRecipient %p\n", this);
 
         env->CallStaticVoidMethod(gBinderProxyOffsets.mClass,
             gBinderProxyOffsets.mSendDeathNotice, mObject);
@@ -399,15 +408,16 @@
             report_exception(env, excep,
                 "*** Uncaught exception returned from death notification!");
         }
-
-        clearReference();
     }
 
     void clearReference()
     {
         sp<DeathRecipientList> list = mList.promote();
         if (list != NULL) {
+            LOGDEATH("Removing JDR %p from DRL %p", this, list.get());
             list->remove(this);
+        } else {
+            LOGDEATH("clearReference() on JDR %p but DRL wp purged", this);
         }
     }
 
@@ -433,7 +443,12 @@
 
 // ----------------------------------------------------------------------------
 
+DeathRecipientList::DeathRecipientList() {
+    LOGDEATH("New DRL @ %p", this);
+}
+
 DeathRecipientList::~DeathRecipientList() {
+    LOGDEATH("Destroy DRL @ %p", this);
     AutoMutex _l(mLock);
 
     // Should never happen -- the JavaDeathRecipient objects that have added themselves
@@ -447,6 +462,7 @@
 void DeathRecipientList::add(const sp<JavaDeathRecipient>& recipient) {
     AutoMutex _l(mLock);
 
+    LOGDEATH("DRL @ %p : add JDR %p", this, recipient.get());
     mList.push_back(recipient);
 }
 
@@ -456,6 +472,7 @@
     List< sp<JavaDeathRecipient> >::iterator iter;
     for (iter = mList.begin(); iter != mList.end(); iter++) {
         if (*iter == recipient) {
+            LOGDEATH("DRL @ %p : remove JDR %p", this, recipient.get());
             mList.erase(iter);
             return;
         }
@@ -518,7 +535,7 @@
 
     object = env->NewObject(gBinderProxyOffsets.mClass, gBinderProxyOffsets.mConstructor);
     if (object != NULL) {
-        LOGV("objectForBinder %p: created new proxy %p !\n", val.get(), object);
+        LOGDEATH("objectForBinder %p: created new proxy %p !\n", val.get(), object);
         // The proxy holds a reference to the native object.
         env->SetIntField(object, gBinderProxyOffsets.mObject, (int)val.get());
         val->incStrong(object);
@@ -663,6 +680,15 @@
 
 static void android_os_Binder_restoreCallingIdentity(JNIEnv* env, jobject clazz, jlong token)
 {
+    // XXX temporary sanity check to debug crashes.
+    int uid = (int)(token>>32);
+    if (uid > 0 && uid < 999) {
+        // In Android currently there are no uids in this range.
+        char buf[128];
+        sprintf(buf, "Restoring bad calling ident: 0x%Lx", token);
+        jniThrowException(env, "java/lang/IllegalStateException", buf);
+        return;
+    }
     IPCThreadState::self()->restoreCallingIdentity(token);
 }
 
@@ -1030,7 +1056,7 @@
         assert(false);
     }
 
-    LOGV("linkToDeath: binder=%p recipient=%p\n", target, recipient);
+    LOGDEATH("linkToDeath: binder=%p recipient=%p\n", target, recipient);
 
     if (!target->localBinder()) {
         DeathRecipientList* list = (DeathRecipientList*)
@@ -1062,7 +1088,7 @@
         return JNI_FALSE;
     }
 
-    LOGV("unlinkToDeath: binder=%p recipient=%p\n", target, recipient);
+    LOGDEATH("unlinkToDeath: binder=%p recipient=%p\n", target, recipient);
 
     if (!target->localBinder()) {
         status_t err = NAME_NOT_FOUND;
@@ -1071,6 +1097,7 @@
         DeathRecipientList* list = (DeathRecipientList*)
                 env->GetIntField(obj, gBinderProxyOffsets.mOrgue);
         sp<JavaDeathRecipient> origJDR = list->find(recipient);
+        LOGDEATH("   unlink found list %p and JDR %p", list, origJDR.get());
         if (origJDR != NULL) {
             wp<IBinder::DeathRecipient> dr;
             err = target->unlinkToDeath(origJDR, NULL, flags, &dr);
@@ -1101,7 +1128,7 @@
     DeathRecipientList* drl = (DeathRecipientList*)
             env->GetIntField(obj, gBinderProxyOffsets.mOrgue);
 
-    LOGV("Destroying BinderProxy %p: binder=%p drl=%p\n", obj, b, drl);
+    LOGDEATH("Destroying BinderProxy %p: binder=%p drl=%p\n", obj, b, drl);
     env->SetIntField(obj, gBinderProxyOffsets.mObject, 0);
     env->SetIntField(obj, gBinderProxyOffsets.mOrgue, 0);
     drl->decStrong((void*)javaObjectForIBinder);
diff --git a/core/jni/android_view_GLES20Canvas.cpp b/core/jni/android_view_GLES20Canvas.cpp
index 7a609a5..a4931ac 100644
--- a/core/jni/android_view_GLES20Canvas.cpp
+++ b/core/jni/android_view_GLES20Canvas.cpp
@@ -35,7 +35,6 @@
 
 #include <DisplayListRenderer.h>
 #include <LayerRenderer.h>
-#include <OpenGLDebugRenderer.h>
 #include <OpenGLRenderer.h>
 #include <SkiaShader.h>
 #include <SkiaColorFilter.h>
@@ -60,7 +59,6 @@
 
 // Debug
 #define DEBUG_RENDERER 0
-#define PROFILE_RENDERER 0
 
 // Debug
 #if DEBUG_RENDERER
@@ -69,10 +67,13 @@
     #define RENDERER_LOGD(...)
 #endif
 
+#define MODIFIER_SHADOW 1
+#define MODIFIER_SHADER 2
+#define MODIFIER_COLOR_FILTER 4
+
 // ----------------------------------------------------------------------------
 
 static struct {
-    jclass clazz;
     jmethodID set;
 } gRectClassInfo;
 
@@ -99,11 +100,7 @@
 
 static OpenGLRenderer* android_view_GLES20Canvas_createRenderer(JNIEnv* env, jobject clazz) {
     RENDERER_LOGD("Create OpenGLRenderer");
-#if PROFILE_RENDERER
-    return new OpenGLDebugRenderer;
-#else
     return new OpenGLRenderer;
-#endif
 }
 
 static void android_view_GLES20Canvas_destroyRenderer(JNIEnv* env, jobject clazz,
@@ -139,7 +136,8 @@
 
 static bool android_view_GLES20Canvas_callDrawGLFunction(JNIEnv* env, jobject clazz,
         OpenGLRenderer* renderer, Functor *functor) {
-    return renderer->callDrawGLFunction(functor);
+    android::uirenderer::Rect dirty;
+    return renderer->callDrawGLFunction(functor, dirty);
 }
 
 // ----------------------------------------------------------------------------
@@ -368,6 +366,13 @@
     }
 }
 
+static void android_view_GLES20Canvas_drawPoints(JNIEnv* env, jobject clazz,
+        OpenGLRenderer* renderer, jfloatArray points, jint offset, jint count, SkPaint* paint) {
+    jfloat* storage = env->GetFloatArrayElements(points, NULL);
+    renderer->drawPoints(storage + offset, count, paint);
+    env->ReleaseFloatArrayElements(points, storage, 0);
+}
+
 static void android_view_GLES20Canvas_drawPath(JNIEnv* env, jobject clazz,
         OpenGLRenderer* renderer, SkPath* path, SkPaint* paint) {
     renderer->drawPath(path, paint);
@@ -376,9 +381,7 @@
 static void android_view_GLES20Canvas_drawLines(JNIEnv* env, jobject clazz,
         OpenGLRenderer* renderer, jfloatArray points, jint offset, jint count, SkPaint* paint) {
     jfloat* storage = env->GetFloatArrayElements(points, NULL);
-
     renderer->drawLines(storage + offset, count, paint);
-
     env->ReleaseFloatArrayElements(points, storage, 0);
 }
 
@@ -387,10 +390,10 @@
 // ----------------------------------------------------------------------------
 
 static void android_view_GLES20Canvas_resetModifiers(JNIEnv* env, jobject clazz,
-        OpenGLRenderer* renderer) {
-    renderer->resetShader();
-    renderer->resetColorFilter();
-    renderer->resetShadow();
+        OpenGLRenderer* renderer, jint modifiers) {
+    if (modifiers & MODIFIER_SHADOW) renderer->resetShadow();
+    if (modifiers & MODIFIER_SHADER) renderer->resetShader();
+    if (modifiers & MODIFIER_COLOR_FILTER) renderer->resetColorFilter();
 }
 
 static void android_view_GLES20Canvas_setupShader(JNIEnv* env, jobject clazz,
@@ -503,8 +506,15 @@
 }
 
 static bool android_view_GLES20Canvas_drawDisplayList(JNIEnv* env,
-        jobject clazz, OpenGLRenderer* renderer, DisplayList* displayList) {
-    return renderer->drawDisplayList(displayList);
+        jobject clazz, OpenGLRenderer* renderer, DisplayList* displayList,
+        jint width, jint height, jobject dirty) {
+    android::uirenderer::Rect bounds;
+    bool redraw = renderer->drawDisplayList(displayList, width, height, bounds);
+    if (redraw && dirty != NULL) {
+        env->CallVoidMethod(dirty, gRectClassInfo.set,
+                int(bounds.left), int(bounds.top), int(bounds.right), int(bounds.bottom));
+    }
+    return redraw;
 }
 
 // ----------------------------------------------------------------------------
@@ -640,11 +650,12 @@
     { "nDrawCircle",        "(IFFFI)V",        (void*) android_view_GLES20Canvas_drawCircle },
     { "nDrawOval",          "(IFFFFI)V",       (void*) android_view_GLES20Canvas_drawOval },
     { "nDrawArc",           "(IFFFFFFZI)V",    (void*) android_view_GLES20Canvas_drawArc },
+    { "nDrawPoints",        "(I[FIII)V",       (void*) android_view_GLES20Canvas_drawPoints },
 
     { "nDrawPath",          "(III)V",          (void*) android_view_GLES20Canvas_drawPath },
     { "nDrawLines",         "(I[FIII)V",       (void*) android_view_GLES20Canvas_drawLines },
 
-    { "nResetModifiers",    "(I)V",            (void*) android_view_GLES20Canvas_resetModifiers },
+    { "nResetModifiers",    "(II)V",           (void*) android_view_GLES20Canvas_resetModifiers },
     { "nSetupShader",       "(II)V",           (void*) android_view_GLES20Canvas_setupShader },
     { "nSetupColorFilter",  "(II)V",           (void*) android_view_GLES20Canvas_setupColorFilter },
     { "nSetupShadow",       "(IFFFI)V",        (void*) android_view_GLES20Canvas_setupShadow },
@@ -663,7 +674,8 @@
     { "nGetDisplayList",         "(I)I",       (void*) android_view_GLES20Canvas_getDisplayList },
     { "nDestroyDisplayList",     "(I)V",       (void*) android_view_GLES20Canvas_destroyDisplayList },
     { "nGetDisplayListRenderer", "(I)I",       (void*) android_view_GLES20Canvas_getDisplayListRenderer },
-    { "nDrawDisplayList",        "(II)Z",      (void*) android_view_GLES20Canvas_drawDisplayList },
+    { "nDrawDisplayList",        "(IIIILandroid/graphics/Rect;)Z",
+                                               (void*) android_view_GLES20Canvas_drawDisplayList },
 
     { "nInterrupt",              "(I)V",       (void*) android_view_GLES20Canvas_interrupt },
     { "nResume",                 "(I)V",       (void*) android_view_GLES20Canvas_resume },
@@ -681,9 +693,8 @@
 #ifdef USE_OPENGL_RENDERER
     #define FIND_CLASS(var, className) \
             var = env->FindClass(className); \
-            LOG_FATAL_IF(! var, "Unable to find class " className); \
-            var = jclass(env->NewGlobalRef(var));
-    
+            LOG_FATAL_IF(! var, "Unable to find class " className);
+
     #define GET_METHOD_ID(var, clazz, methodName, methodDescriptor) \
             var = env->GetMethodID(clazz, methodName, methodDescriptor); \
             LOG_FATAL_IF(! var, "Unable to find method " methodName);
@@ -693,8 +704,9 @@
 #endif
 
 int register_android_view_GLES20Canvas(JNIEnv* env) {
-    FIND_CLASS(gRectClassInfo.clazz, "android/graphics/Rect");
-    GET_METHOD_ID(gRectClassInfo.set, gRectClassInfo.clazz, "set", "(IIII)V");
+    jclass clazz;
+    FIND_CLASS(clazz, "android/graphics/Rect");
+    GET_METHOD_ID(gRectClassInfo.set, clazz, "set", "(IIII)V");
 
     return AndroidRuntime::registerNativeMethods(env, kClassPathName, gMethods, NELEM(gMethods));
 }
diff --git a/core/jni/android_view_InputQueue.cpp b/core/jni/android_view_InputQueue.cpp
index b5a5d2e..80c4871 100644
--- a/core/jni/android_view_InputQueue.cpp
+++ b/core/jni/android_view_InputQueue.cpp
@@ -380,7 +380,7 @@
 #if DEBUG_DISPATCH_CYCLE
         LOGD("channel '%s' ~ Received motion event.", connection->getInputChannelName());
 #endif
-        inputEventObj = android_view_MotionEvent_fromNative(env,
+        inputEventObj = android_view_MotionEvent_obtainAsCopy(env,
                 static_cast<MotionEvent*>(inputEvent));
         dispatchMethodId = gInputQueueClassInfo.dispatchMotionEvent;
         break;
diff --git a/core/jni/android_view_KeyCharacterMap.cpp b/core/jni/android_view_KeyCharacterMap.cpp
index bfeec4f..aba3a72 100644
--- a/core/jni/android_view_KeyCharacterMap.cpp
+++ b/core/jni/android_view_KeyCharacterMap.cpp
@@ -30,8 +30,6 @@
 } gKeyEventClassInfo;
 
 static struct {
-    jclass clazz;
-
     jfieldID keyCode;
     jfieldID metaState;
 } gFallbackActionClassInfo;
@@ -165,8 +163,7 @@
 
 #define FIND_CLASS(var, className) \
         var = env->FindClass(className); \
-        LOG_FATAL_IF(! var, "Unable to find class " className); \
-        var = jclass(env->NewGlobalRef(var));
+        LOG_FATAL_IF(! var, "Unable to find class " className);
 
 #define GET_FIELD_ID(var, clazz, fieldName, fieldDescriptor) \
         var = env->GetFieldID(clazz, fieldName, fieldDescriptor); \
@@ -175,13 +172,15 @@
 int register_android_text_KeyCharacterMap(JNIEnv* env)
 {
     FIND_CLASS(gKeyEventClassInfo.clazz, "android/view/KeyEvent");
+    gKeyEventClassInfo.clazz = jclass(env->NewGlobalRef(gKeyEventClassInfo.clazz));
 
-    FIND_CLASS(gFallbackActionClassInfo.clazz, "android/view/KeyCharacterMap$FallbackAction");
+    jclass clazz;
+    FIND_CLASS(clazz, "android/view/KeyCharacterMap$FallbackAction");
 
-    GET_FIELD_ID(gFallbackActionClassInfo.keyCode, gFallbackActionClassInfo.clazz,
+    GET_FIELD_ID(gFallbackActionClassInfo.keyCode, clazz,
             "keyCode", "I");
 
-    GET_FIELD_ID(gFallbackActionClassInfo.metaState, gFallbackActionClassInfo.clazz,
+    GET_FIELD_ID(gFallbackActionClassInfo.metaState, clazz,
             "metaState", "I");
 
     return AndroidRuntime::registerNativeMethods(env,
diff --git a/core/jni/android_view_MotionEvent.cpp b/core/jni/android_view_MotionEvent.cpp
index 97cba23..4ce471e 100644
--- a/core/jni/android_view_MotionEvent.cpp
+++ b/core/jni/android_view_MotionEvent.cpp
@@ -42,8 +42,6 @@
 } gMotionEventClassInfo;
 
 static struct {
-    jclass clazz;
-
     jfieldID mPackedAxisBits;
     jfieldID mPackedAxisValues;
     jfieldID x;
@@ -59,7 +57,10 @@
 
 // ----------------------------------------------------------------------------
 
-static MotionEvent* android_view_MotionEvent_getNativePtr(JNIEnv* env, jobject eventObj) {
+MotionEvent* android_view_MotionEvent_getNativePtr(JNIEnv* env, jobject eventObj) {
+    if (!eventObj) {
+        return NULL;
+    }
     return reinterpret_cast<MotionEvent*>(
             env->GetIntField(eventObj, gMotionEventClassInfo.mNativePtr));
 }
@@ -70,10 +71,10 @@
             reinterpret_cast<int>(event));
 }
 
-jobject android_view_MotionEvent_fromNative(JNIEnv* env, const MotionEvent* event) {
+jobject android_view_MotionEvent_obtainAsCopy(JNIEnv* env, const MotionEvent* event) {
     jobject eventObj = env->CallStaticObjectMethod(gMotionEventClassInfo.clazz,
             gMotionEventClassInfo.obtain);
-    if (env->ExceptionCheck()) {
+    if (env->ExceptionCheck() || !eventObj) {
         LOGE("An exception occurred while obtaining a motion event.");
         LOGE_EX(env);
         env->ExceptionClear();
@@ -90,18 +91,6 @@
     return eventObj;
 }
 
-status_t android_view_MotionEvent_toNative(JNIEnv* env, jobject eventObj,
-        MotionEvent* event) {
-    MotionEvent* srcEvent = android_view_MotionEvent_getNativePtr(env, eventObj);
-    if (!srcEvent) {
-        LOGE("MotionEvent was finalized");
-        return BAD_VALUE;
-    }
-
-    event->copyFrom(srcEvent, true);
-    return OK;
-}
-
 status_t android_view_MotionEvent_recycle(JNIEnv* env, jobject eventObj) {
     env->CallVoidMethod(eventObj, gMotionEventClassInfo.recycle);
     if (env->ExceptionCheck()) {
@@ -502,13 +491,7 @@
 static jint android_view_MotionEvent_nativeFindPointerIndex(JNIEnv* env, jclass clazz,
         jint nativePtr, jint pointerId) {
     MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr);
-    size_t pointerCount = event->getPointerCount();
-    for (size_t i = 0; i < pointerCount; i++) {
-        if (event->getPointerId(i) == pointerId) {
-            return i;
-        }
-    }
-    return -1;
+    return jint(event->findPointerIndex(pointerId));
 }
 
 static jint android_view_MotionEvent_nativeGetHistorySize(JNIEnv* env, jclass clazz,
@@ -734,8 +717,7 @@
 
 #define FIND_CLASS(var, className) \
         var = env->FindClass(className); \
-        LOG_FATAL_IF(! var, "Unable to find class " className); \
-        var = jclass(env->NewGlobalRef(var));
+        LOG_FATAL_IF(! var, "Unable to find class " className);
 
 #define GET_STATIC_METHOD_ID(var, clazz, methodName, fieldDescriptor) \
         var = env->GetStaticMethodID(clazz, methodName, fieldDescriptor); \
@@ -755,6 +737,7 @@
     LOG_FATAL_IF(res < 0, "Unable to register native methods.");
 
     FIND_CLASS(gMotionEventClassInfo.clazz, "android/view/MotionEvent");
+    gMotionEventClassInfo.clazz = jclass(env->NewGlobalRef(gMotionEventClassInfo.clazz));
 
     GET_STATIC_METHOD_ID(gMotionEventClassInfo.obtain, gMotionEventClassInfo.clazz,
             "obtain", "()Landroid/view/MotionEvent;");
@@ -763,29 +746,30 @@
     GET_FIELD_ID(gMotionEventClassInfo.mNativePtr, gMotionEventClassInfo.clazz,
             "mNativePtr", "I");
 
-    FIND_CLASS(gPointerCoordsClassInfo.clazz, "android/view/MotionEvent$PointerCoords");
+    jclass clazz;
+    FIND_CLASS(clazz, "android/view/MotionEvent$PointerCoords");
 
-    GET_FIELD_ID(gPointerCoordsClassInfo.mPackedAxisBits, gPointerCoordsClassInfo.clazz,
+    GET_FIELD_ID(gPointerCoordsClassInfo.mPackedAxisBits, clazz,
             "mPackedAxisBits", "J");
-    GET_FIELD_ID(gPointerCoordsClassInfo.mPackedAxisValues, gPointerCoordsClassInfo.clazz,
+    GET_FIELD_ID(gPointerCoordsClassInfo.mPackedAxisValues, clazz,
             "mPackedAxisValues", "[F");
-    GET_FIELD_ID(gPointerCoordsClassInfo.x, gPointerCoordsClassInfo.clazz,
+    GET_FIELD_ID(gPointerCoordsClassInfo.x, clazz,
             "x", "F");
-    GET_FIELD_ID(gPointerCoordsClassInfo.y, gPointerCoordsClassInfo.clazz,
+    GET_FIELD_ID(gPointerCoordsClassInfo.y, clazz,
             "y", "F");
-    GET_FIELD_ID(gPointerCoordsClassInfo.pressure, gPointerCoordsClassInfo.clazz,
+    GET_FIELD_ID(gPointerCoordsClassInfo.pressure, clazz,
             "pressure", "F");
-    GET_FIELD_ID(gPointerCoordsClassInfo.size, gPointerCoordsClassInfo.clazz,
+    GET_FIELD_ID(gPointerCoordsClassInfo.size, clazz,
             "size", "F");
-    GET_FIELD_ID(gPointerCoordsClassInfo.touchMajor, gPointerCoordsClassInfo.clazz,
+    GET_FIELD_ID(gPointerCoordsClassInfo.touchMajor, clazz,
             "touchMajor", "F");
-    GET_FIELD_ID(gPointerCoordsClassInfo.touchMinor, gPointerCoordsClassInfo.clazz,
+    GET_FIELD_ID(gPointerCoordsClassInfo.touchMinor, clazz,
             "touchMinor", "F");
-    GET_FIELD_ID(gPointerCoordsClassInfo.toolMajor, gPointerCoordsClassInfo.clazz,
+    GET_FIELD_ID(gPointerCoordsClassInfo.toolMajor, clazz,
             "toolMajor", "F");
-    GET_FIELD_ID(gPointerCoordsClassInfo.toolMinor, gPointerCoordsClassInfo.clazz,
+    GET_FIELD_ID(gPointerCoordsClassInfo.toolMinor, clazz,
             "toolMinor", "F");
-    GET_FIELD_ID(gPointerCoordsClassInfo.orientation, gPointerCoordsClassInfo.clazz,
+    GET_FIELD_ID(gPointerCoordsClassInfo.orientation, clazz,
             "orientation", "F");
 
     return 0;
diff --git a/core/jni/android_view_MotionEvent.h b/core/jni/android_view_MotionEvent.h
index 80dc861..0cf1fb2 100644
--- a/core/jni/android_view_MotionEvent.h
+++ b/core/jni/android_view_MotionEvent.h
@@ -26,12 +26,11 @@
 
 /* Obtains an instance of a DVM MotionEvent object as a copy of a native MotionEvent instance.
  * Returns NULL on error. */
-extern jobject android_view_MotionEvent_fromNative(JNIEnv* env, const MotionEvent* event);
+extern jobject android_view_MotionEvent_obtainAsCopy(JNIEnv* env, const MotionEvent* event);
 
-/* Copies the contents of a DVM MotionEvent object to a native MotionEvent instance.
- * Returns non-zero on error. */
-extern status_t android_view_MotionEvent_toNative(JNIEnv* env, jobject eventObj,
-        MotionEvent* event);
+/* Gets the underlying native MotionEvent instance within a DVM MotionEvent object.
+ * Returns NULL if the event is NULL or if it is uninitialized. */
+extern MotionEvent* android_view_MotionEvent_getNativePtr(JNIEnv* env, jobject eventObj);
 
 /* Recycles a DVM MotionEvent object.
  * Returns non-zero on error. */
diff --git a/core/jni/android_view_Surface.cpp b/core/jni/android_view_Surface.cpp
index bd2e669..9f1b1fd 100644
--- a/core/jni/android_view_Surface.cpp
+++ b/core/jni/android_view_Surface.cpp
@@ -378,7 +378,7 @@
         JNIEnv* env, jobject clazz, jobject argCanvas)
 {
     jobject canvas = env->GetObjectField(clazz, so.canvas);
-    if (canvas != argCanvas) {
+    if (env->IsSameObject(canvas, argCanvas) == JNI_FALSE) {
         doThrow(env, "java/lang/IllegalArgumentException", NULL);
         return;
     }
diff --git a/core/jni/android_view_VelocityTracker.cpp b/core/jni/android_view_VelocityTracker.cpp
new file mode 100644
index 0000000..daa0adc
--- /dev/null
+++ b/core/jni/android_view_VelocityTracker.cpp
@@ -0,0 +1,208 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "VelocityTracker-JNI"
+
+#include "JNIHelp.h"
+
+#include <android_runtime/AndroidRuntime.h>
+#include <utils/Log.h>
+#include <ui/Input.h>
+#include "android_view_MotionEvent.h"
+
+
+namespace android {
+
+// Special constant to request the velocity of the active pointer.
+static const int ACTIVE_POINTER_ID = -1;
+
+// --- VelocityTrackerState ---
+
+class VelocityTrackerState {
+public:
+    VelocityTrackerState();
+
+    void clear();
+    void addMovement(const MotionEvent* event);
+    void computeCurrentVelocity(int32_t units, float maxVelocity);
+    void getVelocity(int32_t id, float* outVx, float* outVy);
+
+private:
+    struct Velocity {
+        float vx, vy;
+    };
+
+    VelocityTracker mVelocityTracker;
+    int32_t mActivePointerId;
+    BitSet32 mCalculatedIdBits;
+    Velocity mCalculatedVelocity[MAX_POINTERS];
+};
+
+VelocityTrackerState::VelocityTrackerState() : mActivePointerId(-1) {
+}
+
+void VelocityTrackerState::clear() {
+    mVelocityTracker.clear();
+    mActivePointerId = -1;
+    mCalculatedIdBits.clear();
+}
+
+void VelocityTrackerState::addMovement(const MotionEvent* event) {
+    mVelocityTracker.addMovement(event);
+}
+
+void VelocityTrackerState::computeCurrentVelocity(int32_t units, float maxVelocity) {
+    BitSet32 idBits(mVelocityTracker.getCurrentPointerIdBits());
+    mCalculatedIdBits = idBits;
+
+    for (uint32_t index = 0; !idBits.isEmpty(); index++) {
+        uint32_t id = idBits.firstMarkedBit();
+        idBits.clearBit(id);
+
+        float vx, vy;
+        mVelocityTracker.getVelocity(id, &vx, &vy);
+
+        vx = vx * units / 1000;
+        vy = vy * units / 1000;
+
+        if (vx > maxVelocity) {
+            vx = maxVelocity;
+        } else if (vx < -maxVelocity) {
+            vx = -maxVelocity;
+        }
+        if (vy > maxVelocity) {
+            vy = maxVelocity;
+        } else if (vy < -maxVelocity) {
+            vy = -maxVelocity;
+        }
+
+        Velocity& velocity = mCalculatedVelocity[index];
+        velocity.vx = vx;
+        velocity.vy = vy;
+    }
+}
+
+void VelocityTrackerState::getVelocity(int32_t id, float* outVx, float* outVy) {
+    if (id == ACTIVE_POINTER_ID) {
+        id = mVelocityTracker.getActivePointerId();
+    }
+
+    float vx, vy;
+    if (id >= 0 && id <= MAX_POINTER_ID && mCalculatedIdBits.hasBit(id)) {
+        uint32_t index = mCalculatedIdBits.getIndexOfBit(id);
+        const Velocity& velocity = mCalculatedVelocity[index];
+        vx = velocity.vx;
+        vy = velocity.vy;
+    } else {
+        vx = 0;
+        vy = 0;
+    }
+
+    if (outVx) {
+        *outVx = vx;
+    }
+    if (outVy) {
+        *outVy = vy;
+    }
+}
+
+
+// --- JNI Methods ---
+
+static jint android_view_VelocityTracker_nativeInitialize(JNIEnv* env, jclass clazz) {
+    return reinterpret_cast<jint>(new VelocityTrackerState());
+}
+
+static void android_view_VelocityTracker_nativeDispose(JNIEnv* env, jclass clazz, jint ptr) {
+    VelocityTrackerState* state = reinterpret_cast<VelocityTrackerState*>(ptr);
+    delete state;
+}
+
+static void android_view_VelocityTracker_nativeClear(JNIEnv* env, jclass clazz, jint ptr) {
+    VelocityTrackerState* state = reinterpret_cast<VelocityTrackerState*>(ptr);
+    state->clear();
+}
+
+static void android_view_VelocityTracker_nativeAddMovement(JNIEnv* env, jclass clazz, jint ptr,
+        jobject eventObj) {
+    const MotionEvent* event = android_view_MotionEvent_getNativePtr(env, eventObj);
+    if (!event) {
+        LOGW("nativeAddMovement failed because MotionEvent was finalized.");
+        return;
+    }
+
+    VelocityTrackerState* state = reinterpret_cast<VelocityTrackerState*>(ptr);
+    state->addMovement(event);
+}
+
+static void android_view_VelocityTracker_nativeComputeCurrentVelocity(JNIEnv* env, jclass clazz,
+        jint ptr, jint units, jfloat maxVelocity) {
+    VelocityTrackerState* state = reinterpret_cast<VelocityTrackerState*>(ptr);
+    state->computeCurrentVelocity(units, maxVelocity);
+}
+
+static jfloat android_view_VelocityTracker_nativeGetXVelocity(JNIEnv* env, jclass clazz,
+        jint ptr, jint id) {
+    VelocityTrackerState* state = reinterpret_cast<VelocityTrackerState*>(ptr);
+    float vx;
+    state->getVelocity(id, &vx, NULL);
+    return vx;
+}
+
+static jfloat android_view_VelocityTracker_nativeGetYVelocity(JNIEnv* env, jclass clazz,
+        jint ptr, jint id) {
+    VelocityTrackerState* state = reinterpret_cast<VelocityTrackerState*>(ptr);
+    float vy;
+    state->getVelocity(id, NULL, &vy);
+    return vy;
+}
+
+
+// --- JNI Registration ---
+
+static JNINativeMethod gVelocityTrackerMethods[] = {
+    /* name, signature, funcPtr */
+    { "nativeInitialize",
+            "()I",
+            (void*)android_view_VelocityTracker_nativeInitialize },
+    { "nativeDispose",
+            "(I)V",
+            (void*)android_view_VelocityTracker_nativeDispose },
+    { "nativeClear",
+            "(I)V",
+            (void*)android_view_VelocityTracker_nativeClear },
+    { "nativeAddMovement",
+            "(ILandroid/view/MotionEvent;)V",
+            (void*)android_view_VelocityTracker_nativeAddMovement },
+    { "nativeComputeCurrentVelocity",
+            "(IIF)V",
+            (void*)android_view_VelocityTracker_nativeComputeCurrentVelocity },
+    { "nativeGetXVelocity",
+            "(II)F",
+            (void*)android_view_VelocityTracker_nativeGetXVelocity },
+    { "nativeGetYVelocity",
+            "(II)F",
+            (void*)android_view_VelocityTracker_nativeGetYVelocity },
+};
+
+int register_android_view_VelocityTracker(JNIEnv* env) {
+    int res = jniRegisterNativeMethods(env, "android/view/VelocityTracker",
+            gVelocityTrackerMethods, NELEM(gVelocityTrackerMethods));
+    LOG_FATAL_IF(res < 0, "Unable to register native methods.");
+    return 0;
+}
+
+} // namespace android
diff --git a/core/jni/com_google_android_gles_jni_EGLImpl.cpp b/core/jni/com_google_android_gles_jni_EGLImpl.cpp
index e7ea8c8..3d24bee 100644
--- a/core/jni/com_google_android_gles_jni_EGLImpl.cpp
+++ b/core/jni/com_google_android_gles_jni_EGLImpl.cpp
@@ -400,7 +400,7 @@
 }
 
 static jint jni_eglGetCurrentSurface(JNIEnv *_env, jobject _this, jint readdraw) {
-    if (!(readdraw == EGL_READ) || (readdraw == EGL_DRAW)) {
+    if ((readdraw != EGL_READ) && (readdraw != EGL_DRAW)) {
         doThrow(_env, "java/lang/IllegalArgumentException");
         return 0;
     }
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 0ad174f..0c9a2ef 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -91,10 +91,15 @@
     <protected-broadcast android:name="android.hardware.usb.action.USB_DEVICE_DETACHED" />
 
     <protected-broadcast android:name="android.nfc.action.LLCP_LINK_STATE_CHANGED" />
+    <protected-broadcast android:name="com.android.nfc_extras.action.RF_FIELD_ON_DETECTED" />
+    <protected-broadcast android:name="com.android.nfc_extras.action.RF_FIELD_OFF_DETECTED" />
+    <protected-broadcast android:name="com.android.nfc_extras.action.AID_SELECTED" />
+
     <protected-broadcast android:name="android.nfc.action.TRANSACTION_DETECTED" />
     <protected-broadcast android:name="android.intent.action.CLEAR_DNS_CACHE" />
     <protected-broadcast android:name="android.intent.action.PROXY_CHANGE" />
 
+
     <!-- ====================================== -->
     <!-- Permissions for things that cost money -->
     <!-- ====================================== -->
@@ -1379,12 +1384,6 @@
                 android:excludeFromRecents="true">
         </activity>
 
-        <activity android:name="com.android.server.usb.UsbResolverActivity"
-            android:theme="@style/Theme.Holo.Dialog.Alert"
-            android:finishOnCloseSystemDialogs="true"
-            android:excludeFromRecents="true">
-        </activity>
-
         <service android:name="com.android.server.LoadAverageService"
                 android:exported="true" />
 
diff --git a/core/res/res/drawable-hdpi/ic_ab_back_holo_dark.png b/core/res/res/drawable-hdpi/ic_ab_back_holo_dark.png
index 52fccf8..7855cda 100644
--- a/core/res/res/drawable-hdpi/ic_ab_back_holo_dark.png
+++ b/core/res/res/drawable-hdpi/ic_ab_back_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_ab_back_holo_light.png b/core/res/res/drawable-hdpi/ic_ab_back_holo_light.png
index 0354599..c062773 100644
--- a/core/res/res/drawable-hdpi/ic_ab_back_holo_light.png
+++ b/core/res/res/drawable-hdpi/ic_ab_back_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_media_embed_play.png b/core/res/res/drawable-hdpi/ic_media_embed_play.png
new file mode 100644
index 0000000..23ac7e4
--- /dev/null
+++ b/core/res/res/drawable-hdpi/ic_media_embed_play.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_media_ff.png b/core/res/res/drawable-hdpi/ic_media_ff.png
index b0dc05b..a892ba2 100644
--- a/core/res/res/drawable-hdpi/ic_media_ff.png
+++ b/core/res/res/drawable-hdpi/ic_media_ff.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_media_fullscreen.png b/core/res/res/drawable-hdpi/ic_media_fullscreen.png
new file mode 100644
index 0000000..0cdbf77
--- /dev/null
+++ b/core/res/res/drawable-hdpi/ic_media_fullscreen.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_media_next.png b/core/res/res/drawable-hdpi/ic_media_next.png
index 2552f4e..2285670 100644
--- a/core/res/res/drawable-hdpi/ic_media_next.png
+++ b/core/res/res/drawable-hdpi/ic_media_next.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_media_pause.png b/core/res/res/drawable-hdpi/ic_media_pause.png
index d4670c2..ffb55cd 100644
--- a/core/res/res/drawable-hdpi/ic_media_pause.png
+++ b/core/res/res/drawable-hdpi/ic_media_pause.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_media_play.png b/core/res/res/drawable-hdpi/ic_media_play.png
index e67ec80..e525bd2 100644
--- a/core/res/res/drawable-hdpi/ic_media_play.png
+++ b/core/res/res/drawable-hdpi/ic_media_play.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_media_previous.png b/core/res/res/drawable-hdpi/ic_media_previous.png
index 05eba71..3333711 100644
--- a/core/res/res/drawable-hdpi/ic_media_previous.png
+++ b/core/res/res/drawable-hdpi/ic_media_previous.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_media_rew.png b/core/res/res/drawable-hdpi/ic_media_rew.png
index 88eed2e..b14e9b9 100644
--- a/core/res/res/drawable-hdpi/ic_media_rew.png
+++ b/core/res/res/drawable-hdpi/ic_media_rew.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_media_video_poster.png b/core/res/res/drawable-hdpi/ic_media_video_poster.png
new file mode 100644
index 0000000..6c1fd6b
--- /dev/null
+++ b/core/res/res/drawable-hdpi/ic_media_video_poster.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_menu_copy_dark.png b/core/res/res/drawable-hdpi/ic_menu_copy_holo_dark.png
similarity index 100%
rename from core/res/res/drawable-hdpi/ic_menu_copy_dark.png
rename to core/res/res/drawable-hdpi/ic_menu_copy_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_menu_copy_light.png b/core/res/res/drawable-hdpi/ic_menu_copy_holo_light.png
similarity index 100%
rename from core/res/res/drawable-hdpi/ic_menu_copy_light.png
rename to core/res/res/drawable-hdpi/ic_menu_copy_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_menu_cut_dark.png b/core/res/res/drawable-hdpi/ic_menu_cut_holo_dark.png
similarity index 100%
rename from core/res/res/drawable-hdpi/ic_menu_cut_dark.png
rename to core/res/res/drawable-hdpi/ic_menu_cut_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_menu_cut_light.png b/core/res/res/drawable-hdpi/ic_menu_cut_holo_light.png
similarity index 100%
rename from core/res/res/drawable-hdpi/ic_menu_cut_light.png
rename to core/res/res/drawable-hdpi/ic_menu_cut_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_menu_find_holo_dark.png b/core/res/res/drawable-hdpi/ic_menu_find_holo_dark.png
new file mode 100644
index 0000000..b888202
--- /dev/null
+++ b/core/res/res/drawable-hdpi/ic_menu_find_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_menu_find_holo_light.png b/core/res/res/drawable-hdpi/ic_menu_find_holo_light.png
new file mode 100644
index 0000000..b888202
--- /dev/null
+++ b/core/res/res/drawable-hdpi/ic_menu_find_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_menu_paste_dark.png b/core/res/res/drawable-hdpi/ic_menu_paste_holo_dark.png
similarity index 100%
rename from core/res/res/drawable-hdpi/ic_menu_paste_dark.png
rename to core/res/res/drawable-hdpi/ic_menu_paste_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_menu_paste_light.png b/core/res/res/drawable-hdpi/ic_menu_paste_holo_light.png
similarity index 100%
rename from core/res/res/drawable-hdpi/ic_menu_paste_light.png
rename to core/res/res/drawable-hdpi/ic_menu_paste_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_menu_search_holo_dark.png b/core/res/res/drawable-hdpi/ic_menu_search_holo_dark.png
new file mode 100644
index 0000000..a7f9bbe
--- /dev/null
+++ b/core/res/res/drawable-hdpi/ic_menu_search_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_menu_share_holo_dark.png b/core/res/res/drawable-hdpi/ic_menu_share_holo_dark.png
new file mode 100644
index 0000000..2837615
--- /dev/null
+++ b/core/res/res/drawable-hdpi/ic_menu_share_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_menu_share_holo_light.png b/core/res/res/drawable-hdpi/ic_menu_share_holo_light.png
new file mode 100644
index 0000000..2837615
--- /dev/null
+++ b/core/res/res/drawable-hdpi/ic_menu_share_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_paste_bubble_disabled_holo.png b/core/res/res/drawable-hdpi/ic_paste_bubble_disabled_holo.png
new file mode 100644
index 0000000..42ac16b
--- /dev/null
+++ b/core/res/res/drawable-hdpi/ic_paste_bubble_disabled_holo.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_notify_call_mute.png b/core/res/res/drawable-hdpi/stat_notify_call_mute.png
index 048f56e..9887faa 100755
--- a/core/res/res/drawable-hdpi/stat_notify_call_mute.png
+++ b/core/res/res/drawable-hdpi/stat_notify_call_mute.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_notify_car_mode.png b/core/res/res/drawable-hdpi/stat_notify_car_mode.png
index 76dd2ae..94f288c 100644
--- a/core/res/res/drawable-hdpi/stat_notify_car_mode.png
+++ b/core/res/res/drawable-hdpi/stat_notify_car_mode.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_notify_chat.png b/core/res/res/drawable-hdpi/stat_notify_chat.png
index d7c1545..bddea50 100644
--- a/core/res/res/drawable-hdpi/stat_notify_chat.png
+++ b/core/res/res/drawable-hdpi/stat_notify_chat.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_notify_disk_full.png b/core/res/res/drawable-hdpi/stat_notify_disk_full.png
index 9956fad..b44ce58 100755
--- a/core/res/res/drawable-hdpi/stat_notify_disk_full.png
+++ b/core/res/res/drawable-hdpi/stat_notify_disk_full.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_notify_email_generic.png b/core/res/res/drawable-hdpi/stat_notify_email_generic.png
index 4ea619c..8d60237 100644
--- a/core/res/res/drawable-hdpi/stat_notify_email_generic.png
+++ b/core/res/res/drawable-hdpi/stat_notify_email_generic.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_notify_error.png b/core/res/res/drawable-hdpi/stat_notify_error.png
index 598094f..6942871 100755
--- a/core/res/res/drawable-hdpi/stat_notify_error.png
+++ b/core/res/res/drawable-hdpi/stat_notify_error.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_notify_gmail.png b/core/res/res/drawable-hdpi/stat_notify_gmail.png
index 7028ea7..bf8582a 100644
--- a/core/res/res/drawable-hdpi/stat_notify_gmail.png
+++ b/core/res/res/drawable-hdpi/stat_notify_gmail.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_notify_missed_call.png b/core/res/res/drawable-hdpi/stat_notify_missed_call.png
index b0f7a6e..6df57ff3 100644
--- a/core/res/res/drawable-hdpi/stat_notify_missed_call.png
+++ b/core/res/res/drawable-hdpi/stat_notify_missed_call.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_notify_sdcard.png b/core/res/res/drawable-hdpi/stat_notify_sdcard.png
index a916488..0857774 100755
--- a/core/res/res/drawable-hdpi/stat_notify_sdcard.png
+++ b/core/res/res/drawable-hdpi/stat_notify_sdcard.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_notify_sdcard_prepare.png b/core/res/res/drawable-hdpi/stat_notify_sdcard_prepare.png
index e267700..3880496 100755
--- a/core/res/res/drawable-hdpi/stat_notify_sdcard_prepare.png
+++ b/core/res/res/drawable-hdpi/stat_notify_sdcard_prepare.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_notify_sdcard_usb.png b/core/res/res/drawable-hdpi/stat_notify_sdcard_usb.png
index 233e438..ac984ef 100755
--- a/core/res/res/drawable-hdpi/stat_notify_sdcard_usb.png
+++ b/core/res/res/drawable-hdpi/stat_notify_sdcard_usb.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_notify_sim_toolkit.png b/core/res/res/drawable-hdpi/stat_notify_sim_toolkit.png
index 42101077..b7ba4ba 100755
--- a/core/res/res/drawable-hdpi/stat_notify_sim_toolkit.png
+++ b/core/res/res/drawable-hdpi/stat_notify_sim_toolkit.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_notify_sync.png b/core/res/res/drawable-hdpi/stat_notify_sync.png
index 2076c55..76319b0 100755
--- a/core/res/res/drawable-hdpi/stat_notify_sync.png
+++ b/core/res/res/drawable-hdpi/stat_notify_sync.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_notify_sync_anim0.png b/core/res/res/drawable-hdpi/stat_notify_sync_anim0.png
index 2076c55..863c3d7 100755
--- a/core/res/res/drawable-hdpi/stat_notify_sync_anim0.png
+++ b/core/res/res/drawable-hdpi/stat_notify_sync_anim0.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_notify_sync_error.png b/core/res/res/drawable-hdpi/stat_notify_sync_error.png
index bade508..0083c3f 100755
--- a/core/res/res/drawable-hdpi/stat_notify_sync_error.png
+++ b/core/res/res/drawable-hdpi/stat_notify_sync_error.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_notify_voicemail.png b/core/res/res/drawable-hdpi/stat_notify_voicemail.png
index 43fe530..499325b 100755
--- a/core/res/res/drawable-hdpi/stat_notify_voicemail.png
+++ b/core/res/res/drawable-hdpi/stat_notify_voicemail.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_notify_wifi_in_range.png b/core/res/res/drawable-hdpi/stat_notify_wifi_in_range.png
index 5c42e53..8d80709 100644
--- a/core/res/res/drawable-hdpi/stat_notify_wifi_in_range.png
+++ b/core/res/res/drawable-hdpi/stat_notify_wifi_in_range.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_adb.png b/core/res/res/drawable-hdpi/stat_sys_adb.png
index af713e8..9c56e24 100755
--- a/core/res/res/drawable-hdpi/stat_sys_adb.png
+++ b/core/res/res/drawable-hdpi/stat_sys_adb.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_data_bluetooth.png b/core/res/res/drawable-hdpi/stat_sys_data_bluetooth.png
index 42a774e..526fbfa 100644
--- a/core/res/res/drawable-hdpi/stat_sys_data_bluetooth.png
+++ b/core/res/res/drawable-hdpi/stat_sys_data_bluetooth.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_data_usb.png b/core/res/res/drawable-hdpi/stat_sys_data_usb.png
index 6987b09..606ef80 100755
--- a/core/res/res/drawable-hdpi/stat_sys_data_usb.png
+++ b/core/res/res/drawable-hdpi/stat_sys_data_usb.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_download_anim0.png b/core/res/res/drawable-hdpi/stat_sys_download_anim0.png
index 943e620..0510128 100644
--- a/core/res/res/drawable-hdpi/stat_sys_download_anim0.png
+++ b/core/res/res/drawable-hdpi/stat_sys_download_anim0.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_download_anim1.png b/core/res/res/drawable-hdpi/stat_sys_download_anim1.png
index 28edae1..631622b 100644
--- a/core/res/res/drawable-hdpi/stat_sys_download_anim1.png
+++ b/core/res/res/drawable-hdpi/stat_sys_download_anim1.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_download_anim2.png b/core/res/res/drawable-hdpi/stat_sys_download_anim2.png
index 556a46f..e300245 100644
--- a/core/res/res/drawable-hdpi/stat_sys_download_anim2.png
+++ b/core/res/res/drawable-hdpi/stat_sys_download_anim2.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_download_anim3.png b/core/res/res/drawable-hdpi/stat_sys_download_anim3.png
index 422d72b..fd220e3 100644
--- a/core/res/res/drawable-hdpi/stat_sys_download_anim3.png
+++ b/core/res/res/drawable-hdpi/stat_sys_download_anim3.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_download_anim4.png b/core/res/res/drawable-hdpi/stat_sys_download_anim4.png
index 24a0db5..a1ea9e3 100644
--- a/core/res/res/drawable-hdpi/stat_sys_download_anim4.png
+++ b/core/res/res/drawable-hdpi/stat_sys_download_anim4.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_download_anim5.png b/core/res/res/drawable-hdpi/stat_sys_download_anim5.png
index 97e5a6b..7804a29 100644
--- a/core/res/res/drawable-hdpi/stat_sys_download_anim5.png
+++ b/core/res/res/drawable-hdpi/stat_sys_download_anim5.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_gps_on.png b/core/res/res/drawable-hdpi/stat_sys_gps_on.png
index 0d6f622..542ebb0 100644
--- a/core/res/res/drawable-hdpi/stat_sys_gps_on.png
+++ b/core/res/res/drawable-hdpi/stat_sys_gps_on.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_secure.png b/core/res/res/drawable-hdpi/stat_sys_secure.png
index 8d24990..c4a17de 100755
--- a/core/res/res/drawable-hdpi/stat_sys_secure.png
+++ b/core/res/res/drawable-hdpi/stat_sys_secure.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_speakerphone.png b/core/res/res/drawable-hdpi/stat_sys_speakerphone.png
index 82c06a9..a9a2b2e 100755
--- a/core/res/res/drawable-hdpi/stat_sys_speakerphone.png
+++ b/core/res/res/drawable-hdpi/stat_sys_speakerphone.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_throttled.png b/core/res/res/drawable-hdpi/stat_sys_throttled.png
index bd8323a..99ae4ac 100755
--- a/core/res/res/drawable-hdpi/stat_sys_throttled.png
+++ b/core/res/res/drawable-hdpi/stat_sys_throttled.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_upload_anim0.png b/core/res/res/drawable-hdpi/stat_sys_upload_anim0.png
index 45f3c7b..48ba735 100644
--- a/core/res/res/drawable-hdpi/stat_sys_upload_anim0.png
+++ b/core/res/res/drawable-hdpi/stat_sys_upload_anim0.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_upload_anim1.png b/core/res/res/drawable-hdpi/stat_sys_upload_anim1.png
index f4d5a72..cbb06a5 100644
--- a/core/res/res/drawable-hdpi/stat_sys_upload_anim1.png
+++ b/core/res/res/drawable-hdpi/stat_sys_upload_anim1.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_upload_anim2.png b/core/res/res/drawable-hdpi/stat_sys_upload_anim2.png
index b7448c8..e4edda9 100644
--- a/core/res/res/drawable-hdpi/stat_sys_upload_anim2.png
+++ b/core/res/res/drawable-hdpi/stat_sys_upload_anim2.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_upload_anim3.png b/core/res/res/drawable-hdpi/stat_sys_upload_anim3.png
index dfbd726..c2a9b03 100644
--- a/core/res/res/drawable-hdpi/stat_sys_upload_anim3.png
+++ b/core/res/res/drawable-hdpi/stat_sys_upload_anim3.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_upload_anim4.png b/core/res/res/drawable-hdpi/stat_sys_upload_anim4.png
index c4513bf..23f2f9d 100644
--- a/core/res/res/drawable-hdpi/stat_sys_upload_anim4.png
+++ b/core/res/res/drawable-hdpi/stat_sys_upload_anim4.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_upload_anim5.png b/core/res/res/drawable-hdpi/stat_sys_upload_anim5.png
index cc21de2..3fd8b7f 100644
--- a/core/res/res/drawable-hdpi/stat_sys_upload_anim5.png
+++ b/core/res/res/drawable-hdpi/stat_sys_upload_anim5.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_warning.png b/core/res/res/drawable-hdpi/stat_sys_warning.png
index 2783d89..0d1a33c 100755
--- a/core/res/res/drawable-hdpi/stat_sys_warning.png
+++ b/core/res/res/drawable-hdpi/stat_sys_warning.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/text_cursor_holo_dark.9.png b/core/res/res/drawable-hdpi/text_cursor_holo_dark.9.png
index b9435b6..ae77fa0 100644
--- a/core/res/res/drawable-hdpi/text_cursor_holo_dark.9.png
+++ b/core/res/res/drawable-hdpi/text_cursor_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/text_cursor_holo_light.9.png b/core/res/res/drawable-hdpi/text_cursor_holo_light.9.png
index 477d820..c6bdfcc 100644
--- a/core/res/res/drawable-hdpi/text_cursor_holo_light.9.png
+++ b/core/res/res/drawable-hdpi/text_cursor_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/textfield_search_default_holo_dark.9.png b/core/res/res/drawable-hdpi/textfield_search_default_holo_dark.9.png
index 5b62564..62e3274 100644
--- a/core/res/res/drawable-hdpi/textfield_search_default_holo_dark.9.png
+++ b/core/res/res/drawable-hdpi/textfield_search_default_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/textfield_search_default_holo_light.9.png b/core/res/res/drawable-hdpi/textfield_search_default_holo_light.9.png
index 881edeb..b7512fa 100644
--- a/core/res/res/drawable-hdpi/textfield_search_default_holo_light.9.png
+++ b/core/res/res/drawable-hdpi/textfield_search_default_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/textfield_search_right_default_holo_dark.9.png b/core/res/res/drawable-hdpi/textfield_search_right_default_holo_dark.9.png
new file mode 100644
index 0000000..bfc6f83
--- /dev/null
+++ b/core/res/res/drawable-hdpi/textfield_search_right_default_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/textfield_search_right_default_holo_light.9.png b/core/res/res/drawable-hdpi/textfield_search_right_default_holo_light.9.png
new file mode 100644
index 0000000..708ba90
--- /dev/null
+++ b/core/res/res/drawable-hdpi/textfield_search_right_default_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/textfield_search_right_selected_holo_dark.9.png b/core/res/res/drawable-hdpi/textfield_search_right_selected_holo_dark.9.png
new file mode 100644
index 0000000..0da1e9c
--- /dev/null
+++ b/core/res/res/drawable-hdpi/textfield_search_right_selected_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/textfield_search_right_selected_holo_light.9.png b/core/res/res/drawable-hdpi/textfield_search_right_selected_holo_light.9.png
new file mode 100644
index 0000000..2e93557
--- /dev/null
+++ b/core/res/res/drawable-hdpi/textfield_search_right_selected_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/textfield_search_selected_holo_dark.9.png b/core/res/res/drawable-hdpi/textfield_search_selected_holo_dark.9.png
index cb3f35b..7aeaad6 100644
--- a/core/res/res/drawable-hdpi/textfield_search_selected_holo_dark.9.png
+++ b/core/res/res/drawable-hdpi/textfield_search_selected_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/textfield_search_selected_holo_light.9.png b/core/res/res/drawable-hdpi/textfield_search_selected_holo_light.9.png
index 742b137..cf46f32 100644
--- a/core/res/res/drawable-hdpi/textfield_search_selected_holo_light.9.png
+++ b/core/res/res/drawable-hdpi/textfield_search_selected_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-ldpi/ic_media_embed_play.png b/core/res/res/drawable-ldpi/ic_media_embed_play.png
new file mode 100644
index 0000000..e7c1972
--- /dev/null
+++ b/core/res/res/drawable-ldpi/ic_media_embed_play.png
Binary files differ
diff --git a/core/res/res/drawable-ldpi/ic_media_fullscreen.png b/core/res/res/drawable-ldpi/ic_media_fullscreen.png
new file mode 100644
index 0000000..1a38c38
--- /dev/null
+++ b/core/res/res/drawable-ldpi/ic_media_fullscreen.png
Binary files differ
diff --git a/core/res/res/drawable-ldpi/ic_media_video_poster.png b/core/res/res/drawable-ldpi/ic_media_video_poster.png
new file mode 100644
index 0000000..786d0e6
--- /dev/null
+++ b/core/res/res/drawable-ldpi/ic_media_video_poster.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_ab_back_holo_dark.png b/core/res/res/drawable-mdpi/ic_ab_back_holo_dark.png
index 959b4e4..ae3e6bf 100644
--- a/core/res/res/drawable-mdpi/ic_ab_back_holo_dark.png
+++ b/core/res/res/drawable-mdpi/ic_ab_back_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_ab_back_holo_light.png b/core/res/res/drawable-mdpi/ic_ab_back_holo_light.png
index 41333b8..c61e3fa 100644
--- a/core/res/res/drawable-mdpi/ic_ab_back_holo_light.png
+++ b/core/res/res/drawable-mdpi/ic_ab_back_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_media_embed_play.png b/core/res/res/drawable-mdpi/ic_media_embed_play.png
new file mode 100644
index 0000000..fc5d8c6
--- /dev/null
+++ b/core/res/res/drawable-mdpi/ic_media_embed_play.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_media_ff.png b/core/res/res/drawable-mdpi/ic_media_ff.png
index d99779d..892772e 100644
--- a/core/res/res/drawable-mdpi/ic_media_ff.png
+++ b/core/res/res/drawable-mdpi/ic_media_ff.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_media_fullscreen.png b/core/res/res/drawable-mdpi/ic_media_fullscreen.png
new file mode 100644
index 0000000..1c60e15
--- /dev/null
+++ b/core/res/res/drawable-mdpi/ic_media_fullscreen.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_media_next.png b/core/res/res/drawable-mdpi/ic_media_next.png
index cee4930..bbe311b 100644
--- a/core/res/res/drawable-mdpi/ic_media_next.png
+++ b/core/res/res/drawable-mdpi/ic_media_next.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_media_pause.png b/core/res/res/drawable-mdpi/ic_media_pause.png
index 9e8b675..e4e8d86 100644
--- a/core/res/res/drawable-mdpi/ic_media_pause.png
+++ b/core/res/res/drawable-mdpi/ic_media_pause.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_media_play.png b/core/res/res/drawable-mdpi/ic_media_play.png
index 41cd65f..8eaf962 100644
--- a/core/res/res/drawable-mdpi/ic_media_play.png
+++ b/core/res/res/drawable-mdpi/ic_media_play.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_media_previous.png b/core/res/res/drawable-mdpi/ic_media_previous.png
index 1be95b4..e9abc7f 100644
--- a/core/res/res/drawable-mdpi/ic_media_previous.png
+++ b/core/res/res/drawable-mdpi/ic_media_previous.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_media_rew.png b/core/res/res/drawable-mdpi/ic_media_rew.png
index 8311508..a5eb94a 100644
--- a/core/res/res/drawable-mdpi/ic_media_rew.png
+++ b/core/res/res/drawable-mdpi/ic_media_rew.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_media_video_poster.png b/core/res/res/drawable-mdpi/ic_media_video_poster.png
new file mode 100644
index 0000000..10bbd74
--- /dev/null
+++ b/core/res/res/drawable-mdpi/ic_media_video_poster.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_menu_copy_dark.png b/core/res/res/drawable-mdpi/ic_menu_copy_holo_dark.png
similarity index 100%
rename from core/res/res/drawable-mdpi/ic_menu_copy_dark.png
rename to core/res/res/drawable-mdpi/ic_menu_copy_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_menu_copy_light.png b/core/res/res/drawable-mdpi/ic_menu_copy_holo_light.png
similarity index 100%
rename from core/res/res/drawable-mdpi/ic_menu_copy_light.png
rename to core/res/res/drawable-mdpi/ic_menu_copy_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_menu_cut_dark.png b/core/res/res/drawable-mdpi/ic_menu_cut_holo_dark.png
similarity index 100%
rename from core/res/res/drawable-mdpi/ic_menu_cut_dark.png
rename to core/res/res/drawable-mdpi/ic_menu_cut_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_menu_cut_light.png b/core/res/res/drawable-mdpi/ic_menu_cut_holo_light.png
similarity index 100%
rename from core/res/res/drawable-mdpi/ic_menu_cut_light.png
rename to core/res/res/drawable-mdpi/ic_menu_cut_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_menu_find_holo_dark.png b/core/res/res/drawable-mdpi/ic_menu_find_holo_dark.png
new file mode 100644
index 0000000..82dcba7
--- /dev/null
+++ b/core/res/res/drawable-mdpi/ic_menu_find_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_menu_find_holo_light.png b/core/res/res/drawable-mdpi/ic_menu_find_holo_light.png
new file mode 100644
index 0000000..82dcba7
--- /dev/null
+++ b/core/res/res/drawable-mdpi/ic_menu_find_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_menu_paste_dark.png b/core/res/res/drawable-mdpi/ic_menu_paste_holo_dark.png
similarity index 100%
rename from core/res/res/drawable-mdpi/ic_menu_paste_dark.png
rename to core/res/res/drawable-mdpi/ic_menu_paste_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_menu_paste_light.png b/core/res/res/drawable-mdpi/ic_menu_paste_holo_light.png
similarity index 100%
rename from core/res/res/drawable-mdpi/ic_menu_paste_light.png
rename to core/res/res/drawable-mdpi/ic_menu_paste_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_menu_search_holo_dark.png b/core/res/res/drawable-mdpi/ic_menu_search_holo_dark.png
new file mode 100755
index 0000000..5d3155e
--- /dev/null
+++ b/core/res/res/drawable-mdpi/ic_menu_search_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_menu_share_holo_dark.png b/core/res/res/drawable-mdpi/ic_menu_share_holo_dark.png
new file mode 100755
index 0000000..d89ca5f
--- /dev/null
+++ b/core/res/res/drawable-mdpi/ic_menu_share_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_menu_share_holo_light.png b/core/res/res/drawable-mdpi/ic_menu_share_holo_light.png
new file mode 100755
index 0000000..d89ca5f
--- /dev/null
+++ b/core/res/res/drawable-mdpi/ic_menu_share_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_paste_bubble_disabled_holo.png b/core/res/res/drawable-mdpi/ic_paste_bubble_disabled_holo.png
new file mode 100644
index 0000000..ce6bd86
--- /dev/null
+++ b/core/res/res/drawable-mdpi/ic_paste_bubble_disabled_holo.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/stat_notify_call_mute.png b/core/res/res/drawable-mdpi/stat_notify_call_mute.png
index be26065..845ec86 100644
--- a/core/res/res/drawable-mdpi/stat_notify_call_mute.png
+++ b/core/res/res/drawable-mdpi/stat_notify_call_mute.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/stat_notify_car_mode.png b/core/res/res/drawable-mdpi/stat_notify_car_mode.png
index 60d9202..dfd2e0a 100644
--- a/core/res/res/drawable-mdpi/stat_notify_car_mode.png
+++ b/core/res/res/drawable-mdpi/stat_notify_car_mode.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/stat_notify_chat.png b/core/res/res/drawable-mdpi/stat_notify_chat.png
index 36ac850..e4464c2 100644
--- a/core/res/res/drawable-mdpi/stat_notify_chat.png
+++ b/core/res/res/drawable-mdpi/stat_notify_chat.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/stat_notify_disk_full.png b/core/res/res/drawable-mdpi/stat_notify_disk_full.png
index 4e198ef..69b513c 100755
--- a/core/res/res/drawable-mdpi/stat_notify_disk_full.png
+++ b/core/res/res/drawable-mdpi/stat_notify_disk_full.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/stat_notify_email_generic.png b/core/res/res/drawable-mdpi/stat_notify_email_generic.png
index a01485e..42d518d 100644
--- a/core/res/res/drawable-mdpi/stat_notify_email_generic.png
+++ b/core/res/res/drawable-mdpi/stat_notify_email_generic.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/stat_notify_error.png b/core/res/res/drawable-mdpi/stat_notify_error.png
index 69c02d7..ddf0a2f 100644
--- a/core/res/res/drawable-mdpi/stat_notify_error.png
+++ b/core/res/res/drawable-mdpi/stat_notify_error.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/stat_notify_gmail.png b/core/res/res/drawable-mdpi/stat_notify_gmail.png
index 55bae33..516e865 100644
--- a/core/res/res/drawable-mdpi/stat_notify_gmail.png
+++ b/core/res/res/drawable-mdpi/stat_notify_gmail.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/stat_notify_missed_call.png b/core/res/res/drawable-mdpi/stat_notify_missed_call.png
index 58030fd..d2e3631 100644
--- a/core/res/res/drawable-mdpi/stat_notify_missed_call.png
+++ b/core/res/res/drawable-mdpi/stat_notify_missed_call.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/stat_notify_sdcard.png b/core/res/res/drawable-mdpi/stat_notify_sdcard.png
index 0071bf4..8f64201 100644
--- a/core/res/res/drawable-mdpi/stat_notify_sdcard.png
+++ b/core/res/res/drawable-mdpi/stat_notify_sdcard.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/stat_notify_sdcard_prepare.png b/core/res/res/drawable-mdpi/stat_notify_sdcard_prepare.png
index c04d70d..fc051fa 100644
--- a/core/res/res/drawable-mdpi/stat_notify_sdcard_prepare.png
+++ b/core/res/res/drawable-mdpi/stat_notify_sdcard_prepare.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/stat_notify_sdcard_usb.png b/core/res/res/drawable-mdpi/stat_notify_sdcard_usb.png
index 2880934..b936f45 100644
--- a/core/res/res/drawable-mdpi/stat_notify_sdcard_usb.png
+++ b/core/res/res/drawable-mdpi/stat_notify_sdcard_usb.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/stat_notify_sim_toolkit.png b/core/res/res/drawable-mdpi/stat_notify_sim_toolkit.png
index ee7b10c..87327b4 100755
--- a/core/res/res/drawable-mdpi/stat_notify_sim_toolkit.png
+++ b/core/res/res/drawable-mdpi/stat_notify_sim_toolkit.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/stat_notify_sync.png b/core/res/res/drawable-mdpi/stat_notify_sync.png
index ef9d4eb..4876b8e 100644
--- a/core/res/res/drawable-mdpi/stat_notify_sync.png
+++ b/core/res/res/drawable-mdpi/stat_notify_sync.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/stat_notify_sync_anim0.png b/core/res/res/drawable-mdpi/stat_notify_sync_anim0.png
index ef9d4eb..8372756 100644
--- a/core/res/res/drawable-mdpi/stat_notify_sync_anim0.png
+++ b/core/res/res/drawable-mdpi/stat_notify_sync_anim0.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/stat_notify_sync_error.png b/core/res/res/drawable-mdpi/stat_notify_sync_error.png
index f55bf58..2725549 100644
--- a/core/res/res/drawable-mdpi/stat_notify_sync_error.png
+++ b/core/res/res/drawable-mdpi/stat_notify_sync_error.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/stat_notify_voicemail.png b/core/res/res/drawable-mdpi/stat_notify_voicemail.png
index b72a07a..67a0f91 100644
--- a/core/res/res/drawable-mdpi/stat_notify_voicemail.png
+++ b/core/res/res/drawable-mdpi/stat_notify_voicemail.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/stat_notify_wifi_in_range.png b/core/res/res/drawable-mdpi/stat_notify_wifi_in_range.png
index 90dd76e..de63297 100644
--- a/core/res/res/drawable-mdpi/stat_notify_wifi_in_range.png
+++ b/core/res/res/drawable-mdpi/stat_notify_wifi_in_range.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/stat_sys_adb.png b/core/res/res/drawable-mdpi/stat_sys_adb.png
index 2c4d2b5..1400bb3 100644
--- a/core/res/res/drawable-mdpi/stat_sys_adb.png
+++ b/core/res/res/drawable-mdpi/stat_sys_adb.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/stat_sys_data_bluetooth.png b/core/res/res/drawable-mdpi/stat_sys_data_bluetooth.png
index f7f554e..46f6901 100644
--- a/core/res/res/drawable-mdpi/stat_sys_data_bluetooth.png
+++ b/core/res/res/drawable-mdpi/stat_sys_data_bluetooth.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/stat_sys_data_usb.png b/core/res/res/drawable-mdpi/stat_sys_data_usb.png
index 6cdfab7..44860bf 100644
--- a/core/res/res/drawable-mdpi/stat_sys_data_usb.png
+++ b/core/res/res/drawable-mdpi/stat_sys_data_usb.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/stat_sys_download_anim0.png b/core/res/res/drawable-mdpi/stat_sys_download_anim0.png
index c6f2f4e..9c77ecb 100644
--- a/core/res/res/drawable-mdpi/stat_sys_download_anim0.png
+++ b/core/res/res/drawable-mdpi/stat_sys_download_anim0.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/stat_sys_download_anim1.png b/core/res/res/drawable-mdpi/stat_sys_download_anim1.png
index 429ebd7..4bf5e6c 100644
--- a/core/res/res/drawable-mdpi/stat_sys_download_anim1.png
+++ b/core/res/res/drawable-mdpi/stat_sys_download_anim1.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/stat_sys_download_anim2.png b/core/res/res/drawable-mdpi/stat_sys_download_anim2.png
index b3de461..2211810 100644
--- a/core/res/res/drawable-mdpi/stat_sys_download_anim2.png
+++ b/core/res/res/drawable-mdpi/stat_sys_download_anim2.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/stat_sys_download_anim3.png b/core/res/res/drawable-mdpi/stat_sys_download_anim3.png
index 195498e..7db3096 100644
--- a/core/res/res/drawable-mdpi/stat_sys_download_anim3.png
+++ b/core/res/res/drawable-mdpi/stat_sys_download_anim3.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/stat_sys_download_anim4.png b/core/res/res/drawable-mdpi/stat_sys_download_anim4.png
index 8fc3e86..894dd63 100644
--- a/core/res/res/drawable-mdpi/stat_sys_download_anim4.png
+++ b/core/res/res/drawable-mdpi/stat_sys_download_anim4.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/stat_sys_download_anim5.png b/core/res/res/drawable-mdpi/stat_sys_download_anim5.png
index c6f2f4e..889c01e 100644
--- a/core/res/res/drawable-mdpi/stat_sys_download_anim5.png
+++ b/core/res/res/drawable-mdpi/stat_sys_download_anim5.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/stat_sys_gps_on.png b/core/res/res/drawable-mdpi/stat_sys_gps_on.png
index ab59f7c..e0b9d6e 100644
--- a/core/res/res/drawable-mdpi/stat_sys_gps_on.png
+++ b/core/res/res/drawable-mdpi/stat_sys_gps_on.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/stat_sys_secure.png b/core/res/res/drawable-mdpi/stat_sys_secure.png
index db73d06..7167c3a 100644
--- a/core/res/res/drawable-mdpi/stat_sys_secure.png
+++ b/core/res/res/drawable-mdpi/stat_sys_secure.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/stat_sys_speakerphone.png b/core/res/res/drawable-mdpi/stat_sys_speakerphone.png
index 0673060..25fef56 100644
--- a/core/res/res/drawable-mdpi/stat_sys_speakerphone.png
+++ b/core/res/res/drawable-mdpi/stat_sys_speakerphone.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/stat_sys_throttled.png b/core/res/res/drawable-mdpi/stat_sys_throttled.png
index 28a293b..2cbe7f4 100644
--- a/core/res/res/drawable-mdpi/stat_sys_throttled.png
+++ b/core/res/res/drawable-mdpi/stat_sys_throttled.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/stat_sys_upload_anim0.png b/core/res/res/drawable-mdpi/stat_sys_upload_anim0.png
index f804e5e..6a05585e 100644
--- a/core/res/res/drawable-mdpi/stat_sys_upload_anim0.png
+++ b/core/res/res/drawable-mdpi/stat_sys_upload_anim0.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/stat_sys_upload_anim1.png b/core/res/res/drawable-mdpi/stat_sys_upload_anim1.png
index 0cbb85c..af492c8 100644
--- a/core/res/res/drawable-mdpi/stat_sys_upload_anim1.png
+++ b/core/res/res/drawable-mdpi/stat_sys_upload_anim1.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/stat_sys_upload_anim2.png b/core/res/res/drawable-mdpi/stat_sys_upload_anim2.png
index cfa74f3..4ba150c8 100644
--- a/core/res/res/drawable-mdpi/stat_sys_upload_anim2.png
+++ b/core/res/res/drawable-mdpi/stat_sys_upload_anim2.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/stat_sys_upload_anim3.png b/core/res/res/drawable-mdpi/stat_sys_upload_anim3.png
index de5c314..cbcf280 100644
--- a/core/res/res/drawable-mdpi/stat_sys_upload_anim3.png
+++ b/core/res/res/drawable-mdpi/stat_sys_upload_anim3.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/stat_sys_upload_anim4.png b/core/res/res/drawable-mdpi/stat_sys_upload_anim4.png
index 8847949..cb8628c 100644
--- a/core/res/res/drawable-mdpi/stat_sys_upload_anim4.png
+++ b/core/res/res/drawable-mdpi/stat_sys_upload_anim4.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/stat_sys_upload_anim5.png b/core/res/res/drawable-mdpi/stat_sys_upload_anim5.png
index f804e5e..e7a5376 100644
--- a/core/res/res/drawable-mdpi/stat_sys_upload_anim5.png
+++ b/core/res/res/drawable-mdpi/stat_sys_upload_anim5.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/stat_sys_warning.png b/core/res/res/drawable-mdpi/stat_sys_warning.png
index 494c96a..2a764fa 100644
--- a/core/res/res/drawable-mdpi/stat_sys_warning.png
+++ b/core/res/res/drawable-mdpi/stat_sys_warning.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/text_cursor_holo_dark.9.png b/core/res/res/drawable-mdpi/text_cursor_holo_dark.9.png
index b9435b6..ae77fa0 100644
--- a/core/res/res/drawable-mdpi/text_cursor_holo_dark.9.png
+++ b/core/res/res/drawable-mdpi/text_cursor_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/text_cursor_holo_light.9.png b/core/res/res/drawable-mdpi/text_cursor_holo_light.9.png
index 477d820..c6bdfcc 100644
--- a/core/res/res/drawable-mdpi/text_cursor_holo_light.9.png
+++ b/core/res/res/drawable-mdpi/text_cursor_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/textfield_search_default_holo_dark.9.png b/core/res/res/drawable-mdpi/textfield_search_default_holo_dark.9.png
index 3549948..62e3274 100644
--- a/core/res/res/drawable-mdpi/textfield_search_default_holo_dark.9.png
+++ b/core/res/res/drawable-mdpi/textfield_search_default_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/textfield_search_default_holo_light.9.png b/core/res/res/drawable-mdpi/textfield_search_default_holo_light.9.png
index 6db03cb..b7512fa 100644
--- a/core/res/res/drawable-mdpi/textfield_search_default_holo_light.9.png
+++ b/core/res/res/drawable-mdpi/textfield_search_default_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/textfield_search_right_default_holo_dark.9.png b/core/res/res/drawable-mdpi/textfield_search_right_default_holo_dark.9.png
new file mode 100644
index 0000000..bfc6f83
--- /dev/null
+++ b/core/res/res/drawable-mdpi/textfield_search_right_default_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/textfield_search_right_default_holo_light.9.png b/core/res/res/drawable-mdpi/textfield_search_right_default_holo_light.9.png
new file mode 100644
index 0000000..708ba90
--- /dev/null
+++ b/core/res/res/drawable-mdpi/textfield_search_right_default_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/textfield_search_right_selected_holo_dark.9.png b/core/res/res/drawable-mdpi/textfield_search_right_selected_holo_dark.9.png
new file mode 100644
index 0000000..0da1e9c
--- /dev/null
+++ b/core/res/res/drawable-mdpi/textfield_search_right_selected_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/textfield_search_right_selected_holo_light.9.png b/core/res/res/drawable-mdpi/textfield_search_right_selected_holo_light.9.png
new file mode 100644
index 0000000..2e93557
--- /dev/null
+++ b/core/res/res/drawable-mdpi/textfield_search_right_selected_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/textfield_search_selected_holo_dark.9.png b/core/res/res/drawable-mdpi/textfield_search_selected_holo_dark.9.png
index 670439a..7aeaad6 100644
--- a/core/res/res/drawable-mdpi/textfield_search_selected_holo_dark.9.png
+++ b/core/res/res/drawable-mdpi/textfield_search_selected_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/textfield_search_selected_holo_light.9.png b/core/res/res/drawable-mdpi/textfield_search_selected_holo_light.9.png
index 90e26e2..cf46f32 100644
--- a/core/res/res/drawable-mdpi/textfield_search_selected_holo_light.9.png
+++ b/core/res/res/drawable-mdpi/textfield_search_selected_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-xlarge-hdpi/stat_sys_battery_charge_anim0.png b/core/res/res/drawable-xlarge-hdpi/stat_sys_battery_charge_anim0.png
index f8063d1..a526fcf 100644
--- a/core/res/res/drawable-xlarge-hdpi/stat_sys_battery_charge_anim0.png
+++ b/core/res/res/drawable-xlarge-hdpi/stat_sys_battery_charge_anim0.png
Binary files differ
diff --git a/core/res/res/drawable-xlarge-mdpi/stat_sys_battery_charge_anim0.png b/core/res/res/drawable-xlarge-mdpi/stat_sys_battery_charge_anim0.png
index 577f7cc..3640f55 100644
--- a/core/res/res/drawable-xlarge-mdpi/stat_sys_battery_charge_anim0.png
+++ b/core/res/res/drawable-xlarge-mdpi/stat_sys_battery_charge_anim0.png
Binary files differ
diff --git a/core/res/res/drawable/expander_group_holo_dark.xml b/core/res/res/drawable/expander_group_holo_dark.xml
index 51a7290..2481dcb 100644
--- a/core/res/res/drawable/expander_group_holo_dark.xml
+++ b/core/res/res/drawable/expander_group_holo_dark.xml
@@ -17,7 +17,7 @@
 <selector xmlns:android="http://schemas.android.com/apk/res/android">
     <item
         android:state_expanded="true"
-        android:drawable="@drawable/expander_open_holo_dark" />
-    <item
         android:drawable="@drawable/expander_close_holo_dark" />
+    <item
+        android:drawable="@drawable/expander_open_holo_dark" />
 </selector>
diff --git a/core/res/res/drawable/expander_group_holo_light.xml b/core/res/res/drawable/expander_group_holo_light.xml
index 0ce71a5..8006574 100644
--- a/core/res/res/drawable/expander_group_holo_light.xml
+++ b/core/res/res/drawable/expander_group_holo_light.xml
@@ -17,7 +17,7 @@
 <selector xmlns:android="http://schemas.android.com/apk/res/android">
     <item
         android:state_expanded="true"
-        android:drawable="@drawable/expander_open_holo_light" />
-    <item
         android:drawable="@drawable/expander_close_holo_light" />
+    <item
+        android:drawable="@drawable/expander_open_holo_light" />
 </selector>
diff --git a/core/res/res/drawable/list_selector_background.xml b/core/res/res/drawable/list_selector_background.xml
index f5eb12d..1222155 100644
--- a/core/res/res/drawable/list_selector_background.xml
+++ b/core/res/res/drawable/list_selector_background.xml
@@ -24,6 +24,6 @@
     <item android:state_focused="true"  android:state_enabled="false"                              android:drawable="@drawable/list_selector_background_disabled" />
     <item android:state_focused="true"                                android:state_pressed="true" android:drawable="@drawable/list_selector_background_transition" />
     <item android:state_focused="false"                               android:state_pressed="true" android:drawable="@drawable/list_selector_background_transition" />
-    <item android:state_focused="true"                                                             android:drawable="@drawable/list_selector_background_focused" />
+    <item android:state_focused="true"                                                             android:drawable="@drawable/list_selector_background_focus" />
     
 </selector>
diff --git a/core/res/res/drawable/textfield_searchview_holo_dark.xml b/core/res/res/drawable/textfield_searchview_holo_dark.xml
new file mode 100644
index 0000000..1396f83
--- /dev/null
+++ b/core/res/res/drawable/textfield_searchview_holo_dark.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2011 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:state_focused="true"
+        android:drawable="@drawable/textfield_search_selected_holo_dark" />
+    <item android:drawable="@drawable/textfield_search_default_holo_dark" />
+</selector>
+
diff --git a/core/res/res/drawable/textfield_searchview_holo_light.xml b/core/res/res/drawable/textfield_searchview_holo_light.xml
new file mode 100644
index 0000000..5198f9c
--- /dev/null
+++ b/core/res/res/drawable/textfield_searchview_holo_light.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2011 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:state_focused="true"
+        android:drawable="@drawable/textfield_search_selected_holo_light" />
+    <item android:drawable="@drawable/textfield_search_default_holo_light" />
+</selector>
+
diff --git a/core/res/res/drawable/textfield_searchview_right_holo_dark.xml b/core/res/res/drawable/textfield_searchview_right_holo_dark.xml
new file mode 100644
index 0000000..b4f1ca1
--- /dev/null
+++ b/core/res/res/drawable/textfield_searchview_right_holo_dark.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2011 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:state_focused="true"
+        android:drawable="@drawable/textfield_search_right_selected_holo_dark" />
+    <item android:drawable="@drawable/textfield_search_right_default_holo_dark" />
+</selector>
+
diff --git a/core/res/res/drawable/textfield_searchview_right_holo_light.xml b/core/res/res/drawable/textfield_searchview_right_holo_light.xml
new file mode 100644
index 0000000..e521bf6
--- /dev/null
+++ b/core/res/res/drawable/textfield_searchview_right_holo_light.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2011 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:state_focused="true"
+        android:drawable="@drawable/textfield_search_right_selected_holo_light" />
+    <item android:drawable="@drawable/textfield_search_right_default_holo_light" />
+</selector>
+
diff --git a/core/res/res/layout/action_bar_home.xml b/core/res/res/layout/action_bar_home.xml
index e8b5637..c82f91d 100644
--- a/core/res/res/layout/action_bar_home.xml
+++ b/core/res/res/layout/action_bar_home.xml
@@ -14,16 +14,18 @@
      limitations under the License.
 -->
 
-<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
-             android:layout_width="wrap_content"
-             android:layout_height="match_parent"
-             android:background="?android:attr/selectableItemBackground">
+<view xmlns:android="http://schemas.android.com/apk/res/android"
+      class="com.android.internal.widget.ActionBarView$HomeView"
+      android:layout_width="wrap_content"
+      android:layout_height="match_parent"
+      android:background="?android:attr/selectableItemBackground" >
     <ImageView android:id="@android:id/up"
                android:src="?android:attr/homeAsUpIndicator"
-               android:layout_gravity="top|left"
-               android:visibility="invisible"
+               android:layout_gravity="center_vertical|left"
+               android:visibility="gone"
                android:layout_width="wrap_content"
-               android:layout_height="wrap_content" />
+               android:layout_height="wrap_content"
+               android:layout_marginRight="-12dip" />
     <ImageView android:id="@android:id/home"
                android:layout_width="wrap_content"
                android:layout_height="match_parent"
@@ -31,4 +33,4 @@
                android:paddingRight="16dip"
                android:layout_gravity="center"
                android:scaleType="center" />
-</FrameLayout>
+</view>
diff --git a/core/res/res/layout/media_controller.xml b/core/res/res/layout/media_controller.xml
index f4a701e..582101a 100644
--- a/core/res/res/layout/media_controller.xml
+++ b/core/res/res/layout/media_controller.xml
@@ -59,7 +59,7 @@
             style="?android:attr/progressBarStyleHorizontal"
             android:layout_width="0dip"
             android:layout_weight="1"
-            android:layout_height="30dip"
+            android:layout_height="32dip"
             android:layout_alignParentLeft="true"
             android:layout_alignParentRight="true" />
 
diff --git a/core/res/res/layout/preference_list_content.xml b/core/res/res/layout/preference_list_content.xml
index 5d034a5..925b715 100644
--- a/core/res/res/layout/preference_list_content.xml
+++ b/core/res/res/layout/preference_list_content.xml
@@ -36,8 +36,6 @@
             android:layout_height="match_parent"
             android:layout_marginRight="@dimen/preference_screen_side_margin_negative"
             android:layout_marginLeft="@dimen/preference_screen_side_margin"
-            android:layout_marginTop="32dp"
-            android:layout_marginBottom="32dp"
             android:layout_weight="10">
 
             <ListView android:id="@android:id/list"
@@ -61,33 +59,9 @@
                 android:layout_width="0px"
                 android:layout_height="match_parent"
                 android:layout_weight="20"
-                android:layout_marginLeft="@dimen/preference_screen_side_margin"
-                android:layout_marginRight="@dimen/preference_screen_side_margin"
-                android:layout_marginTop="16dp"
-                android:layout_marginBottom="16dp"
-                android:background="?attr/detailsElementBackground"
                 android:orientation="vertical"
                 android:visibility="gone" >
 
-            <!-- Breadcrumb inserted here -->
-            <android.app.FragmentBreadCrumbs
-                android:id="@android:id/title"
-                android:layout_height="72dip"
-                android:layout_width="match_parent"
-                android:paddingTop="16dip"
-                android:paddingBottom="8dip"
-                android:gravity="center_vertical|left"
-                android:layout_marginLeft="48dip"
-                android:layout_marginRight="48dip"
-                />
-
-            <ImageView
-                    android:layout_width="match_parent"
-                    android:layout_height="1dip"
-                    android:paddingLeft="32dip"
-                    android:paddingRight="32dip"
-                    android:src="#404040"
-                />
             <android.preference.PreferenceFrameLayout android:id="@+id/prefs"
                     android:layout_width="match_parent"
                     android:layout_height="0dip"
diff --git a/core/res/res/layout/preference_list_content_large.xml b/core/res/res/layout/preference_list_content_large.xml
new file mode 100644
index 0000000..14d188e
--- /dev/null
+++ b/core/res/res/layout/preference_list_content_large.xml
@@ -0,0 +1,140 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/* //device/apps/common/assets/res/layout/list_content.xml
+**
+** Copyright 2011, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:orientation="vertical"
+    android:layout_height="match_parent"
+    android:layout_width="match_parent">
+
+    <LinearLayout
+        android:orientation="horizontal"
+        android:layout_width="match_parent"
+        android:layout_height="0px"
+        android:layout_weight="1">
+
+        <LinearLayout
+            android:id="@+id/headers"
+            android:orientation="vertical"
+            android:layout_width="0px"
+            android:layout_height="match_parent"
+            android:layout_marginRight="@dimen/preference_screen_side_margin_negative"
+            android:layout_marginLeft="@dimen/preference_screen_side_margin"
+            android:layout_marginTop="32dp"
+            android:layout_marginBottom="32dp"
+            android:layout_weight="10">
+
+            <ListView android:id="@android:id/list"
+                android:layout_width="match_parent"
+                android:layout_height="0px"
+                android:layout_weight="1"
+                android:drawSelectorOnTop="false"
+                android:cacheColorHint="@android:color/transparent"
+                android:listPreferredItemHeight="48dp"
+                android:scrollbarAlwaysDrawVerticalTrack="true" />
+
+            <FrameLayout android:id="@+id/list_footer"
+                    android:layout_width="match_parent"
+                    android:layout_height="wrap_content"
+                    android:layout_weight="0" />
+
+        </LinearLayout>
+
+        <LinearLayout
+                android:id="@+id/prefs_frame"
+                android:layout_width="0px"
+                android:layout_height="match_parent"
+                android:layout_weight="20"
+                android:layout_marginLeft="@dimen/preference_screen_side_margin"
+                android:layout_marginRight="@dimen/preference_screen_side_margin"
+                android:layout_marginTop="16dp"
+                android:layout_marginBottom="16dp"
+                android:background="?attr/detailsElementBackground"
+                android:orientation="vertical"
+                android:visibility="gone" >
+
+            <!-- Breadcrumb inserted here -->
+            <android.app.FragmentBreadCrumbs
+                android:id="@android:id/title"
+                android:layout_height="72dip"
+                android:layout_width="match_parent"
+                android:paddingTop="16dip"
+                android:paddingBottom="8dip"
+                android:gravity="center_vertical|left"
+                android:layout_marginLeft="48dip"
+                android:layout_marginRight="48dip"
+                />
+
+            <ImageView
+                    android:layout_width="match_parent"
+                    android:layout_height="1dip"
+                    android:paddingLeft="32dip"
+                    android:paddingRight="32dip"
+                    android:src="#404040"
+                />
+            <android.preference.PreferenceFrameLayout android:id="@+id/prefs"
+                    android:layout_width="match_parent"
+                    android:layout_height="0dip"
+                    android:layout_weight="1"
+                    android:layout_marginTop="-1dip"
+                />
+        </LinearLayout>
+    </LinearLayout>
+
+    <RelativeLayout android:id="@+id/button_bar"
+        android:layout_height="wrap_content"
+        android:layout_width="match_parent"
+        android:layout_weight="0"
+        android:background="@android:drawable/bottom_bar"
+        android:visibility="gone">
+
+        <Button android:id="@+id/back_button"
+            android:layout_width="150dip"
+            android:layout_height="wrap_content"
+            android:layout_margin="5dip"
+            android:layout_alignParentLeft="true"
+            android:drawableLeft="@drawable/ic_btn_back"
+            android:drawablePadding="3dip"
+            android:text="@string/back_button_label"
+        />
+        <LinearLayout
+            android:orientation="horizontal"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_alignParentRight="true">
+
+            <Button android:id="@+id/skip_button"
+                android:layout_width="150dip"
+                android:layout_height="wrap_content"
+                android:layout_margin="5dip"
+                android:text="@string/skip_button_label"
+                android:visibility="gone"
+            />
+
+            <Button android:id="@+id/next_button"
+                android:layout_width="150dip"
+                android:layout_height="wrap_content"
+                android:layout_margin="5dip"
+                android:drawableRight="@drawable/ic_btn_next"
+                android:drawablePadding="3dip"
+                android:text="@string/next_button_label"
+            />
+        </LinearLayout>
+    </RelativeLayout>
+</LinearLayout>
diff --git a/core/res/res/layout-xlarge/preference_list_content_single.xml b/core/res/res/layout/preference_list_content_single_large.xml
similarity index 100%
rename from core/res/res/layout-xlarge/preference_list_content_single.xml
rename to core/res/res/layout/preference_list_content_single_large.xml
diff --git a/core/res/res/layout/preference_list_fragment.xml b/core/res/res/layout/preference_list_fragment.xml
index 393cecf..4044371 100644
--- a/core/res/res/layout/preference_list_fragment.xml
+++ b/core/res/res/layout/preference_list_fragment.xml
@@ -28,10 +28,6 @@
         android:layout_width="match_parent"
         android:layout_height="0px"
         android:layout_weight="1"
-        android:paddingTop="0dip"
-        android:paddingBottom="48dip"
-        android:paddingLeft="32dip"
-        android:paddingRight="32dip"
         android:clipToPadding="false"
         android:drawSelectorOnTop="false"
         android:cacheColorHint="@android:color/transparent"
diff --git a/core/res/res/layout/preference_list_fragment_large.xml b/core/res/res/layout/preference_list_fragment_large.xml
new file mode 100644
index 0000000..cde84ff
--- /dev/null
+++ b/core/res/res/layout/preference_list_fragment_large.xml
@@ -0,0 +1,80 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+** Copyright 2011, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:orientation="vertical"
+    android:layout_height="match_parent"
+    android:layout_width="match_parent"
+    android:background="@android:color/transparent"
+    android:layout_removeBorders="true">
+
+    <ListView android:id="@android:id/list"
+        android:layout_width="match_parent"
+        android:layout_height="0px"
+        android:layout_weight="1"
+        android:paddingTop="0dip"
+        android:paddingBottom="48dip"
+        android:paddingLeft="32dip"
+        android:paddingRight="32dip"
+        android:clipToPadding="false"
+        android:drawSelectorOnTop="false"
+        android:cacheColorHint="@android:color/transparent"
+        android:scrollbarAlwaysDrawVerticalTrack="true" />
+
+    <RelativeLayout android:id="@+id/button_bar"
+        android:layout_height="wrap_content"
+        android:layout_width="match_parent"
+        android:layout_weight="0"
+        android:background="@android:drawable/bottom_bar"
+        android:visibility="gone">
+
+        <Button android:id="@+id/back_button"
+            android:layout_width="150dip"
+            android:layout_height="wrap_content"
+            android:layout_margin="5dip"
+            android:layout_alignParentLeft="true"
+            android:drawableLeft="@drawable/ic_btn_back"
+            android:drawablePadding="3dip"
+            android:text="@string/back_button_label"
+        />
+        <LinearLayout
+            android:orientation="horizontal"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_alignParentRight="true">
+
+            <Button android:id="@+id/skip_button"
+                android:layout_width="150dip"
+                android:layout_height="wrap_content"
+                android:layout_margin="5dip"
+                android:text="@string/skip_button_label"
+                android:visibility="gone"
+            />
+
+            <Button android:id="@+id/next_button"
+                android:layout_width="150dip"
+                android:layout_height="wrap_content"
+                android:layout_margin="5dip"
+                android:drawableRight="@drawable/ic_btn_next"
+                android:drawablePadding="3dip"
+                android:text="@string/next_button_label"
+            />
+        </LinearLayout>
+    </RelativeLayout>
+</LinearLayout>
diff --git a/core/res/res/layout/search_view.xml b/core/res/res/layout/search_view.xml
index c41c2de..face8b2 100644
--- a/core/res/res/layout/search_view.xml
+++ b/core/res/res/layout/search_view.xml
@@ -54,6 +54,10 @@
         android:layout_height="wrap_content"
         android:layout_weight="1"
         android:layout_gravity="center_vertical"
+        android:layout_marginLeft="16dip"
+        android:layout_marginRight="16dip"
+        android:layout_marginTop="4dip"
+        android:layout_marginBottom="4dip"
         android:orientation="horizontal">
 
         <!-- Inner layout contains the app icon, button(s) and EditText -->
@@ -64,7 +68,7 @@
             android:layout_weight="1"
             android:layout_gravity="center_vertical"
             android:orientation="horizontal"
-            android:background="?android:attr/editTextBackground">
+            android:background="?android:attr/searchViewTextField">
 
             <ImageView
                 android:id="@+id/search_app_icon"
@@ -91,7 +95,7 @@
                 android:inputType="text|textAutoComplete"
                 android:imeOptions="actionSearch"
                 android:dropDownHeight="wrap_content"
-                android:dropDownAnchor="@id/search_plate"
+                android:dropDownAnchor="@id/search_edit_frame"
                 android:dropDownVerticalOffset="0dip"
                 android:dropDownHorizontalOffset="0dip"
             />
@@ -110,38 +114,39 @@
 
         </LinearLayout>
 
-    </LinearLayout>
-
-    <LinearLayout
-        android:id="@+id/submit_area"
-        android:orientation="horizontal"
-        android:layout_width="wrap_content"
-        android:layout_height="match_parent">
-
-        <ImageView
-            android:id="@+id/search_go_btn"
+        <LinearLayout
+            android:id="@+id/submit_area"
+            android:orientation="horizontal"
             android:layout_width="wrap_content"
             android:layout_height="match_parent"
-            android:layout_gravity="center_vertical"
-            android:paddingLeft="16dip"
-            android:paddingRight="16dip"
-            android:background="?android:attr/selectableItemBackground"
-            android:src="?android:attr/searchViewGoIcon"
-            android:visibility="gone"
-            android:focusable="true"
-        />
-
-        <ImageView
-            android:id="@+id/search_voice_btn"
-            android:layout_width="wrap_content"
-            android:layout_height="match_parent"
-            android:layout_gravity="center_vertical"
-            android:paddingLeft="16dip"
-            android:paddingRight="16dip"
-            android:src="?android:attr/searchViewVoiceIcon"
-            android:background="?android:attr/selectableItemBackground"
-            android:visibility="gone"
-            android:focusable="true"
-        />
+            android:background="?android:attr/searchViewTextFieldRight">
+    
+            <ImageView
+                android:id="@+id/search_go_btn"
+                android:layout_width="wrap_content"
+                android:layout_height="match_parent"
+                android:layout_gravity="center_vertical"
+                android:paddingLeft="16dip"
+                android:paddingRight="16dip"
+                android:background="?android:attr/selectableItemBackground"
+                android:src="?android:attr/searchViewGoIcon"
+                android:visibility="gone"
+                android:focusable="true"
+            />
+    
+            <ImageView
+                android:id="@+id/search_voice_btn"
+                android:layout_width="wrap_content"
+                android:layout_height="match_parent"
+                android:layout_gravity="center_vertical"
+                android:paddingLeft="16dip"
+                android:paddingRight="16dip"
+                android:src="?android:attr/searchViewVoiceIcon"
+                android:background="?android:attr/selectableItemBackground"
+                android:visibility="gone"
+                android:focusable="true"
+            />
+        </LinearLayout>
     </LinearLayout>
+
 </LinearLayout>
diff --git a/core/res/res/layout/tab_indicator_holo.xml b/core/res/res/layout/tab_indicator_holo.xml
index d37476b..60c80e9 100644
--- a/core/res/res/layout/tab_indicator_holo.xml
+++ b/core/res/res/layout/tab_indicator_holo.xml
@@ -15,32 +15,24 @@
 -->
 
 <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
-    android:layout_width="wrap_content"
-    android:layout_height="56dip"
-    android:layout_weight="0"
-    android:layout_marginLeft="0dip"
-    android:layout_marginRight="0dip"
+    android:layout_width="0dp"
+    android:layout_height="58dp"
+    android:layout_weight="1"
+    android:layout_marginLeft="-3dip"
+    android:layout_marginRight="-3dip"
+    android:paddingBottom="8dp"
     android:background="@android:drawable/tab_indicator_holo">
 
-    <View android:id="@+id/tab_indicator_left_spacer"
-        android:layout_width="16dip"
-        android:layout_height="0dip" />
-
     <ImageView android:id="@+id/icon"
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
-        android:layout_centerVertical="true"
-        android:visibility="gone"
-        android:layout_toRightOf="@id/tab_indicator_left_spacer"
-        android:paddingRight="8dip" />
+        android:layout_centerHorizontal="true" />
 
     <TextView android:id="@+id/title"
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
-        android:layout_centerVertical="true"
-        android:layout_toRightOf="@id/icon"
-        android:paddingLeft="0dip"
-        android:paddingRight="16dip"
+        android:layout_alignParentBottom="true"
+        android:layout_centerHorizontal="true"
         style="?android:attr/tabWidgetStyle" />
-
+    
 </RelativeLayout>
diff --git a/core/res/res/layout/tab_indicator_holo_large.xml b/core/res/res/layout/tab_indicator_holo_large.xml
new file mode 100644
index 0000000..bdd8d11
--- /dev/null
+++ b/core/res/res/layout/tab_indicator_holo_large.xml
@@ -0,0 +1,46 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2011 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+  
+          http://www.apache.org/licenses/LICENSE-2.0
+  
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="wrap_content"
+    android:layout_height="56dip"
+    android:layout_weight="0"
+    android:layout_marginLeft="0dip"
+    android:layout_marginRight="0dip"
+    android:background="@android:drawable/tab_indicator_holo">
+
+    <View android:id="@+id/tab_indicator_left_spacer"
+        android:layout_width="16dip"
+        android:layout_height="0dip" />
+
+    <ImageView android:id="@+id/icon"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_centerVertical="true"
+        android:visibility="gone"
+        android:layout_toRightOf="@id/tab_indicator_left_spacer"
+        android:paddingRight="8dip" />
+
+    <TextView android:id="@+id/title"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_centerVertical="true"
+        android:layout_toRightOf="@id/icon"
+        android:paddingLeft="0dip"
+        android:paddingRight="16dip"
+        style="?android:attr/tabWidgetStyle" />
+
+</RelativeLayout>
diff --git a/core/res/res/layout/text_edit_no_paste_window.xml b/core/res/res/layout/text_edit_no_paste_window.xml
index fa50275..98b16e2 100644
--- a/core/res/res/layout/text_edit_no_paste_window.xml
+++ b/core/res/res/layout/text_edit_no_paste_window.xml
@@ -25,7 +25,7 @@
         android:paddingRight="16dip"
         android:paddingTop="8dip"
         android:paddingBottom="8dip"
-        android:drawableLeft="@android:drawable/ic_menu_paste_dark"
+        android:drawableLeft="@android:drawable/ic_paste_bubble_disabled_holo"
         android:drawablePadding="8dip"
         android:gravity="center"
         android:textAppearance="?android:attr/textAppearanceMediumInverse"
diff --git a/core/res/res/layout/text_edit_side_no_paste_window.xml b/core/res/res/layout/text_edit_side_no_paste_window.xml
index 0ed3849..3eb41fb 100644
--- a/core/res/res/layout/text_edit_side_no_paste_window.xml
+++ b/core/res/res/layout/text_edit_side_no_paste_window.xml
@@ -25,7 +25,7 @@
         android:paddingRight="16dip"
         android:paddingTop="8dip"
         android:paddingBottom="8dip"
-        android:drawableLeft="@android:drawable/ic_menu_paste_dark"
+        android:drawableLeft="@android:drawable/ic_paste_bubble_disabled_holo"
         android:drawablePadding="8dip"
         android:gravity="center"
         android:textAppearance="?android:attr/textAppearanceMediumInverse"
diff --git a/core/res/res/menu/webview_copy.xml b/core/res/res/menu/webview_copy.xml
index ecb82b3..31bcec5 100644
--- a/core/res/res/menu/webview_copy.xml
+++ b/core/res/res/menu/webview_copy.xml
@@ -25,17 +25,17 @@
         android:showAsAction="ifRoom|withText"
         />
     <item android:id="@+id/share"
-        android:icon="@drawable/ic_menu_share"
+        android:icon="?android:attr/actionModeShareDrawable"
         android:title="@string/share"
         android:showAsAction="ifRoom|withText"
         />
     <item android:id="@+id/find"
-        android:icon="@drawable/ic_menu_find"
+        android:icon="?android:attr/actionModeFindDrawable"
         android:title="@string/find"
         android:showAsAction="ifRoom|withText"
         />
     <item android:id="@+id/websearch"
-        android:icon="@drawable/ic_menu_search"
+        android:icon="?android:attr/actionModeWebSearchDrawable"
         android:title="@string/websearch"
         android:showAsAction="ifRoom|withText"
         />
diff --git a/core/res/res/raw-ar-xlarge/incognito_mode_start_page.html b/core/res/res/raw-ar-xlarge/incognito_mode_start_page.html
new file mode 100644
index 0000000..002be41
--- /dev/null
+++ b/core/res/res/raw-ar-xlarge/incognito_mode_start_page.html
@@ -0,0 +1,19 @@
+<html DIR="RTL">
+  <head>
+    <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no" />
+    <title>نافذة جديدة للتصفح المتخفي</title>
+  </head>
+  <body>
+    <p><strong>أنت الآن في وضع التصفح المتخفي</strong> الصفحات التي تشاهدها في هذه النافذة لن تظهر في سجل المتصفح أو سجلّ البحث، ولن تترك آثارًا أخرى للتتبع، مثل ملفات تعريف الارتباط على جهازك بعد أن تغلق نافذة التصفح المتخفي. ورغم ذلك، سيتم الاحتفاظ بأي ملفات تنزلها أو أية إشارات مرجعية تقوم بإنشائها.</p>
+
+    <p><strong>العمل في وضع التصفح المخفي لا يؤثر على طريقة عمل الأشخاص الآخرين أو الخوادم أو البرامج الأخرى. كن على حذر مما يلي:</strong></p>
+
+    <ul>
+      <li>مواقع الويب التي تجمع معلومات عنك أو تشارك الآخرين فيها</li>
+      <li>مزوّدو خدمة الإنترنت أو الموظفون الذين يتتبعون الصفحات التي تزورها</li>
+      <li>البرامج الضارة التي تتبع ضغطات المفاتيح التي تقوم بها مقابل تنزيل وجوه رمزية مجانًا</li>
+      <li>المراقبة من قبل العملاء السريين</li>
+      <li>الأشخاص الذين يقفون خلفك</li>
+    </ul>
+  </body>
+</html>
diff --git a/core/res/res/raw-ar/incognito_mode_start_page.html b/core/res/res/raw-ar/incognito_mode_start_page.html
new file mode 100644
index 0000000..002be41
--- /dev/null
+++ b/core/res/res/raw-ar/incognito_mode_start_page.html
@@ -0,0 +1,19 @@
+<html DIR="RTL">
+  <head>
+    <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no" />
+    <title>نافذة جديدة للتصفح المتخفي</title>
+  </head>
+  <body>
+    <p><strong>أنت الآن في وضع التصفح المتخفي</strong> الصفحات التي تشاهدها في هذه النافذة لن تظهر في سجل المتصفح أو سجلّ البحث، ولن تترك آثارًا أخرى للتتبع، مثل ملفات تعريف الارتباط على جهازك بعد أن تغلق نافذة التصفح المتخفي. ورغم ذلك، سيتم الاحتفاظ بأي ملفات تنزلها أو أية إشارات مرجعية تقوم بإنشائها.</p>
+
+    <p><strong>العمل في وضع التصفح المخفي لا يؤثر على طريقة عمل الأشخاص الآخرين أو الخوادم أو البرامج الأخرى. كن على حذر مما يلي:</strong></p>
+
+    <ul>
+      <li>مواقع الويب التي تجمع معلومات عنك أو تشارك الآخرين فيها</li>
+      <li>مزوّدو خدمة الإنترنت أو الموظفون الذين يتتبعون الصفحات التي تزورها</li>
+      <li>البرامج الضارة التي تتبع ضغطات المفاتيح التي تقوم بها مقابل تنزيل وجوه رمزية مجانًا</li>
+      <li>المراقبة من قبل العملاء السريين</li>
+      <li>الأشخاص الذين يقفون خلفك</li>
+    </ul>
+  </body>
+</html>
diff --git a/core/res/res/raw-bg-xlarge/incognito_mode_start_page.html b/core/res/res/raw-bg-xlarge/incognito_mode_start_page.html
new file mode 100644
index 0000000..ee25ae4
--- /dev/null
+++ b/core/res/res/raw-bg-xlarge/incognito_mode_start_page.html
@@ -0,0 +1,19 @@
+<html DIR="LTR">
+  <head>
+    <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no" />
+    <title>Нов прозорец „инкогнито“</title>
+  </head>
+  <body>
+    <p><strong>Влязохте в режим „инкогнито“</strong>. Страниците, които разглеждате в този прозорец, няма да се показват в историята на браузъра ви, нито в историята на търсенията ви. Те също няма да оставят други следи като „бисквитки“ в устройството ви, след като затворите прозореца в режим „инкогнито“. Ще се съхранят обаче всички файлове, които изтеглите, или отметки, които създадете.</p>
+
+    <p><strong>Преминаването в режим „инкогнито“ не засяга поведението на други хора, сървъри или софтуер. </strong>Внимавайте за:</p>
+
+    <ul>
+      <li>уебсайтове, които събират или споделят информация за вас;</li>
+      <li>доставчици на интернет услуги или служители, които проследяват посещаваните от вас страници;</li>
+      <li>злонамерен софтуер, който ви дава безплатни емотикони, но в замяна проследява натисканията на клавишите от вас;</li>
+      <li>наблюдение от тайните служби;</li>
+      <li>хора, които стоят зад вас.</li>
+    </ul>
+  </body>
+</html>
diff --git a/core/res/res/raw-bg/incognito_mode_start_page.html b/core/res/res/raw-bg/incognito_mode_start_page.html
new file mode 100644
index 0000000..ee25ae4
--- /dev/null
+++ b/core/res/res/raw-bg/incognito_mode_start_page.html
@@ -0,0 +1,19 @@
+<html DIR="LTR">
+  <head>
+    <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no" />
+    <title>Нов прозорец „инкогнито“</title>
+  </head>
+  <body>
+    <p><strong>Влязохте в режим „инкогнито“</strong>. Страниците, които разглеждате в този прозорец, няма да се показват в историята на браузъра ви, нито в историята на търсенията ви. Те също няма да оставят други следи като „бисквитки“ в устройството ви, след като затворите прозореца в режим „инкогнито“. Ще се съхранят обаче всички файлове, които изтеглите, или отметки, които създадете.</p>
+
+    <p><strong>Преминаването в режим „инкогнито“ не засяга поведението на други хора, сървъри или софтуер. </strong>Внимавайте за:</p>
+
+    <ul>
+      <li>уебсайтове, които събират или споделят информация за вас;</li>
+      <li>доставчици на интернет услуги или служители, които проследяват посещаваните от вас страници;</li>
+      <li>злонамерен софтуер, който ви дава безплатни емотикони, но в замяна проследява натисканията на клавишите от вас;</li>
+      <li>наблюдение от тайните служби;</li>
+      <li>хора, които стоят зад вас.</li>
+    </ul>
+  </body>
+</html>
diff --git a/core/res/res/raw-ca-xlarge/incognito_mode_start_page.html b/core/res/res/raw-ca-xlarge/incognito_mode_start_page.html
new file mode 100644
index 0000000..bec3dac
--- /dev/null
+++ b/core/res/res/raw-ca-xlarge/incognito_mode_start_page.html
@@ -0,0 +1,19 @@
+<html DIR="LTR">
+  <head>
+    <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no" />
+    <title>Nova finestra d'incògnit</title>
+  </head>
+  <body>
+    <p><strong>Has passat a l'estat d'incògnit</strong>. Les pàgines que visualitzis en aquesta finestra no apareixeran a l'historial del navegador ni a l'historial de cerques, i no deixaran cap pista, com ara galetes, al dispositiu després de tancar la finestra d'incògnit. Tanmateix, es conservaran tots els fitxers que baixis o les adreces d'interès que creïs.</p>
+
+    <p><strong>Utilitzar el mode d'incògnit no afecta el comportament d'altres usuaris, servidors ni programari. Vés amb compte amb:</strong></p>
+
+    <ul>
+      <li>llocs web que recopilen o comparteixen informació sobre la teva identitat,</li>
+      <li>proveïdors de serveis d'Internet o treballadors que segueixen les pàgines que visites,</li>
+      <li>programari maliciós que segueix les teves pulsacions del teclat a canvi d'emoticones,</li>
+      <li>vigilància per part d'agents secrets,</li>
+      <li>persones que estan darrere teu.</li>
+    </ul>
+  </body>
+</html>
diff --git a/core/res/res/raw-ca/incognito_mode_start_page.html b/core/res/res/raw-ca/incognito_mode_start_page.html
new file mode 100644
index 0000000..bec3dac
--- /dev/null
+++ b/core/res/res/raw-ca/incognito_mode_start_page.html
@@ -0,0 +1,19 @@
+<html DIR="LTR">
+  <head>
+    <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no" />
+    <title>Nova finestra d'incògnit</title>
+  </head>
+  <body>
+    <p><strong>Has passat a l'estat d'incògnit</strong>. Les pàgines que visualitzis en aquesta finestra no apareixeran a l'historial del navegador ni a l'historial de cerques, i no deixaran cap pista, com ara galetes, al dispositiu després de tancar la finestra d'incògnit. Tanmateix, es conservaran tots els fitxers que baixis o les adreces d'interès que creïs.</p>
+
+    <p><strong>Utilitzar el mode d'incògnit no afecta el comportament d'altres usuaris, servidors ni programari. Vés amb compte amb:</strong></p>
+
+    <ul>
+      <li>llocs web que recopilen o comparteixen informació sobre la teva identitat,</li>
+      <li>proveïdors de serveis d'Internet o treballadors que segueixen les pàgines que visites,</li>
+      <li>programari maliciós que segueix les teves pulsacions del teclat a canvi d'emoticones,</li>
+      <li>vigilància per part d'agents secrets,</li>
+      <li>persones que estan darrere teu.</li>
+    </ul>
+  </body>
+</html>
diff --git a/core/res/res/raw-cs-xlarge/incognito_mode_start_page.html b/core/res/res/raw-cs-xlarge/incognito_mode_start_page.html
new file mode 100644
index 0000000..7420393
--- /dev/null
+++ b/core/res/res/raw-cs-xlarge/incognito_mode_start_page.html
@@ -0,0 +1,19 @@
+<html DIR="LTR">
+  <head>
+    <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no" />
+    <title>Nové anonymní okno</title>
+  </head>
+  <body>
+    <p><strong>Spustili jste anonymní režim</strong>. Stránky, které zobrazíte v tomto okně, se nezahrnou do historie prohlížeče ani historie vyhledávání a dokonce po zavření tohoto anonymního okna ve vašem zařízení nezanechají ani žádné jiné stopy například v podobě souborů cookie. Veškeré stažené soubory nebo vytvořené záložky však budou zachovány.</p>
+
+    <p><strong>Použití anonymního režimu nemá vliv na chování jiných osob, serverů nebo softwaru. Dejte si pozor na:</strong></p>
+
+    <ul>
+      <li>Weby, které sbírají nebo sdílejí informace o vás</li>
+      <li>Poskytovatele internetových služeb nebo zaměstnavatele, kteří sledují stránky, které navštěvujete</li>
+      <li>Škodlivý software, který sleduje stisknuté klávesy a výměnou nabízí nové emotikony</li>
+      <li>Tajné agenty</li>
+      <li>Lidi, kteří vám koukají přes rameno</li>
+    </ul>
+  </body>
+</html>
diff --git a/core/res/res/raw-cs/incognito_mode_start_page.html b/core/res/res/raw-cs/incognito_mode_start_page.html
new file mode 100644
index 0000000..7420393
--- /dev/null
+++ b/core/res/res/raw-cs/incognito_mode_start_page.html
@@ -0,0 +1,19 @@
+<html DIR="LTR">
+  <head>
+    <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no" />
+    <title>Nové anonymní okno</title>
+  </head>
+  <body>
+    <p><strong>Spustili jste anonymní režim</strong>. Stránky, které zobrazíte v tomto okně, se nezahrnou do historie prohlížeče ani historie vyhledávání a dokonce po zavření tohoto anonymního okna ve vašem zařízení nezanechají ani žádné jiné stopy například v podobě souborů cookie. Veškeré stažené soubory nebo vytvořené záložky však budou zachovány.</p>
+
+    <p><strong>Použití anonymního režimu nemá vliv na chování jiných osob, serverů nebo softwaru. Dejte si pozor na:</strong></p>
+
+    <ul>
+      <li>Weby, které sbírají nebo sdílejí informace o vás</li>
+      <li>Poskytovatele internetových služeb nebo zaměstnavatele, kteří sledují stránky, které navštěvujete</li>
+      <li>Škodlivý software, který sleduje stisknuté klávesy a výměnou nabízí nové emotikony</li>
+      <li>Tajné agenty</li>
+      <li>Lidi, kteří vám koukají přes rameno</li>
+    </ul>
+  </body>
+</html>
diff --git a/core/res/res/raw-da-xlarge/incognito_mode_start_page.html b/core/res/res/raw-da-xlarge/incognito_mode_start_page.html
new file mode 100644
index 0000000..eae989f
--- /dev/null
+++ b/core/res/res/raw-da-xlarge/incognito_mode_start_page.html
@@ -0,0 +1,19 @@
+<html DIR="LTR">
+  <head>
+    <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no" />
+    <title>Nyt inkognitovindue</title>
+  </head>
+  <body>
+    <p><strong>Nu er du inkognito</strong>. De sider, du besøger i dette vindue, vises ikke i din browser- eller søgeoversigt, og de efterlader ikke andre spor, såsom cookies, på din enhed, når du lukker incognitovinduet. Filer, som du downloader eller bogmærker, som du opretter, gemmes dog.</p>
+
+    <p><strong>At være inkognito er ikke noget, der påvirker andre folk, servere eller software. Vær opmærksom på:</strong></p>
+
+    <ul>
+      <li>Websider, der indsamler eller deler oplysninger om dig</li>
+      <li>Internetserviceudbydere eller arbejdsgivere, der registrerer de sider, du besøger</li>
+      <li>Ondsindet software, der registrerer dine tasteslag til gengæld for gratis smileys</li>
+      <li>Overvågning af hemmelige agenter</li>
+      <li>Folk, der kigger dig over skulderen</li>
+    </ul>
+  </body>
+</html>
diff --git a/core/res/res/raw-da/incognito_mode_start_page.html b/core/res/res/raw-da/incognito_mode_start_page.html
new file mode 100644
index 0000000..eae989f
--- /dev/null
+++ b/core/res/res/raw-da/incognito_mode_start_page.html
@@ -0,0 +1,19 @@
+<html DIR="LTR">
+  <head>
+    <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no" />
+    <title>Nyt inkognitovindue</title>
+  </head>
+  <body>
+    <p><strong>Nu er du inkognito</strong>. De sider, du besøger i dette vindue, vises ikke i din browser- eller søgeoversigt, og de efterlader ikke andre spor, såsom cookies, på din enhed, når du lukker incognitovinduet. Filer, som du downloader eller bogmærker, som du opretter, gemmes dog.</p>
+
+    <p><strong>At være inkognito er ikke noget, der påvirker andre folk, servere eller software. Vær opmærksom på:</strong></p>
+
+    <ul>
+      <li>Websider, der indsamler eller deler oplysninger om dig</li>
+      <li>Internetserviceudbydere eller arbejdsgivere, der registrerer de sider, du besøger</li>
+      <li>Ondsindet software, der registrerer dine tasteslag til gengæld for gratis smileys</li>
+      <li>Overvågning af hemmelige agenter</li>
+      <li>Folk, der kigger dig over skulderen</li>
+    </ul>
+  </body>
+</html>
diff --git a/core/res/res/raw-de-xlarge/incognito_mode_start_page.html b/core/res/res/raw-de-xlarge/incognito_mode_start_page.html
new file mode 100644
index 0000000..1d2cb69
--- /dev/null
+++ b/core/res/res/raw-de-xlarge/incognito_mode_start_page.html
@@ -0,0 +1,19 @@
+<html DIR="LTR">
+  <head>
+    <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no" />
+    <title>Neues Inkognito-Fenster</title>
+  </head>
+  <body>
+    <p><strong>Sie haben den Modus für anonymes Browsen aktiviert</strong>. In diesem Fenster aufgerufene Seiten erscheinen nicht in Ihrem Browser- oder Suchverlauf. Zudem werden nach dem Schließen des Inkognito-Fensters keine anderen Spuren wie etwa Cookies auf Ihrem Gerät gespeichert. Heruntergeladene Dateien oder hinzugefügte Lesezeichen werden jedoch beibehalten.</p>
+
+    <p><strong>Das anonyme Browsen wirkt sich nicht auf das Verhalten von Menschen, Servern oder Software aus. </strong>Vorsicht ist geboten bei:</p>
+
+    <ul>
+      <li>Websites, auf denen Informationen über Sie gesammelt oder weitergegeben werden</li>
+      <li>Internetanbietern oder Arbeitgebern, die die von Ihnen aufgerufenen Seiten protokollieren</li>
+      <li>Bösartiger Software, die Ihnen kostenlose Smileys bietet, dafür aber Ihre Tastatureingaben speichert</li>
+      <li>Geheimagenten</li>
+      <li>Personen, die hinter Ihnen stehen</li>
+    </ul>
+  </body>
+</html>
diff --git a/core/res/res/raw-de/incognito_mode_start_page.html b/core/res/res/raw-de/incognito_mode_start_page.html
new file mode 100644
index 0000000..1d2cb69
--- /dev/null
+++ b/core/res/res/raw-de/incognito_mode_start_page.html
@@ -0,0 +1,19 @@
+<html DIR="LTR">
+  <head>
+    <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no" />
+    <title>Neues Inkognito-Fenster</title>
+  </head>
+  <body>
+    <p><strong>Sie haben den Modus für anonymes Browsen aktiviert</strong>. In diesem Fenster aufgerufene Seiten erscheinen nicht in Ihrem Browser- oder Suchverlauf. Zudem werden nach dem Schließen des Inkognito-Fensters keine anderen Spuren wie etwa Cookies auf Ihrem Gerät gespeichert. Heruntergeladene Dateien oder hinzugefügte Lesezeichen werden jedoch beibehalten.</p>
+
+    <p><strong>Das anonyme Browsen wirkt sich nicht auf das Verhalten von Menschen, Servern oder Software aus. </strong>Vorsicht ist geboten bei:</p>
+
+    <ul>
+      <li>Websites, auf denen Informationen über Sie gesammelt oder weitergegeben werden</li>
+      <li>Internetanbietern oder Arbeitgebern, die die von Ihnen aufgerufenen Seiten protokollieren</li>
+      <li>Bösartiger Software, die Ihnen kostenlose Smileys bietet, dafür aber Ihre Tastatureingaben speichert</li>
+      <li>Geheimagenten</li>
+      <li>Personen, die hinter Ihnen stehen</li>
+    </ul>
+  </body>
+</html>
diff --git a/core/res/res/raw-el-xlarge/incognito_mode_start_page.html b/core/res/res/raw-el-xlarge/incognito_mode_start_page.html
new file mode 100644
index 0000000..5641650
--- /dev/null
+++ b/core/res/res/raw-el-xlarge/incognito_mode_start_page.html
@@ -0,0 +1,19 @@
+<html DIR="LTR">
+  <head>
+    <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no" />
+    <title>Νέο παράθυρο για ανώνυμη περιήγηση</title>
+  </head>
+  <body>
+    <p><strong>Είστε σε κατάσταση ανώνυμης περιήγησης</strong>. Οι σελίδες που θα προβάλλετε σε αυτό το παράθυρο δεν θα εμφανιστούν στο ιστορικό του πρόγράμματος περιήγησης ή στο ιστορικό αναζήτησης. Επίσης, δεν θα αφήσουν ίχνη, όπως cookie, στη συσκευή σας αφού κλείσετε το παράθυρο ανώνυμης περιήγησης. Ωστόσο, τα αρχεία και οι σελιδοδείκτες που θα δημιουργήσετε θα διατηρηθούν.</p>
+
+    <p><strong>Η κατάσταση ανώνυμης περιήγησης δεν επηρεάζει την συμπεριφορά άλλων, διακομιστών ή λογισμικού. Αλλά προσοχή σε:</strong></p>
+
+    <ul>
+      <li>Ιστοτόπους που συλλέγουν ή μοιράζονται πληροφορίες για εσάς</li>
+      <li>Πάροχους υπηρεσιών διαδικτύου ή εργοδότες που παρακολουθούν τις ιστοσελίδες που επισκέπτεστε</li>
+      <li>Κακόβουλο λογισμικό που καταγράφει ότι πληκτρολογείτε με αντάλλαγμα δωρεάν "φατσούλες"</li>
+      <li>Παρακολούθηση από μυστικούς πράκτορες</li>
+      <li>Άτομα που στέκονται πίσω σας</li>
+    </ul>
+  </body>
+</html>
diff --git a/core/res/res/raw-el/incognito_mode_start_page.html b/core/res/res/raw-el/incognito_mode_start_page.html
new file mode 100644
index 0000000..5641650
--- /dev/null
+++ b/core/res/res/raw-el/incognito_mode_start_page.html
@@ -0,0 +1,19 @@
+<html DIR="LTR">
+  <head>
+    <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no" />
+    <title>Νέο παράθυρο για ανώνυμη περιήγηση</title>
+  </head>
+  <body>
+    <p><strong>Είστε σε κατάσταση ανώνυμης περιήγησης</strong>. Οι σελίδες που θα προβάλλετε σε αυτό το παράθυρο δεν θα εμφανιστούν στο ιστορικό του πρόγράμματος περιήγησης ή στο ιστορικό αναζήτησης. Επίσης, δεν θα αφήσουν ίχνη, όπως cookie, στη συσκευή σας αφού κλείσετε το παράθυρο ανώνυμης περιήγησης. Ωστόσο, τα αρχεία και οι σελιδοδείκτες που θα δημιουργήσετε θα διατηρηθούν.</p>
+
+    <p><strong>Η κατάσταση ανώνυμης περιήγησης δεν επηρεάζει την συμπεριφορά άλλων, διακομιστών ή λογισμικού. Αλλά προσοχή σε:</strong></p>
+
+    <ul>
+      <li>Ιστοτόπους που συλλέγουν ή μοιράζονται πληροφορίες για εσάς</li>
+      <li>Πάροχους υπηρεσιών διαδικτύου ή εργοδότες που παρακολουθούν τις ιστοσελίδες που επισκέπτεστε</li>
+      <li>Κακόβουλο λογισμικό που καταγράφει ότι πληκτρολογείτε με αντάλλαγμα δωρεάν "φατσούλες"</li>
+      <li>Παρακολούθηση από μυστικούς πράκτορες</li>
+      <li>Άτομα που στέκονται πίσω σας</li>
+    </ul>
+  </body>
+</html>
diff --git a/core/res/res/raw-en-rGB-xlarge/incognito_mode_start_page.html b/core/res/res/raw-en-rGB-xlarge/incognito_mode_start_page.html
new file mode 100644
index 0000000..7436f98
--- /dev/null
+++ b/core/res/res/raw-en-rGB-xlarge/incognito_mode_start_page.html
@@ -0,0 +1,19 @@
+<html DIR="LTR">
+  <head>
+    <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no" />
+    <title>New incognito window</title>
+  </head>
+  <body>
+    <p><strong>You've gone incognito</strong>. Pages that you view in this window won't appear in your browser history or search history, and they won't leave other traces, such as cookies, on your device after you close the incognito window. However, any files that you download or bookmarks that you create will be preserved.</p>
+
+    <p><strong>Going incognito doesn't affect the behaviour of other people, servers or software. Be cautious of:</strong></p>
+
+    <ul>
+      <li>Websites that collect or share information about you</li>
+      <li>Internet service providers or employers that track the pages that you visit</li>
+      <li>Malicious software that tracks your keystrokes in exchange for free smileys</li>
+      <li>Surveillance by secret agents</li>
+      <li>People standing behind you</li>
+    </ul>
+  </body>
+</html>
diff --git a/core/res/res/raw-en-rGB/incognito_mode_start_page.html b/core/res/res/raw-en-rGB/incognito_mode_start_page.html
new file mode 100644
index 0000000..7436f98
--- /dev/null
+++ b/core/res/res/raw-en-rGB/incognito_mode_start_page.html
@@ -0,0 +1,19 @@
+<html DIR="LTR">
+  <head>
+    <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no" />
+    <title>New incognito window</title>
+  </head>
+  <body>
+    <p><strong>You've gone incognito</strong>. Pages that you view in this window won't appear in your browser history or search history, and they won't leave other traces, such as cookies, on your device after you close the incognito window. However, any files that you download or bookmarks that you create will be preserved.</p>
+
+    <p><strong>Going incognito doesn't affect the behaviour of other people, servers or software. Be cautious of:</strong></p>
+
+    <ul>
+      <li>Websites that collect or share information about you</li>
+      <li>Internet service providers or employers that track the pages that you visit</li>
+      <li>Malicious software that tracks your keystrokes in exchange for free smileys</li>
+      <li>Surveillance by secret agents</li>
+      <li>People standing behind you</li>
+    </ul>
+  </body>
+</html>
diff --git a/core/res/res/raw-es-rUS-xlarge/incognito_mode_start_page.html b/core/res/res/raw-es-rUS-xlarge/incognito_mode_start_page.html
new file mode 100644
index 0000000..d283df5
--- /dev/null
+++ b/core/res/res/raw-es-rUS-xlarge/incognito_mode_start_page.html
@@ -0,0 +1,19 @@
+<html DIR="LTR">
+  <head>
+    <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no" />
+    <title>Nueva ventana de incógnito</title>
+  </head>
+  <body>
+    <p><strong>Estás de incógnito</strong>. Las páginas que veas en esta ventana no aparecerán en el historial de tu navegador ni en el historial de búsquedas, y cuando cierres la ventana de incógnito, tampoco quedará ningún otro rastro, como cookies, en tu dispositivo. Sin embargo, sí se preservarán los archivos que descargues o los favoritos que marques.</p>
+
+    <p><strong>Estar de incógnito no afecta el comportamiento de otras personas, servidores o programas. Ten cuidado con:</strong></p>
+
+    <ul>
+      <li>Sitios web que recaban o comparten tu información</li>
+      <li>Proveedores de servicio de Internet o empleadores que hacen un seguimiento de las páginas que visitas</li>
+      <li>Programas de software maliciosos que hacen un seguimiento de la actividad de tu teclado a cambio de emoticones gratuitos</li>
+      <li>Vigilancia a cargo de agentes secretos</li>
+      <li>Personas paradas atrás tuyo</li>
+    </ul>
+  </body>
+</html>
diff --git a/core/res/res/raw-es-rUS/incognito_mode_start_page.html b/core/res/res/raw-es-rUS/incognito_mode_start_page.html
new file mode 100644
index 0000000..d283df5
--- /dev/null
+++ b/core/res/res/raw-es-rUS/incognito_mode_start_page.html
@@ -0,0 +1,19 @@
+<html DIR="LTR">
+  <head>
+    <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no" />
+    <title>Nueva ventana de incógnito</title>
+  </head>
+  <body>
+    <p><strong>Estás de incógnito</strong>. Las páginas que veas en esta ventana no aparecerán en el historial de tu navegador ni en el historial de búsquedas, y cuando cierres la ventana de incógnito, tampoco quedará ningún otro rastro, como cookies, en tu dispositivo. Sin embargo, sí se preservarán los archivos que descargues o los favoritos que marques.</p>
+
+    <p><strong>Estar de incógnito no afecta el comportamiento de otras personas, servidores o programas. Ten cuidado con:</strong></p>
+
+    <ul>
+      <li>Sitios web que recaban o comparten tu información</li>
+      <li>Proveedores de servicio de Internet o empleadores que hacen un seguimiento de las páginas que visitas</li>
+      <li>Programas de software maliciosos que hacen un seguimiento de la actividad de tu teclado a cambio de emoticones gratuitos</li>
+      <li>Vigilancia a cargo de agentes secretos</li>
+      <li>Personas paradas atrás tuyo</li>
+    </ul>
+  </body>
+</html>
diff --git a/core/res/res/raw-es-xlarge/incognito_mode_start_page.html b/core/res/res/raw-es-xlarge/incognito_mode_start_page.html
new file mode 100644
index 0000000..6d9b501
--- /dev/null
+++ b/core/res/res/raw-es-xlarge/incognito_mode_start_page.html
@@ -0,0 +1,19 @@
+<html DIR="LTR">
+  <head>
+    <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no" />
+    <title>Nueva ventana de incógnito</title>
+  </head>
+  <body>
+    <p><strong>Estás navegando de incógnito</strong>. Las páginas que consultes a través de esta ventana no quedarán registradas en el historial del navegador ni en el historial de búsquedas, y tampoco dejarán otros rastros en el ordenador (como cookies) una vez cerrada. Los archivos que descargues y los marcadores que guardes sí se almacenarán. </p>
+
+    <p><strong>La función de navegación de incógnito no afecta al comportamiento de los servidores o programas de software. Ten cuidado con:</strong></p>
+
+    <ul>
+      <li>sitios web que recopilan o comparten información personal</li>
+      <li>proveedores de servicios de Internet o trabajadores de estas empresas que supervisan las páginas que visitas</li>
+      <li>software malicioso que realiza un seguimiento de las teclas que pulsas a cambio de emoticonos gratuitos</li>
+      <li>actividades de seguimiento por parte de terceros</li>
+      <li>personas merodeando cerca de tu ordenador</li>
+    </ul>
+  </body>
+</html>
diff --git a/core/res/res/raw-es/incognito_mode_start_page.html b/core/res/res/raw-es/incognito_mode_start_page.html
index 43fd37f..6d9b501 100644
--- a/core/res/res/raw-es/incognito_mode_start_page.html
+++ b/core/res/res/raw-es/incognito_mode_start_page.html
@@ -1,26 +1,19 @@
-<html>
+<html DIR="LTR">
   <head>
-    <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no"/>
+    <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no" />
     <title>Nueva ventana de incógnito</title>
   </head>
   <body>
-    <p><strong>Has entrado en el modo &quot;Navegar de incógnito&quot;</strong>. Las páginas
-    que consultes a través de esta ventana no quedarán registradas en el historial del navegador
-    ni en el historial de búsquedas, y tampoco dejarán otros rastros en el equipo (como cookies)
-    una vez cerrada. Aunque sí quedarán almacenados los archivos que descargues y los marcadores
-    que guardes durante la sesión.</p>
+    <p><strong>Estás navegando de incógnito</strong>. Las páginas que consultes a través de esta ventana no quedarán registradas en el historial del navegador ni en el historial de búsquedas, y tampoco dejarán otros rastros en el ordenador (como cookies) una vez cerrada. Los archivos que descargues y los marcadores que guardes sí se almacenarán. </p>
 
-    <p><strong>La función &quot;Navegar de incógnito&quot; no afecta al comportamiento de
-    otros usuarios, servidores o programas. Atención con:</strong></p>
+    <p><strong>La función de navegación de incógnito no afecta al comportamiento de los servidores o programas de software. Ten cuidado con:</strong></p>
 
     <ul>
-      <li>sitios web que recopilan o comparten información personal,</li>
-      <li>proveedores de servicios de Internet o trabajadores de estas empresas que
-      supervisan las páginas que visita el usuario,</li>
-      <li>software malicioso que realiza un seguimiento de las teclas que pulsa el usuario a
-      cambio de unos emoticones gratuitos,</li>
-      <li>el seguimiento por parte de detectives privados,</li>
-      <li>personas merodeando cerca de tu equipo.</li>
+      <li>sitios web que recopilan o comparten información personal</li>
+      <li>proveedores de servicios de Internet o trabajadores de estas empresas que supervisan las páginas que visitas</li>
+      <li>software malicioso que realiza un seguimiento de las teclas que pulsas a cambio de emoticonos gratuitos</li>
+      <li>actividades de seguimiento por parte de terceros</li>
+      <li>personas merodeando cerca de tu ordenador</li>
     </ul>
   </body>
 </html>
diff --git a/core/res/res/raw-fa-xlarge/incognito_mode_start_page.html b/core/res/res/raw-fa-xlarge/incognito_mode_start_page.html
new file mode 100644
index 0000000..f004120
--- /dev/null
+++ b/core/res/res/raw-fa-xlarge/incognito_mode_start_page.html
@@ -0,0 +1,19 @@
+<html DIR="RTL">
+  <head>
+    <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no" />
+    <title>پنجره ناشناس جدید</title>
+  </head>
+  <body>
+    <p><strong>شما به صورت ناشناس وارد شده اید</strong> صفحاتی که شما در این پنجره مشاهده میکنید در سابقه مرورگر یا سابقه جستجوی شما ظاهر نمیشوند، و پس از بستن پنجره ناشناس، دنباله ای از خود مانند کوکی ها روی دستگاه شما بر جای نمیگذارند. به هر حال، فایل های دانلود شده و نشانکهای صفحه ای که ایجاد کرده اید باقی خواهند ماند.</p>
+
+    <p><strong>وارد شدن به صورت ناشناس، تاثیری بر روی رفتار افراد دیگر، سرورها و یا نرم افزارها ندارد. در خصوص موارد زیر هشیار باشید:</strong></p>
+
+    <ul>
+      <li>وبسایت هایی که اطلاعاتی را در مورد شما جمع آوری کرده و به اشتراک میگذارند</li>
+      <li>تامین کننده های خدمات اینترنتی شما یا کارمندانی که صفحاتی که شما بازدید کرده اید را پیگیری میکنند</li>
+      <li>نرم افزارهای مخربی که در ازای نشانک های رایگان، ضربات کلیدهای شما را ذخیره میکنند</li>
+      <li>نظارت توسط نمایندگان سری</li>
+      <li>افرادی که پشت سرتان ایستاده اند</li>
+    </ul>
+  </body>
+</html>
diff --git a/core/res/res/raw-fa/incognito_mode_start_page.html b/core/res/res/raw-fa/incognito_mode_start_page.html
new file mode 100644
index 0000000..f004120
--- /dev/null
+++ b/core/res/res/raw-fa/incognito_mode_start_page.html
@@ -0,0 +1,19 @@
+<html DIR="RTL">
+  <head>
+    <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no" />
+    <title>پنجره ناشناس جدید</title>
+  </head>
+  <body>
+    <p><strong>شما به صورت ناشناس وارد شده اید</strong> صفحاتی که شما در این پنجره مشاهده میکنید در سابقه مرورگر یا سابقه جستجوی شما ظاهر نمیشوند، و پس از بستن پنجره ناشناس، دنباله ای از خود مانند کوکی ها روی دستگاه شما بر جای نمیگذارند. به هر حال، فایل های دانلود شده و نشانکهای صفحه ای که ایجاد کرده اید باقی خواهند ماند.</p>
+
+    <p><strong>وارد شدن به صورت ناشناس، تاثیری بر روی رفتار افراد دیگر، سرورها و یا نرم افزارها ندارد. در خصوص موارد زیر هشیار باشید:</strong></p>
+
+    <ul>
+      <li>وبسایت هایی که اطلاعاتی را در مورد شما جمع آوری کرده و به اشتراک میگذارند</li>
+      <li>تامین کننده های خدمات اینترنتی شما یا کارمندانی که صفحاتی که شما بازدید کرده اید را پیگیری میکنند</li>
+      <li>نرم افزارهای مخربی که در ازای نشانک های رایگان، ضربات کلیدهای شما را ذخیره میکنند</li>
+      <li>نظارت توسط نمایندگان سری</li>
+      <li>افرادی که پشت سرتان ایستاده اند</li>
+    </ul>
+  </body>
+</html>
diff --git a/core/res/res/raw-fi-xlarge/incognito_mode_start_page.html b/core/res/res/raw-fi-xlarge/incognito_mode_start_page.html
new file mode 100644
index 0000000..feb9f4f
--- /dev/null
+++ b/core/res/res/raw-fi-xlarge/incognito_mode_start_page.html
@@ -0,0 +1,19 @@
+<html DIR="LTR">
+  <head>
+    <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no" />
+    <title>Uusi incognito-ikkuna</title>
+  </head>
+  <body>
+    <p><strong>Olet nyt incognito-tilassa</strong>. Incognito-tilassa katsellut sivut eivät näy selainhistoriassa eikä hakuhistoriassa. Ne eivät myöskään jätä muita jälkiä, kuten evästeitä, sivun sulkemisen jälkeen. Lataamasi tiedostot tai luomasi kirjanmerkit tosin tallentuvat.</p>
+
+    <p><strong>Incognito-tilaan siirtyminen ei vaikuta muiden ihmisten, palvelimien tai tietokoneohjelmien toimintaan. Varo:</strong></p>
+
+    <ul>
+      <li>Verkkosivustoja jotka keräävät sinusta tietoa ja/tai jakavat sitä eteenpäin</li>
+      <li>Internet-palveluntarjoajia ja työnantajia jotka seuraavat sivuja, joilla käyt</li>
+      <li>Haittaohjelmia jotka seuraavat näppäimistön toimintaa ja tarjoavat vastineeksi ilmaisia hymiöitä</li>
+      <li>Salaisten agenttien seurantaa</li>
+      <li>Ihmisiä jotka seisovat takanasi</li>
+    </ul>
+  </body>
+</html>
diff --git a/core/res/res/raw-fi/incognito_mode_start_page.html b/core/res/res/raw-fi/incognito_mode_start_page.html
new file mode 100644
index 0000000..feb9f4f
--- /dev/null
+++ b/core/res/res/raw-fi/incognito_mode_start_page.html
@@ -0,0 +1,19 @@
+<html DIR="LTR">
+  <head>
+    <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no" />
+    <title>Uusi incognito-ikkuna</title>
+  </head>
+  <body>
+    <p><strong>Olet nyt incognito-tilassa</strong>. Incognito-tilassa katsellut sivut eivät näy selainhistoriassa eikä hakuhistoriassa. Ne eivät myöskään jätä muita jälkiä, kuten evästeitä, sivun sulkemisen jälkeen. Lataamasi tiedostot tai luomasi kirjanmerkit tosin tallentuvat.</p>
+
+    <p><strong>Incognito-tilaan siirtyminen ei vaikuta muiden ihmisten, palvelimien tai tietokoneohjelmien toimintaan. Varo:</strong></p>
+
+    <ul>
+      <li>Verkkosivustoja jotka keräävät sinusta tietoa ja/tai jakavat sitä eteenpäin</li>
+      <li>Internet-palveluntarjoajia ja työnantajia jotka seuraavat sivuja, joilla käyt</li>
+      <li>Haittaohjelmia jotka seuraavat näppäimistön toimintaa ja tarjoavat vastineeksi ilmaisia hymiöitä</li>
+      <li>Salaisten agenttien seurantaa</li>
+      <li>Ihmisiä jotka seisovat takanasi</li>
+    </ul>
+  </body>
+</html>
diff --git a/core/res/res/raw-fr-xlarge/incognito_mode_start_page.html b/core/res/res/raw-fr-xlarge/incognito_mode_start_page.html
new file mode 100644
index 0000000..8962cdf
--- /dev/null
+++ b/core/res/res/raw-fr-xlarge/incognito_mode_start_page.html
@@ -0,0 +1,19 @@
+<html DIR="LTR">
+  <head>
+    <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no" />
+    <title>Nouvelle fenêtre de navigation privée</title>
+  </head>
+  <body>
+    <p><strong>Vous êtes passé en navigation privée</strong>. Les pages que vous consultez dans cette fenêtre n'apparaîtront ni dans l'historique de votre navigateur, ni dans l'historique des recherches, et ne laisseront aucune trace (comme les cookies) sur votre appareil une fois que vous aurez fermé la fenêtre de navigation privée. Tous les fichiers téléchargés et les favoris créés seront toutefois conservés.</p>
+
+    <p><strong>Passer en navigation privée n'a aucun effet sur les autres utilisateurs, serveurs ou logiciels. Méfiez-vous :</strong></p>
+
+    <ul>
+      <li>Des sites Web qui collectent ou partagent des informations vous concernant</li>
+      <li>Des fournisseurs d'accès Internet ou des employeurs qui conservent une trace des pages que vous visitez</li>
+      <li>Des programmes indésirables qui enregistrent vos frappes en échange d'émoticônes gratuites</li>
+      <li>Des personnes qui pourraient surveiller vos activités</li>
+      <li>Des personnes qui se tiennent derrière vous</li>
+    </ul>
+  </body>
+</html>
diff --git a/core/res/res/raw-fr/incognito_mode_start_page.html b/core/res/res/raw-fr/incognito_mode_start_page.html
new file mode 100644
index 0000000..8962cdf
--- /dev/null
+++ b/core/res/res/raw-fr/incognito_mode_start_page.html
@@ -0,0 +1,19 @@
+<html DIR="LTR">
+  <head>
+    <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no" />
+    <title>Nouvelle fenêtre de navigation privée</title>
+  </head>
+  <body>
+    <p><strong>Vous êtes passé en navigation privée</strong>. Les pages que vous consultez dans cette fenêtre n'apparaîtront ni dans l'historique de votre navigateur, ni dans l'historique des recherches, et ne laisseront aucune trace (comme les cookies) sur votre appareil une fois que vous aurez fermé la fenêtre de navigation privée. Tous les fichiers téléchargés et les favoris créés seront toutefois conservés.</p>
+
+    <p><strong>Passer en navigation privée n'a aucun effet sur les autres utilisateurs, serveurs ou logiciels. Méfiez-vous :</strong></p>
+
+    <ul>
+      <li>Des sites Web qui collectent ou partagent des informations vous concernant</li>
+      <li>Des fournisseurs d'accès Internet ou des employeurs qui conservent une trace des pages que vous visitez</li>
+      <li>Des programmes indésirables qui enregistrent vos frappes en échange d'émoticônes gratuites</li>
+      <li>Des personnes qui pourraient surveiller vos activités</li>
+      <li>Des personnes qui se tiennent derrière vous</li>
+    </ul>
+  </body>
+</html>
diff --git a/core/res/res/raw-hi-xlarge/incognito_mode_start_page.html b/core/res/res/raw-hi-xlarge/incognito_mode_start_page.html
new file mode 100644
index 0000000..f73c41d
--- /dev/null
+++ b/core/res/res/raw-hi-xlarge/incognito_mode_start_page.html
@@ -0,0 +1,19 @@
+<html DIR="LTR">
+  <head>
+    <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no" />
+    <title>नई गुप्त विंडो</title>
+  </head>
+  <body>
+    <p><strong>आप गुप्त मोड में हैं</strong>. इस विंडो में देखे गए पृष्ठ आपके ब्राउज़र इतिहास  या खोज इतिहास में प्रकट नहीं होंगे, और वे आपके डिवाइस पर गुप्त विंडो बंद करने के बाद और कोई चिह्न जैसे कुकीज़, नहीं छोड़ते. हालांकि डाउनलोड की गई या बुकमार्क की गई कोई भी फ़ाइल संरक्षित रखी जाएगी.</p>
+
+    <p><strong>गुप्त मोड में होने से दूसरे लोगों, सर्वर. या सॉफ़्टवेयर पर कोई प्रभाव नहीं होता. इनका ध्यान रखें</strong></p>
+
+    <ul>
+      <li>वे वेबसाइट जो आपके बारे में जानकारी एकत्र या शेयर करती हैं</li>
+      <li>इंटरनेट सेवा प्रदाता या नियोक्ता जो आपके द्वारा विज़िट किए गए पृष्ठों पर नज़र रखते हैं</li>
+      <li>दुर्भावनापूर्ण सॉफ़्टवेयर जो मुफ़्त स्माइली के बदले आपके कीस्ट्रोक पर नज़र रखते हैं.</li>
+      <li>गुप्तचरों द्वारा निगरानी</li>
+      <li>आपके पीछे खड़े लोग</li>
+    </ul>
+  </body>
+</html>
diff --git a/core/res/res/raw-hi/incognito_mode_start_page.html b/core/res/res/raw-hi/incognito_mode_start_page.html
new file mode 100644
index 0000000..f73c41d
--- /dev/null
+++ b/core/res/res/raw-hi/incognito_mode_start_page.html
@@ -0,0 +1,19 @@
+<html DIR="LTR">
+  <head>
+    <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no" />
+    <title>नई गुप्त विंडो</title>
+  </head>
+  <body>
+    <p><strong>आप गुप्त मोड में हैं</strong>. इस विंडो में देखे गए पृष्ठ आपके ब्राउज़र इतिहास  या खोज इतिहास में प्रकट नहीं होंगे, और वे आपके डिवाइस पर गुप्त विंडो बंद करने के बाद और कोई चिह्न जैसे कुकीज़, नहीं छोड़ते. हालांकि डाउनलोड की गई या बुकमार्क की गई कोई भी फ़ाइल संरक्षित रखी जाएगी.</p>
+
+    <p><strong>गुप्त मोड में होने से दूसरे लोगों, सर्वर. या सॉफ़्टवेयर पर कोई प्रभाव नहीं होता. इनका ध्यान रखें</strong></p>
+
+    <ul>
+      <li>वे वेबसाइट जो आपके बारे में जानकारी एकत्र या शेयर करती हैं</li>
+      <li>इंटरनेट सेवा प्रदाता या नियोक्ता जो आपके द्वारा विज़िट किए गए पृष्ठों पर नज़र रखते हैं</li>
+      <li>दुर्भावनापूर्ण सॉफ़्टवेयर जो मुफ़्त स्माइली के बदले आपके कीस्ट्रोक पर नज़र रखते हैं.</li>
+      <li>गुप्तचरों द्वारा निगरानी</li>
+      <li>आपके पीछे खड़े लोग</li>
+    </ul>
+  </body>
+</html>
diff --git a/core/res/res/raw-hr-xlarge/incognito_mode_start_page.html b/core/res/res/raw-hr-xlarge/incognito_mode_start_page.html
new file mode 100644
index 0000000..6f20fe0
--- /dev/null
+++ b/core/res/res/raw-hr-xlarge/incognito_mode_start_page.html
@@ -0,0 +1,19 @@
+<html DIR="LTR">
+  <head>
+    <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no" />
+    <title>Novi anonimni prozor</title>
+  </head>
+  <body>
+    <p><strong>Sada ste anonimni</strong>. Stranice koje pregledavate u ovom prozoru neće se pojaviti u povijesti preglednika ili povijesti pretraživanja, neće ostaviti tragove, poput kolačića, na vašem uređaju nakon što zatvorite anonimni prozor. Međutim, sve datoteke koje preuzmete ili oznake koje stvorite bit će sačuvane.</p>
+
+    <p><strong>Anonimno pregledavanje neće utjecati na ponašanje drugih osoba, poslužitelja ili softvera. Pazite na sljedeće:</strong></p>
+
+    <ul>
+      <li>Web-lokacije koje prikupljaju ili dijele informacije o vama</li>
+      <li>Davatelje internetskih usluga ili poslodavce koji prate stranice koje posjećujete</li>
+      <li>Zlonamjerni softver koji prati koje tipke pritišćete u zamjenu za besplatne emotikone</li>
+      <li>Nadzor tajnih službi</li>
+      <li>Osobe koje stoje iza vas</li>
+    </ul>
+  </body>
+</html>
diff --git a/core/res/res/raw-hr/incognito_mode_start_page.html b/core/res/res/raw-hr/incognito_mode_start_page.html
new file mode 100644
index 0000000..6f20fe0
--- /dev/null
+++ b/core/res/res/raw-hr/incognito_mode_start_page.html
@@ -0,0 +1,19 @@
+<html DIR="LTR">
+  <head>
+    <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no" />
+    <title>Novi anonimni prozor</title>
+  </head>
+  <body>
+    <p><strong>Sada ste anonimni</strong>. Stranice koje pregledavate u ovom prozoru neće se pojaviti u povijesti preglednika ili povijesti pretraživanja, neće ostaviti tragove, poput kolačića, na vašem uređaju nakon što zatvorite anonimni prozor. Međutim, sve datoteke koje preuzmete ili oznake koje stvorite bit će sačuvane.</p>
+
+    <p><strong>Anonimno pregledavanje neće utjecati na ponašanje drugih osoba, poslužitelja ili softvera. Pazite na sljedeće:</strong></p>
+
+    <ul>
+      <li>Web-lokacije koje prikupljaju ili dijele informacije o vama</li>
+      <li>Davatelje internetskih usluga ili poslodavce koji prate stranice koje posjećujete</li>
+      <li>Zlonamjerni softver koji prati koje tipke pritišćete u zamjenu za besplatne emotikone</li>
+      <li>Nadzor tajnih službi</li>
+      <li>Osobe koje stoje iza vas</li>
+    </ul>
+  </body>
+</html>
diff --git a/core/res/res/raw-hu-xlarge/incognito_mode_start_page.html b/core/res/res/raw-hu-xlarge/incognito_mode_start_page.html
new file mode 100644
index 0000000..38b0806
--- /dev/null
+++ b/core/res/res/raw-hu-xlarge/incognito_mode_start_page.html
@@ -0,0 +1,19 @@
+<html DIR="LTR">
+  <head>
+    <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no" />
+    <title>Új inkognitóablak</title>
+  </head>
+  <body>
+    <p><strong>Ön inkognitó módra váltott</strong>. Az inkognitóablakban megtekintett oldalak nem jelennek meg böngészője előzményeiben, illetve keresési előzményeiben, és nem hagynak más nyomot pl. cookie-t sem a számítógépén az inkognitóablak bezárását követően. A letöltött fájlok, valamint a létrehozott könyvjelzők azonban megmaradnak.</p>
+
+    <p><strong>Az inkognitó üzemmód nem befolyásolja a többi felhasználó, szerver vagy szoftver viselkedését. Ügyeljen a következőkre:</strong></p>
+
+    <ul>
+      <li>Olyan webhelyek, amelyek információt gyűjtenek vagy osztanak meg Önről</li>
+      <li>Olyan internetszolgáltatók vagy alkalmazottaik, akik nyomon követik az Ön által látogatott oldalakat</li>
+      <li>Olyan kártékony szoftverek, amelyek ingyenes hangulatjelekért cserébe nyomon követik billentyűbeviteleit</li>
+      <li>Titkos ügynökök megfigyelése</li>
+      <li>Az Ön mögött álló emberek</li>
+    </ul>
+  </body>
+</html>
diff --git a/core/res/res/raw-hu/incognito_mode_start_page.html b/core/res/res/raw-hu/incognito_mode_start_page.html
new file mode 100644
index 0000000..38b0806
--- /dev/null
+++ b/core/res/res/raw-hu/incognito_mode_start_page.html
@@ -0,0 +1,19 @@
+<html DIR="LTR">
+  <head>
+    <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no" />
+    <title>Új inkognitóablak</title>
+  </head>
+  <body>
+    <p><strong>Ön inkognitó módra váltott</strong>. Az inkognitóablakban megtekintett oldalak nem jelennek meg böngészője előzményeiben, illetve keresési előzményeiben, és nem hagynak más nyomot pl. cookie-t sem a számítógépén az inkognitóablak bezárását követően. A letöltött fájlok, valamint a létrehozott könyvjelzők azonban megmaradnak.</p>
+
+    <p><strong>Az inkognitó üzemmód nem befolyásolja a többi felhasználó, szerver vagy szoftver viselkedését. Ügyeljen a következőkre:</strong></p>
+
+    <ul>
+      <li>Olyan webhelyek, amelyek információt gyűjtenek vagy osztanak meg Önről</li>
+      <li>Olyan internetszolgáltatók vagy alkalmazottaik, akik nyomon követik az Ön által látogatott oldalakat</li>
+      <li>Olyan kártékony szoftverek, amelyek ingyenes hangulatjelekért cserébe nyomon követik billentyűbeviteleit</li>
+      <li>Titkos ügynökök megfigyelése</li>
+      <li>Az Ön mögött álló emberek</li>
+    </ul>
+  </body>
+</html>
diff --git a/core/res/res/raw-id-xlarge/incognito_mode_start_page.html b/core/res/res/raw-id-xlarge/incognito_mode_start_page.html
new file mode 100644
index 0000000..788c088
--- /dev/null
+++ b/core/res/res/raw-id-xlarge/incognito_mode_start_page.html
@@ -0,0 +1,19 @@
+<html DIR="LTR">
+  <head>
+    <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no" />
+    <title>Jendela penyamaran baru</title>
+  </head>
+  <body>
+    <p><strong>Anda menggunakan penyamaran</strong>. Laman yang Anda lihat di jendela ini tidak akan ditampilkan dalam riwayat peramban atau riwayat penelusuran, dan tidak akan meninggalkan jejak, seperti kuki, di perangkat setelah jendela penyamaran ditutup. Namun, berkas yang diunduh atau bookmark yang dibuat akan disimpan.</p>
+
+    <p><strong>Menggunakan penyamaran tidak mempengaruhi perilaku orang lain, server, atau perangkat lunak. Waspadai:</strong></p>
+
+    <ul>
+      <li>Situs web yang mengumpulkan atau berbagi informasi tentang Anda</li>
+      <li>Penyedia layanan internet atau tempat kerja yang melacak laman yang Anda kunjungi</li>
+      <li>Perangkat lunak jahat yang melacak penekanan tombol dengan imbalan smiley gratis</li>
+      <li>Pemantauan oleh agen rahasia</li>
+      <li>Orang yang berdiri di belakang Anda</li>
+    </ul>
+  </body>
+</html>
diff --git a/core/res/res/raw-id/incognito_mode_start_page.html b/core/res/res/raw-id/incognito_mode_start_page.html
new file mode 100644
index 0000000..788c088
--- /dev/null
+++ b/core/res/res/raw-id/incognito_mode_start_page.html
@@ -0,0 +1,19 @@
+<html DIR="LTR">
+  <head>
+    <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no" />
+    <title>Jendela penyamaran baru</title>
+  </head>
+  <body>
+    <p><strong>Anda menggunakan penyamaran</strong>. Laman yang Anda lihat di jendela ini tidak akan ditampilkan dalam riwayat peramban atau riwayat penelusuran, dan tidak akan meninggalkan jejak, seperti kuki, di perangkat setelah jendela penyamaran ditutup. Namun, berkas yang diunduh atau bookmark yang dibuat akan disimpan.</p>
+
+    <p><strong>Menggunakan penyamaran tidak mempengaruhi perilaku orang lain, server, atau perangkat lunak. Waspadai:</strong></p>
+
+    <ul>
+      <li>Situs web yang mengumpulkan atau berbagi informasi tentang Anda</li>
+      <li>Penyedia layanan internet atau tempat kerja yang melacak laman yang Anda kunjungi</li>
+      <li>Perangkat lunak jahat yang melacak penekanan tombol dengan imbalan smiley gratis</li>
+      <li>Pemantauan oleh agen rahasia</li>
+      <li>Orang yang berdiri di belakang Anda</li>
+    </ul>
+  </body>
+</html>
diff --git a/core/res/res/raw-it-xlarge/incognito_mode_start_page.html b/core/res/res/raw-it-xlarge/incognito_mode_start_page.html
new file mode 100644
index 0000000..4a34874
--- /dev/null
+++ b/core/res/res/raw-it-xlarge/incognito_mode_start_page.html
@@ -0,0 +1,19 @@
+<html DIR="LTR">
+  <head>
+    <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no" />
+    <title>Nuova finestra di navigazione in incognito</title>
+  </head>
+  <body>
+    <p><strong>Sei passato alla navigazione in incognito</strong>. Le pagine aperte in questa finestra non vengono registrate nella cronologia di navigazione o di ricerca, e non lasciano traccia sul tuo computer, ad esempio sotto forma di cookie, una volta chiusa la finestra. Tuttavia, qualsiasi file scaricato o preferito creato verrà conservato.</p>
+
+    <p><strong>La navigazione in incognito non influisce sul comportamento di altri utenti, server o software. Diffida di:</strong></p>
+
+    <ul>
+      <li>Siti web che raccolgono o condividono informazioni su di te</li>
+      <li>Provider di servizi Internet o datori di lavoro che registrano le pagine da te visitate</li>
+      <li>Software dannosi che registrano le sequenze di tasti da te utilizzate in cambio di smiley gratuiti</li>
+      <li>Agenti segreti</li>
+      <li>Persone che ti stanno alle spalle</li>
+    </ul>
+  </body>
+</html>
diff --git a/core/res/res/raw-it/incognito_mode_start_page.html b/core/res/res/raw-it/incognito_mode_start_page.html
new file mode 100644
index 0000000..4a34874
--- /dev/null
+++ b/core/res/res/raw-it/incognito_mode_start_page.html
@@ -0,0 +1,19 @@
+<html DIR="LTR">
+  <head>
+    <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no" />
+    <title>Nuova finestra di navigazione in incognito</title>
+  </head>
+  <body>
+    <p><strong>Sei passato alla navigazione in incognito</strong>. Le pagine aperte in questa finestra non vengono registrate nella cronologia di navigazione o di ricerca, e non lasciano traccia sul tuo computer, ad esempio sotto forma di cookie, una volta chiusa la finestra. Tuttavia, qualsiasi file scaricato o preferito creato verrà conservato.</p>
+
+    <p><strong>La navigazione in incognito non influisce sul comportamento di altri utenti, server o software. Diffida di:</strong></p>
+
+    <ul>
+      <li>Siti web che raccolgono o condividono informazioni su di te</li>
+      <li>Provider di servizi Internet o datori di lavoro che registrano le pagine da te visitate</li>
+      <li>Software dannosi che registrano le sequenze di tasti da te utilizzate in cambio di smiley gratuiti</li>
+      <li>Agenti segreti</li>
+      <li>Persone che ti stanno alle spalle</li>
+    </ul>
+  </body>
+</html>
diff --git a/core/res/res/raw-iw-xlarge/incognito_mode_start_page.html b/core/res/res/raw-iw-xlarge/incognito_mode_start_page.html
new file mode 100644
index 0000000..368dea0
--- /dev/null
+++ b/core/res/res/raw-iw-xlarge/incognito_mode_start_page.html
@@ -0,0 +1,19 @@
+<html DIR="RTL">
+  <head>
+    <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no" />
+    <title>חלון חדש של גלישה בסתר</title>
+  </head>
+  <body>
+    <p><strong>עברת למצב של גלישה בסתר</strong>. דפים שאתה רואה בחלון זה לא יופיעו בהיסטוריית הדפדפן או בהיסטוריית החיפושים שלך, והם לא ישאירו עקבות אחרים, כמו קובצי cookie, לאחר שתסגור את חלון הגלישה בסתר. עם זאת, כל קובץ שאתה מוריד או כוכביות שאתה יוצר יישמרו.</p>
+
+    <p><strong> גלישה בסתר לא משפיעה על התנהגותם של אנשים אחרים, שרתים  אחרים או תוכנות אחרות. היזהר מ:</strong></p>
+
+    <ul>
+      <li>אתרים שאוספים נתונים או משתפים מידע לגביך</li>
+      <li>ספקי שירות אינטרנט או עובדים שעוקבים אחר הדפים שבהם אתה מבקר</li>
+      <li>תוכנה זדונית שעוקבת אחר ההקשות שלך על המקשים בתמורה לסימני סמיילי בחינם</li>
+      <li>מעקב של סוכנים חשאיים</li>
+      <li>אנשים שעומדים מאחוריך</li>
+    </ul>
+  </body>
+</html>
diff --git a/core/res/res/raw-iw/incognito_mode_start_page.html b/core/res/res/raw-iw/incognito_mode_start_page.html
new file mode 100644
index 0000000..368dea0
--- /dev/null
+++ b/core/res/res/raw-iw/incognito_mode_start_page.html
@@ -0,0 +1,19 @@
+<html DIR="RTL">
+  <head>
+    <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no" />
+    <title>חלון חדש של גלישה בסתר</title>
+  </head>
+  <body>
+    <p><strong>עברת למצב של גלישה בסתר</strong>. דפים שאתה רואה בחלון זה לא יופיעו בהיסטוריית הדפדפן או בהיסטוריית החיפושים שלך, והם לא ישאירו עקבות אחרים, כמו קובצי cookie, לאחר שתסגור את חלון הגלישה בסתר. עם זאת, כל קובץ שאתה מוריד או כוכביות שאתה יוצר יישמרו.</p>
+
+    <p><strong> גלישה בסתר לא משפיעה על התנהגותם של אנשים אחרים, שרתים  אחרים או תוכנות אחרות. היזהר מ:</strong></p>
+
+    <ul>
+      <li>אתרים שאוספים נתונים או משתפים מידע לגביך</li>
+      <li>ספקי שירות אינטרנט או עובדים שעוקבים אחר הדפים שבהם אתה מבקר</li>
+      <li>תוכנה זדונית שעוקבת אחר ההקשות שלך על המקשים בתמורה לסימני סמיילי בחינם</li>
+      <li>מעקב של סוכנים חשאיים</li>
+      <li>אנשים שעומדים מאחוריך</li>
+    </ul>
+  </body>
+</html>
diff --git a/core/res/res/raw-ja-xlarge/incognito_mode_start_page.html b/core/res/res/raw-ja-xlarge/incognito_mode_start_page.html
new file mode 100644
index 0000000..a58ad05
--- /dev/null
+++ b/core/res/res/raw-ja-xlarge/incognito_mode_start_page.html
@@ -0,0 +1,19 @@
+<html DIR="LTR">
+  <head>
+    <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no" />
+    <title>新しいシークレットウィンドウ</title>
+  </head>
+  <body>
+    <p><strong>シークレットモードを使用中です</strong>。このウィンドウで開いたページはブラウザの履歴や検索履歴に残りません。このウィンドウを閉じるとCookieなどの記録も端末から消去されます。ただし、ダウンロードしたファイルやブックマークしたページは保存されます。</p>
+
+    <p><strong>シークレットモードが他のユーザーやサーバー、ソフトウェアの動作に影響することはありません。なお、下記のようなケースにご注意ください。</strong></p>
+
+    <ul>
+      <li>ユーザーの情報を収集、共有するウェブサイト</li>
+      <li>アクセスしたページをトラッキングするインターネットサービスプロバイダや雇用主</li>
+      <li>無料ダウンロードなどと一緒にインストールされ、キーストロークを記録するマルウェア</li>
+      <li>スパイ、諜報活動</li>
+      <li>背後にいる人</li>
+    </ul>
+  </body>
+</html>
diff --git a/core/res/res/raw-ja/incognito_mode_start_page.html b/core/res/res/raw-ja/incognito_mode_start_page.html
new file mode 100644
index 0000000..a58ad05
--- /dev/null
+++ b/core/res/res/raw-ja/incognito_mode_start_page.html
@@ -0,0 +1,19 @@
+<html DIR="LTR">
+  <head>
+    <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no" />
+    <title>新しいシークレットウィンドウ</title>
+  </head>
+  <body>
+    <p><strong>シークレットモードを使用中です</strong>。このウィンドウで開いたページはブラウザの履歴や検索履歴に残りません。このウィンドウを閉じるとCookieなどの記録も端末から消去されます。ただし、ダウンロードしたファイルやブックマークしたページは保存されます。</p>
+
+    <p><strong>シークレットモードが他のユーザーやサーバー、ソフトウェアの動作に影響することはありません。なお、下記のようなケースにご注意ください。</strong></p>
+
+    <ul>
+      <li>ユーザーの情報を収集、共有するウェブサイト</li>
+      <li>アクセスしたページをトラッキングするインターネットサービスプロバイダや雇用主</li>
+      <li>無料ダウンロードなどと一緒にインストールされ、キーストロークを記録するマルウェア</li>
+      <li>スパイ、諜報活動</li>
+      <li>背後にいる人</li>
+    </ul>
+  </body>
+</html>
diff --git a/core/res/res/raw-ko-xlarge/incognito_mode_start_page.html b/core/res/res/raw-ko-xlarge/incognito_mode_start_page.html
new file mode 100644
index 0000000..0e703b1
--- /dev/null
+++ b/core/res/res/raw-ko-xlarge/incognito_mode_start_page.html
@@ -0,0 +1,19 @@
+<html DIR="LTR">
+  <head>
+    <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no" />
+    <title>새 시크릿 창</title>
+  </head>
+  <body>
+    <p><strong>시크릿 모드로 들어오셨습니다.</strong> 이 창에서 보는 페이지는 브라우저 기록이나 검색기록에 남지 않으며, 시크릿 창을 닫은 뒤 기기에 쿠기와 같은 흔적도 남기지 않습니다. 다운로드한 파일이나 생성한 북마크는 보관됩니다. </p>
+
+    <p><strong>시크릿 모드를 이용해도 다른 사용자, 서버, 소프트웨어에 영향을 주지는 않습니다. 다음을 주의하세요.</strong></p>
+
+    <ul>
+      <li>사용자에 대한 정보를 모으고 공유하는 웹사이트</li>
+      <li>방문 페이지를 추적하는 인터넷 서비스 제공업체나 직원 </li>
+      <li>스마일 이모티콘을 제공한다는 명목으로 입력 내용을 추적하는 악성 소프트웨어</li>
+      <li>비밀 개체를 통한 감시</li>
+      <li>뒤에서 사용자의 작업내용을 지켜보는 사람</li>
+    </ul>
+  </body>
+</html>
diff --git a/core/res/res/raw-ko/incognito_mode_start_page.html b/core/res/res/raw-ko/incognito_mode_start_page.html
new file mode 100644
index 0000000..0e703b1
--- /dev/null
+++ b/core/res/res/raw-ko/incognito_mode_start_page.html
@@ -0,0 +1,19 @@
+<html DIR="LTR">
+  <head>
+    <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no" />
+    <title>새 시크릿 창</title>
+  </head>
+  <body>
+    <p><strong>시크릿 모드로 들어오셨습니다.</strong> 이 창에서 보는 페이지는 브라우저 기록이나 검색기록에 남지 않으며, 시크릿 창을 닫은 뒤 기기에 쿠기와 같은 흔적도 남기지 않습니다. 다운로드한 파일이나 생성한 북마크는 보관됩니다. </p>
+
+    <p><strong>시크릿 모드를 이용해도 다른 사용자, 서버, 소프트웨어에 영향을 주지는 않습니다. 다음을 주의하세요.</strong></p>
+
+    <ul>
+      <li>사용자에 대한 정보를 모으고 공유하는 웹사이트</li>
+      <li>방문 페이지를 추적하는 인터넷 서비스 제공업체나 직원 </li>
+      <li>스마일 이모티콘을 제공한다는 명목으로 입력 내용을 추적하는 악성 소프트웨어</li>
+      <li>비밀 개체를 통한 감시</li>
+      <li>뒤에서 사용자의 작업내용을 지켜보는 사람</li>
+    </ul>
+  </body>
+</html>
diff --git a/core/res/res/raw-lt-xlarge/incognito_mode_start_page.html b/core/res/res/raw-lt-xlarge/incognito_mode_start_page.html
new file mode 100644
index 0000000..9244ae4
--- /dev/null
+++ b/core/res/res/raw-lt-xlarge/incognito_mode_start_page.html
@@ -0,0 +1,19 @@
+<html DIR="LTR">
+  <head>
+    <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no" />
+    <title>Naujas inkognito langas</title>
+  </head>
+  <body>
+    <p><strong>Naršote inkognito režimu</strong>. Šiame lange peržiūrimi puslapiai nebus išsaugomi naršyklės istorijoje ar paieškos istorijoje ir uždarius inkognito langą nepaliks jokių kitų žymių, pvz., slapukų. Tačiau bus išsaugoti atsisiųsti failai ar sukurtos žymos.</p>
+
+    <p><strong>Naršymas inkognito režimu nedaro jokios įtakos kitiems asmenims, serveriams ar programinei įrangai. Saugokitės:</strong></p>
+
+    <ul>
+      <li>svetainių, kurios renka ar platina informaciją apie jus</li>
+      <li>interneto paslaugos teikėjų ar darbdavių, kurie stebi, kuriuos puslapius peržiūrite</li>
+      <li>kenkėjiškos programinės įrangos, kuri siūlydama nemokamų šypsniukų fiksuoja klavišų paspaudimus</li>
+      <li>jus galinčių sekti slaptųjų agentų</li>
+      <li>už nugaros stovinčių asmenų</li>
+    </ul>
+  </body>
+</html>
diff --git a/core/res/res/raw-lt/incognito_mode_start_page.html b/core/res/res/raw-lt/incognito_mode_start_page.html
new file mode 100644
index 0000000..9244ae4
--- /dev/null
+++ b/core/res/res/raw-lt/incognito_mode_start_page.html
@@ -0,0 +1,19 @@
+<html DIR="LTR">
+  <head>
+    <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no" />
+    <title>Naujas inkognito langas</title>
+  </head>
+  <body>
+    <p><strong>Naršote inkognito režimu</strong>. Šiame lange peržiūrimi puslapiai nebus išsaugomi naršyklės istorijoje ar paieškos istorijoje ir uždarius inkognito langą nepaliks jokių kitų žymių, pvz., slapukų. Tačiau bus išsaugoti atsisiųsti failai ar sukurtos žymos.</p>
+
+    <p><strong>Naršymas inkognito režimu nedaro jokios įtakos kitiems asmenims, serveriams ar programinei įrangai. Saugokitės:</strong></p>
+
+    <ul>
+      <li>svetainių, kurios renka ar platina informaciją apie jus</li>
+      <li>interneto paslaugos teikėjų ar darbdavių, kurie stebi, kuriuos puslapius peržiūrite</li>
+      <li>kenkėjiškos programinės įrangos, kuri siūlydama nemokamų šypsniukų fiksuoja klavišų paspaudimus</li>
+      <li>jus galinčių sekti slaptųjų agentų</li>
+      <li>už nugaros stovinčių asmenų</li>
+    </ul>
+  </body>
+</html>
diff --git a/core/res/res/raw-lv-xlarge/incognito_mode_start_page.html b/core/res/res/raw-lv-xlarge/incognito_mode_start_page.html
new file mode 100644
index 0000000..f325ef5
--- /dev/null
+++ b/core/res/res/raw-lv-xlarge/incognito_mode_start_page.html
@@ -0,0 +1,19 @@
+<html DIR="LTR">
+  <head>
+    <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no" />
+    <title>Jauns inkognito logs</title>
+  </head>
+  <body>
+    <p><strong>Jūs esat ieslēdzis inkognito režīmu</strong>. Šajā logā aplūkotās lapas neparādīsies jūsu pārlūkprogrammas vēsturē vai meklēšanas vēsturē, tās arī neatstās citas pēdas, piemēram, sīkfailus, jūsu ierīcē pēc inkognito režīma loga aizvēršanas. Tomēr visi jūsu lejupielādētie faili vai izveidotās grāmatzīmes tiks saglabātas.</p>
+
+    <p><strong>Inkognito režīma ieslēgšana neietekmēs citu personu, serveru vai programmatūras darbību. Uzmanieties no</strong></p>
+
+    <ul>
+      <li>vietnēm, kas apkopo vai koplieto informāciju par jums;</li>
+      <li>interneta pakalpojumu sniedzējiem vai darba devējiem, kas izseko jūsu apmeklētajām lapām;</li>
+      <li>maldprogrammatūras, kas izseko jūsu taustiņsitieniem apmaiņā par bezmaksas smaidiņiem;</li>
+      <li>slepeno aģentu veiktas izmeklēšanas;</li>
+      <li>personām, kas stāv aiz jums.</li>
+    </ul>
+  </body>
+</html>
diff --git a/core/res/res/raw-lv/incognito_mode_start_page.html b/core/res/res/raw-lv/incognito_mode_start_page.html
new file mode 100644
index 0000000..f325ef5
--- /dev/null
+++ b/core/res/res/raw-lv/incognito_mode_start_page.html
@@ -0,0 +1,19 @@
+<html DIR="LTR">
+  <head>
+    <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no" />
+    <title>Jauns inkognito logs</title>
+  </head>
+  <body>
+    <p><strong>Jūs esat ieslēdzis inkognito režīmu</strong>. Šajā logā aplūkotās lapas neparādīsies jūsu pārlūkprogrammas vēsturē vai meklēšanas vēsturē, tās arī neatstās citas pēdas, piemēram, sīkfailus, jūsu ierīcē pēc inkognito režīma loga aizvēršanas. Tomēr visi jūsu lejupielādētie faili vai izveidotās grāmatzīmes tiks saglabātas.</p>
+
+    <p><strong>Inkognito režīma ieslēgšana neietekmēs citu personu, serveru vai programmatūras darbību. Uzmanieties no</strong></p>
+
+    <ul>
+      <li>vietnēm, kas apkopo vai koplieto informāciju par jums;</li>
+      <li>interneta pakalpojumu sniedzējiem vai darba devējiem, kas izseko jūsu apmeklētajām lapām;</li>
+      <li>maldprogrammatūras, kas izseko jūsu taustiņsitieniem apmaiņā par bezmaksas smaidiņiem;</li>
+      <li>slepeno aģentu veiktas izmeklēšanas;</li>
+      <li>personām, kas stāv aiz jums.</li>
+    </ul>
+  </body>
+</html>
diff --git a/core/res/res/raw-nb-xlarge/incognito_mode_start_page.html b/core/res/res/raw-nb-xlarge/incognito_mode_start_page.html
new file mode 100644
index 0000000..724e734
--- /dev/null
+++ b/core/res/res/raw-nb-xlarge/incognito_mode_start_page.html
@@ -0,0 +1,19 @@
+<html DIR="LTR">
+  <head>
+    <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no" />
+    <title>Nytt inkognitovindu</title>
+  </head>
+  <body>
+    <p><strong></strong>Du er nå inkognito Sider du besøker i dette vinduet blir ikke lagret i nettleser- eller søkelogg, og etterlater ikke andre spor, f. eks. informasjonskapsler, på enheten din etter at du har lukket vinduet. Filer du laster ned eller bokmerker du lager blir derimot lagret.</p>
+
+    <p><strong>Det at du er inkognito endrer ikke hvordan andre mennesker, tjenere eller programmer oppfører seg. Pass deg for:</strong></p>
+
+    <ul>
+      <li>Nettsider som samler eller deler informasjon om deg</li>
+      <li>Nettleverandører eller arbeidsgivere som overvåker hvilke sider du besøker</li>
+      <li>Skadelige programmer som følger med på tastetrykk i bytte mot smilefjes</li>
+      <li>Hemmelige agenter som spionerer på deg</li>
+      <li>Folk som titter over skulderen din</li>
+    </ul>
+  </body>
+</html>
diff --git a/core/res/res/raw-nb/incognito_mode_start_page.html b/core/res/res/raw-nb/incognito_mode_start_page.html
new file mode 100644
index 0000000..724e734
--- /dev/null
+++ b/core/res/res/raw-nb/incognito_mode_start_page.html
@@ -0,0 +1,19 @@
+<html DIR="LTR">
+  <head>
+    <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no" />
+    <title>Nytt inkognitovindu</title>
+  </head>
+  <body>
+    <p><strong></strong>Du er nå inkognito Sider du besøker i dette vinduet blir ikke lagret i nettleser- eller søkelogg, og etterlater ikke andre spor, f. eks. informasjonskapsler, på enheten din etter at du har lukket vinduet. Filer du laster ned eller bokmerker du lager blir derimot lagret.</p>
+
+    <p><strong>Det at du er inkognito endrer ikke hvordan andre mennesker, tjenere eller programmer oppfører seg. Pass deg for:</strong></p>
+
+    <ul>
+      <li>Nettsider som samler eller deler informasjon om deg</li>
+      <li>Nettleverandører eller arbeidsgivere som overvåker hvilke sider du besøker</li>
+      <li>Skadelige programmer som følger med på tastetrykk i bytte mot smilefjes</li>
+      <li>Hemmelige agenter som spionerer på deg</li>
+      <li>Folk som titter over skulderen din</li>
+    </ul>
+  </body>
+</html>
diff --git a/core/res/res/raw-nl-xlarge/incognito_mode_start_page.html b/core/res/res/raw-nl-xlarge/incognito_mode_start_page.html
new file mode 100644
index 0000000..92fedd7
--- /dev/null
+++ b/core/res/res/raw-nl-xlarge/incognito_mode_start_page.html
@@ -0,0 +1,19 @@
+<html DIR="LTR">
+  <head>
+    <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no" />
+    <title>Nieuw incognitovenster</title>
+  </head>
+  <body>
+    <p><strong>U bent nu incognito</strong> De pagina's die u in dit venster bekijkt worden niet opgenomen in de browsergeschiedenis en de zoekgeschiedenis en laten geen cookies of andere sporen na op uw apparaat nadat u het incognitovenster hebt gesloten. Alle bestanden die u downloadt en bladwijzers die u maakt, blijven echter behouden.</p>
+
+    <p><strong>Incognito zijn heeft geen invloed op het gedrag van andere personen, servers of software. Wees op uw hoede voor:</strong></p>
+
+    <ul>
+      <li>Websites die informatie over u verzamelen of delen</li>
+      <li>Internetproviders of werkgevers die bijhouden welke pagina's u bezoekt</li>
+      <li>Schadelijke software die uw toetsaanslagen registreert in ruil voor gratis emoticons</li>
+      <li>Spionage door geheim agenten</li>
+      <li>Mensen die achter u staan</li>
+    </ul>
+  </body>
+</html>
diff --git a/core/res/res/raw-nl/incognito_mode_start_page.html b/core/res/res/raw-nl/incognito_mode_start_page.html
new file mode 100644
index 0000000..92fedd7
--- /dev/null
+++ b/core/res/res/raw-nl/incognito_mode_start_page.html
@@ -0,0 +1,19 @@
+<html DIR="LTR">
+  <head>
+    <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no" />
+    <title>Nieuw incognitovenster</title>
+  </head>
+  <body>
+    <p><strong>U bent nu incognito</strong> De pagina's die u in dit venster bekijkt worden niet opgenomen in de browsergeschiedenis en de zoekgeschiedenis en laten geen cookies of andere sporen na op uw apparaat nadat u het incognitovenster hebt gesloten. Alle bestanden die u downloadt en bladwijzers die u maakt, blijven echter behouden.</p>
+
+    <p><strong>Incognito zijn heeft geen invloed op het gedrag van andere personen, servers of software. Wees op uw hoede voor:</strong></p>
+
+    <ul>
+      <li>Websites die informatie over u verzamelen of delen</li>
+      <li>Internetproviders of werkgevers die bijhouden welke pagina's u bezoekt</li>
+      <li>Schadelijke software die uw toetsaanslagen registreert in ruil voor gratis emoticons</li>
+      <li>Spionage door geheim agenten</li>
+      <li>Mensen die achter u staan</li>
+    </ul>
+  </body>
+</html>
diff --git a/core/res/res/raw-pl-xlarge/incognito_mode_start_page.html b/core/res/res/raw-pl-xlarge/incognito_mode_start_page.html
new file mode 100644
index 0000000..9748ead
--- /dev/null
+++ b/core/res/res/raw-pl-xlarge/incognito_mode_start_page.html
@@ -0,0 +1,19 @@
+<html DIR="LTR">
+  <head>
+    <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no" />
+    <title>Nowe okno incognito</title>
+  </head>
+  <body>
+    <p><strong>Jesteś teraz incognito</strong> Strony przeglądane w tym oknie nie będą wyświetlane w historii przeglądarki ani w historii wyszukiwania. Po zamknięciu okna incognito na komputerze nie zostanie po nich żaden ślad np. w postaci plików cookie. Zachowane zostaną jednak pobrane pliki lub utworzone zakładki.</p>
+
+    <p><strong>Przejście do trybu incognito nie ma wpływu na działania innych osób, serwery ani oprogramowanie. Należy uważać na:</strong></p>
+
+    <ul>
+      <li>witryny zbierające lub udostępniające dane na temat użytkowników</li>
+      <li>dostawców usług internetowych oraz pracowników monitorujących strony odwiedzane przez użytkowników</li>
+      <li>złośliwe oprogramowanie śledzące naciśnięcia klawiszy (np. w zamian za darmowe emotikony)</li>
+      <li>aktywność wywiadowczą tajnych agentów</li>
+      <li>osoby stojące za plecami</li>
+    </ul>
+  </body>
+</html>
diff --git a/core/res/res/raw-pl/incognito_mode_start_page.html b/core/res/res/raw-pl/incognito_mode_start_page.html
new file mode 100644
index 0000000..9748ead
--- /dev/null
+++ b/core/res/res/raw-pl/incognito_mode_start_page.html
@@ -0,0 +1,19 @@
+<html DIR="LTR">
+  <head>
+    <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no" />
+    <title>Nowe okno incognito</title>
+  </head>
+  <body>
+    <p><strong>Jesteś teraz incognito</strong> Strony przeglądane w tym oknie nie będą wyświetlane w historii przeglądarki ani w historii wyszukiwania. Po zamknięciu okna incognito na komputerze nie zostanie po nich żaden ślad np. w postaci plików cookie. Zachowane zostaną jednak pobrane pliki lub utworzone zakładki.</p>
+
+    <p><strong>Przejście do trybu incognito nie ma wpływu na działania innych osób, serwery ani oprogramowanie. Należy uważać na:</strong></p>
+
+    <ul>
+      <li>witryny zbierające lub udostępniające dane na temat użytkowników</li>
+      <li>dostawców usług internetowych oraz pracowników monitorujących strony odwiedzane przez użytkowników</li>
+      <li>złośliwe oprogramowanie śledzące naciśnięcia klawiszy (np. w zamian za darmowe emotikony)</li>
+      <li>aktywność wywiadowczą tajnych agentów</li>
+      <li>osoby stojące za plecami</li>
+    </ul>
+  </body>
+</html>
diff --git a/core/res/res/raw-pt-rPT-xlarge/incognito_mode_start_page.html b/core/res/res/raw-pt-rPT-xlarge/incognito_mode_start_page.html
new file mode 100644
index 0000000..89a5ab0
--- /dev/null
+++ b/core/res/res/raw-pt-rPT-xlarge/incognito_mode_start_page.html
@@ -0,0 +1,19 @@
+<html DIR="LTR">
+  <head>
+    <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no" />
+    <title>Nova janela de navegação anónima</title>
+  </head>
+  <body>
+    <p><strong>Está no modo de navegação anónima</strong>. As páginas que visualizar nesta janela não vão aparecer nos históricos de pesquisa ou de navegação e não deixarão quaisquer vestígios (por exemplo cookies) no computador depois de fechar a janela. No entanto se transferir ficheiros ou criar marcadores, estes serão preservados.</p>
+
+    <p><strong>Navegar no modo de navegação anónima não afecta o comportamento de outras pessoas, nem o comportamento de servidores ou programas. Tenha cuidado com:</strong></p>
+
+    <ul>
+      <li>Web sites que recolhem ou partilham informações sobre si</li>
+      <li>Serviços de fornecimento de internet ou empregadores que monitorizam as páginas que você visita</li>
+      <li>Programas maliciosos que monitorizam as teclas em que carrega em troca de ícones expressivos ("smileys")</li>
+      <li>Vigilância de agentes secretos</li>
+      <li>Pessoas que estejam perto de si</li>
+    </ul>
+  </body>
+</html>
diff --git a/core/res/res/raw-pt-rPT/incognito_mode_start_page.html b/core/res/res/raw-pt-rPT/incognito_mode_start_page.html
new file mode 100644
index 0000000..89a5ab0
--- /dev/null
+++ b/core/res/res/raw-pt-rPT/incognito_mode_start_page.html
@@ -0,0 +1,19 @@
+<html DIR="LTR">
+  <head>
+    <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no" />
+    <title>Nova janela de navegação anónima</title>
+  </head>
+  <body>
+    <p><strong>Está no modo de navegação anónima</strong>. As páginas que visualizar nesta janela não vão aparecer nos históricos de pesquisa ou de navegação e não deixarão quaisquer vestígios (por exemplo cookies) no computador depois de fechar a janela. No entanto se transferir ficheiros ou criar marcadores, estes serão preservados.</p>
+
+    <p><strong>Navegar no modo de navegação anónima não afecta o comportamento de outras pessoas, nem o comportamento de servidores ou programas. Tenha cuidado com:</strong></p>
+
+    <ul>
+      <li>Web sites que recolhem ou partilham informações sobre si</li>
+      <li>Serviços de fornecimento de internet ou empregadores que monitorizam as páginas que você visita</li>
+      <li>Programas maliciosos que monitorizam as teclas em que carrega em troca de ícones expressivos ("smileys")</li>
+      <li>Vigilância de agentes secretos</li>
+      <li>Pessoas que estejam perto de si</li>
+    </ul>
+  </body>
+</html>
diff --git a/core/res/res/raw-pt-xlarge/incognito_mode_start_page.html b/core/res/res/raw-pt-xlarge/incognito_mode_start_page.html
new file mode 100644
index 0000000..b301eda
--- /dev/null
+++ b/core/res/res/raw-pt-xlarge/incognito_mode_start_page.html
@@ -0,0 +1,19 @@
+<html DIR="LTR">
+  <head>
+    <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no" />
+    <title>Nova janela anônima</title>
+  </head>
+  <body>
+    <p><strong>Você ficou anônimo</strong>. As páginas que você vê nesta janela não aparecerão no histórico do seu navegador ou da sua pesquisa e não deixarão rastros, como cookies, no seu dispositivo depois que você fechar a janela anônima. Quaisquer arquivos que você fizer o download ou favoritos que criar serão preservados.</p>
+
+    <p><strong>Tornar-se anônimo não afeta o comportamento de outras pessoas, servidores ou software. Esteja atento a:</strong></p>
+
+    <ul>
+      <li>Websites que coletam ou compartilham informações sobre você</li>
+      <li>Provedores de serviços de internet ou funcionários que rastreiam as páginas que você visita</li>
+      <li>Softwares maliciosos que rastreiam os seus toques de teclado em troca de ícones gratuitos</li>
+      <li>Vigilância por agentes secretos</li>
+      <li>Pessoas paradas detrás de você</li>
+    </ul>
+  </body>
+</html>
diff --git a/core/res/res/raw-pt/incognito_mode_start_page.html b/core/res/res/raw-pt/incognito_mode_start_page.html
new file mode 100644
index 0000000..b301eda
--- /dev/null
+++ b/core/res/res/raw-pt/incognito_mode_start_page.html
@@ -0,0 +1,19 @@
+<html DIR="LTR">
+  <head>
+    <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no" />
+    <title>Nova janela anônima</title>
+  </head>
+  <body>
+    <p><strong>Você ficou anônimo</strong>. As páginas que você vê nesta janela não aparecerão no histórico do seu navegador ou da sua pesquisa e não deixarão rastros, como cookies, no seu dispositivo depois que você fechar a janela anônima. Quaisquer arquivos que você fizer o download ou favoritos que criar serão preservados.</p>
+
+    <p><strong>Tornar-se anônimo não afeta o comportamento de outras pessoas, servidores ou software. Esteja atento a:</strong></p>
+
+    <ul>
+      <li>Websites que coletam ou compartilham informações sobre você</li>
+      <li>Provedores de serviços de internet ou funcionários que rastreiam as páginas que você visita</li>
+      <li>Softwares maliciosos que rastreiam os seus toques de teclado em troca de ícones gratuitos</li>
+      <li>Vigilância por agentes secretos</li>
+      <li>Pessoas paradas detrás de você</li>
+    </ul>
+  </body>
+</html>
diff --git a/core/res/res/raw-ro-xlarge/incognito_mode_start_page.html b/core/res/res/raw-ro-xlarge/incognito_mode_start_page.html
new file mode 100644
index 0000000..3e499d3
--- /dev/null
+++ b/core/res/res/raw-ro-xlarge/incognito_mode_start_page.html
@@ -0,0 +1,19 @@
+<html DIR="LTR">
+  <head>
+    <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no" />
+    <title>Fereastră incognito nouă</title>
+  </head>
+  <body>
+    <p><strong>Navigaţi incognito</strong>. Paginile pe care le afişaţi în această fereastră nu vor apărea în istoricul browserului sau al căutărilor şi nu vor lăsa alte urme, precum cookie-uri, pe dispozitivul dvs. după ce închideţi fereastra incognito. Dar fişierele descărcate şi marcajele create vor fi păstrate.</p>
+
+    <p><strong>Navigarea incognito nu influenţează comportamentul altor persoane, servere sau aplicaţii software. Fiţi atent(ă) la:</strong></p>
+
+    <ul>
+      <li>site-urile web care colectează sau distribuie informaţii despre dvs.;</li>
+      <li>furnizorii de servicii de internet sau angajatorii care urmăresc paginile pe care le accesaţi;</li>
+      <li>aplicaţiile software rău intenţionate care vă urmăresc apăsările pe taste promiţându-vă că vă oferă emoticonuri gratuite;</li>
+      <li>acţiunile de monitorizare efectuate de agenţi secreţi;</li>
+      <li>persoanele din spatele dvs.</li>
+    </ul>
+  </body>
+</html>
diff --git a/core/res/res/raw-ro/incognito_mode_start_page.html b/core/res/res/raw-ro/incognito_mode_start_page.html
new file mode 100644
index 0000000..3e499d3
--- /dev/null
+++ b/core/res/res/raw-ro/incognito_mode_start_page.html
@@ -0,0 +1,19 @@
+<html DIR="LTR">
+  <head>
+    <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no" />
+    <title>Fereastră incognito nouă</title>
+  </head>
+  <body>
+    <p><strong>Navigaţi incognito</strong>. Paginile pe care le afişaţi în această fereastră nu vor apărea în istoricul browserului sau al căutărilor şi nu vor lăsa alte urme, precum cookie-uri, pe dispozitivul dvs. după ce închideţi fereastra incognito. Dar fişierele descărcate şi marcajele create vor fi păstrate.</p>
+
+    <p><strong>Navigarea incognito nu influenţează comportamentul altor persoane, servere sau aplicaţii software. Fiţi atent(ă) la:</strong></p>
+
+    <ul>
+      <li>site-urile web care colectează sau distribuie informaţii despre dvs.;</li>
+      <li>furnizorii de servicii de internet sau angajatorii care urmăresc paginile pe care le accesaţi;</li>
+      <li>aplicaţiile software rău intenţionate care vă urmăresc apăsările pe taste promiţându-vă că vă oferă emoticonuri gratuite;</li>
+      <li>acţiunile de monitorizare efectuate de agenţi secreţi;</li>
+      <li>persoanele din spatele dvs.</li>
+    </ul>
+  </body>
+</html>
diff --git a/core/res/res/raw-ru-xlarge/incognito_mode_start_page.html b/core/res/res/raw-ru-xlarge/incognito_mode_start_page.html
new file mode 100644
index 0000000..ae7b59c
--- /dev/null
+++ b/core/res/res/raw-ru-xlarge/incognito_mode_start_page.html
@@ -0,0 +1,19 @@
+<html DIR="LTR">
+  <head>
+    <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no" />
+    <title>Новое окно в режиме инкогнито</title>
+  </head>
+  <body>
+    <p><strong>Вы перешли в режим инкогнито</strong>. Страницы, которые вы просматриваете в окне в режиме инкогнито, не появятся в истории вашего браузера или истории поиска, а также не оставят на вашем компьютере других следов, таких как файлы cookie, когда вы закроете это окно. Тем не менее, все файлы, которые вы загружаете, или закладки, которые вы создаете, останутся в целости и сохранности. </p>
+
+    <p><strong>Переход в режим инкогнито не влияет на поведение других пользователей, серверов или программ. Опасайтесь:</strong></p>
+
+    <ul>
+      <li>Веб-сайтов, которые собирают информацию о вас или передают ее другим</li>
+      <li>Поставщиков услуг Интернета или их сотрудников, которые отслеживают, какие страницы вы посещаете</li>
+      <li>Вредоносного ПО, которое отслеживает нажатие клавиш клавиатуры в обмен на бесплатные смайлики</li>
+      <li>Слежки тайными агентами</li>
+      <li>Людей, которые стоят у вас за спиной</li>
+    </ul>
+  </body>
+</html>
diff --git a/core/res/res/raw-ru/incognito_mode_start_page.html b/core/res/res/raw-ru/incognito_mode_start_page.html
new file mode 100644
index 0000000..ae7b59c
--- /dev/null
+++ b/core/res/res/raw-ru/incognito_mode_start_page.html
@@ -0,0 +1,19 @@
+<html DIR="LTR">
+  <head>
+    <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no" />
+    <title>Новое окно в режиме инкогнито</title>
+  </head>
+  <body>
+    <p><strong>Вы перешли в режим инкогнито</strong>. Страницы, которые вы просматриваете в окне в режиме инкогнито, не появятся в истории вашего браузера или истории поиска, а также не оставят на вашем компьютере других следов, таких как файлы cookie, когда вы закроете это окно. Тем не менее, все файлы, которые вы загружаете, или закладки, которые вы создаете, останутся в целости и сохранности. </p>
+
+    <p><strong>Переход в режим инкогнито не влияет на поведение других пользователей, серверов или программ. Опасайтесь:</strong></p>
+
+    <ul>
+      <li>Веб-сайтов, которые собирают информацию о вас или передают ее другим</li>
+      <li>Поставщиков услуг Интернета или их сотрудников, которые отслеживают, какие страницы вы посещаете</li>
+      <li>Вредоносного ПО, которое отслеживает нажатие клавиш клавиатуры в обмен на бесплатные смайлики</li>
+      <li>Слежки тайными агентами</li>
+      <li>Людей, которые стоят у вас за спиной</li>
+    </ul>
+  </body>
+</html>
diff --git a/core/res/res/raw-sk-xlarge/incognito_mode_start_page.html b/core/res/res/raw-sk-xlarge/incognito_mode_start_page.html
new file mode 100644
index 0000000..5b138f1
--- /dev/null
+++ b/core/res/res/raw-sk-xlarge/incognito_mode_start_page.html
@@ -0,0 +1,19 @@
+<html DIR="LTR">
+  <head>
+    <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no" />
+    <title>Nové okno inkognito</title>
+  </head>
+  <body>
+    <p><strong>Ste v režime inkognito</strong> Stránky, ktoré si pozriete v tomto okne, sa nezobrazia v histórii prehliadača ani v histórii vyhľadávania. Po zavretí okna inkognito na zariadení nezostanú ani žiadne iné stopy, ako sú napr. súbory cookie. Napriek tomu však zostanú zachované všetky prevzaté súbory aj záložky, ktoré ste vytvorili.</p>
+
+    <p><strong>Režim inkognito neovplyvňuje správanie iných ľudí, serverov ani softvéru. Dávajte si pozor na:</strong></p>
+
+    <ul>
+      <li>webové stránky, ktoré zbierajú alebo zdieľajú vaše informácie;</li>
+      <li>poskytovateľov internetových služieb alebo zamestnancov, ktorí sledujú vaše navštívené stránky;</li>
+      <li>škodlivý softvér, ktorý sleduje ktoré klávesy stláčate výmenou za smajlíkov zadarmo;</li>
+      <li>sledovanie tajnými agentmi;</li>
+      <li>ľudí, ktorí stoja za vami.</li>
+    </ul>
+  </body>
+</html>
diff --git a/core/res/res/raw-sk/incognito_mode_start_page.html b/core/res/res/raw-sk/incognito_mode_start_page.html
new file mode 100644
index 0000000..5b138f1
--- /dev/null
+++ b/core/res/res/raw-sk/incognito_mode_start_page.html
@@ -0,0 +1,19 @@
+<html DIR="LTR">
+  <head>
+    <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no" />
+    <title>Nové okno inkognito</title>
+  </head>
+  <body>
+    <p><strong>Ste v režime inkognito</strong> Stránky, ktoré si pozriete v tomto okne, sa nezobrazia v histórii prehliadača ani v histórii vyhľadávania. Po zavretí okna inkognito na zariadení nezostanú ani žiadne iné stopy, ako sú napr. súbory cookie. Napriek tomu však zostanú zachované všetky prevzaté súbory aj záložky, ktoré ste vytvorili.</p>
+
+    <p><strong>Režim inkognito neovplyvňuje správanie iných ľudí, serverov ani softvéru. Dávajte si pozor na:</strong></p>
+
+    <ul>
+      <li>webové stránky, ktoré zbierajú alebo zdieľajú vaše informácie;</li>
+      <li>poskytovateľov internetových služieb alebo zamestnancov, ktorí sledujú vaše navštívené stránky;</li>
+      <li>škodlivý softvér, ktorý sleduje ktoré klávesy stláčate výmenou za smajlíkov zadarmo;</li>
+      <li>sledovanie tajnými agentmi;</li>
+      <li>ľudí, ktorí stoja za vami.</li>
+    </ul>
+  </body>
+</html>
diff --git a/core/res/res/raw-sl-xlarge/incognito_mode_start_page.html b/core/res/res/raw-sl-xlarge/incognito_mode_start_page.html
new file mode 100644
index 0000000..33a8b08
--- /dev/null
+++ b/core/res/res/raw-sl-xlarge/incognito_mode_start_page.html
@@ -0,0 +1,19 @@
+<html DIR="LTR">
+  <head>
+    <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no" />
+    <title>Novo okno brez beleženja zgodovine</title>
+  </head>
+  <body>
+    <p><strong>Ste v načinu brez beleženja zgodovine.</strong> Strani, ki si jih ogledate v tem oknu, ne bodo prikazane v zgodovini brskalnika ali zgodovini iskanja, prav tako v vaši napravi ne bodo pustile sledi, kot npr. piškotkov, ko zaprete stran, ki jo imate odprto v tem načinu. Datoteke, ki jih prenesete ali zaznamki, ki jih ustvarite, bodo ohranjeni.</p>
+
+    <p><strong>Funkcije brez beleženja zgodovine ne vplivajo na obnašanje drugih oseb, strežnikov ali programske opreme. Pazite na:</strong></p>
+
+    <ul>
+      <li>Spletna mesta, ki zbirajo informacije o vas ali jih dajejo v skupno rabo.</li>
+      <li>Ponudnike internetnih storitev ali zaposlene, ki spremljajo spletna mesta, ki ste jih obiskali.</li>
+      <li>Zlonamerno programsko opremo, ki spremlja vaše tipkanje, v zameno pa vam ponuja brezplačne čustvene simbole.</li>
+      <li>Nadzor tajnih agentov.</li>
+      <li>Osebe, ki stojijo za vašim hrbtom.</li>
+    </ul>
+  </body>
+</html>
diff --git a/core/res/res/raw-sl/incognito_mode_start_page.html b/core/res/res/raw-sl/incognito_mode_start_page.html
new file mode 100644
index 0000000..33a8b08
--- /dev/null
+++ b/core/res/res/raw-sl/incognito_mode_start_page.html
@@ -0,0 +1,19 @@
+<html DIR="LTR">
+  <head>
+    <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no" />
+    <title>Novo okno brez beleženja zgodovine</title>
+  </head>
+  <body>
+    <p><strong>Ste v načinu brez beleženja zgodovine.</strong> Strani, ki si jih ogledate v tem oknu, ne bodo prikazane v zgodovini brskalnika ali zgodovini iskanja, prav tako v vaši napravi ne bodo pustile sledi, kot npr. piškotkov, ko zaprete stran, ki jo imate odprto v tem načinu. Datoteke, ki jih prenesete ali zaznamki, ki jih ustvarite, bodo ohranjeni.</p>
+
+    <p><strong>Funkcije brez beleženja zgodovine ne vplivajo na obnašanje drugih oseb, strežnikov ali programske opreme. Pazite na:</strong></p>
+
+    <ul>
+      <li>Spletna mesta, ki zbirajo informacije o vas ali jih dajejo v skupno rabo.</li>
+      <li>Ponudnike internetnih storitev ali zaposlene, ki spremljajo spletna mesta, ki ste jih obiskali.</li>
+      <li>Zlonamerno programsko opremo, ki spremlja vaše tipkanje, v zameno pa vam ponuja brezplačne čustvene simbole.</li>
+      <li>Nadzor tajnih agentov.</li>
+      <li>Osebe, ki stojijo za vašim hrbtom.</li>
+    </ul>
+  </body>
+</html>
diff --git a/core/res/res/raw-sr-xlarge/incognito_mode_start_page.html b/core/res/res/raw-sr-xlarge/incognito_mode_start_page.html
new file mode 100644
index 0000000..b1fbcb1
--- /dev/null
+++ b/core/res/res/raw-sr-xlarge/incognito_mode_start_page.html
@@ -0,0 +1,19 @@
+<html DIR="LTR">
+  <head>
+    <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no" />
+    <title>Нов прозор без архивирања</title>
+  </head>
+  <body>
+    <p><strong>Ушли сте у режим без архивирања</strong> Странице које гледате у овом прозору се неће појавити у историји прегледања ни историји претраге, нити ће оставити друге трагове, попут колачића, на вашем уређају када затворите овај прозор. Међутим, ако преузмете датотеке или направите обележиваче, они ће бити сачувани.</p>
+
+    <p><strong>Режим без архивирања не утиче на понашање других људи, сервера нити софтвера. Чувајте се:</strong></p>
+
+    <ul>
+      <li>Веб сајтова који прикупљају и деле податке о вама</li>
+      <li>Добављача интернет услуга или запослених који прате странице које посетите</li>
+      <li>Злонамерног софтвера који прати шта куцате</li>
+      <li>Надзора тајних агената</li>
+      <li>Људи који вам стоје иза леђа</li>
+    </ul>
+  </body>
+</html>
diff --git a/core/res/res/raw-sr/incognito_mode_start_page.html b/core/res/res/raw-sr/incognito_mode_start_page.html
new file mode 100644
index 0000000..b1fbcb1
--- /dev/null
+++ b/core/res/res/raw-sr/incognito_mode_start_page.html
@@ -0,0 +1,19 @@
+<html DIR="LTR">
+  <head>
+    <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no" />
+    <title>Нов прозор без архивирања</title>
+  </head>
+  <body>
+    <p><strong>Ушли сте у режим без архивирања</strong> Странице које гледате у овом прозору се неће појавити у историји прегледања ни историји претраге, нити ће оставити друге трагове, попут колачића, на вашем уређају када затворите овај прозор. Међутим, ако преузмете датотеке или направите обележиваче, они ће бити сачувани.</p>
+
+    <p><strong>Режим без архивирања не утиче на понашање других људи, сервера нити софтвера. Чувајте се:</strong></p>
+
+    <ul>
+      <li>Веб сајтова који прикупљају и деле податке о вама</li>
+      <li>Добављача интернет услуга или запослених који прате странице које посетите</li>
+      <li>Злонамерног софтвера који прати шта куцате</li>
+      <li>Надзора тајних агената</li>
+      <li>Људи који вам стоје иза леђа</li>
+    </ul>
+  </body>
+</html>
diff --git a/core/res/res/raw-sv-xlarge/incognito_mode_start_page.html b/core/res/res/raw-sv-xlarge/incognito_mode_start_page.html
new file mode 100644
index 0000000..5ebbb22
--- /dev/null
+++ b/core/res/res/raw-sv-xlarge/incognito_mode_start_page.html
@@ -0,0 +1,19 @@
+<html DIR="LTR">
+  <head>
+    <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no" />
+    <title>Nytt inkognitofönster</title>
+  </head>
+  <body>
+    <p><strong>Du använder inkognitoläget</strong>. Sidor som du har läst i detta fönster visas inte i din webbläsarhistorik eller sökhistorik. De lämnar inga spår efter sig, till exempel cookies, i din enhet efter att du stängt inkognitofönstret. Alla filer som du hämtar eller bokmärken du skapar sparas dock.</p>
+
+    <p><strong>Att använda datorn inkognito påverkar inte användare, servrar eller program. Se upp för:</strong></p>
+
+    <ul>
+      <li>Webbplatser som samlar eller delar information om dig</li>
+      <li>Internetleverantörer eller arbetsgivare som spårar var du surfar</li>
+      <li>Skadlig programvara som spårar dina tangenttryckningar som nyckelloggare</li>
+      <li>Övervakning av hemliga agenter</li>
+      <li>Personer som står bakom dig</li>
+    </ul>
+  </body>
+</html>
diff --git a/core/res/res/raw-sv/incognito_mode_start_page.html b/core/res/res/raw-sv/incognito_mode_start_page.html
new file mode 100644
index 0000000..5ebbb22
--- /dev/null
+++ b/core/res/res/raw-sv/incognito_mode_start_page.html
@@ -0,0 +1,19 @@
+<html DIR="LTR">
+  <head>
+    <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no" />
+    <title>Nytt inkognitofönster</title>
+  </head>
+  <body>
+    <p><strong>Du använder inkognitoläget</strong>. Sidor som du har läst i detta fönster visas inte i din webbläsarhistorik eller sökhistorik. De lämnar inga spår efter sig, till exempel cookies, i din enhet efter att du stängt inkognitofönstret. Alla filer som du hämtar eller bokmärken du skapar sparas dock.</p>
+
+    <p><strong>Att använda datorn inkognito påverkar inte användare, servrar eller program. Se upp för:</strong></p>
+
+    <ul>
+      <li>Webbplatser som samlar eller delar information om dig</li>
+      <li>Internetleverantörer eller arbetsgivare som spårar var du surfar</li>
+      <li>Skadlig programvara som spårar dina tangenttryckningar som nyckelloggare</li>
+      <li>Övervakning av hemliga agenter</li>
+      <li>Personer som står bakom dig</li>
+    </ul>
+  </body>
+</html>
diff --git a/core/res/res/raw-th-xlarge/incognito_mode_start_page.html b/core/res/res/raw-th-xlarge/incognito_mode_start_page.html
new file mode 100644
index 0000000..29c64eb
--- /dev/null
+++ b/core/res/res/raw-th-xlarge/incognito_mode_start_page.html
@@ -0,0 +1,19 @@
+<html DIR="LTR">
+  <head>
+    <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no" />
+    <title>หน้าต่างใหม่ที่ไม่ระบุตัวตน</title>
+  </head>
+  <body>
+    <p><strong>คุณได้เข้าสู่โหมดไม่ระบุตัวตนแล้ว</strong> หน้าเว็บที่คุณดูในหน้าต่างนี้จะไม่ปรากฏในประวัติของเบราว์เซอร์หรือประวัติการค้นหาของคุณ และจะไม่ทิ้งร่องรอยอื่นๆ เช่น คุกกี้ ไว้บนอุปกรณ์หลังจากที่คุณปิดหน้าต่างที่ไม่ระบุตัวตนนี้แล้ว อย่างไรก็ตาม ไฟล์ที่คุณดาวน์โหลดหรือบุ๊กมาร์กที่สร้างขึ้นจะถูกเก็บไว้</p>
+
+    <p><strong>การเข้าสู่โหมดไม่ระบุตัวตนจะไม่กระทบต่อการทำงานของบุคคล เซิร์ฟเวอร์ หรือซอฟต์แวร์อื่น โปรดระวัง:</strong></p>
+
+    <ul>
+      <li>เว็บไซต์ที่เก็บหรือแบ่งปันข้อมูลเกี่ยวกับคุณ</li>
+      <li>ผู้ให้บริการอินเทอร์เน็ตหรือนายจ้างที่ติดตามหน้าเว็บที่คุณเข้าชม</li>
+      <li>ซอฟต์แวร์มุ่งร้ายที่ติดตามการกดแป้นพิมพ์โดยมากับของฟรี</li>
+      <li>การตรวจสอบของหน่วยสืบราชการลับ</li>
+      <li>บุคคลที่ยืนอยู่ข้างหลังคุณ</li>
+    </ul>
+  </body>
+</html>
diff --git a/core/res/res/raw-th/incognito_mode_start_page.html b/core/res/res/raw-th/incognito_mode_start_page.html
new file mode 100644
index 0000000..29c64eb
--- /dev/null
+++ b/core/res/res/raw-th/incognito_mode_start_page.html
@@ -0,0 +1,19 @@
+<html DIR="LTR">
+  <head>
+    <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no" />
+    <title>หน้าต่างใหม่ที่ไม่ระบุตัวตน</title>
+  </head>
+  <body>
+    <p><strong>คุณได้เข้าสู่โหมดไม่ระบุตัวตนแล้ว</strong> หน้าเว็บที่คุณดูในหน้าต่างนี้จะไม่ปรากฏในประวัติของเบราว์เซอร์หรือประวัติการค้นหาของคุณ และจะไม่ทิ้งร่องรอยอื่นๆ เช่น คุกกี้ ไว้บนอุปกรณ์หลังจากที่คุณปิดหน้าต่างที่ไม่ระบุตัวตนนี้แล้ว อย่างไรก็ตาม ไฟล์ที่คุณดาวน์โหลดหรือบุ๊กมาร์กที่สร้างขึ้นจะถูกเก็บไว้</p>
+
+    <p><strong>การเข้าสู่โหมดไม่ระบุตัวตนจะไม่กระทบต่อการทำงานของบุคคล เซิร์ฟเวอร์ หรือซอฟต์แวร์อื่น โปรดระวัง:</strong></p>
+
+    <ul>
+      <li>เว็บไซต์ที่เก็บหรือแบ่งปันข้อมูลเกี่ยวกับคุณ</li>
+      <li>ผู้ให้บริการอินเทอร์เน็ตหรือนายจ้างที่ติดตามหน้าเว็บที่คุณเข้าชม</li>
+      <li>ซอฟต์แวร์มุ่งร้ายที่ติดตามการกดแป้นพิมพ์โดยมากับของฟรี</li>
+      <li>การตรวจสอบของหน่วยสืบราชการลับ</li>
+      <li>บุคคลที่ยืนอยู่ข้างหลังคุณ</li>
+    </ul>
+  </body>
+</html>
diff --git a/core/res/res/raw-tl-xlarge/incognito_mode_start_page.html b/core/res/res/raw-tl-xlarge/incognito_mode_start_page.html
new file mode 100644
index 0000000..6ce5853
--- /dev/null
+++ b/core/res/res/raw-tl-xlarge/incognito_mode_start_page.html
@@ -0,0 +1,19 @@
+<html DIR="LTR">
+  <head>
+    <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no" />
+    <title>Bagong incognito window</title>
+  </head>
+  <body>
+    <p><strong>Nag-incognito ka</strong>. Hindi lalabas sa iyong kasaysayan ng pag-browse at kasaysayan ng paghahanap ang mga pahinang tiningnan mo sa window na ito, at hindi sila mag-iiwan ng ibang bakas, gaya ng cookies, sa iyong device matapos mong isara ang window na incognito. Gayunpaman, pananatiliin ang anumang mga file na iyong na-download o ang iyong mga ginawang bookmark.</p>
+
+    <p><strong>Hindi nakakaapekto ang pagiging incognito sa gawi ng ibang mga tao, server, o software. Maging maingat sa:</strong></p>
+
+    <ul>
+      <li>Mga website na kumokolekta o nagbabahagi ng impormasyong tungkol sa iyo</li>
+      <li>Mga internet service provider o mga employer na  sinusubaybayan ang mga pahinang binibisita mo</li>
+      <li>Malicious software na sinusubaybayan ang iyong mga keystroke kapalit ng mga libreng smiley</li>
+      <li>Pagmamasid ng mga secret agent</li>
+      <li>Mga tao na nakatayo sa likuran mo</li>
+    </ul>
+  </body>
+</html>
diff --git a/core/res/res/raw-tl/incognito_mode_start_page.html b/core/res/res/raw-tl/incognito_mode_start_page.html
new file mode 100644
index 0000000..6ce5853
--- /dev/null
+++ b/core/res/res/raw-tl/incognito_mode_start_page.html
@@ -0,0 +1,19 @@
+<html DIR="LTR">
+  <head>
+    <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no" />
+    <title>Bagong incognito window</title>
+  </head>
+  <body>
+    <p><strong>Nag-incognito ka</strong>. Hindi lalabas sa iyong kasaysayan ng pag-browse at kasaysayan ng paghahanap ang mga pahinang tiningnan mo sa window na ito, at hindi sila mag-iiwan ng ibang bakas, gaya ng cookies, sa iyong device matapos mong isara ang window na incognito. Gayunpaman, pananatiliin ang anumang mga file na iyong na-download o ang iyong mga ginawang bookmark.</p>
+
+    <p><strong>Hindi nakakaapekto ang pagiging incognito sa gawi ng ibang mga tao, server, o software. Maging maingat sa:</strong></p>
+
+    <ul>
+      <li>Mga website na kumokolekta o nagbabahagi ng impormasyong tungkol sa iyo</li>
+      <li>Mga internet service provider o mga employer na  sinusubaybayan ang mga pahinang binibisita mo</li>
+      <li>Malicious software na sinusubaybayan ang iyong mga keystroke kapalit ng mga libreng smiley</li>
+      <li>Pagmamasid ng mga secret agent</li>
+      <li>Mga tao na nakatayo sa likuran mo</li>
+    </ul>
+  </body>
+</html>
diff --git a/core/res/res/raw-tr-xlarge/incognito_mode_start_page.html b/core/res/res/raw-tr-xlarge/incognito_mode_start_page.html
new file mode 100644
index 0000000..c570cc7
--- /dev/null
+++ b/core/res/res/raw-tr-xlarge/incognito_mode_start_page.html
@@ -0,0 +1,19 @@
+<html DIR="LTR">
+  <head>
+    <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no" />
+    <title>Yeni gizli pencere</title>
+  </head>
+  <body>
+    <p><strong>Gizli moda geçtiniz</strong> Bu pencerede görüntülediğiniz sayfalar tarayıcı geçmişinizde veya arama geçmişinizde görünmez ve gizli pencereyi kapatmanızın ardından cihazınızda çerezler gibi izler bırakmaz. Ancak, indirdiğiniz dosyalar ve oluşturduğunuz favoriler korunur.</p>
+
+    <p><strong>Gizli moda geçmeniz diğer kişilerin, sunucuların veya yazılımların davranışlarını etkilemez. Şu konularda dikkatli olun:</strong></p>
+
+    <ul>
+      <li>Hakkınızda bilgi toplayan veya paylaşan web siteleri</li>
+      <li>Ziyaret ettiğiniz sayfaları izleyen şirket çalışanları veya servis sağlayıcıları</li>
+      <li>Ücretsiz ifade simgeleri karşılığında tuş vuruşlarınızı takip eden kötü niyetli yazılımlar</li>
+      <li>Gizli ajanlar tarafından takip edilme</li>
+      <li>Arkanızda dikilip ne yaptığınıza bakan kişiler</li>
+    </ul>
+  </body>
+</html>
diff --git a/core/res/res/raw-tr/incognito_mode_start_page.html b/core/res/res/raw-tr/incognito_mode_start_page.html
new file mode 100644
index 0000000..c570cc7
--- /dev/null
+++ b/core/res/res/raw-tr/incognito_mode_start_page.html
@@ -0,0 +1,19 @@
+<html DIR="LTR">
+  <head>
+    <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no" />
+    <title>Yeni gizli pencere</title>
+  </head>
+  <body>
+    <p><strong>Gizli moda geçtiniz</strong> Bu pencerede görüntülediğiniz sayfalar tarayıcı geçmişinizde veya arama geçmişinizde görünmez ve gizli pencereyi kapatmanızın ardından cihazınızda çerezler gibi izler bırakmaz. Ancak, indirdiğiniz dosyalar ve oluşturduğunuz favoriler korunur.</p>
+
+    <p><strong>Gizli moda geçmeniz diğer kişilerin, sunucuların veya yazılımların davranışlarını etkilemez. Şu konularda dikkatli olun:</strong></p>
+
+    <ul>
+      <li>Hakkınızda bilgi toplayan veya paylaşan web siteleri</li>
+      <li>Ziyaret ettiğiniz sayfaları izleyen şirket çalışanları veya servis sağlayıcıları</li>
+      <li>Ücretsiz ifade simgeleri karşılığında tuş vuruşlarınızı takip eden kötü niyetli yazılımlar</li>
+      <li>Gizli ajanlar tarafından takip edilme</li>
+      <li>Arkanızda dikilip ne yaptığınıza bakan kişiler</li>
+    </ul>
+  </body>
+</html>
diff --git a/core/res/res/raw-uk-xlarge/incognito_mode_start_page.html b/core/res/res/raw-uk-xlarge/incognito_mode_start_page.html
new file mode 100644
index 0000000..8852854
--- /dev/null
+++ b/core/res/res/raw-uk-xlarge/incognito_mode_start_page.html
@@ -0,0 +1,19 @@
+<html DIR="LTR">
+  <head>
+    <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no" />
+    <title>Нове анонімне вікно</title>
+  </head>
+  <body>
+    <p><strong>Ви в анонімному режимі</strong>. Сторінки, які ви переглядаєте в цьому вікні, не з’являться в історії веб-переглядача чи в історії пошуку. Вони також не залишать жодних слідів, як-от файлів cookie, у вашому пристрої після того, як ви закриєте анонімне вікно. Однак, завантажені файли та збережені закладки залишаться.</p>
+
+    <p><strong>Анонімний режим не впливає на поведінку інших людей, серверів чи програмного забезпечення. Остерігайтеся:</strong></p>
+
+    <ul>
+      <li>веб-сайтів, які збирають чи поширюють інформацію про вас</li>
+      <li>постачальників інтернет-послуг або роботодавців, які відстежують сторінки, які ви відвідуєте</li>
+      <li>зловмисного програмного забезпечення, яке пропонує безкоштовні смайли, натомість реєструючи клавіші, які ви натискаєте</li>
+      <li>нагляду збоку секретних служб</li>
+      <li>людей за вашою спиною</li>
+    </ul>
+  </body>
+</html>
diff --git a/core/res/res/raw-uk/incognito_mode_start_page.html b/core/res/res/raw-uk/incognito_mode_start_page.html
new file mode 100644
index 0000000..8852854
--- /dev/null
+++ b/core/res/res/raw-uk/incognito_mode_start_page.html
@@ -0,0 +1,19 @@
+<html DIR="LTR">
+  <head>
+    <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no" />
+    <title>Нове анонімне вікно</title>
+  </head>
+  <body>
+    <p><strong>Ви в анонімному режимі</strong>. Сторінки, які ви переглядаєте в цьому вікні, не з’являться в історії веб-переглядача чи в історії пошуку. Вони також не залишать жодних слідів, як-от файлів cookie, у вашому пристрої після того, як ви закриєте анонімне вікно. Однак, завантажені файли та збережені закладки залишаться.</p>
+
+    <p><strong>Анонімний режим не впливає на поведінку інших людей, серверів чи програмного забезпечення. Остерігайтеся:</strong></p>
+
+    <ul>
+      <li>веб-сайтів, які збирають чи поширюють інформацію про вас</li>
+      <li>постачальників інтернет-послуг або роботодавців, які відстежують сторінки, які ви відвідуєте</li>
+      <li>зловмисного програмного забезпечення, яке пропонує безкоштовні смайли, натомість реєструючи клавіші, які ви натискаєте</li>
+      <li>нагляду збоку секретних служб</li>
+      <li>людей за вашою спиною</li>
+    </ul>
+  </body>
+</html>
diff --git a/core/res/res/raw-vi-xlarge/incognito_mode_start_page.html b/core/res/res/raw-vi-xlarge/incognito_mode_start_page.html
new file mode 100644
index 0000000..9902cde
--- /dev/null
+++ b/core/res/res/raw-vi-xlarge/incognito_mode_start_page.html
@@ -0,0 +1,19 @@
+<html DIR="LTR">
+  <head>
+    <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no" />
+    <title>Cửa sổ ẩn danh mới</title>
+  </head>
+  <body>
+    <p><strong>Bạn đã sử dụng cửa sổ ẩn danh</strong>. Các trang bạn xem trong cửa sổ này sẽ không xuất hiện trong lịch sử của trình duyệt hoặc lịch sử tìm kiếm và chúng cũng không để lại dấu vết như cookie trên thiết bị sau khi bạn đóng cửa sổ ẩn danh. Tuy nhiên, mọi tệp bạn tải xuống hoặc mọi dấu trang bạn tạo sẽ được giữ nguyên.</p>
+
+    <p><strong>Sử dụng cửa sổ ẩn danh không ảnh hưởng đến hành vi của người khác, của máy chủ hoặc phần mềm. Hãy cảnh giác với:</strong></p>
+
+    <ul>
+      <li>Các trang web thu thập hoặc chia sẻ thông tin về bạn</li>
+      <li>Nhà cung cấp dịch vụ Internet hoặc ông chủ muốn theo dõi những trang bạn đã truy cập</li>
+      <li>Phần mềm độc hại theo dõi thao tác gõ phím khi nhập các mặt cười</li>
+      <li>Sự theo dõi của các cơ quan tình báo</li>
+      <li>Những người đứng đằng sau bạn</li>
+    </ul>
+  </body>
+</html>
diff --git a/core/res/res/raw-vi/incognito_mode_start_page.html b/core/res/res/raw-vi/incognito_mode_start_page.html
new file mode 100644
index 0000000..9902cde
--- /dev/null
+++ b/core/res/res/raw-vi/incognito_mode_start_page.html
@@ -0,0 +1,19 @@
+<html DIR="LTR">
+  <head>
+    <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no" />
+    <title>Cửa sổ ẩn danh mới</title>
+  </head>
+  <body>
+    <p><strong>Bạn đã sử dụng cửa sổ ẩn danh</strong>. Các trang bạn xem trong cửa sổ này sẽ không xuất hiện trong lịch sử của trình duyệt hoặc lịch sử tìm kiếm và chúng cũng không để lại dấu vết như cookie trên thiết bị sau khi bạn đóng cửa sổ ẩn danh. Tuy nhiên, mọi tệp bạn tải xuống hoặc mọi dấu trang bạn tạo sẽ được giữ nguyên.</p>
+
+    <p><strong>Sử dụng cửa sổ ẩn danh không ảnh hưởng đến hành vi của người khác, của máy chủ hoặc phần mềm. Hãy cảnh giác với:</strong></p>
+
+    <ul>
+      <li>Các trang web thu thập hoặc chia sẻ thông tin về bạn</li>
+      <li>Nhà cung cấp dịch vụ Internet hoặc ông chủ muốn theo dõi những trang bạn đã truy cập</li>
+      <li>Phần mềm độc hại theo dõi thao tác gõ phím khi nhập các mặt cười</li>
+      <li>Sự theo dõi của các cơ quan tình báo</li>
+      <li>Những người đứng đằng sau bạn</li>
+    </ul>
+  </body>
+</html>
diff --git a/core/res/res/raw-xlarge/incognito_mode_start_page.html b/core/res/res/raw-xlarge/incognito_mode_start_page.html
new file mode 100644
index 0000000..492658d
--- /dev/null
+++ b/core/res/res/raw-xlarge/incognito_mode_start_page.html
@@ -0,0 +1,24 @@
+<html>
+  <head>
+    <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no"/>
+    <title>New incognito tab</title>
+  </head>
+  <body>
+    <p><strong>You've gone incognito</strong>. Pages you view in this tab
+      won't appear in your browser history or search history, and they won't
+      leave other traces, like cookies, on your device after you close the
+      incognito tab. Any files you download or bookmarks you create will be
+      preserved, however.</p>
+
+    <p><strong>Going incognito doesn't affect the behavior of other people,
+      servers, or software. Be wary of:</strong></p>
+
+    <ul>
+      <li>Websites that collect or share information about you</li>
+      <li>Internet service providers or employers that track the pages you visit</li>
+      <li>Malicious software that tracks your keystrokes in exchange for free smileys</li>
+      <li>Surveillance by secret agents</li>
+      <li>People standing behind you</li>
+    </ul>
+  </body>
+</html>
diff --git a/core/res/res/raw-zh-rCN-xlarge/incognito_mode_start_page.html b/core/res/res/raw-zh-rCN-xlarge/incognito_mode_start_page.html
new file mode 100644
index 0000000..2caf8f8b
--- /dev/null
+++ b/core/res/res/raw-zh-rCN-xlarge/incognito_mode_start_page.html
@@ -0,0 +1,19 @@
+<html DIR="LTR">
+  <head>
+    <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no" />
+    <title>新建隐身窗口</title>
+  </head>
+  <body>
+    <p><strong>您已进入隐身模式</strong>。当关闭隐身窗口后,您在此窗口中查看的网页将不会出现在您的浏览器历史记录或搜索记录中,也不会在您的设备留下任何踪迹(如 cookie)。但是,您下载的任何文件或您创建的书签会予以保留。</p>
+
+    <p><strong>进入隐身模式不会影响他人、其他服务器或软件的行为。敬请提防:</strong></p>
+
+    <ul>
+      <li>搜集并分享有关您的信息的网站</li>
+      <li>跟踪您所访问的网页的互联网服务提供商或雇主</li>
+      <li>跟踪您的键盘输入内容以换取免费表情符号的恶意软件</li>
+      <li>对您进行监视的秘密代理</li>
+      <li>站在您身后的人</li>
+    </ul>
+  </body>
+</html>
diff --git a/core/res/res/raw-zh-rCN/incognito_mode_start_page.html b/core/res/res/raw-zh-rCN/incognito_mode_start_page.html
new file mode 100644
index 0000000..2caf8f8b
--- /dev/null
+++ b/core/res/res/raw-zh-rCN/incognito_mode_start_page.html
@@ -0,0 +1,19 @@
+<html DIR="LTR">
+  <head>
+    <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no" />
+    <title>新建隐身窗口</title>
+  </head>
+  <body>
+    <p><strong>您已进入隐身模式</strong>。当关闭隐身窗口后,您在此窗口中查看的网页将不会出现在您的浏览器历史记录或搜索记录中,也不会在您的设备留下任何踪迹(如 cookie)。但是,您下载的任何文件或您创建的书签会予以保留。</p>
+
+    <p><strong>进入隐身模式不会影响他人、其他服务器或软件的行为。敬请提防:</strong></p>
+
+    <ul>
+      <li>搜集并分享有关您的信息的网站</li>
+      <li>跟踪您所访问的网页的互联网服务提供商或雇主</li>
+      <li>跟踪您的键盘输入内容以换取免费表情符号的恶意软件</li>
+      <li>对您进行监视的秘密代理</li>
+      <li>站在您身后的人</li>
+    </ul>
+  </body>
+</html>
diff --git a/core/res/res/raw-zh-rTW-xlarge/incognito_mode_start_page.html b/core/res/res/raw-zh-rTW-xlarge/incognito_mode_start_page.html
new file mode 100644
index 0000000..54eb40b
--- /dev/null
+++ b/core/res/res/raw-zh-rTW-xlarge/incognito_mode_start_page.html
@@ -0,0 +1,19 @@
+<html DIR="LTR">
+  <head>
+    <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no" />
+    <title>新的無痕式視窗</title>
+  </head>
+  <body>
+    <p><strong>您已開啟無痕式視窗</strong>。透過這個視窗開啟的網頁都不會出現在瀏覽器記錄和搜尋記錄中,而且您關閉此類視窗之後,裝置上並不會保留任何相關記錄 (例如 cookie)。不過系統會保存您的下載檔案和書籤。</p>
+
+    <p><strong>無痕式視窗無法掌控人、伺服器和軟體的行為,所以請小心下列的人事物:</strong></p>
+
+    <ul>
+      <li>會收集或分享您的相關資訊的網站</li>
+      <li>會追蹤您造訪網頁的網路服務供應商或雇主</li>
+      <li>以免費下載為誘因引誘您點擊的連結,其中通常隱藏鍵盤記錄惡意軟體</li>
+      <li>情報特務的監控</li>
+      <li>站在您身後的人</li>
+    </ul>
+  </body>
+</html>
diff --git a/core/res/res/raw-zh-rTW/incognito_mode_start_page.html b/core/res/res/raw-zh-rTW/incognito_mode_start_page.html
new file mode 100644
index 0000000..54eb40b
--- /dev/null
+++ b/core/res/res/raw-zh-rTW/incognito_mode_start_page.html
@@ -0,0 +1,19 @@
+<html DIR="LTR">
+  <head>
+    <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no" />
+    <title>新的無痕式視窗</title>
+  </head>
+  <body>
+    <p><strong>您已開啟無痕式視窗</strong>。透過這個視窗開啟的網頁都不會出現在瀏覽器記錄和搜尋記錄中,而且您關閉此類視窗之後,裝置上並不會保留任何相關記錄 (例如 cookie)。不過系統會保存您的下載檔案和書籤。</p>
+
+    <p><strong>無痕式視窗無法掌控人、伺服器和軟體的行為,所以請小心下列的人事物:</strong></p>
+
+    <ul>
+      <li>會收集或分享您的相關資訊的網站</li>
+      <li>會追蹤您造訪網頁的網路服務供應商或雇主</li>
+      <li>以免費下載為誘因引誘您點擊的連結,其中通常隱藏鍵盤記錄惡意軟體</li>
+      <li>情報特務的監控</li>
+      <li>站在您身後的人</li>
+    </ul>
+  </body>
+</html>
diff --git a/core/res/res/values-ar/strings.xml b/core/res/res/values-ar/strings.xml
index 6d1f1aa..3731aaa 100644
--- a/core/res/res/values-ar/strings.xml
+++ b/core/res/res/values-ar/strings.xml
@@ -361,8 +361,8 @@
     <string name="permdesc_vibrate" msgid="2886677177257789187">"للسماح للتطبيق بالتحكم في الهزاز."</string>
     <string name="permlab_flashlight" msgid="2155920810121984215">"التحكم في الضوء الوامض"</string>
     <string name="permdesc_flashlight" msgid="6433045942283802309">"للسماح للتطبيق بالتحكم في الضوء الوامض."</string>
-    <string name="permlab_accessUsb" msgid="7362327818655760496">"الدخول إلى أجهزة USB"</string>
-    <string name="permdesc_accessUsb" msgid="2414271762914049292">"للسماح للتطبيق بالدخول إلى أجهزة USB."</string>
+    <string name="permlab_manageUsb" msgid="1113453430645402723">"إدارة التفضيلات والأذونات لأجهزة USB"</string>
+    <string name="permdesc_manageUsb" msgid="6148489202092166164">"للسماح للتطبيق بإدارة التفضيلات والأذونات لأجهزة USB."</string>
     <string name="permlab_accessMtp" msgid="4953468676795917042">"تنفيذ بروتوكول MTP"</string>
     <string name="permdesc_accessMtp" msgid="6532961200486791570">"لإتاحة الدخول إلى برنامج تشغيل kernel MTP لتنفيذ بروتوكول MTP USB."</string>
     <string name="permlab_hardware_test" msgid="4148290860400659146">"اختبار الأجهزة"</string>
@@ -484,8 +484,8 @@
     <string name="policydesc_wipeData" product="default" msgid="7669895333814222586">"محو بيانات الهاتف بدون تحذير، وذلك عبر إجراء إعادة الضبط بحسب بيانات المصنع"</string>
     <string name="policylab_setGlobalProxy" msgid="2784828293747791446">"تعيين الخادم الوكيل العمومي للجهاز"</string>
     <string name="policydesc_setGlobalProxy" msgid="6387497466660154931">"تعيين الخادم الوكيل العمومي للجهاز لكي يتم استخدامه أثناء تمكين السياسة. يعين مشرف الجهاز الأول فقط الخادم الوكيل العمومي الفعال."</string>
-    <!-- outdated translation 4740941403188940274 -->     <string name="policylab_expirePassword" msgid="885279151847254056">"تعيين انتهاء صلاحية كلمة المرور"</string>
-    <!-- outdated translation 6626724939177185949 -->     <string name="policydesc_expirePassword" msgid="4844430354224822074">"التحكم في الوقت المستغرق قبل الحاجة إلى تغيير كلمة مرور شاشة التوقف"</string>
+    <string name="policylab_expirePassword" msgid="885279151847254056">"ضبط انتهاء كلمة مرور تأمين شاشة"</string>
+    <string name="policydesc_expirePassword" msgid="4844430354224822074">"التحكم في عدد مرات تغيير كلمة مرور تأمين الشاشة"</string>
     <string name="policylab_encryptedStorage" msgid="8901326199909132915">"تعيين تشفير التخزين"</string>
     <string name="policydesc_encryptedStorage" msgid="2504984732631479399">"طلب تشفير بيانات التطبيق المخزنة"</string>
   <string-array name="phoneTypes">
@@ -814,6 +814,7 @@
     <string name="alwaysUse" msgid="4583018368000610438">"الاستخدام بشكل افتراضي لهذا الإجراء."</string>
     <string name="clearDefaultHintMsg" msgid="4815455344600932173">"محو الإعداد الافتراضي في الإعدادات الرئيسية &gt; التطبيقات &gt; إدارة التطبيقات."</string>
     <string name="chooseActivity" msgid="1009246475582238425">"تحديد إجراء"</string>
+    <string name="chooseUsbActivity" msgid="7892597146032121735">"تحديد تطبيق لجهاز USB"</string>
     <string name="noApplications" msgid="1691104391758345586">"ليس هناك تطبيقات يمكنها تنفيذ هذا الإجراء."</string>
     <string name="aerr_title" msgid="653922989522758100">"عذرًا!"</string>
     <string name="aerr_application" msgid="4683614104336409186">"توقف التطبيق <xliff:g id="APPLICATION">%1$s</xliff:g> (العملية <xliff:g id="PROCESS">%2$s</xliff:g>) على نحو غير متوقع. الرجاء المحاولة مرة أخرى."</string>
diff --git a/core/res/res/values-bg/strings.xml b/core/res/res/values-bg/strings.xml
index ca36b5c..0173f45 100644
--- a/core/res/res/values-bg/strings.xml
+++ b/core/res/res/values-bg/strings.xml
@@ -361,8 +361,8 @@
     <string name="permdesc_vibrate" msgid="2886677177257789187">"Разрешава на приложението да контролира устройството за вибрация."</string>
     <string name="permlab_flashlight" msgid="2155920810121984215">"контролиране на фенерчето"</string>
     <string name="permdesc_flashlight" msgid="6433045942283802309">"Разрешава на приложението да контролира фенерчето."</string>
-    <string name="permlab_accessUsb" msgid="7362327818655760496">"достъп до USB устройства"</string>
-    <string name="permdesc_accessUsb" msgid="2414271762914049292">"Разрешава на приложението достъп до USB устройства."</string>
+    <string name="permlab_manageUsb" msgid="1113453430645402723">"управление на предпочитанията и разрешенията за USB устройства"</string>
+    <string name="permdesc_manageUsb" msgid="6148489202092166164">"Разрешава на приложението да управлява предпочитанията и разрешенията за USB устройства."</string>
     <string name="permlab_accessMtp" msgid="4953468676795917042">"внедряване на MTP протокол"</string>
     <string name="permdesc_accessMtp" msgid="6532961200486791570">"Разрешава достъп до MTP драйвера на ядрото за внедряване на протокола MTP през USB."</string>
     <string name="permlab_hardware_test" msgid="4148290860400659146">"тест на хардуера"</string>
@@ -484,8 +484,8 @@
     <string name="policydesc_wipeData" product="default" msgid="7669895333814222586">"Изтриване на данните в телефона без предупреждение чрез възстановяване на фабричните настройки"</string>
     <string name="policylab_setGlobalProxy" msgid="2784828293747791446">"Задаване на глобален прокси сървър за устройството"</string>
     <string name="policydesc_setGlobalProxy" msgid="6387497466660154931">"Задаване на глобалния прокси сървър, който да се използва, когато правилото е активирано. Само първият администратор на устройството задава действителния глобален прокси сървър."</string>
-    <!-- outdated translation 4740941403188940274 -->     <string name="policylab_expirePassword" msgid="885279151847254056">"Задаване на срок на валидност на паролата"</string>
-    <!-- outdated translation 6626724939177185949 -->     <string name="policydesc_expirePassword" msgid="4844430354224822074">"Контролирайте след колко време трябва да се променя паролата за заключване на екрана"</string>
+    <string name="policylab_expirePassword" msgid="885279151847254056">"Изтичане на паролата"</string>
+    <string name="policydesc_expirePassword" msgid="4844430354224822074">"Контролирайте колко често трябва да се променя паролата за заключен екран"</string>
     <string name="policylab_encryptedStorage" msgid="8901326199909132915">"Шифроване за хранилището"</string>
     <string name="policydesc_encryptedStorage" msgid="2504984732631479399">"Изисква съхраняваните данни за приложенията да бъдат шифровани"</string>
   <string-array name="phoneTypes">
@@ -814,6 +814,7 @@
     <string name="alwaysUse" msgid="4583018368000610438">"Използване по подразбиране за това действие."</string>
     <string name="clearDefaultHintMsg" msgid="4815455344600932173">"Изчистване на стандартната стойност в „Начални настройки“ &gt; „Приложения“ &gt; „Управление на приложенията“."</string>
     <string name="chooseActivity" msgid="1009246475582238425">"Избиране на действие"</string>
+    <string name="chooseUsbActivity" msgid="7892597146032121735">"Избор на приложение за USB устройството"</string>
     <string name="noApplications" msgid="1691104391758345586">"Това действие не може да се изпълни от нито едно приложение."</string>
     <string name="aerr_title" msgid="653922989522758100">"Съжаляваме!"</string>
     <string name="aerr_application" msgid="4683614104336409186">"Приложението „<xliff:g id="APPLICATION">%1$s</xliff:g>“ (процес „<xliff:g id="PROCESS">%2$s</xliff:g>“) спря неочаквано. Моля, опитайте отново."</string>
diff --git a/core/res/res/values-ca/strings.xml b/core/res/res/values-ca/strings.xml
index d506c67..e94e7e5 100644
--- a/core/res/res/values-ca/strings.xml
+++ b/core/res/res/values-ca/strings.xml
@@ -361,8 +361,8 @@
     <string name="permdesc_vibrate" msgid="2886677177257789187">"Permet a l\'aplicació controlar el vibrador."</string>
     <string name="permlab_flashlight" msgid="2155920810121984215">"controlar el flaix"</string>
     <string name="permdesc_flashlight" msgid="6433045942283802309">"Permet a l\'aplicació controlar el flaix."</string>
-    <string name="permlab_accessUsb" msgid="7362327818655760496">"accedeix a dispositius USB"</string>
-    <string name="permdesc_accessUsb" msgid="2414271762914049292">"Permet que l\'aplicació accedeixi als dispositius USB."</string>
+    <string name="permlab_manageUsb" msgid="1113453430645402723">"gestiona les preferències i els permisos dels dispositius USB"</string>
+    <string name="permdesc_manageUsb" msgid="6148489202092166164">"Permet que l\'aplicació gestioni les preferències i els permisos dels dispositius USB."</string>
     <string name="permlab_accessMtp" msgid="4953468676795917042">"implementa el protocol MTP"</string>
     <string name="permdesc_accessMtp" msgid="6532961200486791570">"Permet l\'accés al programa de control MTP de kernel per implementar el protocol USB d\'MTP."</string>
     <string name="permlab_hardware_test" msgid="4148290860400659146">"provar el maquinari"</string>
@@ -484,8 +484,8 @@
     <string name="policydesc_wipeData" product="default" msgid="7669895333814222586">"Esborra les dades del telèfon sense advertiment mitjançant un restabliment de les dades de fàbrica"</string>
     <string name="policylab_setGlobalProxy" msgid="2784828293747791446">"Defineix el servidor intermediari global del dispositiu"</string>
     <string name="policydesc_setGlobalProxy" msgid="6387497466660154931">"Defineix el servidor intermediari global del dispositiu que cal utilitzar mentre la política estigui activada. Només el primer administrador del dispositiu pot definir el servidor intermediari global efectiu."</string>
-    <!-- outdated translation 4740941403188940274 -->     <string name="policylab_expirePassword" msgid="885279151847254056">"Defineix la caducitat de la contrasenya"</string>
-    <!-- outdated translation 6626724939177185949 -->     <string name="policydesc_expirePassword" msgid="4844430354224822074">"Controla quant de temps abans de la pantalla de bloqueig cal canviar la contrasenya"</string>
+    <string name="policylab_expirePassword" msgid="885279151847254056">"Defineix la caducitat de la contrasenya de bloqueig de pantalla"</string>
+    <string name="policydesc_expirePassword" msgid="4844430354224822074">"Controla la freqüència amb què cal canviar la contrasenya de bloqueig de pantalla"</string>
     <string name="policylab_encryptedStorage" msgid="8901326199909132915">"Encriptació d’emmagatzematge"</string>
     <string name="policydesc_encryptedStorage" msgid="2504984732631479399">"Requereix que les dades de l\'aplicació emmagatzemades estiguin encriptades"</string>
   <string-array name="phoneTypes">
@@ -814,6 +814,7 @@
     <string name="alwaysUse" msgid="4583018368000610438">"Utilitza-ho de manera predeterminada per a aquesta acció."</string>
     <string name="clearDefaultHintMsg" msgid="4815455344600932173">"Esborra el valor predeterminat a Configuració de la pantalla d\'inici &gt; Aplicacions &gt; Gestiona les aplicacions."</string>
     <string name="chooseActivity" msgid="1009246475582238425">"Seleccioneu una acció"</string>
+    <string name="chooseUsbActivity" msgid="7892597146032121735">"Selecciona una aplicació per al dispositiu USB"</string>
     <string name="noApplications" msgid="1691104391758345586">"No hi ha cap aplicació que pugui dur a terme aquesta acció."</string>
     <string name="aerr_title" msgid="653922989522758100">"Ho sentim."</string>
     <string name="aerr_application" msgid="4683614104336409186">"L\'aplicació <xliff:g id="APPLICATION">%1$s</xliff:g> (procés <xliff:g id="PROCESS">%2$s</xliff:g>) s\'ha aturat inesperadament. Torneu-ho a provar."</string>
diff --git a/core/res/res/values-cs/strings.xml b/core/res/res/values-cs/strings.xml
index afc8a2e..0102536 100644
--- a/core/res/res/values-cs/strings.xml
+++ b/core/res/res/values-cs/strings.xml
@@ -361,8 +361,8 @@
     <string name="permdesc_vibrate" msgid="2886677177257789187">"Umožňuje aplikaci ovládat vibrace."</string>
     <string name="permlab_flashlight" msgid="2155920810121984215">"ovládání kontrolky"</string>
     <string name="permdesc_flashlight" msgid="6433045942283802309">"Umožňuje aplikaci ovládat kontrolku."</string>
-    <string name="permlab_accessUsb" msgid="7362327818655760496">"přístup k zařízením USB"</string>
-    <string name="permdesc_accessUsb" msgid="2414271762914049292">"Umožní aplikaci přístup k zařízením USB."</string>
+    <string name="permlab_manageUsb" msgid="1113453430645402723">"spravovat nastavení a oprávnění pro zařízení USB"</string>
+    <string name="permdesc_manageUsb" msgid="6148489202092166164">"Umožňuje aplikaci spravovat nastavení a oprávnění pro zařízení USB."</string>
     <string name="permlab_accessMtp" msgid="4953468676795917042">"implementace protokolu MTP"</string>
     <string name="permdesc_accessMtp" msgid="6532961200486791570">"Povoluje přístup k ovladači protokolu MTP jádra za účelem implementace protokolu MTP USB."</string>
     <string name="permlab_hardware_test" msgid="4148290860400659146">"testování hardwaru"</string>
@@ -484,8 +484,8 @@
     <string name="policydesc_wipeData" product="default" msgid="7669895333814222586">"Bez upozornění smazat všechna data telefonu obnovením továrních dat"</string>
     <string name="policylab_setGlobalProxy" msgid="2784828293747791446">"Nastavit globální proxy server zařízení"</string>
     <string name="policydesc_setGlobalProxy" msgid="6387497466660154931">"Vyberte globální proxy server, který se bude používat, když jsou zásady aktivní. Aktuální globální proxy server nastavuje pouze první správce zařízení."</string>
-    <!-- outdated translation 4740941403188940274 -->     <string name="policylab_expirePassword" msgid="885279151847254056">"Nastavit konec platnosti hesla"</string>
-    <!-- outdated translation 6626724939177185949 -->     <string name="policydesc_expirePassword" msgid="4844430354224822074">"Ovládání doby, po jejímž uplynutí je nutné změnit heslo pro odemknutí obrazovky"</string>
+    <string name="policylab_expirePassword" msgid="885279151847254056">"Nastavit vypršení hesla zámku"</string>
+    <string name="policydesc_expirePassword" msgid="4844430354224822074">"Určuje, jak často je třeba měnit heslo pro uzamčení obrazovky"</string>
     <string name="policylab_encryptedStorage" msgid="8901326199909132915">"Nastavit šifrování úložiště"</string>
     <string name="policydesc_encryptedStorage" msgid="2504984732631479399">"Požadovat šifrování ukládaných dat"</string>
   <string-array name="phoneTypes">
@@ -814,6 +814,7 @@
     <string name="alwaysUse" msgid="4583018368000610438">"Použít jako výchozí nastavení pro tuto činnost."</string>
     <string name="clearDefaultHintMsg" msgid="4815455344600932173">"Vymažte výchozí hodnoty v Nastavení plochy &gt; Aplikace &gt; Správa aplikací."</string>
     <string name="chooseActivity" msgid="1009246475582238425">"Vyberte akci"</string>
+    <string name="chooseUsbActivity" msgid="7892597146032121735">"Zvolte aplikaci pro zařízení USB"</string>
     <string name="noApplications" msgid="1691104391758345586">"Tuto činnost nemohou provádět žádné aplikace."</string>
     <string name="aerr_title" msgid="653922989522758100">"Omlouváme se"</string>
     <string name="aerr_application" msgid="4683614104336409186">"Aplikace <xliff:g id="APPLICATION">%1$s</xliff:g> (proces <xliff:g id="PROCESS">%2$s</xliff:g>) byla neočekávaně ukončena. Zkuste to znovu."</string>
diff --git a/core/res/res/values-da/strings.xml b/core/res/res/values-da/strings.xml
index 3e283fc..93b59aa 100644
--- a/core/res/res/values-da/strings.xml
+++ b/core/res/res/values-da/strings.xml
@@ -361,8 +361,8 @@
     <string name="permdesc_vibrate" msgid="2886677177257789187">"Lader programmet kontrollere vibratoren."</string>
     <string name="permlab_flashlight" msgid="2155920810121984215">"kontroller lommelygte"</string>
     <string name="permdesc_flashlight" msgid="6433045942283802309">"Tillader, at programmet kontrollerer lommelygten."</string>
-    <string name="permlab_accessUsb" msgid="7362327818655760496">"adgang til USB-enheder."</string>
-    <string name="permdesc_accessUsb" msgid="2414271762914049292">"Tillader, at programmet har adgang til USB-enheder."</string>
+    <string name="permlab_manageUsb" msgid="1113453430645402723">"administrer præferencer og tilladelser for USB-enheder"</string>
+    <string name="permdesc_manageUsb" msgid="6148489202092166164">"Tillader, at programmet administrerer præferencer og tilladelser for USB-enheder."</string>
     <string name="permlab_accessMtp" msgid="4953468676795917042">"implementere MTP-protokol"</string>
     <string name="permdesc_accessMtp" msgid="6532961200486791570">"Tillader adgang til kerne-MTP-driveren for at implementere MTB USB-protokollen."</string>
     <string name="permlab_hardware_test" msgid="4148290860400659146">"test hardware"</string>
@@ -484,8 +484,8 @@
     <string name="policydesc_wipeData" product="default" msgid="7669895333814222586">"Slet telefonens data uden varsel ved at gendanne fabriksindstillinger"</string>
     <string name="policylab_setGlobalProxy" msgid="2784828293747791446">"Angiv enhedens globale proxy"</string>
     <string name="policydesc_setGlobalProxy" msgid="6387497466660154931">"Angiv enhedens globale proxy, der skal bruges, mens politikken er aktiveret. Kun den første enhedsadministrator angiver den effektive globale proxy."</string>
-    <!-- outdated translation 4740941403188940274 -->     <string name="policylab_expirePassword" msgid="885279151847254056">"Angiv udløb for adgangskode"</string>
-    <!-- outdated translation 6626724939177185949 -->     <string name="policydesc_expirePassword" msgid="4844430354224822074">"Kontroller, hvor lang tid der skal gå, før adgangskoden til skærmlåsen skal ændres."</string>
+    <string name="policylab_expirePassword" msgid="885279151847254056">"Angiv udløb for skærmlåskoden"</string>
+    <string name="policydesc_expirePassword" msgid="4844430354224822074">"Administrer, hvor tit skærmlåsens adgangskode skal skiftes"</string>
     <string name="policylab_encryptedStorage" msgid="8901326199909132915">"Angiv kryptering af lager"</string>
     <string name="policydesc_encryptedStorage" msgid="2504984732631479399">"Kræv, at gemte programdata krypteres"</string>
   <string-array name="phoneTypes">
@@ -814,6 +814,7 @@
     <string name="alwaysUse" msgid="4583018368000610438">"Brug som standard til denne handling."</string>
     <string name="clearDefaultHintMsg" msgid="4815455344600932173">"Ryd standard i Startindstillinger &gt; Programmer &gt; Administrer programmer."</string>
     <string name="chooseActivity" msgid="1009246475582238425">"Vælg en handling"</string>
+    <string name="chooseUsbActivity" msgid="7892597146032121735">"Vælg et program for USB-enheden"</string>
     <string name="noApplications" msgid="1691104391758345586">"Der er ingen programmer, der kan foretage denne handling."</string>
     <string name="aerr_title" msgid="653922989522758100">"Beklager!"</string>
     <string name="aerr_application" msgid="4683614104336409186">"Programmet <xliff:g id="APPLICATION">%1$s</xliff:g> (proces <xliff:g id="PROCESS">%2$s</xliff:g>) er standset uventet. Prøv igen."</string>
diff --git a/core/res/res/values-de/strings.xml b/core/res/res/values-de/strings.xml
index ccee3d0..db3e9d9 100644
--- a/core/res/res/values-de/strings.xml
+++ b/core/res/res/values-de/strings.xml
@@ -49,7 +49,7 @@
     <string name="needPuk" msgid="919668385956251611">"Ihre SIM-Karte ist mit einem PUK gesperrt. Geben Sie zum Entsperren den PUK-Code ein."</string>
     <string name="needPuk2" msgid="4526033371987193070">"Geben Sie zum Entsperren der SIM-Karte den PUK2 ein."</string>
     <string name="ClipMmi" msgid="6952821216480289285">"Anrufer-ID für eingehenden Anruf"</string>
-    <string name="ClirMmi" msgid="7784673673446833091">"Anrufer-ID für abgehenden Anruf"</string>
+    <string name="ClirMmi" msgid="7784673673446833091">"Anrufer-ID für ausgehenden Anruf"</string>
     <string name="CfMmi" msgid="5123218989141573515">"Rufweiterleitung"</string>
     <string name="CwMmi" msgid="9129678056795016867">"Anklopfen"</string>
     <string name="BaMmi" msgid="455193067926770581">"Anrufsperre"</string>
@@ -153,18 +153,18 @@
     <string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"Flugmodus ist AUS."</string>
     <string name="status_bar_notification_info_overflow" msgid="5833510281787786290">"100 +"</string>
     <string name="safeMode" msgid="2788228061547930246">"Abgesicherter Modus"</string>
-    <string name="android_system_label" msgid="6577375335728551336">"Android System"</string>
+    <string name="android_system_label" msgid="6577375335728551336">"Android-System"</string>
     <string name="permgrouplab_costMoney" msgid="5429808217861460401">"Kostenpflichtige Dienste"</string>
-    <string name="permgroupdesc_costMoney" msgid="8193824940620517189">"Ermöglicht Anwendungen die Ausführung eventuell kostenpflichtiger Aktionen."</string>
+    <string name="permgroupdesc_costMoney" msgid="8193824940620517189">"Ermöglicht Anwendungen die Ausführung eventuell kostenpflichtiger Aktionen"</string>
     <string name="permgrouplab_messages" msgid="7521249148445456662">"Ihre Nachrichten"</string>
     <string name="permgroupdesc_messages" msgid="7045736972019211994">"Lesen und schreiben Sie Ihre SMS, E-Mails und anderen Nachrichten."</string>
     <string name="permgrouplab_personalInfo" msgid="3519163141070533474">"Ihre persönlichen Informationen"</string>
-    <string name="permgroupdesc_personalInfo" product="tablet" msgid="6975389054186265786">"Direkter Zugriff auf die Kontakte und den Kalender Ihres Tablets."</string>
-    <string name="permgroupdesc_personalInfo" product="default" msgid="5488050357388806068">"Direkter Zugriff auf die Kontakte und den Kalender Ihres Telefons."</string>
+    <string name="permgroupdesc_personalInfo" product="tablet" msgid="6975389054186265786">"Direkter Zugriff auf die Kontakte und den Kalender Ihres Tablets"</string>
+    <string name="permgroupdesc_personalInfo" product="default" msgid="5488050357388806068">"Direkter Zugriff auf die Kontakte und den Kalender Ihres Telefons"</string>
     <string name="permgrouplab_location" msgid="635149742436692049">"Ihren Standort"</string>
     <string name="permgroupdesc_location" msgid="2430258821648348660">"Ihren physischen Standort überwachen"</string>
     <string name="permgrouplab_network" msgid="5808983377727109831">"Netzwerkkommunikation"</string>
-    <string name="permgroupdesc_network" msgid="5035763698958415998">"Ermöglicht Anwendungen den Zugriff auf verschiedene Netzwerkfunktionen."</string>
+    <string name="permgroupdesc_network" msgid="5035763698958415998">"Ermöglicht Anwendungen den Zugriff auf verschiedene Netzwerkfunktionen"</string>
     <string name="permgrouplab_accounts" msgid="3359646291125325519">"Ihre Konten"</string>
     <string name="permgroupdesc_accounts" msgid="4948732641827091312">"Zugriff auf verfügbare Konten"</string>
     <string name="permgrouplab_hardwareControls" msgid="7998214968791599326">"Hardware-Steuerelemente"</string>
@@ -177,14 +177,14 @@
     <string name="permgroupdesc_developmentTools" msgid="9056431193893809814">"Funktionen nur für Anwendungsentwickler vorgesehen."</string>
     <string name="permgrouplab_storage" msgid="1971118770546336966">"Speicher"</string>
     <string name="permgroupdesc_storage" product="nosdcard" msgid="7442318502446874999">"Zugriff auf USB-Speicher"</string>
-    <string name="permgroupdesc_storage" product="default" msgid="9203302214915355774">"Greift auf die SD-Karte zu."</string>
+    <string name="permgroupdesc_storage" product="default" msgid="9203302214915355774">"Zugriff auf SD-Karte"</string>
     <string name="permlab_statusBar" msgid="7417192629601890791">"Statusleiste deaktivieren oder ändern"</string>
-    <string name="permdesc_statusBar" msgid="1365473595331989732">"Ermöglicht der Anwendung, die Statusanzeige zu deaktivieren oder Systemsymbole hinzuzufügen oder zu entfernen."</string>
+    <string name="permdesc_statusBar" msgid="1365473595331989732">"Ermöglicht der Anwendung, die Statusanzeige zu deaktivieren oder Systemsymbole hinzuzufügen oder zu entfernen"</string>
     <string name="permlab_statusBarService" msgid="7247281911387931485">"Statusleiste"</string>
-    <string name="permdesc_statusBarService" msgid="4097605867643520920">"Ermöglicht der Anwendung, zur Statusleiste zu werden."</string>
+    <string name="permdesc_statusBarService" msgid="4097605867643520920">"Ermöglicht der Anwendung, zur Statusleiste zu werden"</string>
     <string name="permlab_expandStatusBar" msgid="1148198785937489264">"Statusleiste ein-/ausblenden"</string>
-    <string name="permdesc_expandStatusBar" msgid="7088604400110768665">"Ermöglicht der Anwendung, die Statusleiste ein- oder auszublenden."</string>
-    <string name="permlab_processOutgoingCalls" msgid="1136262550878335980">"Abgehende Anrufe abfangen"</string>
+    <string name="permdesc_expandStatusBar" msgid="7088604400110768665">"Ermöglicht der Anwendung, die Statusleiste ein- oder auszublenden"</string>
+    <string name="permlab_processOutgoingCalls" msgid="1136262550878335980">"Ausgehende Anrufe abfangen"</string>
     <string name="permdesc_processOutgoingCalls" msgid="2228988201852654461">"Ermöglicht einer Anwendung, abgehende Anrufe zu verarbeiten und die zu wählende Nummer zu ändern. Schädliche Anwendungen können so abgehende Anrufe eventuell überwachen, umleiten oder verhindern."</string>
     <string name="permlab_receiveSms" msgid="2697628268086208535">"SMS empfangen"</string>
     <string name="permdesc_receiveSms" msgid="6298292335965966117">"Ermöglicht der Anwendung, Kurzmitteilungen zu empfangen und zu verarbeiten. Schädliche Anwendungen können Ihre Nachrichten möglicherweise überwachen oder löschen, bevor sie angezeigt werden."</string>
@@ -207,13 +207,13 @@
     <string name="permlab_setDebugApp" msgid="4339730312925176742">"Fehlerbeseitigung für Anwendung aktivieren"</string>
     <string name="permdesc_setDebugApp" msgid="5584310661711990702">"Ermöglicht einer Anwendung, die Fehlerbeseitigung für eine andere Anwendung zu aktivieren. Schädliche Anwendungen können so andere Anwendungen löschen."</string>
     <string name="permlab_changeConfiguration" msgid="8214475779521218295">"UI-Einstellungen ändern"</string>
-    <string name="permdesc_changeConfiguration" msgid="3465121501528064399">"Ermöglicht einer Anwendung, die aktuelle Konfiguration zu ändern, etwa das Gebietsschema oder die Schriftgröße."</string>
+    <string name="permdesc_changeConfiguration" msgid="3465121501528064399">"Ermöglicht einer Anwendung, die aktuelle Konfiguration zu ändern, etwa das Gebietsschema oder die Schriftgröße"</string>
     <string name="permlab_enableCarMode" msgid="5684504058192921098">"Automodus aktivieren"</string>
-    <string name="permdesc_enableCarMode" msgid="5673461159384850628">"Ermöglicht einer Anwendung, den Automodus zu aktivieren."</string>
+    <string name="permdesc_enableCarMode" msgid="5673461159384850628">"Ermöglicht einer Anwendung, den Automodus zu aktivieren"</string>
     <string name="permlab_killBackgroundProcesses" msgid="8373714752793061963">"Hintergrundprozesse beenden"</string>
     <string name="permdesc_killBackgroundProcesses" msgid="2908829602869383753">"Ermöglicht einer Anwendung, Hintergrundprozesse anderer Anwendungen auch bei ausreichendem Speicher zu beenden."</string>
     <string name="permlab_forceStopPackages" msgid="1447830113260156236">"Beenden anderer Anwendungen erzwingen"</string>
-    <string name="permdesc_forceStopPackages" msgid="7263036616161367402">"Ermöglicht einer Anwendung, das Beenden anderer Anwendungen zu erzwingen."</string>
+    <string name="permdesc_forceStopPackages" msgid="7263036616161367402">"Ermöglicht einer Anwendung, das Beenden anderer Anwendungen zu erzwingen"</string>
     <string name="permlab_forceBack" msgid="1804196839880393631">"Schließen von Anwendung erzwingen"</string>
     <string name="permdesc_forceBack" msgid="6534109744159919013">"Ermöglicht einer Anwendung, alle Aktivitäten, die im Vordergrund ablaufen, zu beenden und in den Hintergrund zu schieben. Sollte nicht für normale Anwendungen benötigt werden."</string>
     <string name="permlab_dump" msgid="1681799862438954752">"Systeminternen Status abrufen"</string>
@@ -241,9 +241,9 @@
     <string name="permlab_internalSystemWindow" msgid="2148563628140193231">"nicht autorisierte Fenster anzeigen"</string>
     <string name="permdesc_internalSystemWindow" msgid="5895082268284998469">"Ermöglicht die Erstellung von Fenstern, die von der Benutzeroberfläche des internen Systems verwendet werden. Nicht für normale Anwendungen geeignet."</string>
     <string name="permlab_systemAlertWindow" msgid="3372321942941168324">"Warnungen auf Systemebene anzeigen"</string>
-    <string name="permdesc_systemAlertWindow" msgid="2884149573672821318">"Ermöglicht einer Anwendung, Fenster mit Systemwarnungen anzuzeigen. Schädliche Anwendungen können so das gesamte Display einnehmen."</string>
+    <string name="permdesc_systemAlertWindow" msgid="2884149573672821318">"Ermöglicht einer Anwendung, Fenster mit Systemwarnungen anzuzeigen. Schädliche Anwendungen können so die Kontrolle über das gesamte Display übernehmen."</string>
     <string name="permlab_setAnimationScale" msgid="2805103241153907174">"Allgemeine Animationsgeschwindigkeit einstellen"</string>
-    <string name="permdesc_setAnimationScale" msgid="7181522138912391988">"Ermöglicht einer Anwendung, die allgemeine Animationsgeschwindigkeit (schnellere oder langsamere Animationen) jederzeit anzupassen."</string>
+    <string name="permdesc_setAnimationScale" msgid="7181522138912391988">"Ermöglicht einer Anwendung, die allgemeine Animationsgeschwindigkeit (schnellere oder langsamere Animationen) jederzeit anzupassen"</string>
     <string name="permlab_manageAppTokens" msgid="17124341698093865">"Anwendungs-Tokens verwalten"</string>
     <string name="permdesc_manageAppTokens" msgid="977127907524195988">"Ermöglicht Anwendungen, Ihre eigenen Tokens zu erstellen und zu verwalten. Hierbei wird die normale Z-Reihenfolge umgangen. Dies sollte nicht für normale Anwendungen benötigt werden."</string>
     <string name="permlab_injectEvents" msgid="1378746584023586600">"Tasten und Steuerungstasten drücken"</string>
@@ -262,24 +262,24 @@
     <string name="permlab_setOrientation" msgid="3365947717163866844">"Bildschirmausrichtung ändern"</string>
     <string name="permdesc_setOrientation" msgid="6335814461615851863">"Ermöglicht der Anwendung, die Bildschirmdrehung jederzeit zu ändern. Sollte nicht für normale Anwendungen benötigt werden."</string>
     <string name="permlab_signalPersistentProcesses" msgid="4255467255488653854">"Linux-Signale an Anwendungen senden"</string>
-    <string name="permdesc_signalPersistentProcesses" msgid="3565530463215015289">"Ermöglicht der Anwendung, das Senden des gelieferten Signals an alle anhaltenden Prozesse zu fordern."</string>
+    <string name="permdesc_signalPersistentProcesses" msgid="3565530463215015289">"Ermöglicht der Anwendung, das Senden des gelieferten Signals an alle anhaltenden Prozesse zu fordern"</string>
     <string name="permlab_persistentActivity" msgid="8659652042401085862">"Anwendungen permanent ausführen"</string>
-    <string name="permdesc_persistentActivity" msgid="5037199778265006008">"Ermöglicht einer Anwendung, eigene Komponenten persistent zu machen, damit das System diese nicht für andere Anwendungen nutzen kann."</string>
+    <string name="permdesc_persistentActivity" msgid="5037199778265006008">"Ermöglicht einer Anwendung, eigene Komponenten persistent zu machen, damit das System diese nicht für andere Anwendungen nutzen kann"</string>
     <string name="permlab_deletePackages" msgid="3343439331576348805">"Anwendungen löschen"</string>
     <string name="permdesc_deletePackages" msgid="3634943677518723314">"Ermöglicht einer Anwendung, Android-Pakete zu löschen. Schädliche Anwendungen können so wichtige Anwendungen löschen."</string>
     <string name="permlab_clearAppUserData" msgid="2192134353540277878">"Daten anderer Anwendungen löschen"</string>
-    <string name="permdesc_clearAppUserData" msgid="7546345080434325456">"Ermöglicht einer Anwendung das Löschen von Nutzerdaten."</string>
+    <string name="permdesc_clearAppUserData" msgid="7546345080434325456">"Ermöglicht einer Anwendung das Löschen von Nutzerdaten"</string>
     <string name="permlab_deleteCacheFiles" msgid="1518556602634276725">"Caches anderer Anwendungen löschen"</string>
-    <string name="permdesc_deleteCacheFiles" msgid="2283074077168165971">"Ermöglicht einer Anwendung, Cache-Dateien zu löschen."</string>
+    <string name="permdesc_deleteCacheFiles" msgid="2283074077168165971">"Ermöglicht einer Anwendung, Cache-Dateien zu löschen"</string>
     <string name="permlab_getPackageSize" msgid="4799785352306641460">"Speicherplatz der Anwendung abrufen"</string>
-    <string name="permdesc_getPackageSize" msgid="5557253039670753437">"Ermöglicht einer Anwendung, ihre Code-, Daten- und Cache-Größe abzurufen."</string>
+    <string name="permdesc_getPackageSize" msgid="5557253039670753437">"Ermöglicht einer Anwendung, ihre Code-, Daten- und Cache-Größe abzurufen"</string>
     <string name="permlab_installPackages" msgid="335800214119051089">"Anwendungen direkt installieren"</string>
     <string name="permdesc_installPackages" msgid="526669220850066132">"Ermöglicht einer Anwendung, neue oder aktualisierte Android-Pakete zu installieren. Schädliche Anwendungen können so neue Anwendungen mit beliebig umfangreichen Berechtigungen hinzufügen."</string>
     <string name="permlab_clearAppCache" msgid="4747698311163766540">"Alle Cache-Daten der Anwendung löschen"</string>
     <string name="permdesc_clearAppCache" product="tablet" msgid="3097119797652477973">"Ermöglicht einer Anwendung, Tablet-Speicher durch das Löschen von Dateien im Cache-Verzeichnis der Anwendung freizugeben. Der Zugriff beschränkt sich in der Regel auf Systemprozesse."</string>
     <string name="permdesc_clearAppCache" product="default" msgid="7740465694193671402">"Ermöglicht einer Anwendung, Telefonspeicher durch das Löschen von Dateien im Cache-Verzeichnis der Anwendung freizugeben. Der Zugriff beschränkt sich in der Regel auf Systemprozesse."</string>
     <string name="permlab_movePackage" msgid="728454979946503926">"Anwendungsressourcen verschieben"</string>
-    <string name="permdesc_movePackage" msgid="6323049291923925277">"Ermöglicht einer Anwendung, Anwendungsressourcen von interne auf externe Medien zu verschieben und umgekehrt."</string>
+    <string name="permdesc_movePackage" msgid="6323049291923925277">"Ermöglicht einer Anwendung, Anwendungsressourcen von internen auf externe Medien zu verschieben und umgekehrt"</string>
     <string name="permlab_readLogs" msgid="6615778543198967614">"Lesen vertraulicher Protokolldaten"</string>
     <string name="permdesc_readLogs" product="tablet" msgid="4077356893924755294">"Ermöglicht einer Anwendung, die verschiedenen Protokolldateien des Systems zu lesen. So können allgemeine Informationen zu den auf Ihrem Tablet durchgeführten Aktionen eingesehen werden. Diese können persönliche oder geheime Daten enthalten."</string>
     <string name="permdesc_readLogs" product="default" msgid="8896449437464867766">"Ermöglicht einer Anwendung, die verschiedenen Protokolldateien des Systems zu lesen. So können allgemeine Informationen zu den auf Ihrem Telefon durchgeführten Aktionen eingesehen werden. Diese können persönliche oder geheime Daten enthalten."</string>
@@ -300,8 +300,8 @@
     <string name="permdesc_receiveBootCompleted" product="tablet" msgid="7530977064379338199">"Ermöglicht einer Anwendung, sich selbst zu starten, sobald das System gebootet wurde. Dadurch kann es länger dauern, bis das Tablet gestartet wird, und durch die ständige Aktivität der Anwendung wird die gesamte Leistung des Tablets beeinträchtigt."</string>
     <string name="permdesc_receiveBootCompleted" product="default" msgid="698336728415008796">"Ermöglicht einer Anwendung, sich selbst zu starten, sobald das System gebootet wurde. Dadurch kann es länger dauern, bis das Telefon gestartet wird, und durch die ständige Aktivität der Anwendung wird die gesamte Leistung des Telefons beeinträchtigt."</string>
     <string name="permlab_broadcastSticky" msgid="7919126372606881614">"dauerhaften Broadcast senden"</string>
-    <string name="permdesc_broadcastSticky" product="tablet" msgid="6322249605930062595">"Ermöglicht einer Anwendung, dauerhafte Broadcasts zu senden, die auch nach dem Ende des Broadcasts bestehen bleiben. Schädliche Anwendungen können das Tablet langsam oder instabil machen, da zu viel Speicherplatz belegt ist."</string>
-    <string name="permdesc_broadcastSticky" product="default" msgid="1920045289234052219">"Ermöglicht einer Anwendung, dauerhafte Broadcasts zu senden, die auch nach dem Ende des Broadcasts bestehen bleiben. Schädliche Anwendungen können das Telefon langsam oder unstabil machen, da zuviel Speicherplatz belegt ist."</string>
+    <string name="permdesc_broadcastSticky" product="tablet" msgid="6322249605930062595">"Ermöglicht einer Anwendung, dauerhafte Broadcasts zu senden, die auch nach dem Ende des Broadcasts bestehen bleiben. Schädliche Anwendungen können das Tablet langsam oder instabil machen, da zu viel Speicherplatz belegt wird."</string>
+    <string name="permdesc_broadcastSticky" product="default" msgid="1920045289234052219">"Ermöglicht einer Anwendung, dauerhafte Broadcasts zu senden, die auch nach dem Ende des Broadcasts bestehen bleiben. Schädliche Anwendungen können das Telefon langsam oder unstabil machen, da zuviel Speicherplatz belegt wird."</string>
     <string name="permlab_readContacts" msgid="6219652189510218240">"Kontaktdaten lesen"</string>
     <string name="permdesc_readContacts" product="tablet" msgid="7596158687301157686">"Ermöglicht einer Anwendung, alle auf Ihrem Tablet gespeicherten Kontaktdaten (Adressen) zu lesen. Schädliche Anwendungen können so Ihre Daten an andere Personen senden."</string>
     <string name="permdesc_readContacts" product="default" msgid="3371591512896545975">"Ermöglicht einer Anwendung, alle auf Ihrem Telefon gespeicherten Kontaktdaten (Adressen) zu lesen. Schädliche Anwendungen können so Ihre Daten an andere Personen senden."</string>
@@ -312,8 +312,8 @@
     <string name="permdesc_readCalendar" product="tablet" msgid="5905870265734599678">"Ermöglicht einer Anwendung, alle auf Ihrem Tablet gespeicherten Kalenderereignisse zu lesen. Schädliche Anwendungen können so Ihre Kalenderereignisse an andere Personen senden."</string>
     <string name="permdesc_readCalendar" product="default" msgid="5533029139652095734">"Ermöglicht einer Anwendung, alle auf Ihrem Telefon gespeicherten Kalenderereignisse zu lesen. Schädliche Anwendungen können so Ihre Kalenderereignisse an andere Personen senden."</string>
     <string name="permlab_writeCalendar" msgid="3894879352594904361">"Kalendereinträge hinzufügen oder ändern und E-Mails an Gäste senden"</string>
-    <string name="permdesc_writeCalendar" msgid="2988871373544154221">"Ermöglicht einer Anwendung, Einträge auf Ihrem Kalender hinzuzufügen oder zu ändern, die E-Mails an Gäste senden können. Schädliche Anwendungen können so Ihre Kalenderdaten löschen oder verändern oder E-Mails versenden."</string>
-    <string name="permlab_accessMockLocation" msgid="8688334974036823330">"Falsche Standortquellen für Testzwecke"</string>
+    <string name="permdesc_writeCalendar" msgid="2988871373544154221">"Ermöglicht einer Anwendung, Einträge in Ihrem Kalender hinzuzufügen oder zu ändern, wodurch E-Mails an Gäste gesendet werden können. Schädliche Anwendungen können so Ihre Kalenderdaten löschen oder verändern oder E-Mails versenden."</string>
+    <string name="permlab_accessMockLocation" msgid="8688334974036823330">"Simulierte Standortquellen für Testzwecke"</string>
     <string name="permdesc_accessMockLocation" msgid="7648286063459727252">"Erstellt falsche Standortquellen für Testzwecke. Schädliche Anwendungen können so den von den echten Standortquellen wie GPS oder Netzwerkanbieter zurückgegebenen Standort und/oder Status überschreiben."</string>
     <string name="permlab_accessLocationExtraCommands" msgid="2836308076720553837">"Auf zusätzliche Dienstanbieterbefehle für Standort zugreifen"</string>
     <string name="permdesc_accessLocationExtraCommands" msgid="1948144701382451721">"Zugriff auf zusätzliche Dienstanbieterbefehle für Standort. Schädliche Anwendungen könnten so die Funktionsweise von GPS oder anderen Standortquellen beeinträchtigen."</string>
@@ -324,29 +324,29 @@
     <string name="permdesc_accessFineLocation" product="default" msgid="7411213317434337331">"Zugriff auf genaue Standortquellen wie GPS auf dem Telefon (falls verfügbar). Schädliche Anwendungen können damit bestimmen, so Sie sich befinden und so Ihren Akku zusätzlich belasten."</string>
     <string name="permlab_accessCoarseLocation" msgid="4642255009181975828">"ungefährer (netzwerkbasierter) Standort"</string>
     <string name="permdesc_accessCoarseLocation" product="tablet" msgid="3704633168985466045">"Greift auf Quellen mit ungefähren Standortbestimmungen wie die Datenbank des Mobilfunknetzes zu, um falls möglich den ungefähren Standort des Tablets zu bestimmen. Schädliche Anwendungen können damit herauszufinden, wo Sie sich ungefähr befinden."</string>
-    <string name="permdesc_accessCoarseLocation" product="default" msgid="8235655958070862293">"Greift auf Quellen mit ungefähren Standortbestimmungen wie die Datenbank des Mobilfunknetzwerks zu, um falls möglich den ungefähren Standort des Telefons zu bestimmen. Schädliche Anwendungen können damit herauszufinden, wo Sie sich ungefähr befinden."</string>
+    <string name="permdesc_accessCoarseLocation" product="default" msgid="8235655958070862293">"Greift auf Quellen mit ungefähren Standortbestimmungen wie die Datenbank des Mobilfunknetzes zu, um falls möglich den ungefähren Standort des Tablets festzustellen. Schädliche Anwendungen können damit herausfinden, wo Sie sich ungefähr befinden"</string>
     <string name="permlab_accessSurfaceFlinger" msgid="2363969641792388947">"Auf SurfaceFlinger zugreifen"</string>
-    <string name="permdesc_accessSurfaceFlinger" msgid="6805241830020733025">"Ermöglicht einer Anwendung, die systemnahen SurfaceFlinger-Funktionen zu verwenden."</string>
+    <string name="permdesc_accessSurfaceFlinger" msgid="6805241830020733025">"Ermöglicht einer Anwendung, die systemnahen SurfaceFlinger-Funktionen zu verwenden"</string>
     <string name="permlab_readFrameBuffer" msgid="6690504248178498136">"Frame-Puffer lesen"</string>
-    <string name="permdesc_readFrameBuffer" msgid="7530020370469942528">"Ermöglicht einer Anwendung, den Content des Frame-Puffers zu lesen."</string>
+    <string name="permdesc_readFrameBuffer" msgid="7530020370469942528">"Ermöglicht einer Anwendung, den Content des Frame-Puffers zu lesen"</string>
     <string name="permlab_modifyAudioSettings" msgid="6095859937069146086">"Audio-Einstellungen ändern"</string>
-    <string name="permdesc_modifyAudioSettings" msgid="5793461287365991922">"Ermöglicht der Anwendung, Änderungen an allgemeinen Audioeinstellungen wie Lautstärke und Weiterleitung vorzunehmen."</string>
+    <string name="permdesc_modifyAudioSettings" msgid="5793461287365991922">"Ermöglicht der Anwendung, Änderungen an allgemeinen Audioeinstellungen wie Lautstärke und Weiterleitung vorzunehmen"</string>
     <string name="permlab_recordAudio" msgid="3876049771427466323">"Audio aufnehmen"</string>
-    <string name="permdesc_recordAudio" msgid="6493228261176552356">"Ermöglicht der Anwendung, auf den Pfad für Audioaufzeichnungen zuzugreifen."</string>
+    <string name="permdesc_recordAudio" msgid="6493228261176552356">"Ermöglicht der Anwendung, auf den Pfad für Audioaufzeichnungen zuzugreifen"</string>
     <string name="permlab_camera" msgid="3616391919559751192">"Bilder und Videos aufnehmen"</string>
     <string name="permdesc_camera" msgid="6004878235852154239">"Ermöglicht der Anwendung, Fotos und Videos mit der Kamera aufzunehmen. So kann die Anwendung jederzeit Bilder aus dem Sichtfeld der Kamera erfassen."</string>
     <string name="permlab_brick" product="tablet" msgid="2961292205764488304">"Tablet dauerhaft deaktivieren"</string>
-    <string name="permlab_brick" product="default" msgid="8337817093326370537">"Telefon dauerhaft deaktivieren."</string>
+    <string name="permlab_brick" product="default" msgid="8337817093326370537">"Telefon dauerhaft deaktivieren"</string>
     <string name="permdesc_brick" product="tablet" msgid="7379164636920817963">"Ermöglicht der Anwendung, das gesamte Tablet dauerhaft zu deaktivieren. Dies birgt hohe Risiken."</string>
     <string name="permdesc_brick" product="default" msgid="5569526552607599221">"Ermöglicht der Anwendung, das gesamte Telefon dauerhaft zu deaktivieren. Dies birgt hohe Risiken."</string>
     <string name="permlab_reboot" product="tablet" msgid="3436634972561795002">"Tablet-Neustart erzwingen"</string>
     <string name="permlab_reboot" product="default" msgid="2898560872462638242">"Neustart des Telefons erzwingen"</string>
     <string name="permdesc_reboot" product="tablet" msgid="4555793623560701557">"Ermöglicht der Anwendung, einen Neustart des Tablets zu erzwingen."</string>
-    <string name="permdesc_reboot" product="default" msgid="7914933292815491782">"Ermöglicht der Anwendung, einen Neustart des Telefons zu erzwingen."</string>
+    <string name="permdesc_reboot" product="default" msgid="7914933292815491782">"Ermöglicht der Anwendung, einen Neustart des Telefons zu erzwingen"</string>
     <string name="permlab_mount_unmount_filesystems" msgid="1761023272170956541">"Dateisysteme bereitstellen oder Bereitstellung aufheben"</string>
-    <string name="permdesc_mount_unmount_filesystems" msgid="6253263792535859767">"Ermöglicht der Anwendung, Dateisysteme für austauschbare Datenträger bereitzustellen oder die Bereitstellung aufzuheben."</string>
+    <string name="permdesc_mount_unmount_filesystems" msgid="6253263792535859767">"Ermöglicht der Anwendung, Dateisysteme für austauschbare Datenträger bereitzustellen oder die Bereitstellung aufzuheben"</string>
     <string name="permlab_mount_format_filesystems" msgid="5523285143576718981">"Externen Speicher formatieren"</string>
-    <string name="permdesc_mount_format_filesystems" msgid="574060044906047386">"Ermöglicht der Anwendung, austauschbare Datenträger zu formatieren."</string>
+    <string name="permdesc_mount_format_filesystems" msgid="574060044906047386">"Ermöglicht der Anwendung, austauschbare Datenträger zu formatieren"</string>
     <string name="permlab_asec_access" msgid="3411338632002193846">"Informationen zum internen Speicher abrufen"</string>
     <string name="permdesc_asec_access" msgid="8820326551687285439">"Ermöglicht der Anwendung, Informationen zum internen Speicher abzurufen."</string>
     <string name="permlab_asec_create" msgid="6414757234789336327">"Internen Speicher erstellen"</string>
@@ -358,15 +358,15 @@
     <string name="permlab_asec_rename" msgid="7496633954080472417">"Internen Speicher umbenennen"</string>
     <string name="permdesc_asec_rename" msgid="2152829985238876790">"Ermöglicht der Anwendung, den internen Speicher umzubenennen."</string>
     <string name="permlab_vibrate" msgid="7768356019980849603">"Vibrationsalarm steuern"</string>
-    <string name="permdesc_vibrate" msgid="2886677177257789187">"Ermöglicht der Anwendung, den Vibrationsalarm zu steuern."</string>
+    <string name="permdesc_vibrate" msgid="2886677177257789187">"Ermöglicht der Anwendung, den Vibrationsalarm zu steuern"</string>
     <string name="permlab_flashlight" msgid="2155920810121984215">"Lichtanzeige steuern"</string>
-    <string name="permdesc_flashlight" msgid="6433045942283802309">"Ermöglicht der Anwendung, die Lichtanzeige zu steuern."</string>
-    <string name="permlab_accessUsb" msgid="7362327818655760496">"auf USB-Geräte zugreifen"</string>
-    <string name="permdesc_accessUsb" msgid="2414271762914049292">"Ermöglicht der Anwendung den Zugriff auf USB-Geräte."</string>
+    <string name="permdesc_flashlight" msgid="6433045942283802309">"Ermöglicht der Anwendung, die Lichtanzeige zu steuern"</string>
+    <string name="permlab_manageUsb" msgid="1113453430645402723">"Einstellungen und Berechtigungen für USB-Geräte verwalten"</string>
+    <string name="permdesc_manageUsb" msgid="6148489202092166164">"Ermöglicht der Anwendung das Verwalten von Einstellungen und Berechtigungen für USB-Geräte"</string>
     <string name="permlab_accessMtp" msgid="4953468676795917042">"MTP-Protokoll implementieren"</string>
     <string name="permdesc_accessMtp" msgid="6532961200486791570">"Erlaubt den Zugriff auf den Kernel-MTP-Treiber zur Implementierung des MTP-USB-Protokolls."</string>
     <string name="permlab_hardware_test" msgid="4148290860400659146">"Hardware testen"</string>
-    <string name="permdesc_hardware_test" msgid="3668894686500081699">"Ermöglicht einer Anwendung, verschiedene Peripherie-Geräte zu Hardware-Testzwecken zu steuern."</string>
+    <string name="permdesc_hardware_test" msgid="3668894686500081699">"Ermöglicht einer Anwendung, verschiedene Peripherie-Geräte zu Hardware-Testzwecken zu steuern"</string>
     <string name="permlab_callPhone" msgid="3925836347681847954">"Telefonnummern direkt anrufen"</string>
     <string name="permdesc_callPhone" msgid="3369867353692722456">"Ermöglicht dem Anwendungen, Rufnummern ohne Ihr Eingreifen zu wählen. Schädliche Anwendungen können für unerwartete Anrufe auf Ihrer Telefonrechnung verantwortlich sein. Das Wählen von Notrufnummern ist allerdings nicht möglich."</string>
     <string name="permlab_callPrivileged" msgid="4198349211108497879">"Alle Telefonnummern direkt anrufen"</string>
@@ -387,80 +387,80 @@
     <string name="permlab_wakeLock" product="tablet" msgid="1531731435011495015">"Standby-Modus des Tablets deaktivieren"</string>
     <string name="permlab_wakeLock" product="default" msgid="573480187941496130">"Standby-Modus deaktivieren"</string>
     <string name="permdesc_wakeLock" product="tablet" msgid="4032181488045338551">"Ermöglicht einer Anwendung, den Standby-Modus des Tablets zu deaktivieren."</string>
-    <string name="permdesc_wakeLock" product="default" msgid="7584036471227467099">"Ermöglicht einer Anwendung, den Standby-Modus des Telefons zu deaktivieren."</string>
+    <string name="permdesc_wakeLock" product="default" msgid="7584036471227467099">"Ermöglicht einer Anwendung, den Standby-Modus des Telefons zu deaktivieren"</string>
     <string name="permlab_devicePower" product="tablet" msgid="2787034722616350417">"Tablet ein- oder ausschalten"</string>
     <string name="permlab_devicePower" product="default" msgid="4928622470980943206">"Gerät ein- oder ausschalten"</string>
     <string name="permdesc_devicePower" product="tablet" msgid="3853773100100451905">"Ermöglicht der Anwendung, das Tablet ein- oder auszuschalten."</string>
-    <string name="permdesc_devicePower" product="default" msgid="4577331933252444818">"Ermöglicht der Anwendung, das Telefon ein- oder auszuschalten."</string>
+    <string name="permdesc_devicePower" product="default" msgid="4577331933252444818">"Ermöglicht der Anwendung, das Telefon ein- oder auszuschalten"</string>
     <string name="permlab_factoryTest" msgid="3715225492696416187">"In Werkstestmodus ausführen"</string>
-    <string name="permdesc_factoryTest" product="tablet" msgid="3952059318359653091">"Führt einen systemnahen Herstellertest durch, in dessen Rahmen auf die gesamte Tablet-Hardware zugegriffen werden kann. Nur verfügbar, wenn ein Tablet im Werkstestmodus ausgeführt wird."</string>
-    <string name="permdesc_factoryTest" product="default" msgid="8136644990319244802">"Führt einen systemnahen Herstellertest durch, in dessen Rahmen auf die gesamte Telefonhardware zugegriffen werden kann. Nur verfügbar, wenn ein Telefon im Werkstestmodus ausgeführt wird."</string>
+    <string name="permdesc_factoryTest" product="tablet" msgid="3952059318359653091">"Führt einen systemnahen Herstellertest durch, in dessen Rahmen auf die gesamte Tablet-Hardware zugegriffen werden kann. Nur verfügbar, wenn ein Tablet im Herstellertestmodus ausgeführt wird."</string>
+    <string name="permdesc_factoryTest" product="default" msgid="8136644990319244802">"Führt einen systemnahen Herstellertest durch, in dessen Rahmen auf die gesamte Telefon-Hardware zugegriffen werden kann. Nur verfügbar, wenn ein Telefon im Herstellertestmodus ausgeführt wird."</string>
     <string name="permlab_setWallpaper" msgid="6627192333373465143">"Hintergrund festlegen"</string>
-    <string name="permdesc_setWallpaper" msgid="6417041752170585837">"Ermöglicht der Anwendung, den System-Hintergrund festzulegen."</string>
+    <string name="permdesc_setWallpaper" msgid="6417041752170585837">"Ermöglicht der Anwendung, den System-Hintergrund festzulegen"</string>
     <string name="permlab_setWallpaperHints" msgid="3600721069353106851">"Größenhinweise für Hintergrund festlegen"</string>
-    <string name="permdesc_setWallpaperHints" msgid="6019479164008079626">"Ermöglicht der Anwendung, die Größenhinweise für den Hintergrund festzulegen."</string>
+    <string name="permdesc_setWallpaperHints" msgid="6019479164008079626">"Ermöglicht der Anwendung, die Größenhinweise für den Hintergrund festzulegen"</string>
     <string name="permlab_masterClear" msgid="2315750423139697397">"System auf Werkseinstellung zurücksetzen"</string>
     <string name="permdesc_masterClear" msgid="5033465107545174514">"Ermöglicht einer Anwendung, das System komplett auf Werkseinstellung zurückzusetzen. Hierbei werden alle Daten, Konfigurationen und installierten Anwendungen gelöscht."</string>
     <string name="permlab_setTime" msgid="2021614829591775646">"Zeit einstellen"</string>
-    <string name="permdesc_setTime" product="tablet" msgid="209693136361006073">"Ermöglicht einer Anwendung, die Uhrzeit des Tablets zu ändern."</string>
-    <string name="permdesc_setTime" product="default" msgid="667294309287080045">"Ermöglicht einer Anwendung, die Uhrzeit des Telefons zu ändern."</string>
+    <string name="permdesc_setTime" product="tablet" msgid="209693136361006073">"Ermöglicht einer Anwendung, die Uhrzeit des Tablets zu ändern"</string>
+    <string name="permdesc_setTime" product="default" msgid="667294309287080045">"Ermöglicht einer Anwendung, die Uhrzeit des Telefons zu ändern"</string>
     <string name="permlab_setTimeZone" msgid="2945079801013077340">"Zeitzone festlegen"</string>
     <string name="permdesc_setTimeZone" product="tablet" msgid="2522877107613885139">"Ermöglicht einer Anwendung, die Zeitzone des Tablets zu ändern."</string>
-    <string name="permdesc_setTimeZone" product="default" msgid="1902540227418179364">"Ermöglicht einer Anwendung, die Zeitzone des Telefons zu ändern."</string>
+    <string name="permdesc_setTimeZone" product="default" msgid="1902540227418179364">"Ermöglicht einer Anwendung, die Zeitzone des Telefons zu ändern"</string>
     <string name="permlab_accountManagerService" msgid="4829262349691386986">"Als Konto-Manager fungieren"</string>
-    <string name="permdesc_accountManagerService" msgid="6056903274106394752">"Ermöglicht einer Anwendung, Anrufe an Konto-Authentifizierer zu tätigen."</string>
+    <string name="permdesc_accountManagerService" msgid="6056903274106394752">"Ermöglicht einer Anwendung, Anrufe an Konto-Authentifizierer zu tätigen"</string>
     <string name="permlab_getAccounts" msgid="4549918644233460103">"bekannte Konten suchen"</string>
     <string name="permdesc_getAccounts" product="tablet" msgid="857622793935544694">"Ermöglicht einer Anwendung, eine Liste der dem Tablet bekannten Konten abzurufen."</string>
-    <string name="permdesc_getAccounts" product="default" msgid="6839262446413155394">"Ermöglicht einer Anwendung, eine Liste der dem Telefon bekannten Konten abzurufen."</string>
+    <string name="permdesc_getAccounts" product="default" msgid="6839262446413155394">"Ermöglicht einer Anwendung, eine Liste der dem Telefon bekannten Konten abzurufen"</string>
     <string name="permlab_authenticateAccounts" msgid="3940505577982882450">"Als Kontoauthentifizierer fungieren"</string>
-    <string name="permdesc_authenticateAccounts" msgid="4006839406474208874">"Ermöglicht einer Anwendung, die Kontoauthentifizierungsfunktionen des Konto-Managers zu verwenden, einschließlich die Funktionen zum Erstellen von Konten und zum Abrufen und Einstellen der entsprechenden Passwörter."</string>
+    <string name="permdesc_authenticateAccounts" msgid="4006839406474208874">"Ermöglicht einer Anwendung, die Kontoauthentifizierungsfunktionen des Konto-Managers zu verwenden, einschließlich die Funktionen zum Erstellen von Konten und zum Abrufen und Einstellen der entsprechenden Passwörter"</string>
     <string name="permlab_manageAccounts" msgid="4440380488312204365">"Kontoliste verwalten"</string>
-    <string name="permdesc_manageAccounts" msgid="8804114016661104517">"Ermöglicht einer Anwendung, Konten hinzuzufügen und zu entfernen oder deren Passwörter zu löschen."</string>
+    <string name="permdesc_manageAccounts" msgid="8804114016661104517">"Ermöglicht einer Anwendung, Konten hinzuzufügen und zu entfernen oder deren Passwörter zu löschen"</string>
     <string name="permlab_useCredentials" msgid="6401886092818819856">"Authentifizierungsinformationen eines Kontos verwenden"</string>
-    <string name="permdesc_useCredentials" msgid="7416570544619546974">"Ermöglicht einer Anwendung, Authentifizierungs-Token anzufordern."</string>
+    <string name="permdesc_useCredentials" msgid="7416570544619546974">"Ermöglicht einer Anwendung, Authentifizierungs-Token anzufordern"</string>
     <string name="permlab_accessNetworkState" msgid="6865575199464405769">"Netzwerkstatus anzeigen"</string>
-    <string name="permdesc_accessNetworkState" msgid="558721128707712766">"Ermöglicht einer Anwendung, den Status aller Netzwerke anzuzeigen."</string>
+    <string name="permdesc_accessNetworkState" msgid="558721128707712766">"Ermöglicht einer Anwendung, den Status aller Netzwerke anzuzeigen"</string>
     <string name="permlab_createNetworkSockets" msgid="9121633680349549585">"uneingeschränkter Internetzugriff"</string>
-    <string name="permdesc_createNetworkSockets" msgid="4593339106921772192">"Ermöglicht einer Anwendung, Netzwerk-Sockets einzurichten."</string>
+    <string name="permdesc_createNetworkSockets" msgid="4593339106921772192">"Ermöglicht einer Anwendung, Netzwerk-Sockets einzurichten"</string>
     <string name="permlab_writeApnSettings" msgid="7823599210086622545">"Einstellungen für Zugriffspunktname schreiben"</string>
-    <string name="permdesc_writeApnSettings" msgid="7443433457842966680">"Ermöglicht einer Anwendung, die APN-Einstellungen wie Proxy und Port eines Zugriffspunkts zu ändern."</string>
+    <string name="permdesc_writeApnSettings" msgid="7443433457842966680">"Ermöglicht einer Anwendung, die APN-Einstellungen wie Proxy und Port eines Zugriffspunkts zu ändern"</string>
     <string name="permlab_changeNetworkState" msgid="958884291454327309">"Netzwerkkonnektivität ändern"</string>
-    <string name="permdesc_changeNetworkState" msgid="4199958910396387075">"Ermöglicht einer Anwendung, den Status der Netzwerkkonnektivität zu ändern."</string>
+    <string name="permdesc_changeNetworkState" msgid="4199958910396387075">"Ermöglicht einer Anwendung, den Status der Netzwerkkonnektivität zu ändern"</string>
     <string name="permlab_changeTetherState" msgid="2702121155761140799">"Tethering-Konnektivität ändern"</string>
-    <string name="permdesc_changeTetherState" msgid="8905815579146349568">"Ermöglicht einer Anwendung, den Status der Tethering-Konnektivität zu ändern."</string>
+    <string name="permdesc_changeTetherState" msgid="8905815579146349568">"Ermöglicht einer Anwendung, den Status der Tethering-Konnektivität zu ändern"</string>
     <string name="permlab_changeBackgroundDataSetting" msgid="1400666012671648741">"Einstellung zur Verwendung von Hintergrunddaten ändern"</string>
-    <string name="permdesc_changeBackgroundDataSetting" msgid="1001482853266638864">"Ermöglicht einer Anwendung, die Einstellung der Verwendung von Hintergrunddaten zu ändern."</string>
+    <string name="permdesc_changeBackgroundDataSetting" msgid="1001482853266638864">"Ermöglicht einer Anwendung, die Einstellung der Verwendung von Hintergrunddaten zu ändern"</string>
     <string name="permlab_accessWifiState" msgid="8100926650211034400">"WLAN-Status anzeigen"</string>
-    <string name="permdesc_accessWifiState" msgid="485796529139236346">"Ermöglicht einer Anwendung, die Informationen zum WLAN-Status einzusehen."</string>
+    <string name="permdesc_accessWifiState" msgid="485796529139236346">"Ermöglicht einer Anwendung, die Informationen zum WLAN-Status einzusehen"</string>
     <string name="permlab_changeWifiState" msgid="7280632711057112137">"WLAN-Status ändern"</string>
-    <string name="permdesc_changeWifiState" msgid="2950383153656873267">"Ermöglicht einer Anwendung, eine Verbindung zu den WLAN-Zugangspunkten herzustellen und diese zu trennen oder Änderungen an den konfigurierten WLAN-Netzwerken vorzunehmen."</string>
+    <string name="permdesc_changeWifiState" msgid="2950383153656873267">"Ermöglicht einer Anwendung, eine Verbindung zu den WLAN-Zugangspunkten herzustellen und diese zu trennen oder Änderungen an den konfigurierten WLAN-Netzwerken vorzunehmen"</string>
     <string name="permlab_changeWifiMulticastState" msgid="1368253871483254784">"WLAN-Multicast-Empfang zulassen"</string>
     <string name="permdesc_changeWifiMulticastState" msgid="8199464507656067553">"Ermöglicht einer Anwendung, Datenpakete zu empfangen, die nicht direkt an Ihr Gerät gerichtet sind. Dies kann bei der Erkennung von in der Nähe angebotenen Diensten hilfreich sein. Diese Einstellung verbraucht mehr Energie als der Nicht-Multicast-Modus."</string>
     <string name="permlab_bluetoothAdmin" msgid="1092209628459341292">"Bluetooth-Verwaltung"</string>
     <string name="permdesc_bluetoothAdmin" product="tablet" msgid="3511795757324345837">"Ermöglicht einer Anwendung, das lokale Bluetooth-Tablet zu konfigurieren, Remote-Geräte zu erkennen und eine Verbindung zu diesen herzustellen."</string>
-    <string name="permdesc_bluetoothAdmin" product="default" msgid="7256289774667054555">"Ermöglicht einer Anwendung, das lokale Bluetooth-Telefon zu konfigurieren, Remote-Geräte zu erkennen und eine Verbindung zu diesen herzustellen."</string>
+    <string name="permdesc_bluetoothAdmin" product="default" msgid="7256289774667054555">"Ermöglicht einer Anwendung, das lokale Bluetooth-Telefon zu konfigurieren, Remote-Geräte zu erkennen und eine Verbindung zu diesen herzustellen"</string>
     <string name="permlab_bluetooth" msgid="8361038707857018732">"Bluetooth-Verbindungen herstellen"</string>
     <string name="permdesc_bluetooth" product="tablet" msgid="4191941825910543803">"Ermöglicht einer Anwendung, die Konfiguration des lokalen Bluetooth-Tablets einzusehen und Verbindungen mit Partnergeräten herzustellen und zu akzeptieren."</string>
-    <string name="permdesc_bluetooth" product="default" msgid="762515380679392945">"Ermöglicht einer Anwendung, die Konfiguration des lokalen Bluetooth-Telefons einzusehen und Verbindungen mit Partnergeräten herzustellen und zu akzeptieren."</string>
+    <string name="permdesc_bluetooth" product="default" msgid="762515380679392945">"Ermöglicht einer Anwendung, die Konfiguration des lokalen Bluetooth-Telefons einzusehen und Verbindungen mit Partnergeräten herzustellen und zu akzeptieren"</string>
     <string name="permlab_nfc" msgid="4423351274757876953">"Nahfeldkommunikation steuern"</string>
-    <string name="permdesc_nfc" msgid="9171401851954407226">"Ermöglicht einer Anwendung die Kommunikation mit Tags für die Nahfeldkommunikation, Karten und Readern."</string>
+    <string name="permdesc_nfc" msgid="9171401851954407226">"Ermöglicht einer Anwendung die Kommunikation mit Tags für Nahfeldkommunikation, Karten und Lesegeräte"</string>
     <string name="permlab_disableKeyguard" msgid="4977406164311535092">"Tastensperre deaktivieren"</string>
     <string name="permdesc_disableKeyguard" msgid="3189763479326302017">"Ermöglicht einer Anwendung, die Tastensperre sowie den damit verbundenen Passwortschutz zu deaktivieren. So wird die Tastensperre vom Telefon deaktiviert, wenn ein Anruf eingeht, und nach Beendigung des Anrufs wieder aktiviert."</string>
     <string name="permlab_readSyncSettings" msgid="6201810008230503052">"Synchronisierungseinstellungen lesen"</string>
-    <string name="permdesc_readSyncSettings" msgid="5315925706353341823">"Ermöglicht einer Anwendung, die Synchronisierungseinstellungen zu lesen, etwa ob die Synchronisierung für Kontakte aktiviert ist oder nicht."</string>
+    <string name="permdesc_readSyncSettings" msgid="5315925706353341823">"Ermöglicht einer Anwendung, die Synchronisierungseinstellungen zu lesen, etwa ob die Synchronisierung für Kontakte aktiviert ist oder nicht"</string>
     <string name="permlab_writeSyncSettings" msgid="6297138566442486462">"Synchronisierungseinstellungen schreiben"</string>
-    <string name="permdesc_writeSyncSettings" msgid="2498201614431360044">"Ermöglicht einer Anwendung, die Synchronisierungseinstellungen zu ändern, etwa ob die Synchronisierung für Kontakte aktiviert ist oder nicht."</string>
+    <string name="permdesc_writeSyncSettings" msgid="2498201614431360044">"Ermöglicht einer Anwendung, die Synchronisierungseinstellungen zu ändern, etwa ob die Synchronisierung für Kontakte aktiviert ist oder nicht"</string>
     <string name="permlab_readSyncStats" msgid="7396577451360202448">"Synchronisierungsstatistiken lesen"</string>
-    <string name="permdesc_readSyncStats" msgid="7511448343374465000">"Ermöglicht einer Anwendung, die Synchronisierungsstatistiken zu lesen, etwa den Verlauf der bereits durchgeführten Synchronisierungen."</string>
+    <string name="permdesc_readSyncStats" msgid="7511448343374465000">"Ermöglicht einer Anwendung, die Synchronisierungsstatistiken zu lesen, etwa den Verlauf der bereits durchgeführten Synchronisierungen"</string>
     <string name="permlab_subscribedFeedsRead" msgid="4756609637053353318">"abonnierte Feeds lesen"</string>
-    <string name="permdesc_subscribedFeedsRead" msgid="3622200625634207660">"Ermöglicht einer Anwendung, Details zu den zurzeit synchronisierten Feeds abzurufen."</string>
+    <string name="permdesc_subscribedFeedsRead" msgid="3622200625634207660">"Ermöglicht einer Anwendung, Details zu den zurzeit synchronisierten Feeds abzurufen"</string>
     <string name="permlab_subscribedFeedsWrite" msgid="9015246325408209296">"abonnierte Feeds schreiben"</string>
     <string name="permdesc_subscribedFeedsWrite" msgid="8121607099326533878">"Ermöglicht einer Anwendung, Änderungen an den kürzlich synchronisierten Feeds vorzunehmen. Schädliche Anwendungen könnten so Ihre synchronisierten Feeds ändern."</string>
     <string name="permlab_readDictionary" msgid="432535716804748781">"nutzerdefiniertes Wörterbuch lesen"</string>
-    <string name="permdesc_readDictionary" msgid="1082972603576360690">"Ermöglicht einer Anwendung, alle privaten Wörter, Namen und Ausdrücke zu lesen, die ein Nutzer in seinem Wörterbuch gespeichert hat."</string>
+    <string name="permdesc_readDictionary" msgid="1082972603576360690">"Ermöglicht einer Anwendung, alle privaten Wörter, Namen und Ausdrücke zu lesen, die ein Nutzer in seinem Wörterbuch gespeichert hat"</string>
     <string name="permlab_writeDictionary" msgid="6703109511836343341">"in nutzerdefiniertes Wörterbuch schreiben"</string>
-    <string name="permdesc_writeDictionary" msgid="2241256206524082880">"Ermöglicht einer Anwendung, Ihrem Wörterbuch neue Einträge hinzuzufügen."</string>
-    <string name="permlab_sdcardWrite" product="nosdcard" msgid="85430876310764752">"USB-Speicherinh. ändern/lösch."</string>
+    <string name="permdesc_writeDictionary" msgid="2241256206524082880">"Ermöglicht einer Anwendung, Ihrem Wörterbuch neue Einträge hinzuzufügen"</string>
+    <string name="permlab_sdcardWrite" product="nosdcard" msgid="85430876310764752">"USB-Speicherinhalt ändern/löschen"</string>
     <string name="permlab_sdcardWrite" product="default" msgid="8079403759001777291">"SD-Karten-Inhalt ändern/löschen"</string>
     <string name="permdesc_sdcardWrite" product="nosdcard" msgid="6594393334785738252">"Ermöglicht der Anwendung Schreiben in USB-Speicher"</string>
     <string name="permdesc_sdcardWrite" product="default" msgid="6643963204976471878">"Ermöglicht einer Anwendung, auf die SD-Karte zu schreiben"</string>
@@ -469,7 +469,7 @@
     <string name="permlab_cache_filesystem" msgid="5656487264819669824">"Zugriff auf das Cache-Dateisystem"</string>
     <string name="permdesc_cache_filesystem" msgid="1624734528435659906">"Gewährt einer Anwendung Lese- und Schreibzugriff auf das Cache-Dateisystem."</string>
     <string name="permlab_use_sip" msgid="5986952362795870502">"Internetanrufe tätigen/annehmen"</string>
-    <string name="permdesc_use_sip" msgid="6320376185606661843">"Ermöglicht einer Anwendung die Verwendung des SIP-Dienstes zum Tätigen/Annehmen von Internetanrufen."</string>
+    <string name="permdesc_use_sip" msgid="6320376185606661843">"Ermöglicht einer Anwendung die Verwendung des SIP-Dienstes zum Tätigen/Annehmen von Internetanrufen"</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"Passwortregeln festlegen"</string>
     <string name="policydesc_limitPassword" msgid="9083400080861728056">"Zulässige Länge und Zeichen für Passwörter zum Entsperren des Displays festlegen"</string>
     <string name="policylab_watchLogin" msgid="914130646942199503">"Versuche zum Entsperren des Displays überwachen"</string>
@@ -478,14 +478,14 @@
     <string name="policylab_resetPassword" msgid="2620077191242688955">"Passwort zum Entsperren des Displays ändern"</string>
     <string name="policydesc_resetPassword" msgid="5391240616981297361">"Passwort zum Entsperren des Displays ändern"</string>
     <string name="policylab_forceLock" msgid="2274085384704248431">"Display sperren"</string>
-    <string name="policydesc_forceLock" msgid="5696964126226028442">"Steuern Sie, wie und wann das Display gesperrt wird."</string>
+    <string name="policydesc_forceLock" msgid="5696964126226028442">"Festlegen, wie und wann das Display gesperrt wird"</string>
     <string name="policylab_wipeData" msgid="3910545446758639713">"Alle Daten löschen"</string>
     <string name="policydesc_wipeData" product="tablet" msgid="314455232799486222">"Auf Werkseinstellungen zurücksetzen und Daten auf dem Tablet ohne Warnung löschen"</string>
     <string name="policydesc_wipeData" product="default" msgid="7669895333814222586">"Auf Werkseinstellungen zurücksetzen und Daten auf dem Telefon ohne Warnung löschen"</string>
     <string name="policylab_setGlobalProxy" msgid="2784828293747791446">"Den globalen Proxy des Geräts festlegen"</string>
-    <string name="policydesc_setGlobalProxy" msgid="6387497466660154931">"Den globalen Proxy des Geräts zur Verwendung während der Aktivierung der Richtlinie festlegen. Nur der erste Geräteadministrator kann den gültigen globalen Proxy festlegen."</string>
-    <!-- outdated translation 4740941403188940274 -->     <string name="policylab_expirePassword" msgid="885279151847254056">"Ablauf des Passworts festlegen"</string>
-    <!-- outdated translation 6626724939177185949 -->     <string name="policydesc_expirePassword" msgid="4844430354224822074">"Zeitraum bis zur Änderung des Passworts für die Bildschirmsperre festlegen"</string>
+    <string name="policydesc_setGlobalProxy" msgid="6387497466660154931">"Den bei aktivierter Richtlinie zu verwendenden globalen Proxy des Geräts festlegen. Nur der erste Geräteadministrator kann den gültigen globalen Proxy festlegen."</string>
+    <string name="policylab_expirePassword" msgid="885279151847254056">"Ablauf von Sperr-Passwort festlegen"</string>
+    <string name="policydesc_expirePassword" msgid="4844430354224822074">"Legen Sie fest, wie häufig das Passwort zum Sperren des Bildschirms geändert werden muss."</string>
     <string name="policylab_encryptedStorage" msgid="8901326199909132915">"Speicherverschlüsselung"</string>
     <string name="policydesc_encryptedStorage" msgid="2504984732631479399">"Anforderung, dass gespeicherte Anwendungsdaten verschlüsselt werden"</string>
   <string-array name="phoneTypes">
@@ -495,19 +495,19 @@
     <item msgid="1103601433382158155">"Fax (geschäftl.)"</item>
     <item msgid="1735177144948329370">"Fax (privat)"</item>
     <item msgid="603878674477207394">"Pager"</item>
-    <item msgid="1650824275177931637">"Sonstige"</item>
+    <item msgid="1650824275177931637">"Andere"</item>
     <item msgid="9192514806975898961">"Benutzerdefiniert"</item>
   </string-array>
   <string-array name="emailAddressTypes">
     <item msgid="8073994352956129127">"Privat"</item>
     <item msgid="7084237356602625604">"Geschäftlich"</item>
-    <item msgid="1112044410659011023">"Sonstige"</item>
+    <item msgid="1112044410659011023">"Andere"</item>
     <item msgid="2374913952870110618">"Benutzerdefiniert"</item>
   </string-array>
   <string-array name="postalAddressTypes">
     <item msgid="6880257626740047286">"Privat"</item>
     <item msgid="5629153956045109251">"Geschäftlich"</item>
-    <item msgid="4966604264500343469">"Sonstige"</item>
+    <item msgid="4966604264500343469">"Andere"</item>
     <item msgid="4932682847595299369">"Benutzerdefiniert"</item>
   </string-array>
   <string-array name="imAddressTypes">
@@ -518,7 +518,7 @@
   </string-array>
   <string-array name="organizationTypes">
     <item msgid="7546335612189115615">"Geschäftlich"</item>
-    <item msgid="4378074129049520373">"Sonstige"</item>
+    <item msgid="4378074129049520373">"Andere"</item>
     <item msgid="3455047468583965104">"Benutzerdefiniert"</item>
   </string-array>
   <string-array name="imProtocols">
@@ -593,10 +593,10 @@
     <string name="relationTypeMother" msgid="4578571352962758304">"Mutter"</string>
     <string name="relationTypeParent" msgid="4755635567562925226">"Elternteil"</string>
     <string name="relationTypePartner" msgid="7266490285120262781">"Partner"</string>
-    <string name="relationTypeReferredBy" msgid="101573059844135524">"Weitergeleitet von"</string>
+    <string name="relationTypeReferredBy" msgid="101573059844135524">"Empfehlung von"</string>
     <string name="relationTypeRelative" msgid="1799819930085610271">"Verwandter"</string>
     <string name="relationTypeSister" msgid="1735983554479076481">"Schwester"</string>
-    <string name="relationTypeSpouse" msgid="394136939428698117">"Gatte/Gattin"</string>
+    <string name="relationTypeSpouse" msgid="394136939428698117">"Ehepartner"</string>
     <string name="sipAddressTypeCustom" msgid="2473580593111590945">"Benutzerdefiniert"</string>
     <string name="sipAddressTypeHome" msgid="6093598181069359295">"Privat"</string>
     <string name="sipAddressTypeWork" msgid="6920725730797099047">"Geschäftlich"</string>
@@ -609,7 +609,7 @@
     <string name="keyguard_label_text" msgid="861796461028298424">"Drücken Sie zum Entsperren die Menütaste und dann auf \"0\"."</string>
     <string name="emergency_call_dialog_number_for_display" msgid="696192103195090970">"Notrufnummer"</string>
     <string name="lockscreen_carrier_default" msgid="8812714795156374435">"(kein Dienst)"</string>
-    <string name="lockscreen_screen_locked" msgid="7288443074806832904">"Display gesperrt."</string>
+    <string name="lockscreen_screen_locked" msgid="7288443074806832904">"Display gesperrt"</string>
     <string name="lockscreen_instructions_when_pattern_enabled" msgid="46154051614126049">"Drücken Sie die Menütaste, um das Telefon zu entsperren oder einen Notruf zu tätigen."</string>
     <string name="lockscreen_instructions_when_pattern_disabled" msgid="686260028797158364">"Zum Entsperren die Menütaste drücken"</string>
     <string name="lockscreen_pattern_instructions" msgid="7478703254964810302">"Muster zum Entsperren zeichnen"</string>
@@ -628,7 +628,7 @@
     <string name="lockscreen_missing_sim_instructions" msgid="8874620818937719067">"Bitte legen Sie eine SIM-Karte ein."</string>
     <string name="emergency_calls_only" msgid="6733978304386365407">"Nur Notrufe"</string>
     <string name="lockscreen_network_locked_message" msgid="143389224986028501">"Netzwerk gesperrt"</string>
-    <string name="lockscreen_sim_puk_locked_message" msgid="7441797339976230">"SIM-Karte ist gesperrt. PUK-Eingabe erforderlich."</string>
+    <string name="lockscreen_sim_puk_locked_message" msgid="7441797339976230">"PUK-Sperre auf SIM"</string>
     <string name="lockscreen_sim_puk_locked_instructions" msgid="635967534992394321">"Weitere Informationen finden Sie in der Bedienungsanleitung oder wenden Sie sich an den Kundendienst."</string>
     <string name="lockscreen_sim_locked_message" msgid="8066660129206001039">"Bitte PIN-Code eingeben"</string>
     <string name="lockscreen_sim_unlock_progress_dialog_message" msgid="595323214052881264">"SIM-Karte wird entsperrt..."</string>
@@ -672,7 +672,7 @@
     <string name="autofill_address_summary_separator" msgid="7483307893170324129">", "</string>
     <string name="autofill_address_summary_format" msgid="4874459455786827344">"$1$2$3"</string>
     <string name="permlab_readHistoryBookmarks" msgid="1284843728203412135">"Browserverlauf und Lesezeichen lesen"</string>
-    <string name="permdesc_readHistoryBookmarks" msgid="4981489815467617191">"Ermöglicht der Anwendung, alle URLs, die mit dem Browser besucht wurden, sowie alle Lesezeichen des Browsers zu lesen."</string>
+    <string name="permdesc_readHistoryBookmarks" msgid="4981489815467617191">"Ermöglicht der Anwendung, alle URLs, die mit dem Browser besucht wurden, sowie alle Lesezeichen des Browsers zu lesen"</string>
     <string name="permlab_writeHistoryBookmarks" msgid="9009434109836280374">"Browserverlauf und Lesezeichen schreiben"</string>
     <string name="permdesc_writeHistoryBookmarks" product="tablet" msgid="7193514090469945307">"Ermöglicht einer Anwendung, den auf Ihrem Tablet gespeicherten Browserverlauf und die Lesezeichen zu ändern. Schädliche Anwendungen können so Ihre Browserdaten löschen oder ändern."</string>
     <string name="permdesc_writeHistoryBookmarks" product="default" msgid="945571990357114950">"Ermöglicht einer Anwendung, den auf Ihrem Telefon gespeicherten Browserverlauf und die Lesezeichen zu ändern. Schädliche Anwendungen können so Ihre Browserdaten löschen oder ändern."</string>
@@ -691,7 +691,7 @@
     <string name="menu_space_shortcut_label" msgid="2410328639272162537">"Leerzeichen"</string>
     <string name="menu_enter_shortcut_label" msgid="2743362785111309668">"Enter"</string>
     <string name="menu_delete_shortcut_label" msgid="3658178007202748164">"löschen"</string>
-    <string name="search_go" msgid="8298016669822141719">"Suche"</string>
+    <string name="search_go" msgid="8298016669822141719">"Suchen"</string>
     <string name="oneMonthDurationPast" msgid="7396384508953779925">"Vor 1 Monat"</string>
     <string name="beforeOneMonthDurationPast" msgid="909134546836499826">"Vor mehr als 1 Monat"</string>
   <plurals name="num_seconds_ago">
@@ -801,7 +801,7 @@
     <string name="editTextMenuTitle" msgid="4909135564941815494">"Textaktionen"</string>
     <string name="low_internal_storage_view_title" msgid="1399732408701697546">"Geringer Speicher"</string>
     <string name="low_internal_storage_view_text" product="tablet" msgid="4231085657068852042">"Kaum noch Tablet-Speicher frei"</string>
-    <string name="low_internal_storage_view_text" product="default" msgid="635106544616378836">"Kaum noch Telefonspeicher frei."</string>
+    <string name="low_internal_storage_view_text" product="default" msgid="635106544616378836">"Kaum noch Telefonspeicher frei"</string>
     <string name="ok" msgid="5970060430562524910">"OK"</string>
     <string name="cancel" msgid="6442560571259935130">"Abbrechen"</string>
     <string name="yes" msgid="5362982303337969312">"OK"</string>
@@ -809,11 +809,12 @@
     <string name="dialog_alert_title" msgid="2049658708609043103">"Achtung"</string>
     <string name="loading" msgid="1760724998928255250">"Wird geladen..."</string>
     <string name="capital_on" msgid="1544682755514494298">"EIN"</string>
-    <string name="capital_off" msgid="6815870386972805832">"Aus"</string>
+    <string name="capital_off" msgid="6815870386972805832">"AUS"</string>
     <string name="whichApplication" msgid="4533185947064773386">"Aktion durchführen mit"</string>
-    <string name="alwaysUse" msgid="4583018368000610438">"Standardmäßig für diese Aktion verwenden."</string>
-    <string name="clearDefaultHintMsg" msgid="4815455344600932173">"Standardeinstellung zurücksetzen unter \"Einstellungen &gt; Anwendungen &gt; Anwendungen verwalten\"."</string>
+    <string name="alwaysUse" msgid="4583018368000610438">"Standardmäßig für diese Aktion verwenden"</string>
+    <string name="clearDefaultHintMsg" msgid="4815455344600932173">"Standardeinstellung zurücksetzen unter \"Einstellungen &gt; Anwendungen &gt; Anwendungen verwalten\""</string>
     <string name="chooseActivity" msgid="1009246475582238425">"Aktion auswählen"</string>
+    <string name="chooseUsbActivity" msgid="7892597146032121735">"Anwendung für das USB-Gerät auswählen"</string>
     <string name="noApplications" msgid="1691104391758345586">"Diese Aktion kann von keiner Anwendung ausgeführt werden."</string>
     <string name="aerr_title" msgid="653922989522758100">"Tut uns leid!"</string>
     <string name="aerr_application" msgid="4683614104336409186">"Die Anwendung <xliff:g id="APPLICATION">%1$s</xliff:g> (Prozess <xliff:g id="PROCESS">%2$s</xliff:g>) wurde unerwartet beendet. Versuchen Sie es erneut."</string>
@@ -832,13 +833,13 @@
     <string name="smv_application" msgid="295583804361236288">"Die Anwendung <xliff:g id="APPLICATION">%1$s</xliff:g> (Prozess <xliff:g id="PROCESS">%2$s</xliff:g>) hat gegen ihre selbsterzwungene StrictMode-Richtlinie verstoßen."</string>
     <string name="smv_process" msgid="5120397012047462446">"Der Prozess <xliff:g id="PROCESS">%1$s</xliff:g> hat gegen seine selbsterzwungene StrictMode-Richtlinie verstoßen."</string>
     <string name="heavy_weight_notification" msgid="9087063985776626166">"<xliff:g id="APP">%1$s</xliff:g> läuft"</string>
-    <string name="heavy_weight_notification_detail" msgid="2423977499339403402">"Auswählen zum Wechseln in die Anwendung"</string>
+    <string name="heavy_weight_notification_detail" msgid="2423977499339403402">"Zum Wechseln in die Anwendung auswählen"</string>
     <string name="heavy_weight_switcher_title" msgid="1135403633766694316">"Anwendung wechseln?"</string>
     <string name="heavy_weight_switcher_text" msgid="4592075610079319667">"Es läuft gerade eine andere Anwendung, die vor dem Start einer neuen beendet werden muss."</string>
     <string name="old_app_action" msgid="493129172238566282">"Zu <xliff:g id="OLD_APP">%1$s</xliff:g> zurückkehren"</string>
-    <string name="old_app_description" msgid="942967900237208466">"Die neue Anwendung nicht starten."</string>
+    <string name="old_app_description" msgid="942967900237208466">"Die neue Anwendung nicht starten"</string>
     <string name="new_app_action" msgid="5472756926945440706">"<xliff:g id="OLD_APP">%1$s</xliff:g> starten"</string>
-    <string name="new_app_description" msgid="6830398339826789493">"Anwendung beenden, ohne zu speichern."</string>
+    <string name="new_app_description" msgid="6830398339826789493">"Anwendung beenden, ohne zu speichern"</string>
     <string name="sendText" msgid="5132506121645618310">"Aktion für Text auswählen"</string>
     <string name="volume_ringtone" msgid="6885421406845734650">"Klingeltonlautstärke"</string>
     <string name="volume_music" msgid="5421651157138628171">"Medienlautstärke"</string>
@@ -885,14 +886,14 @@
     <string name="usb_storage_notification_title" msgid="8175892554757216525">"USB-Verbindung"</string>
     <string name="usb_storage_notification_message" msgid="7380082404288219341">"Zum Kopieren von Dateien zum/vom Computer"</string>
     <string name="usb_storage_stop_notification_title" msgid="2336058396663516017">"USB-Speicher deaktivieren"</string>
-    <string name="usb_storage_stop_notification_message" msgid="2591813490269841539">"Auswählen, um USB-Speicher zu deaktivieren."</string>
+    <string name="usb_storage_stop_notification_message" msgid="2591813490269841539">"USB-Speicher deaktivieren: auswählen"</string>
     <string name="usb_storage_stop_title" msgid="660129851708775853">"USB-Speicher in Verwendung"</string>
     <string name="usb_storage_stop_message" product="nosdcard" msgid="1368842269463745067">"Stellen Sie vor dem Deaktivieren des USB-Speichers sicher, dass Sie den Android-USB-Speicher von Ihrem Computer getrennt (\"ausgeworfen\") haben."</string>
-    <string name="usb_storage_stop_message" product="default" msgid="3613713396426604104">"Stellen Sie vor dem Deaktivieren des USB-Speichers sicher, dass Sie Ihre Android-SD-Karte von Ihrem Computer getrennt (\"ausgeworfen\") haben."</string>
+    <string name="usb_storage_stop_message" product="default" msgid="3613713396426604104">"Achten Sie vor dem Deaktivieren des USB-Speichers darauf, dass Sie die Android-SD-Karte von Ihrem Computer getrennt (\"ausgeworfen\") haben."</string>
     <string name="usb_storage_stop_button_mount" msgid="7060218034900696029">"USB-Speicher deaktivieren"</string>
     <string name="usb_storage_stop_error_message" msgid="143881914840412108">"Beim Deaktivieren des USB-Speichers ist ein Problem aufgetreten. Überprüfen Sie, ob Sie den USB-Host getrennt haben, und versuchen Sie es erneut."</string>
     <string name="dlg_confirm_kill_storage_users_title" msgid="963039033470478697">"USB-Speicher aktivieren"</string>
-    <string name="dlg_confirm_kill_storage_users_text" msgid="3202838234780505886">"Wenn Sie den USB-Speicher aktivieren, werden einige von Ihnen verwendeten Anwendungen angehalten und sind möglicherweise nicht verfügbar, bis Sie den USB-Speicher wieder deaktivieren."</string>
+    <string name="dlg_confirm_kill_storage_users_text" msgid="3202838234780505886">"Wenn Sie den USB-Speicher aktivieren, werden einige von Ihnen verwendete Anwendungen angehalten und sind möglicherweise nicht verfügbar, bis Sie den USB-Speicher wieder deaktivieren."</string>
     <string name="dlg_error_title" msgid="8048999973837339174">"USB-Vorgang fehlgeschlagen"</string>
     <string name="dlg_ok" msgid="7376953167039865701">"OK"</string>
     <string name="extmedia_format_title" product="nosdcard" msgid="7980995592595097841">"USB-Sp. formatieren"</string>
@@ -901,40 +902,40 @@
     <string name="extmedia_format_message" product="default" msgid="3621369962433523619">"Möchten Sie die SD-Karte wirklich formatieren? Alle Daten auf Ihrer Karte gehen dann verloren."</string>
     <string name="extmedia_format_button_format" msgid="4131064560127478695">"Format"</string>
     <string name="adb_active_notification_title" msgid="6729044778949189918">"USB-Debugging verbunden"</string>
-    <string name="adb_active_notification_message" msgid="8470296818270110396">"Auswählen, um USB-Debugging zu deaktivieren."</string>
+    <string name="adb_active_notification_message" msgid="8470296818270110396">"USB-Debugging deaktivieren: auswählen"</string>
     <string name="select_input_method" msgid="6865512749462072765">"Eingabemethode auswählen"</string>
     <string name="configure_input_methods" msgid="6324843080254191535">"Eingabemethoden konfigurieren"</string>
     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="candidates_style" msgid="4333913089637062257"><u>"Kandidaten"</u></string>
     <string name="ext_media_checking_notification_title" product="nosdcard" msgid="3449816005351468560">"USB-Speicher wird vorbereitet."</string>
-    <string name="ext_media_checking_notification_title" product="default" msgid="5457603418970994050">"SD-Karte wird vorbereitet"</string>
+    <string name="ext_media_checking_notification_title" product="default" msgid="5457603418970994050">"SD-Karte wird vorbereitet..."</string>
     <string name="ext_media_checking_notification_message" msgid="8287319882926737053">"Suche nach Fehlern"</string>
     <string name="ext_media_nofs_notification_title" product="nosdcard" msgid="7788040745686229307">"USB-Speicher leer"</string>
     <string name="ext_media_nofs_notification_title" product="default" msgid="780477838241212997">"SD-Karte leer"</string>
     <string name="ext_media_nofs_notification_message" product="nosdcard" msgid="8623130522556087311">"USB-Speicher ist leer oder verfügt über ein nicht unterstütztes Dateisystem."</string>
     <string name="ext_media_nofs_notification_message" product="default" msgid="3817704088027829380">"SD-Karte ist leer oder verfügt über ein nicht unterstütztes Dateisystem."</string>
     <string name="ext_media_unmountable_notification_title" product="nosdcard" msgid="2090046769532713563">"USB-Speicher beschädigt"</string>
-    <string name="ext_media_unmountable_notification_title" product="default" msgid="6410723906019100189">"Beschädigte SD-Karte"</string>
-    <string name="ext_media_unmountable_notification_message" product="nosdcard" msgid="529021299294450667">"USB-Speicher ist beschädigt. Sie müssen ihn neu formatieren."</string>
-    <string name="ext_media_unmountable_notification_message" product="default" msgid="6902531775948238989">"Die SD-Karte ist beschädigt. Sie müssen Ihre Karte eventuell neu formatieren."</string>
-    <string name="ext_media_badremoval_notification_title" product="nosdcard" msgid="1661683031330951073">"USB-Speicher unerw. entfernt"</string>
+    <string name="ext_media_unmountable_notification_title" product="default" msgid="6410723906019100189">"SD-Karte beschädigt"</string>
+    <string name="ext_media_unmountable_notification_message" product="nosdcard" msgid="529021299294450667">"Der USB-Speicher ist beschädigt. Sie müssen ihn eventuell neu formatieren."</string>
+    <string name="ext_media_unmountable_notification_message" product="default" msgid="6902531775948238989">"Die SD-Karte ist beschädigt. Sie müssen sie eventuell neu formatieren."</string>
+    <string name="ext_media_badremoval_notification_title" product="nosdcard" msgid="1661683031330951073">"USB-Speicher unerwartet entfernt"</string>
     <string name="ext_media_badremoval_notification_title" product="default" msgid="6872152882604407837">"SD-Karte unerwartet entfernt"</string>
     <string name="ext_media_badremoval_notification_message" product="nosdcard" msgid="4329848819865594241">"Trennen Sie den USB-Speicher vor dem Entfernen, um Datenverlust zu vermeiden."</string>
     <string name="ext_media_badremoval_notification_message" product="default" msgid="7260183293747448241">"SD-Karte vor dem Entnehmen trennen, um Datenverlust zu vermeiden."</string>
-    <string name="ext_media_safe_unmount_notification_title" product="nosdcard" msgid="3967973893270360230">"USB-Speicher kann entf. werden"</string>
+    <string name="ext_media_safe_unmount_notification_title" product="nosdcard" msgid="3967973893270360230">"USB-Speicher kann entfernt werden."</string>
     <string name="ext_media_safe_unmount_notification_title" product="default" msgid="6729801130790616200">"SD-Karte kann entfernt werden."</string>
     <string name="ext_media_safe_unmount_notification_message" product="nosdcard" msgid="6142195361606493530">"Der USB-Speicher kann entfernt werden."</string>
     <string name="ext_media_safe_unmount_notification_message" product="default" msgid="568841278138377604">"Die SD-Karte kann entfernt werden."</string>
     <string name="ext_media_nomedia_notification_title" product="nosdcard" msgid="4486377230140227651">"USB-Speicher entfernt"</string>
     <string name="ext_media_nomedia_notification_title" product="default" msgid="8902518030404381318">"SD-Karte entfernt"</string>
     <string name="ext_media_nomedia_notification_message" product="nosdcard" msgid="6921126162580574143">"USB-Speicher entfernt. Neuen Datenträger einlegen"</string>
-    <string name="ext_media_nomedia_notification_message" product="default" msgid="3870120652983659641">"SD-Karte entfernt. Legen Sie eine neue ein."</string>
+    <string name="ext_media_nomedia_notification_message" product="default" msgid="3870120652983659641">"SD-Karte entfernt. Neue Karte einlegen"</string>
     <string name="activity_list_empty" msgid="4168820609403385789">"Keine passenden Aktivitäten gefunden"</string>
     <string name="permlab_pkgUsageStats" msgid="8787352074326748892">"Nutzungsstatistik der Komponente aktualisieren"</string>
     <string name="permdesc_pkgUsageStats" msgid="891553695716752835">"Ermöglicht die Änderung von gesammelten Nutzungsstatistiken der Komponente. Nicht für normale Anwendungen vorgesehen."</string>
-    <string name="permlab_copyProtectedData" msgid="1660908117394854464">"Ermöglicht das Aufrufen des Standard-Containerdienstes zum Kopieren von Inhalt. Keine Verwendung bei normalen Anwendungen."</string>
-    <string name="permdesc_copyProtectedData" msgid="537780957633976401">"Ermöglicht das Aufrufen des Standard-Containerdienstes zum Kopieren von Inhalt. Keine Verwendung bei normalen Anwendungen."</string>
+    <string name="permlab_copyProtectedData" msgid="1660908117394854464">"Ermöglicht das Aufrufen des Standard-Containerdienstes zum Kopieren von Inhalt. Nicht zum Gebrauch mit normalen Anwendungen."</string>
+    <string name="permdesc_copyProtectedData" msgid="537780957633976401">"Ermöglicht das Aufrufen des Standard-Containerdienstes zum Kopieren von Inhalt. Nicht zum Gebrauch mit normalen Anwendungen."</string>
     <string name="tutorial_double_tap_to_zoom_message_short" msgid="1311810005957319690">"Für Zoomeinstellung zweimal berühren"</string>
     <string name="gadget_host_error_inflating" msgid="2613287218853846830">"Fehler beim Vergrößern des Widgets"</string>
     <string name="ime_action_go" msgid="8320845651737369027">"Los"</string>
@@ -963,7 +964,7 @@
     <string name="pptp_vpn_description" msgid="2688045385181439401">"Point-to-Point-Tunneling-Protokoll"</string>
     <string name="l2tp_vpn_description" msgid="3750692169378923304">"Layer-2-Tunneling-Protokoll"</string>
     <string name="l2tp_ipsec_psk_vpn_description" msgid="3945043564008303239">"L2TP/IPSec-VPN mit vorinstalliertem Schlüssel"</string>
-    <string name="l2tp_ipsec_crt_vpn_description" msgid="5382714073103653577">"Zertifikat mit vorinstalliertem Schlüssel"</string>
+    <string name="l2tp_ipsec_crt_vpn_description" msgid="5382714073103653577">"L2TP/IPSec-VPN mit Zertifikat"</string>
     <string name="upload_file" msgid="2897957172366730416">"Datei auswählen"</string>
     <string name="no_file_chosen" msgid="6363648562170759465">"Keine Datei ausgewählt"</string>
     <string name="reset" msgid="2448168080964209908">"Zurücksetzen"</string>
@@ -976,9 +977,9 @@
     <string name="next_button_label" msgid="1080555104677992408">"Weiter"</string>
     <string name="skip_button_label" msgid="1275362299471631819">"Überspringen"</string>
     <string name="throttle_warning_notification_title" msgid="4890894267454867276">"Hohe Mobildatennutzung"</string>
-    <string name="throttle_warning_notification_message" msgid="2609734763845705708">"Weitere Informationen über die Mobildatennutzung durch Berühren aufrufen"</string>
+    <string name="throttle_warning_notification_message" msgid="2609734763845705708">"Durch Berühren weitere Informationen zur Mobildatennutzung aufrufen"</string>
     <string name="throttled_notification_title" msgid="6269541897729781332">"Mobildatenlimit überschritten"</string>
-    <string name="throttled_notification_message" msgid="4712369856601275146">"Weitere Informationen über die Mobildatennutzung durch Berühren aufrufen"</string>
+    <string name="throttled_notification_message" msgid="4712369856601275146">"Durch Berühren weitere Informationen zur Mobildatennutzung aufrufen"</string>
     <string name="no_matches" msgid="8129421908915840737">"Keine Treffer"</string>
     <string name="find_on_page" msgid="1946799233822820384">"Auf Seite suchen"</string>
   <plurals name="matches_found">
@@ -999,7 +1000,7 @@
     <string name="media_shared" product="nosdcard" msgid="5830814349250834225">"Der USB-Speicher wird derzeit von einem Computer verwendet."</string>
     <string name="media_shared" product="default" msgid="5706130568133540435">"Die SD-Karte wird derzeit von einem Computer verwendet."</string>
     <string name="media_unknown_state" msgid="729192782197290385">"Unbekannter Status des externen Speichermediums"</string>
-    <string name="share" msgid="1778686618230011964">"Freigeben"</string>
+    <string name="share" msgid="1778686618230011964">"Weitergeben"</string>
     <string name="find" msgid="4808270900322985960">"Suchen"</string>
     <string name="websearch" msgid="4337157977400211589">"Websuche"</string>
     <string name="gpsNotifTicker" msgid="5622683912616496172">"Standortabfrage von <xliff:g id="NAME">%s</xliff:g>"</string>
diff --git a/core/res/res/values-el/strings.xml b/core/res/res/values-el/strings.xml
index edcb213..571dc43 100644
--- a/core/res/res/values-el/strings.xml
+++ b/core/res/res/values-el/strings.xml
@@ -361,8 +361,8 @@
     <string name="permdesc_vibrate" msgid="2886677177257789187">"Επιτρέπει στην εφαρμογή τον έλεγχο του δονητή."</string>
     <string name="permlab_flashlight" msgid="2155920810121984215">"έλεγχος φακού"</string>
     <string name="permdesc_flashlight" msgid="6433045942283802309">"Επιτρέπει στην εφαρμογή τον έλεγχο του φακού."</string>
-    <string name="permlab_accessUsb" msgid="7362327818655760496">"πρόσβαση σε συσκευές USB"</string>
-    <string name="permdesc_accessUsb" msgid="2414271762914049292">"Επιτρέπει στην εφαρμογή την πρόσβαση σε συσκευές USB."</string>
+    <string name="permlab_manageUsb" msgid="1113453430645402723">"διαχείριση προτιμήσεων και αδειών για συσκευές USB"</string>
+    <string name="permdesc_manageUsb" msgid="6148489202092166164">"Επιτρέπει στην εφαρμογή να διαχειρίζεται προτιμήσεις και άδειες για συσκευές USB."</string>
     <string name="permlab_accessMtp" msgid="4953468676795917042">"εφαρμογή πρωτοκόλλου MTP"</string>
     <string name="permdesc_accessMtp" msgid="6532961200486791570">"Επιτρέπει την πρόσβαση στο πρόγραμμα οδήγησης kernel MTP για την εφαρμογή του πρωτοκόλλου MTP USB."</string>
     <string name="permlab_hardware_test" msgid="4148290860400659146">"δοκιμή υλικού"</string>
@@ -484,8 +484,8 @@
     <string name="policydesc_wipeData" product="default" msgid="7669895333814222586">"Διαγραφή των δεδομένων του τηλεφώνου χωρίς προειδοποίηση με επαναφορά των εργοστασιακών δεδομένων"</string>
     <string name="policylab_setGlobalProxy" msgid="2784828293747791446">"Ρύθμιση του γενικού διακομιστή μεσολάβησης της συσκευής"</string>
     <string name="policydesc_setGlobalProxy" msgid="6387497466660154931">"Ορίστε τη χρήση του γενικού διακομιστή μεσολάβησης της συσκευής όταν είναι ενεργοποιημένη η πολιτική. Μόνο ο διαχειριστής της πρώτης συσκευής ορίζει τον ισχύοντα γενικό διακομιστή μεσολάβησης."</string>
-    <!-- outdated translation 4740941403188940274 -->     <string name="policylab_expirePassword" msgid="885279151847254056">"Ορισμός λήξης κωδικού πρόσβασης"</string>
-    <!-- outdated translation 6626724939177185949 -->     <string name="policydesc_expirePassword" msgid="4844430354224822074">"Ελέγξτε πόσος χρόνος απομένει προτού πρέπει να αλλάξετε τον κωδικό πρόσβασης κλειδώματος της οθόνης"</string>
+    <string name="policylab_expirePassword" msgid="885279151847254056">"Ορισμός λήξης κωδ. κλειδ. οθ."</string>
+    <string name="policydesc_expirePassword" msgid="4844430354224822074">"Επιλέξτε πόσο συχνά θα πρέπει να αλλάζει ο κωδικός πρόσβασης κλειδώματος οθόνης"</string>
     <string name="policylab_encryptedStorage" msgid="8901326199909132915">"Ορισμός κρυπτογρ. αποθ. χώρου"</string>
     <string name="policydesc_encryptedStorage" msgid="2504984732631479399">"Να απαιτείται η κρυπτογράφηση των αποθηκευμένων δεδομένων εφαρμογής"</string>
   <string-array name="phoneTypes">
@@ -814,6 +814,7 @@
     <string name="alwaysUse" msgid="4583018368000610438">"Χρήση από προεπιλογή για αυτήν την ενέργεια."</string>
     <string name="clearDefaultHintMsg" msgid="4815455344600932173">"Εκκαθάριση προεπιλεγμένων σε Ρυθμίσεις αρχικής σελίδας &gt; Εφαρμογές &gt; Διαχείριση εφαρμογών."</string>
     <string name="chooseActivity" msgid="1009246475582238425">"Επιλέξτε μια ενέργεια"</string>
+    <string name="chooseUsbActivity" msgid="7892597146032121735">"Επιλέξτε μια εφαρμογή για τη συσκευή USB"</string>
     <string name="noApplications" msgid="1691104391758345586">"Δεν υπάρχουν εφαρμογές, οι οποίες μπορούν να εκτελέσουν αυτήν την ενέργεια."</string>
     <string name="aerr_title" msgid="653922989522758100">"Λυπούμαστε!"</string>
     <string name="aerr_application" msgid="4683614104336409186">"Υπήρξε μη αναμενόμενη διακοπή της εφαρμογής <xliff:g id="APPLICATION">%1$s</xliff:g> (διαδικασία <xliff:g id="PROCESS">%2$s</xliff:g>). Προσπαθήστε ξανά."</string>
diff --git a/core/res/res/values-en-rGB/strings.xml b/core/res/res/values-en-rGB/strings.xml
index b8f624e..7015d48 100644
--- a/core/res/res/values-en-rGB/strings.xml
+++ b/core/res/res/values-en-rGB/strings.xml
@@ -361,8 +361,8 @@
     <string name="permdesc_vibrate" msgid="2886677177257789187">"Allows the application to control the vibrator."</string>
     <string name="permlab_flashlight" msgid="2155920810121984215">"control flashlight"</string>
     <string name="permdesc_flashlight" msgid="6433045942283802309">"Allows the application to control the flashlight."</string>
-    <string name="permlab_accessUsb" msgid="7362327818655760496">"access USB devices"</string>
-    <string name="permdesc_accessUsb" msgid="2414271762914049292">"Allows the application to access USB devices."</string>
+    <string name="permlab_manageUsb" msgid="1113453430645402723">"manage preferences and permissions for USB devices"</string>
+    <string name="permdesc_manageUsb" msgid="6148489202092166164">"Allows the application to manage preferences and permissions for USB devices."</string>
     <string name="permlab_accessMtp" msgid="4953468676795917042">"implement MTP protocol"</string>
     <string name="permdesc_accessMtp" msgid="6532961200486791570">"Allows access to the kernel MTP driver to implement the MTP USB protocol."</string>
     <string name="permlab_hardware_test" msgid="4148290860400659146">"test hardware"</string>
@@ -484,8 +484,8 @@
     <string name="policydesc_wipeData" product="default" msgid="7669895333814222586">"Erase the phone\'s data without warning by performing a factory data reset"</string>
     <string name="policylab_setGlobalProxy" msgid="2784828293747791446">"Set the device global proxy"</string>
     <string name="policydesc_setGlobalProxy" msgid="6387497466660154931">"Set the device\'s global proxy to be used while policy is enabled. Only the first device admin sets the effective global proxy."</string>
-    <!-- outdated translation 4740941403188940274 -->     <string name="policylab_expirePassword" msgid="885279151847254056">"Set password expiry"</string>
-    <!-- outdated translation 6626724939177185949 -->     <string name="policydesc_expirePassword" msgid="4844430354224822074">"Control how long before lock-screen password needs to be changed"</string>
+    <string name="policylab_expirePassword" msgid="885279151847254056">"Set lock-screen password expiry"</string>
+    <string name="policydesc_expirePassword" msgid="4844430354224822074">"Control how frequently the lock-screen password must be changed"</string>
     <string name="policylab_encryptedStorage" msgid="8901326199909132915">"Set storage encryption"</string>
     <string name="policydesc_encryptedStorage" msgid="2504984732631479399">"Require that stored application data be encrypted"</string>
   <string-array name="phoneTypes">
@@ -814,6 +814,7 @@
     <string name="alwaysUse" msgid="4583018368000610438">"Use by default for this action."</string>
     <string name="clearDefaultHintMsg" msgid="4815455344600932173">"Clear default in Home Settings &gt; Applications &gt; Manage applications."</string>
     <string name="chooseActivity" msgid="1009246475582238425">"Select an action"</string>
+    <string name="chooseUsbActivity" msgid="7892597146032121735">"Select an application for the USB device"</string>
     <string name="noApplications" msgid="1691104391758345586">"No applications can perform this action."</string>
     <string name="aerr_title" msgid="653922989522758100">"Sorry!"</string>
     <string name="aerr_application" msgid="4683614104336409186">"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>
@@ -879,7 +880,7 @@
     <string name="usb_storage_title" msgid="5901459041398751495">"USB connected"</string>
     <string name="usb_storage_message" product="nosdcard" msgid="6631094834151575841">"You have connected to your computer via USB. Touch the button below if you want to copy files between your computer and your Android‘s USB storage."</string>
     <string name="usb_storage_message" product="default" msgid="4510858346516069238">"You have connected to your computer via USB. Touch the button below if you want to copy files between your computer and your Android‘s SD card."</string>
-    <string name="usb_storage_button_mount" msgid="1052259930369508235">"Turn off USB storage"</string>
+    <string name="usb_storage_button_mount" msgid="1052259930369508235">"Turn on USB storage"</string>
     <string name="usb_storage_error_message" product="nosdcard" msgid="3276413764430468454">"There is a problem with using your USB storage for USB mass storage."</string>
     <string name="usb_storage_error_message" product="default" msgid="120810397713773275">"There is a problem with using your SD card for USB mass storage."</string>
     <string name="usb_storage_notification_title" msgid="8175892554757216525">"USB connected"</string>
diff --git a/core/res/res/values-es-rUS-xlarge/strings.xml b/core/res/res/values-es-rUS-xlarge/strings.xml
deleted file mode 100644
index b1409ba..0000000
--- a/core/res/res/values-es-rUS-xlarge/strings.xml
+++ /dev/null
@@ -1,337 +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">
-    <!-- XL -->
-    <string name="fileSizeSuffix" msgid="3468563433835560758">"Segmento <xliff:g id="NUMBER">%1$s</xliff:g><xliff:g id="UNIT">%2$s</xliff:g>"</string>
-    <!-- XL -->
-    <string name="unknownName" msgid="3202822008051920747">"(Desconocido)"</string>
-    <!-- XL -->
-    <string name="defaultVoiceMailAlphaTag" msgid="3668436100965334106">"Buzón de voz"</string>
-    <!-- XL -->
-    <string name="serviceClassVoice" msgid="7086876533404179039">"Google Voice"</string>
-    <!-- XL -->
-    <string name="cfTemplateNotForwarded" msgid="8534356655497306518">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: no se ha reenviado"</string>
-    <!-- XL -->
-    <string name="cfTemplateRegistered" msgid="1255841210142514510">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: no se ha reenviado"</string>
-    <!-- XL -->
-    <string name="cfTemplateRegisteredTime" msgid="7798907169190952367">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: no se ha reenviado"</string>
-    <!-- XL -->
-    <string name="notification_title" msgid="5210128823045542445">"Error al acceder a <xliff:g id="ACCOUNT">%1$s</xliff:g>"</string>
-    <!-- XL -->
-    <string name="low_memory" product="tablet" msgid="4855646606241379548">"¡El espacio de almacenamiento de la tableta está completo! Elimina algunos archivos para liberar espacio."</string>
-    <string name="low_memory" product="default" msgid="9195238880281578473">"¡El espacio de almacenamiento está completo! Elimina algunos archivos para liberar espacio."</string>
-    <!-- XL -->
-    <string name="power_dialog" product="tablet" msgid="6884163545695410971">"Opciones de tableta"</string>
-    <string name="power_dialog" product="default" msgid="8882103237148972564">"Opciones de teléfono"</string>
-    <!-- XL -->
-    <string name="silent_mode" msgid="5687977677409351252">"Modo silencio"</string>
-    <!-- XL -->
-    <string name="shutdown_confirm" product="tablet" msgid="5776903973889956395">"Tu tableta se apagará."</string>
-    <string name="shutdown_confirm" product="default" msgid="3040950969577046278">"Tu teléfono se apagará."</string>
-    <!-- XL -->
-    <string name="global_actions" product="tablet" msgid="110297659383505180">"Opciones de tableta"</string>
-    <string name="global_actions" product="default" msgid="2108237350837066773">"Opciones de teléfono"</string>
-    <!-- XL -->
-    <string name="global_action_toggle_silent_mode" msgid="4538951049191334644">"Modo silencio"</string>
-    <!-- XL -->
-    <string name="global_action_silent_mode_off_status" msgid="9045822172493147761">"El sonido está ENCENDIDO"</string>
-    <!-- XL -->
-    <string name="global_actions_airplane_mode_on_status" msgid="7272433204482202219">"El modo avión está ENCENDIDO"</string>
-    <!-- XL -->
-    <string name="android_system_label" msgid="844561213652704593">"Sistema Androide"</string>
-    <!-- XL -->
-    <string name="permgroupdesc_costMoney" msgid="4836624191696189469">"Admitir que las aplicaciones realicen actividades que se cobran."</string>
-    <!-- XL -->
-    <string name="permgroupdesc_developmentTools" msgid="5514251182135739578">"Las funciones sólo son necesarias para los programadores de aplicaciones."</string>
-    <!-- XL -->
-    <string name="permgrouplab_storage" msgid="746210798053836644">"Almacenamiento"</string>
-    <!-- XL -->
-    <string name="permdesc_readSms" product="tablet" msgid="3026416194429353337">"Permite que la aplicación lea los mensajes SMS almacenados en tu tableta o tarjeta SIM. Las aplicaciones maliciosas pueden leer tus mensajes confidenciales."</string>
-    <string name="permdesc_readSms" product="default" msgid="191875931331016383">"Admite que la aplicación lea los mensajes SMS almacenados en tu teléfono o tarjeta SIM. Las aplicaciones maliciosas pueden leer tus mensajes confidenciales."</string>
-    <!-- XL -->
-    <string name="permdesc_writeSms" product="tablet" msgid="692041754996169941">"Permite que la aplicación escriba a los mensajes SMS almacenados en tu tableta o tarjeta SIM. Las aplicaciones maliciosas pueden borrar tus mensajes."</string>
-    <string name="permdesc_writeSms" product="default" msgid="1659315878254882599">"Admite que la aplicación escriba a los mensajes SMS almacenados en tu teléfono o tarjeta SIM. Las aplicaciones maliciosas pueden borrar tus mensajes."</string>
-    <!-- XL -->
-    <string name="permlab_forceStopPackages" msgid="1277034765943155677">"provocar la detención de otras aplicaciones"</string>
-    <!-- XL -->
-    <string name="permlab_forceBack" msgid="4272218642115232597">"cerrar la aplicación a la fuerza"</string>
-    <!-- XL -->
-    <string name="permdesc_injectEvents" product="tablet" msgid="6096352450860864899">"Permite que una aplicación ofrezca sus propios eventos de entrada (presionar teclas, etc.) a otras aplicaciones. Las aplicaciones maliciosas pueden utilizarlo para tomar el control de la tableta."</string>
-    <string name="permdesc_injectEvents" product="default" msgid="2842435693076075109">"Admite una aplicación que ofrece sus propios eventos de entrada (presionar teclas, etc.) a otras aplicaciones. Las aplicaciones maliciosas pueden utilizarlo para tomar el control del teléfono."</string>
-    <!-- XL -->
-    <string name="permdesc_clearAppCache" product="tablet" msgid="1147333973960547529">"Permite que una aplicación libere espacio de almacenamiento en la tableta eliminando archivos del directorio de memoria caché de la aplicación. En general, el acceso es muy restringido para el proceso del sistema."</string>
-    <string name="permdesc_clearAppCache" product="default" msgid="5790679870501740958">"Admite una aplicación que libera espacio de almacenamiento en el teléfono al eliminar archivos del directorio de memoria caché de la aplicación. En general, el acceso es muy restringido para el proceso del sistema."</string>
-    <!-- XL -->
-    <string name="permdesc_readLogs" product="tablet" msgid="3701009088710926065">"Permite que una aplicación lea diversos archivos de registro del sistema. Esto le permite descubrir información general acerca de lo que haces con la tableta, y puede potencialmente incluir información personal o privada."</string>
-    <string name="permdesc_readLogs" product="default" msgid="8520101632251038537">"Admite una aplicación que lee diversos archivos de registro del sistema. Esto te permite descubrir información general acerca de lo que haces con el teléfono, y puede potencialmente incluir información personal o privada."</string>
-    <!-- XL -->
-    <string name="permdesc_changeComponentState" product="tablet" msgid="1791075936446230356">"Permite que una aplicación cambie si se debe activar o no un componente de otra aplicación. Las aplicaciones maliciosas pueden utilizarlo para desactivar funciones importantes de la tableta. Se debe tener cuidado con el permiso, ya que es posible que los componentes de la aplicación alcancen un estado inservible, imperfecto e inestable."</string>
-    <string name="permdesc_changeComponentState" product="default" msgid="587130297076242796">"Permite que una aplicación cambie si se debe activar o no un componente de otra aplicación. Las aplicaciones maliciosas pueden utilizarlo para desactivar funciones importantes del teléfono. Se debe tener cuidado con el permiso, ya que es posible que los componentes de la aplicación alcancen un estado inservible, imperfecto e inestable."</string>
-    <!-- XL -->
-    <string name="permdesc_receiveBootCompleted" product="tablet" msgid="8660405432665162821">"Permite que una aplicación se inicie en cuanto el sistema haya finalizado la inicialización. Esto puede ocasionar que la tableta demore más en inicializar y que la aplicación retarde el funcionamiento total de la tableta al estar en ejecución constante."</string>
-    <string name="permdesc_receiveBootCompleted" product="default" msgid="1827765096700833418">"Admite una aplicación que se inicia cuando el sistema haya finalizado la inicialización. Esto puede ocasionar que se demore más tiempo en inicializar el teléfono y que la aplicación retarde el funcionamiento total del teléfono al estar en ejecución constante."</string>
-    <!-- XL -->
-    <string name="permdesc_readContacts" product="tablet" msgid="1611730857475623952">"Permite que una aplicación lea todos los datos de de contacto (direcciones) almacenados en tu tableta. Las aplicaciones maliciosas pueden utilizarlo para enviar tus datos a otras personas."</string>
-    <string name="permdesc_readContacts" product="default" msgid="6610535719925788049">"Admite una aplicación que lee todos los datos de (direcciones) de contactos almacenados en tu teléfono. Las aplicaciones maliciosas pueden utilizarlo para enviar tus eventos de calendario a otras personas."</string>
-    <!-- XL -->
-    <string name="permdesc_writeContacts" product="tablet" msgid="4572703488642353934">"Permite que una aplicación modifique los datos de (dirección) guardados en tu tableta. Las aplicaciones maliciosas pueden utilizarlo para borrar o modificar los datos de contacto."</string>
-    <string name="permdesc_writeContacts" product="default" msgid="714397557711969040">"Admite una aplicación que modifica los datos de (dirección de) contacto guardados en tu teléfono. Las aplicaciones maliciosas pueden utilizarlo para borrar o modificar los datos de contacto."</string>
-    <!-- XL -->
-    <string name="permdesc_readCalendar" product="tablet" msgid="2991522150157238929">"Permite que una aplicación lea todos los eventos de calendario almacenados en tu tableta. Las aplicaciones maliciosas pueden utilizarlo para enviar tus eventos de calendario a otras personas."</string>
-    <string name="permdesc_readCalendar" product="default" msgid="2618681024074734985">"Admite que una aplicación lea todos los eventos de calendario almacenados en tu teléfono. Las aplicaciones maliciosas pueden utilizarlo para enviar tus eventos de calendario a otras personas."</string>
-    <!-- XL -->
-    <string name="permdesc_accessFineLocation" product="tablet" msgid="9186984659787705379">"Accede a las fuentes de ubicación precisa, como el Sistema de posicionamiento global en la tableta, si está disponible. Las aplicaciones maliciosas pueden utilizarlo para determinar donde te encuentras y puede consumir energía adicional de la batería."</string>
-    <string name="permdesc_accessFineLocation" product="default" msgid="7130852247133907221">"Accede a las fuentes de ubicación precisa, como el Sistema de posicionamiento global en el teléfono, si está disponible. Las aplicaciones maliciosas pueden utilizarlo para determinar donde te encuentras y puede consumir energía adicional de la batería."</string>
-    <!-- XL -->
-    <string name="permdesc_accessCoarseLocation" product="tablet" msgid="2943949975553225591">"Accede a las fuentes de ubicación aproximada, como la base de datos de la red de celulares, para determinar la ubicación aproximada de un tableta, si está disponible. Las aplicaciones maliciosas pueden utilizarlo para determinar aproximadamente dónde te encuentras."</string>
-    <string name="permdesc_accessCoarseLocation" product="default" msgid="7474972764638621839">"Accede a las fuentes de ubicación aproximada, como la base de datos de la red de celulares, para determinar una ubicación telefónica aproximada, si está disponible. Las aplicaciones maliciosas pueden utilizarlo para determinar aproximadamente donde te encuentras."</string>
-    <!-- XL -->
-    <string name="permlab_brick" product="tablet" msgid="6967130388106614085">"inhabilitar tableta de forma permanente"</string>
-    <string name="permlab_brick" product="default" msgid="3120283238813720510">"desactivar teléfono de manera permanente"</string>
-    <!-- XL -->
-    <string name="permdesc_brick" product="tablet" msgid="8506097851567246888">"Permite que la aplicación desactive todo la tableta de manera permanente. Esto es muy peligroso."</string>
-    <string name="permdesc_brick" product="default" msgid="6696459767254028146">"Admite que la aplicación desactive todo el teléfono de manera permanente. Esto es muy peligroso."</string>
-    <!-- XL -->
-    <string name="permlab_reboot" product="tablet" msgid="8299304590708874992">"forzar reinicio de la tableta"</string>
-    <string name="permlab_reboot" product="default" msgid="7761230490609718232">"provocar el reinicio del teléfono"</string>
-    <!-- XL -->
-    <string name="permdesc_reboot" product="tablet" msgid="8289402537687518137">"Permite que la aplicación provoque el reinicio de la tableta."</string>
-    <string name="permdesc_reboot" product="default" msgid="2425170170087532554">"Admite que la aplicación provoque que el teléfono se reinicie."</string>
-    <!-- XL -->
-    <string name="permlab_performCdmaProvisioning" product="tablet" msgid="1602175938040327630">"iniciar directamente la configuración CDMA de la tableta"</string>
-    <string name="permlab_performCdmaProvisioning" product="default" msgid="2364447039211144234">"comienza directamente la configuración CDMA del teléfono"</string>
-    <!-- XL -->
-    <string name="permlab_checkinProperties" msgid="8770356116386811264">"acceder a las propiedades de registro"</string>
-    <!-- XL -->
-    <string name="permlab_bindGadget" msgid="2772444448613501375">"elegir controles"</string>
-    <!-- XL -->
-    <string name="permdesc_bindGadget" msgid="5172327215211875807">"Admite que la aplicación indique al sistema cuáles controles puede utilizar cada aplicación. Con este permiso, las aplicaciones pueden brindar acceso a los datos personales a otras aplicaciones. Las aplicaciones normales no deben utilizarlo."</string>
-    <!-- XL -->
-    <string name="permlab_wakeLock" product="tablet" msgid="8548785337425173690">"evitar que la tableta entre en estado de inactividad"</string>
-    <string name="permlab_wakeLock" product="default" msgid="7590534090355174805">"evitar que el teléfono entre en estado de inactividad"</string>
-    <!-- XL -->
-    <string name="permdesc_wakeLock" product="tablet" msgid="6871828582124115814">"Permite que una aplicación evite que la tableta entre en estado de inactividad."</string>
-    <string name="permdesc_wakeLock" product="default" msgid="1200311528451468554">"Admite una aplicación que evita que el teléfono entre en estado de inactividad."</string>
-    <!-- XL -->
-    <string name="permlab_devicePower" product="tablet" msgid="4737873025369971061">"apagar o encender la tableta"</string>
-    <string name="permlab_devicePower" product="default" msgid="6879460773734563850">"apagar o encender el teléfono"</string>
-    <!-- XL -->
-    <string name="permdesc_devicePower" product="tablet" msgid="5930342678996327905">"Permite que una aplicación encienda o apague la tableta."</string>
-    <string name="permdesc_devicePower" product="default" msgid="6653901512148320818">"Admite que la aplicación encienda o apague el teléfono."</string>
-    <!-- XL -->
-    <string name="permdesc_factoryTest" product="tablet" msgid="396653994609190055">"Se ejecuta como una prueba de fábrica de bajo nivel que permite un acceso completo al hardware de la tableta. Sólo disponible cuando la tableta se ejecuta en el modo de prueba de fábrica."</string>
-    <string name="permdesc_factoryTest" product="default" msgid="4581239666568781766">"Se ejecuta como una prueba de fábrica de bajo nivel que permite un acceso completo al hardware del teléfono. Sólo disponible cuando un teléfono se ejecuta en el modo de prueba de fábrica."</string>
-    <!-- XL -->
-    <string name="permlab_setWallpaper" msgid="845032615203772571">"establecer fondo de pantalla"</string>
-    <!-- XL -->
-    <string name="permdesc_setWallpaper" msgid="3378501759667797259">"Admite que la aplicación establezca el fondo de pantalla del sistema."</string>
-    <!-- XL -->
-    <string name="permlab_setWallpaperHints" msgid="4995885499848128983">"establecer sugerencias de tamaño del fondo de pantalla"</string>
-    <!-- XL -->
-    <string name="permdesc_setWallpaperHints" msgid="8857901708691279048">"Admite que la aplicación establezca las sugerencias de tamaño del fondo de pantalla del sistema."</string>
-    <!-- XL -->
-    <string name="permdesc_setTime" product="tablet" msgid="7329574196603775554">"Permite que una aplicación cambie la hora de la tableta."</string>
-    <string name="permdesc_setTime" product="default" msgid="7787175369529849526">"Permite a una aplicación cambiar la hora del teléfono."</string>
-    <!-- XL -->
-    <string name="permdesc_setTimeZone" product="tablet" msgid="3851480395450283316">"Permite que una aplicación cambie la zona horaria de la tableta."</string>
-    <string name="permdesc_setTimeZone" product="default" msgid="3231143515254577541">"Admite una aplicación que cambia la zona horaria del teléfono."</string>
-    <!-- XL -->
-    <string name="permdesc_getAccounts" product="tablet" msgid="374861616407073729">"Permite que una aplicación obtenga una la lista de cuentas conocidas por la tableta."</string>
-    <string name="permdesc_getAccounts" product="default" msgid="6356501268884684429">"Admite una aplicación que obtiene la lista de cuentas conocidas del teléfono."</string>
-    <!-- XL -->
-    <string name="permdesc_bluetoothAdmin" product="tablet" msgid="8034248164659819866">"Permite que una aplicación configure el Bluetooth local de la tableta, y descubra y se vincule con dispositivos remotos."</string>
-    <string name="permdesc_bluetoothAdmin" product="default" msgid="2555370145147752776">"Admite una aplicación que configura el teléfono Bluetooth local y descubre y se vincula con dispositivos remotos."</string>
-    <!-- XL -->
-    <string name="permdesc_bluetooth" product="tablet" msgid="4631562404621086816">"Permite que una aplicación vea la configuración de la tableta Bluetooth local, y que realice y acepte conexiones con dispositivos vinculados."</string>
-    <string name="permdesc_bluetooth" product="default" msgid="1202135959389935958">"Admite una aplicación que ve la configuración del teléfono Bluetooth local, y realiza y acepta conexiones con dispositivos vinculados."</string>
-    <!-- XL -->
-    <string name="policydesc_watchLogin" product="tablet" msgid="7927990389488709968">"Supervisar el número de contraseñas incorrectas ingresadas al desbloquear la pantalla, y bloquear la tableta o eliminar todos los datos del teléfono si se ingresan demasiadas contraseñas incorrectas."</string>
-    <string name="policydesc_watchLogin" product="default" msgid="4998594853332798741">"Supervisa el número de contraseñas incorrectas ingresadas al desbloquear la pantalla, y bloquee el teléfono o elimine todos los datos del teléfono si se ingresan demasiadas contraseñas incorrectas."</string>
-    <!-- XL -->
-    <string name="policydesc_wipeData" product="tablet" msgid="7871059407132175855">"Borrar los datos de la tableta sin advertencias, restableciendo la configuración de fábrica"</string>
-    <string name="policydesc_wipeData" product="default" msgid="6003127471292136411">"Borrar los datos del teléfono sin advertencias al restablecer la configuración original"</string>
-    <!-- XL -->
-  <string-array name="phoneTypes">
-    <item msgid="7066790683658405096">"Pantalla principal"</item>
-    <item msgid="5813675571320075289">"Teléfono móvil"</item>
-    <item msgid="1236863745322977021">"Trabajo"</item>
-    <item msgid="7018038125868933566">"Fax laboral"</item>
-    <item msgid="4280105707643078852">"Fax personal"</item>
-    <item msgid="6527083287534782580">"Localizador"</item>
-    <item msgid="706618935041239888">"Otro"</item>
-    <item msgid="8099625332540070724">"Personalizado"</item>
-  </string-array>
-    <!-- XL -->
-  <string-array name="emailAddressTypes">
-    <item msgid="8080673853442355385">"Pantalla principal"</item>
-    <item msgid="924798042157989715">"Trabajo"</item>
-    <item msgid="1959796935508361158">"Otro"</item>
-    <item msgid="756534161520555926">"Personalizado"</item>
-  </string-array>
-    <!-- XL -->
-  <string-array name="postalAddressTypes">
-    <item msgid="1166454994471190496">"Pantalla principal"</item>
-    <item msgid="3602955376664951787">"Trabajo"</item>
-    <item msgid="4646105398231575508">"Otro"</item>
-    <item msgid="8191179302220976184">"Personalizado"</item>
-  </string-array>
-    <!-- XL -->
-  <string-array name="imAddressTypes">
-    <item msgid="2528436635522549040">"Pantalla principal"</item>
-    <item msgid="5834207144511084508">"Trabajo"</item>
-    <item msgid="3796683891024584813">"Otro"</item>
-    <item msgid="6644316676098098833">"Personalizado"</item>
-  </string-array>
-    <!-- XL -->
-  <string-array name="organizationTypes">
-    <item msgid="6571823895277482483">"Trabajo"</item>
-    <item msgid="4013674940836786104">"Otro"</item>
-    <item msgid="8549998141814637453">"Personalizado"</item>
-  </string-array>
-    <!-- XL -->
-    <string name="phoneTypeHome" msgid="2087652870939635038">"Pantalla principal"</string>
-    <!-- XL -->
-    <string name="phoneTypeMobile" msgid="7084573626440935140">"Teléfono móvil"</string>
-    <!-- XL -->
-    <string name="emailTypeHome" msgid="1298773522695936612">"Pantalla principal"</string>
-    <!-- XL -->
-    <string name="emailTypeMobile" msgid="5515624509217674980">"Teléfono móvil"</string>
-    <!-- XL -->
-    <string name="postalTypeHome" msgid="7553888805834710738">"Pantalla principal"</string>
-    <!-- XL -->
-    <string name="imTypeHome" msgid="3732426015472142690">"Pantalla principal"</string>
-    <!-- XL -->
-    <string name="sipAddressTypeHome" msgid="8212230577724692911">"Pantalla principal"</string>
-    <!-- XL -->
-    <string name="lockscreen_pattern_instructions" msgid="9171665895877154059">"Extraer el patrón para desbloquear"</string>
-    <!-- XL -->
-    <string name="lockscreen_battery_short" msgid="891372653127247039">"Segmento <xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
-    <!-- XL -->
-    <string name="lockscreen_missing_sim_message" product="tablet" msgid="3961770350078423154">"No hay tarjeta SIM en la tableta."</string>
-    <string name="lockscreen_missing_sim_message" product="default" msgid="5997031739677800758">"No hay tarjeta SIM en el teléfono."</string>
-    <!-- XL -->
-    <string name="lockscreen_too_many_failed_attempts_dialog_message" msgid="2429599468920598896">"Has establecido incorrectamente tu gráfico de desbloqueo <xliff:g id="NUMBER_0">%d</xliff:g> veces. "\n\n"Vuelve a intentarlo en <xliff:g id="NUMBER_1">%d</xliff:g> segundos."</string>
-    <!-- XL -->
-    <string name="lockscreen_failed_attempts_almost_glogin" product="tablet" msgid="3211267232692817092">"Has establecido incorrectamente tu gráfico de desbloqueo <xliff:g id="NUMBER_0">%d</xliff:g> veces. Luego de <xliff:g id="NUMBER_1">%d</xliff:g> intentos incorrectos más, se te solicitará que desbloquees tu tableta al acceder a Google."\n\n" Vuelve a intentarlo en <xliff:g id="NUMBER_2">%d</xliff:g> segundos."</string>
-    <string name="lockscreen_failed_attempts_almost_glogin" product="default" msgid="7097890594752816076">"Has establecido incorrectamente tu gráfico de desbloqueo <xliff:g id="NUMBER_0">%d</xliff:g> veces. Luego de <xliff:g id="NUMBER_1">%d</xliff:g> intentos incorrectos, se te solicitará que desbloquees tu teléfono al acceder a Google. "\n\n" Vuelve a intentarlo en <xliff:g id="NUMBER_2">%d</xliff:g> segundos."</string>
-    <!-- XL -->
-    <string name="lockscreen_glogin_submit_button" msgid="4760302858316749698">"Acceder"</string>
-    <!-- XL -->
-    <string name="lockscreen_glogin_invalid_input" msgid="7265806099449246244">"Nombre de usuario o contraseña no válidos."</string>
-    <!-- XL -->
-    <string name="hour_ampm" msgid="6161399724998500216">"Segmento <xliff:g id="HOUR">%-l</xliff:g><xliff:g id="AMPM">%P</xliff:g>"</string>
-    <!-- XL -->
-    <string name="hour_cap_ampm" msgid="724197720606114012">"Segmento <xliff:g id="HOUR">%-l</xliff:g><xliff:g id="AMPM">%p</xliff:g>"</string>
-    <!-- XL -->
-    <string name="double_tap_toast" msgid="2893001600485832537">"Sugerencia: presiona dos veces para acercar y alejar"</string>
-    <!-- XL -->
-    <string name="autofill_address_name_separator" msgid="5171727678145785075">" Segmento "</string>
-    <!-- XL -->
-    <string name="permlab_readHistoryBookmarks" msgid="6148149152792104516">"leer historial y favoritos del navegador"</string>
-    <!-- XL -->
-    <string name="permdesc_readHistoryBookmarks" msgid="7371336472744100059">"Permite a la aplicación leer todas las URL que ha visitado el navegador y todos los favoritos del navegador."</string>
-    <!-- XL -->
-    <string name="permlab_writeHistoryBookmarks" msgid="1369319390968848231">"escribir historial y favoritos del navegador"</string>
-    <!-- XL -->
-    <string name="permdesc_writeHistoryBookmarks" product="tablet" msgid="3870229397949634482">"Permite que una aplicación modifique el historial de navegación y los favoritos del navegador almacenados en tu tableta. Las aplicaciones maliciosas pueden utilizarlo para borrar o modificar los datos en tu navegador."</string>
-    <string name="permdesc_writeHistoryBookmarks" product="default" msgid="6845659334691579933">"Permite a una aplicación modificar el historial y los favoritos del navegador almacenados en tu teléfono. Las aplicaciones maliciosas pueden utilizarlo para borrar o modificar tus datos."</string>
-    <!-- XL -->
-    <string name="permlab_setAlarm" msgid="8112208516527103653">"fija la alarma en el reloj de alarma"</string>
-    <!-- XL -->
-    <string name="permdesc_setAlarm" msgid="5454386032150297784">"Permite a la aplicación fijar una alarma en una aplicación de alarma. Es posible que algunas aplicaciones de alarma no implementen esta función."</string>
-    <!-- XL -->
-    <string name="menu_delete_shortcut_label" msgid="8482704027019632634">"eliminar"</string>
-    <!-- XL -->
-  <plurals name="num_minutes_ago">
-    <item quantity="one" msgid="468685153446407901">"hace 1 minuto"</item>
-    <item quantity="other" msgid="211907662145171054">"Hace <xliff:g id="COUNT">%d</xliff:g> minutos"</item>
-  </plurals>
-    <!-- XL -->
-  <plurals name="num_hours_ago">
-    <item quantity="one" msgid="2172827344495633666">"hace 1 hora"</item>
-    <item quantity="other" msgid="6094391999921908511">"Hace <xliff:g id="COUNT">%d</xliff:g> horas"</item>
-  </plurals>
-    <!-- XL -->
-  <plurals name="num_days_ago">
-    <item quantity="one" msgid="3766494702684657165">"ayer"</item>
-    <item quantity="other" msgid="5030316952487658828">"Hace <xliff:g id="COUNT">%d</xliff:g> días"</item>
-  </plurals>
-    <!-- XL -->
-  <plurals name="abbrev_num_seconds_ago">
-    <item quantity="one" msgid="1441918190525197797">"hace 1 s"</item>
-    <item quantity="other" msgid="3958332340802316933">"hace <xliff:g id="COUNT">%d</xliff:g> segundos"</item>
-  </plurals>
-    <!-- XL -->
-  <plurals name="abbrev_num_minutes_ago">
-    <item quantity="one" msgid="3404245071272952255">"hace 1 min"</item>
-    <item quantity="other" msgid="6004808520903389765">"hace <xliff:g id="COUNT">%d</xliff:g> min"</item>
-  </plurals>
-    <!-- XL -->
-  <plurals name="abbrev_num_hours_ago">
-    <item quantity="one" msgid="806010152744475654">"hace 1 hora"</item>
-    <item quantity="other" msgid="7553525762196895290">"Hace <xliff:g id="COUNT">%d</xliff:g> horas"</item>
-  </plurals>
-    <!-- XL -->
-  <plurals name="abbrev_num_days_ago">
-    <item quantity="one" msgid="5819444260187611238">"ayer"</item>
-    <item quantity="other" msgid="1069986768190052012">"Hace <xliff:g id="COUNT">%d</xliff:g> días"</item>
-  </plurals>
-    <!-- XL -->
-    <string name="preposition_for_time" msgid="3606608741888559522">"a la/s <xliff:g id="TIME">%s</xliff:g>"</string>
-    <!-- XL -->
-    <string name="minutes" msgid="1486240209627391507">"min"</string>
-    <!-- XL -->
-    <string name="selectAll" msgid="847570914566450966">"Seleccionar todos"</string>
-    <!-- XL -->
-    <string name="low_internal_storage_view_text" product="tablet" msgid="6497548813789342134">"Está quedando poco espacio de almacenamiento en la tableta."</string>
-    <string name="low_internal_storage_view_text" product="default" msgid="2901569701336868928">"Hay poco espacio de almacenamiento en el teléfono."</string>
-    <!-- XL -->
-    <string name="capital_on" msgid="5705918046896729554">"ENCENDIDO"</string>
-    <!-- XL -->
-    <string name="wait" msgid="8036803866051401072">"Espera"</string>
-    <!-- XL -->
-    <string name="heavy_weight_notification" msgid="5762367358298413602">"<xliff:g id="APP">%1$s</xliff:g> se está ejecutando"</string>
-    <!-- XL -->
-    <string name="ext_media_checking_notification_title" product="nosdcard" msgid="103298639852047758">"Preparando almacenamiento USB"</string>
-    <string name="ext_media_checking_notification_title" product="default" msgid="2111086053471573248">"Preparando la tarjeta SD"</string>
-    <!-- XL -->
-    <string name="ime_action_done" msgid="7200237418945571897">"Listo"</string>
-    <!-- XL -->
-    <string name="wallpaper_binding_label" msgid="6966627494441714436">"Fondo de pantalla"</string>
-    <!-- XL -->
-    <string name="websearch" msgid="904596193450917688">"Búsqueda web"</string>
-    <!-- XL -->
-    <string name="status_bar_notification_info_overflow" msgid="1081154808901480710">"100+"</string>
-    <!-- XL -->
-    <string name="permlab_accessMtp" msgid="2385215229145694622">"implementar protocolo MTP"</string>
-    <!-- XL -->
-    <string name="permdesc_accessMtp" msgid="4707854877711083465">"Permite acceso al driver kernel MTP para implementar el protocolo MTP USB."</string>
-    <!-- XL -->
-    <string name="permlab_mediaStorageWrite" product="default" msgid="5585262071354704256">"modificar/eliminar los contenidos del almacenamientos de medios internos"</string>
-    <!-- XL -->
-    <string name="permdesc_mediaStorageWrite" product="default" msgid="2372999661142345443">"Permite que una aplicación modifique los contenidos del almacenamiento interno de medios."</string>
-    <!-- XL -->
-    <string name="autofill_address_summary_name_format" msgid="7531610259426153850">"$1$2$3"</string>
-    <!-- XL -->
-    <string name="autofill_address_summary_format" msgid="8398158823767723887">"$1$2$3"</string>
-    <!-- XL -->
-    <string name="gpsNotifTicker" msgid="6612390321359669319">"Solicitud de ubicación de <xliff:g id="NAME">%s</xliff:g>"</string>
-    <!-- XL -->
-    <string name="gpsNotifTitle" msgid="7533028619350196545">"Solicitud de ubicación"</string>
-    <!-- XL -->
-    <string name="gpsNotifMessage" msgid="5592972401593755530">"Solicitado por <xliff:g id="NAME">%1$s</xliff:g> (<xliff:g id="SERVICE">%2$s</xliff:g>)"</string>
-    <!-- XL -->
-    <string name="gpsVerifYes" msgid="1511016393202739483">"Sí"</string>
-    <!-- XL -->
-    <string name="gpsVerifNo" msgid="661731239940896232">"No"</string>
-    <!-- XL -->
-    <string name="sync_too_many_deletes" msgid="6088394702274114202">"Eliminar el límite excedido"</string>
-    <!-- XL -->
-    <string name="sync_too_many_deletes_desc" msgid="4794082462774743277">"Existen <xliff:g id="NUMBER_OF_DELETED_ITEMS">%1$d</xliff:g> artículos eliminados para <xliff:g id="TYPE_OF_SYNC">%2$s</xliff:g>, cuenta <xliff:g id="ACCOUNT_NAME">%3$s</xliff:g>. ¿Qué te gustaría hacer?"</string>
-    <!-- XL -->
-    <string name="sync_really_delete" msgid="7782215155483034729">"Eliminar artículos."</string>
-    <!-- XL -->
-    <string name="sync_undo_deletes" msgid="6501390120900825477">"Deshacer eliminaciones."</string>
-    <!-- XL -->
-    <string name="sync_do_nothing" msgid="612038572646360281">"No hagas nada por el momento."</string>
-</resources>
diff --git a/core/res/res/values-es-rUS/strings.xml b/core/res/res/values-es-rUS/strings.xml
index 35d425b..0052b18 100644
--- a/core/res/res/values-es-rUS/strings.xml
+++ b/core/res/res/values-es-rUS/strings.xml
@@ -211,7 +211,7 @@
     <string name="permlab_enableCarMode" msgid="5684504058192921098">"habilitar el modo de auto"</string>
     <string name="permdesc_enableCarMode" msgid="5673461159384850628">"Permite que una aplicación habilite el modo auto."</string>
     <string name="permlab_killBackgroundProcesses" msgid="8373714752793061963">"eliminar los procesos de fondo"</string>
-    <string name="permdesc_killBackgroundProcesses" msgid="2908829602869383753">"Permite que una aplicación elimine los procesos de fondo de otras aplicaciones, aun si la memoria no es baja."</string>
+    <string name="permdesc_killBackgroundProcesses" msgid="2908829602869383753">"Permite que una aplicación elimine los procesos de fondo de otras aplicaciones, aun si la no queda poco espacio en la memoria."</string>
     <string name="permlab_forceStopPackages" msgid="1447830113260156236">"forzar la detención de otras aplicaciones"</string>
     <string name="permdesc_forceStopPackages" msgid="7263036616161367402">"Permite que una aplicación provoque la detención de otras aplicaciones."</string>
     <string name="permlab_forceBack" msgid="1804196839880393631">"provocar que la aplicación se acerque"</string>
@@ -257,7 +257,7 @@
     <string name="permdesc_bindWallpaper" msgid="5287754520361915347">"Permite al propietario vincularse a la interfaz de nivel superior de un fondo de pantalla. Se debe evitar utilizarlo en aplicaciones normales."</string>
     <string name="permlab_bindRemoteViews" msgid="5697987759897367099">"vincular a un servicio de widget"</string>
     <string name="permdesc_bindRemoteViews" msgid="2930855984822926963">"Permite al propietario vincularse a la interfaz de nivel superior del servicio de widget. Se debe evitar utilizarlo en aplicaciones normales."</string>
-    <string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"interactuar con un administrador de dispositivo"</string>
+    <string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"interactuar con un administrador de dispositivos"</string>
     <string name="permdesc_bindDeviceAdmin" msgid="8714424333082216979">"Permite que el propietario envíe sus intentos a un administrador de dispositivos. No se necesita para las aplicaciones normales."</string>
     <string name="permlab_setOrientation" msgid="3365947717163866844">"cambiar la orientación de la pantalla"</string>
     <string name="permdesc_setOrientation" msgid="6335814461615851863">"Admite una aplicación que cambia la rotación de la pantalla en cualquier momento. Se debe evitar utilizarlo en aplicaciones normales."</string>
@@ -277,12 +277,12 @@
     <string name="permdesc_installPackages" msgid="526669220850066132">"Admite una aplicación que instala paquetes de Android nuevos o actualizados. Las aplicaciones maliciosas pueden utilizarlo para agregar aplicaciones nuevas con permisos arbitrariamente potentes."</string>
     <string name="permlab_clearAppCache" msgid="4747698311163766540">"eliminar todos los datos de memoria caché de la aplicación"</string>
     <string name="permdesc_clearAppCache" product="tablet" msgid="3097119797652477973">"Permite que una aplicación libere espacio de almacenamiento en el tablet eliminando archivos del directorio de memoria caché de la aplicación. En general, el acceso es muy restringido para el proceso del sistema."</string>
-    <string name="permdesc_clearAppCache" product="default" msgid="7740465694193671402">"Admite una aplicación que libera espacio de almacenamiento en el teléfono al eliminar archivos del directorio de memoria caché de la aplicación. En general, el acceso es muy restringido para el proceso del sistema."</string>
+    <string name="permdesc_clearAppCache" product="default" msgid="7740465694193671402">"Permite que una aplicación libere espacio de almacenamiento en el teléfono borrando archivos del directorio de memoria caché de la aplicación. En general el acceso está muy restringido al proceso del sistema."</string>
     <string name="permlab_movePackage" msgid="728454979946503926">"Mover recursos de la aplicación"</string>
     <string name="permdesc_movePackage" msgid="6323049291923925277">"Permite a una aplicación mover recursos de aplicación de medios internos a externos y viceversa."</string>
     <string name="permlab_readLogs" msgid="6615778543198967614">"lee los datos confidenciales del registro"</string>
     <string name="permdesc_readLogs" product="tablet" msgid="4077356893924755294">"Permite que una aplicación lea diversos archivos de registro del sistema. Esto le permite descubrir información general acerca de lo que haces con el tablet, y puede potencialmente incluir información personal o privada."</string>
-    <string name="permdesc_readLogs" product="default" msgid="8896449437464867766">"Admite una aplicación que lee diversos archivos de registro del sistema. Esto te permite descubrir información general acerca de lo que haces con el teléfono, y puede potencialmente incluir información personal o privada."</string>
+    <string name="permdesc_readLogs" product="default" msgid="8896449437464867766">"Permite que una aplicación lea los diversos archivos de registro del sistema. Esto le permite descubrir información general acerca de lo que haces con el teléfono, y puede potencialmente incluir información personal o privada."</string>
     <string name="permlab_diagnostic" msgid="8076743953908000342">"leer y escribir a recursos dentro del grupo de diagnóstico"</string>
     <string name="permdesc_diagnostic" msgid="3121238373951637049">"Admite una aplicación que lee y escribe a cualquier recurso dentro del grupo de diagnóstico; por ejemplo, archivos con /dev. Esto puede afectar potencialmente la estabilidad y la seguridad del sistema. Debe utilizarlo SÓLO el fabricante o el operador en los diagnósticos específicos del hardware."</string>
     <string name="permlab_changeComponentState" msgid="79425198834329406">"activar o desactivar componentes de la aplicación"</string>
@@ -296,15 +296,15 @@
     <string name="permdesc_writeSecureSettings" msgid="5497873143539034724">"Permite a una aplicación modificar los datos de la configuración segura de los sistemas. Las aplicaciones normales no deben utilizarlo."</string>
     <string name="permlab_writeGservices" msgid="2149426664226152185">"modificar el mapa de servicios de Google"</string>
     <string name="permdesc_writeGservices" msgid="6602362746516676175">"Admite una aplicación que modifica el mapa de servicios de Google. Las aplicaciones normales no deben utilizarlo."</string>
-    <string name="permlab_receiveBootCompleted" msgid="7776779842866993377">"iniciar automáticamente durante la inicialización"</string>
+    <string name="permlab_receiveBootCompleted" msgid="7776779842866993377">"ejecutar automáticamente al iniciar"</string>
     <string name="permdesc_receiveBootCompleted" product="tablet" msgid="7530977064379338199">"Permite que una aplicación se inicie en cuanto el sistema haya finalizado la inicialización. Esto puede ocasionar que el tablet demore más en inicializar y que la aplicación retarde el funcionamiento total del tablet al estar en ejecución constante."</string>
-    <string name="permdesc_receiveBootCompleted" product="default" msgid="698336728415008796">"Admite una aplicación que se inicia cuando el sistema haya finalizado la inicialización. Esto puede ocasionar que se demore más tiempo en inicializar el teléfono y que la aplicación retarde el funcionamiento total del teléfono al estar en ejecución constante."</string>
+    <string name="permdesc_receiveBootCompleted" product="default" msgid="698336728415008796">"Permite que una aplicación se inicie en cuanto el sistema haya finalizado la inicialización. Esto puede ocasionar que el teléfono tarde más en inicializarse y que la aplicación demore el funcionamiento total del teléfono al estar en ejecución constante."</string>
     <string name="permlab_broadcastSticky" msgid="7919126372606881614">"enviar emisiones pegajosas"</string>
     <string name="permdesc_broadcastSticky" product="tablet" msgid="6322249605930062595">"Permite que una aplicación envíe emisiones adhesivas, que permanecen luego de que finaliza la emisión. Las aplicaciones maliciosas pueden hacer que la tableta funcione más lento y esté inestable haciendo que utilicen demasiada memoria."</string>
     <string name="permdesc_broadcastSticky" product="default" msgid="1920045289234052219">"Admite una aplicación que envía emisiones pegajosas, las cuales permanecen luego de que finaliza la emisión. Las aplicaciones maliciosas pueden hacer lento e inestable al teléfono, ya que ocasiona que utilice demasiada memoria."</string>
     <string name="permlab_readContacts" msgid="6219652189510218240">"leer datos de contacto"</string>
     <string name="permdesc_readContacts" product="tablet" msgid="7596158687301157686">"Permite que una aplicación lea todos los datos de de contacto (direcciones) almacenados en tu tablet. Las aplicaciones maliciosas pueden utilizarlo para enviar tus datos a otras personas."</string>
-    <string name="permdesc_readContacts" product="default" msgid="3371591512896545975">"Admite una aplicación que lee todos los datos de (direcciones) de contactos almacenados en tu teléfono. Las aplicaciones maliciosas pueden utilizarlo para enviar tus eventos de calendario a otras personas."</string>
+    <string name="permdesc_readContacts" product="default" msgid="3371591512896545975">"Permite que una aplicación lea todos los datos (direcciones) de contactos almacenados en tu tablet. Las aplicaciones maliciosas pueden utilizarlo para enviar tus datos a otras personas."</string>
     <string name="permlab_writeContacts" msgid="644616215860933284">"escribir datos de contacto"</string>
     <string name="permdesc_writeContacts" product="tablet" msgid="7782689510038568495">"Permite que una aplicación modifique los datos de (dirección) guardados en tu tablet. Las aplicaciones maliciosas pueden utilizarlo para borrar o modificar los datos de contacto."</string>
     <string name="permdesc_writeContacts" product="default" msgid="3924383579108183601">"Admite una aplicación que modifica los datos de (dirección de) contacto guardados en tu teléfono. Las aplicaciones maliciosas pueden utilizarlo para borrar o modificar los datos de contacto."</string>
@@ -340,9 +340,9 @@
     <string name="permdesc_brick" product="tablet" msgid="7379164636920817963">"Permite que la aplicación desactive todo el tablet de manera permanente. Esto es muy peligroso."</string>
     <string name="permdesc_brick" product="default" msgid="5569526552607599221">"Admite que la aplicación desactive todo el teléfono de manera permanente. Esto es muy peligroso."</string>
     <string name="permlab_reboot" product="tablet" msgid="3436634972561795002">"forzar reinicio del tablet"</string>
-    <string name="permlab_reboot" product="default" msgid="2898560872462638242">"provocar el reinicio del teléfono"</string>
+    <string name="permlab_reboot" product="default" msgid="2898560872462638242">"forzar reinicio del teléfono"</string>
     <string name="permdesc_reboot" product="tablet" msgid="4555793623560701557">"Permite que la aplicación provoque el reinicio del tablet."</string>
-    <string name="permdesc_reboot" product="default" msgid="7914933292815491782">"Admite que la aplicación provoque que el teléfono se reinicie."</string>
+    <string name="permdesc_reboot" product="default" msgid="7914933292815491782">"Permite que la aplicación fuerce el reinicio del tablet."</string>
     <string name="permlab_mount_unmount_filesystems" msgid="1761023272170956541">"montar y desmontar filesystems"</string>
     <string name="permdesc_mount_unmount_filesystems" msgid="6253263792535859767">"Admite que la aplicación monte y desmonte filesystems para obtener almacenamiento extraíble."</string>
     <string name="permlab_mount_format_filesystems" msgid="5523285143576718981">"espacio de almacenamiento externo del formato"</string>
@@ -361,8 +361,8 @@
     <string name="permdesc_vibrate" msgid="2886677177257789187">"Admite que la aplicación controle el vibrador."</string>
     <string name="permlab_flashlight" msgid="2155920810121984215">"controlar linterna"</string>
     <string name="permdesc_flashlight" msgid="6433045942283802309">"Admite que la aplicación controle la linterna."</string>
-    <string name="permlab_accessUsb" msgid="7362327818655760496">"acceder a dispositivos USB"</string>
-    <string name="permdesc_accessUsb" msgid="2414271762914049292">"Permite que la aplicación acceda a dispositivos USB."</string>
+    <string name="permlab_manageUsb" msgid="1113453430645402723">"administrar preferencias y permisos para los dispositivos USB"</string>
+    <string name="permdesc_manageUsb" msgid="6148489202092166164">"Permite a la aplicación administrar preferencias y permisos para los dispositivos USB."</string>
     <string name="permlab_accessMtp" msgid="4953468676795917042">"implementar protocolo MTP"</string>
     <string name="permdesc_accessMtp" msgid="6532961200486791570">"Permite acceso al driver kernel MTP para implementar el protocolo MTP USB."</string>
     <string name="permlab_hardware_test" msgid="4148290860400659146">"probar el hardware"</string>
@@ -372,7 +372,7 @@
     <string name="permlab_callPrivileged" msgid="4198349211108497879">"llamar directamente a cualquier número de teléfono"</string>
     <string name="permdesc_callPrivileged" msgid="244405067160028452">"Admite que la aplicación llame a cualquier número de teléfono, incluidos los números de emergencia, sin tu intervención. Las aplicaciones maliciosas pueden realizar llamadas innecesarias e ilegales a los servicios de emergencia."</string>
     <string name="permlab_performCdmaProvisioning" product="tablet" msgid="4842576994144604821">"iniciar directamente la configuración CDMA del tablet"</string>
-    <string name="permlab_performCdmaProvisioning" product="default" msgid="5604848095315421425">"comienza directamente la configuración CDMA del teléfono"</string>
+    <string name="permlab_performCdmaProvisioning" product="default" msgid="5604848095315421425">"iniciar directamente la configuración CDMA del teléfono"</string>
     <string name="permdesc_performCdmaProvisioning" msgid="6457447676108355905">"Admite la aplicación para comenzar con el aprovisionamiento CDMA. Las aplicaciones maliciosas pueden comenzar con el aprovisionamiento CDMA sin necesidad."</string>
     <string name="permlab_locationUpdates" msgid="7785408253364335740">"controlar las notificaciones de actualización de ubicación"</string>
     <string name="permdesc_locationUpdates" msgid="2300018303720930256">"Permite activar y desactivar las notificaciones de actualización de ubicación de la radio. Las aplicaciones normales no deben utilizarlo."</string>
@@ -427,7 +427,7 @@
     <string name="permlab_changeNetworkState" msgid="958884291454327309">"cambiar la conectividad de la red"</string>
     <string name="permdesc_changeNetworkState" msgid="4199958910396387075">"Permite que una aplicación cambie el estado de la conectividad de red."</string>
     <string name="permlab_changeTetherState" msgid="2702121155761140799">"Cambiar la conectividad de anclaje a red"</string>
-    <string name="permdesc_changeTetherState" msgid="8905815579146349568">"Permite que una aplicación cambie el estado de la conectividad de red del anclaje."</string>
+    <string name="permdesc_changeTetherState" msgid="8905815579146349568">"ermite que una aplicación cambie el estado de la conectividad de anclaje a red."</string>
     <string name="permlab_changeBackgroundDataSetting" msgid="1400666012671648741">"cambiar la configuración del uso de datos del fondo"</string>
     <string name="permdesc_changeBackgroundDataSetting" msgid="1001482853266638864">"Admite una aplicación que cambia la configuración del uso de datos del fondo."</string>
     <string name="permlab_accessWifiState" msgid="8100926650211034400">"ver el estado de Wi-Fi"</string>
@@ -484,8 +484,8 @@
     <string name="policydesc_wipeData" product="default" msgid="7669895333814222586">"Borrar los datos del teléfono sin advertencias al restablecer la configuración original"</string>
     <string name="policylab_setGlobalProxy" msgid="2784828293747791446">"Configura el proxy global de dispositivo"</string>
     <string name="policydesc_setGlobalProxy" msgid="6387497466660154931">"Configuración del proxy global de dispositivo que se utilizará mientras se habilita la política. Sólo la primera administración de dispositivo configura el proxy global efectivo."</string>
-    <!-- outdated translation 4740941403188940274 -->     <string name="policylab_expirePassword" msgid="885279151847254056">"Establecer la caducidad de la contraseña"</string>
-    <!-- outdated translation 6626724939177185949 -->     <string name="policydesc_expirePassword" msgid="4844430354224822074">"Verifica cuánto tiempo antes debes cambiar la contraseña de la pantalla de bloqueo"</string>
+    <string name="policylab_expirePassword" msgid="885279151847254056">"Establecer la caducidad del bloqueo de pantalla"</string>
+    <string name="policydesc_expirePassword" msgid="4844430354224822074">"Controlar cuán a menudo se debe cambiar la contraseña de bloqueo de pantalla"</string>
     <string name="policylab_encryptedStorage" msgid="8901326199909132915">"Establecer la encriptación del almacenamiento"</string>
     <string name="policydesc_encryptedStorage" msgid="2504984732631479399">"Requiere que los datos almacenados de la aplicación estén encriptados"</string>
   <string-array name="phoneTypes">
@@ -814,6 +814,7 @@
     <string name="alwaysUse" msgid="4583018368000610438">"Utilizar de manera predeterminada en esta acción."</string>
     <string name="clearDefaultHintMsg" msgid="4815455344600932173">"Borrar la predeterminación en Configuración de la página principal &gt; Aplicaciones &gt; Administrar aplicaciones."</string>
     <string name="chooseActivity" msgid="1009246475582238425">"Seleccionar una acción"</string>
+    <string name="chooseUsbActivity" msgid="7892597146032121735">"Selecciona una aplicación para el dispositivo USB."</string>
     <string name="noApplications" msgid="1691104391758345586">"Ninguna aplicación puede realizar esta acción."</string>
     <string name="aerr_title" msgid="653922989522758100">"¡Lo sentimos!"</string>
     <string name="aerr_application" msgid="4683614104336409186">"La aplicación <xliff:g id="APPLICATION">%1$s</xliff:g> (proceso <xliff:g id="PROCESS">%2$s</xliff:g>) se ha detenido de forma imprevista. Vuelve a intentarlo."</string>
@@ -831,7 +832,7 @@
     <string name="launch_warning_original" msgid="188102023021668683">"<xliff:g id="APP_NAME">%1$s</xliff:g> se inició originalmente."</string>
     <string name="smv_application" msgid="295583804361236288">"La aplicación <xliff:g id="APPLICATION">%1$s</xliff:g> (proceso <xliff:g id="PROCESS">%2$s</xliff:g>) ha violado su política StrictMode autoimpuesta."</string>
     <string name="smv_process" msgid="5120397012047462446">"El proceso <xliff:g id="PROCESS">%1$s</xliff:g> ha violado su política StrictMode autoimpuesta."</string>
-    <string name="heavy_weight_notification" msgid="9087063985776626166">"<xliff:g id="APP">%1$s</xliff:g> Correr"</string>
+    <string name="heavy_weight_notification" msgid="9087063985776626166">"<xliff:g id="APP">%1$s</xliff:g> en ejecución"</string>
     <string name="heavy_weight_notification_detail" msgid="2423977499339403402">"Selecciona cambiar la aplicación"</string>
     <string name="heavy_weight_switcher_title" msgid="1135403633766694316">"¿Deseas cambiar aplicaciones?"</string>
     <string name="heavy_weight_switcher_text" msgid="4592075610079319667">"Ya se está ejecutando una aplicación que debe detenerse antes de iniciar una nueva."</string>
@@ -919,17 +920,17 @@
     <string name="ext_media_unmountable_notification_message" product="nosdcard" msgid="529021299294450667">"Almacenamiento USB dañado. Es posible que debas reformatearlo."</string>
     <string name="ext_media_unmountable_notification_message" product="default" msgid="6902531775948238989">"Tarjeta SD dañada. Es posible que debas reformatearla."</string>
     <string name="ext_media_badremoval_notification_title" product="nosdcard" msgid="1661683031330951073">"Almacenamiento USB extraído inesperadamente"</string>
-    <string name="ext_media_badremoval_notification_title" product="default" msgid="6872152882604407837">"Tarjeta SD extraída de forma imprevista"</string>
+    <string name="ext_media_badremoval_notification_title" product="default" msgid="6872152882604407837">"Almacenamiento USB extraído de forma imprevista"</string>
     <string name="ext_media_badremoval_notification_message" product="nosdcard" msgid="4329848819865594241">"Desmontar el almacenamiento USB antes de extraerlo para evitar la pérdida de datos."</string>
     <string name="ext_media_badremoval_notification_message" product="default" msgid="7260183293747448241">"Desmontar la tarjeta SD antes de extraerla para evitar la pérdida de datos."</string>
     <string name="ext_media_safe_unmount_notification_title" product="nosdcard" msgid="3967973893270360230">"Es seguro extraer el almacenamiento USB"</string>
-    <string name="ext_media_safe_unmount_notification_title" product="default" msgid="6729801130790616200">"Tarjeta SD fácil de extraer"</string>
+    <string name="ext_media_safe_unmount_notification_title" product="default" msgid="6729801130790616200">"Es seguro extraer la tarjeta SD"</string>
     <string name="ext_media_safe_unmount_notification_message" product="nosdcard" msgid="6142195361606493530">"Puedes extraer de forma segura el almacenamiento USB."</string>
-    <string name="ext_media_safe_unmount_notification_message" product="default" msgid="568841278138377604">"Puedes eliminar la tarjeta SD sin riesgos."</string>
+    <string name="ext_media_safe_unmount_notification_message" product="default" msgid="568841278138377604">"Puedes extraer de forma segura la tarjeta SD."</string>
     <string name="ext_media_nomedia_notification_title" product="nosdcard" msgid="4486377230140227651">"Almacenamiento USB extraído"</string>
     <string name="ext_media_nomedia_notification_title" product="default" msgid="8902518030404381318">"Tarjeta SD extraída"</string>
     <string name="ext_media_nomedia_notification_message" product="nosdcard" msgid="6921126162580574143">"Almacenamiento USB eliminado. Insertar nuevos medios."</string>
-    <string name="ext_media_nomedia_notification_message" product="default" msgid="3870120652983659641">"Tarjeta SD eliminada. Inserta una nueva."</string>
+    <string name="ext_media_nomedia_notification_message" product="default" msgid="3870120652983659641">"Tarjeta SD extraída. Insertar una nueva."</string>
     <string name="activity_list_empty" msgid="4168820609403385789">"No se encontraron actividades coincidentes"</string>
     <string name="permlab_pkgUsageStats" msgid="8787352074326748892">"actualizar la estadística de uso de los componentes"</string>
     <string name="permdesc_pkgUsageStats" msgid="891553695716752835">"Permite la modificación de estadísticas recopiladas sobre el uso de componentes. Las aplicaciones normales no deben utilizarlo."</string>
@@ -962,8 +963,8 @@
     <string name="chooser_wallpaper" msgid="7873476199295190279">"Cambiar fondo de pantalla"</string>
     <string name="pptp_vpn_description" msgid="2688045385181439401">"Protocolo de túnel punto a punto"</string>
     <string name="l2tp_vpn_description" msgid="3750692169378923304">"Protocolo de túnel de nivel 2"</string>
-    <string name="l2tp_ipsec_psk_vpn_description" msgid="3945043564008303239">"Clave previamente compartida según L2TP/IPSec VPN"</string>
-    <string name="l2tp_ipsec_crt_vpn_description" msgid="5382714073103653577">"Certificado según L2TP/IPSec VPN"</string>
+    <string name="l2tp_ipsec_psk_vpn_description" msgid="3945043564008303239">"VPN L2TP/IPSec basada en clave compartida previamente"</string>
+    <string name="l2tp_ipsec_crt_vpn_description" msgid="5382714073103653577">"VPN L2TP/IPSec basada en certificado"</string>
     <string name="upload_file" msgid="2897957172366730416">"Elegir archivo"</string>
     <string name="no_file_chosen" msgid="6363648562170759465">"No se seleccionó un archivo."</string>
     <string name="reset" msgid="2448168080964209908">"Restablecer"</string>
@@ -991,7 +992,7 @@
     <string name="progress_erasing" product="nosdcard" msgid="4183664626203056915">"Borrando almacenamiento USB..."</string>
     <string name="progress_erasing" product="default" msgid="2115214724367534095">"Borrando tarjeta SD..."</string>
     <string name="format_error" product="nosdcard" msgid="4320339096529911637">"No pudo borrar el almacenamiento USB."</string>
-    <string name="format_error" product="default" msgid="1343380371925238343">"No pudo borrar la tarjeta SD."</string>
+    <string name="format_error" product="default" msgid="1343380371925238343">"No se pudo borrar la tarjeta SD."</string>
     <string name="media_bad_removal" msgid="7960864061016603281">"Se ha extraído la tarjeta SD antes de ser desmontada."</string>
     <string name="media_checking" product="nosdcard" msgid="418188720009569693">"Se está verificando el almacenamiento USB en este momento."</string>
     <string name="media_checking" product="default" msgid="7334762503904827481">"Se está verificando la tarjeta SD en este momento."</string>
diff --git a/core/res/res/values-es/strings.xml b/core/res/res/values-es/strings.xml
index 41fa758..bdca91f 100644
--- a/core/res/res/values-es/strings.xml
+++ b/core/res/res/values-es/strings.xml
@@ -361,8 +361,8 @@
     <string name="permdesc_vibrate" msgid="2886677177257789187">"Permite que la aplicación controle la función de vibración."</string>
     <string name="permlab_flashlight" msgid="2155920810121984215">"controlar linterna"</string>
     <string name="permdesc_flashlight" msgid="6433045942283802309">"Permite que la aplicación controle la función de linterna."</string>
-    <string name="permlab_accessUsb" msgid="7362327818655760496">"acceso a dispositivos USB"</string>
-    <string name="permdesc_accessUsb" msgid="2414271762914049292">"La aplicación puede acceder a dispositivos USB."</string>
+    <string name="permlab_manageUsb" msgid="1113453430645402723">"administrar preferencias y permisos de dispositivos USB"</string>
+    <string name="permdesc_manageUsb" msgid="6148489202092166164">"Permite que la aplicación administre las preferencias y los permisos de los dispositivos USB."</string>
     <string name="permlab_accessMtp" msgid="4953468676795917042">"implementar protocolo MTP"</string>
     <string name="permdesc_accessMtp" msgid="6532961200486791570">"Permite el acceso al controlador MTP del kernel para implementar el protocolo USB MTP."</string>
     <string name="permlab_hardware_test" msgid="4148290860400659146">"probar hardware"</string>
@@ -484,8 +484,8 @@
     <string name="policydesc_wipeData" product="default" msgid="7669895333814222586">"Borrado de los datos del teléfono sin avisar restableciendo datos de fábrica"</string>
     <string name="policylab_setGlobalProxy" msgid="2784828293747791446">"Definir el servidor proxy global"</string>
     <string name="policydesc_setGlobalProxy" msgid="6387497466660154931">"Define el servidor proxy global que se debe utilizar mientras la política esté habilitada. Solo el primer administrador de dispositivos define el servidor proxy global efectivo."</string>
-    <!-- outdated translation 4740941403188940274 -->     <string name="policylab_expirePassword" msgid="885279151847254056">"Definir caducidad de contraseña"</string>
-    <!-- outdated translation 6626724939177185949 -->     <string name="policydesc_expirePassword" msgid="4844430354224822074">"Permite controlar cuándo se debe cambiar la contraseña de bloqueo de la pantalla."</string>
+    <string name="policylab_expirePassword" msgid="885279151847254056">"Definir caducidad bloqueo pantalla"</string>
+    <string name="policydesc_expirePassword" msgid="4844430354224822074">"Controlar la frecuencia con la que se debe cambiar el bloqueo de pantalla"</string>
     <string name="policylab_encryptedStorage" msgid="8901326199909132915">"Encriptación de almacenamiento"</string>
     <string name="policydesc_encryptedStorage" msgid="2504984732631479399">"Exige que se encripten los datos de la aplicación almacenados."</string>
   <string-array name="phoneTypes">
@@ -814,6 +814,7 @@
     <string name="alwaysUse" msgid="4583018368000610438">"Utilizar de forma predeterminada para esta acción"</string>
     <string name="clearDefaultHintMsg" msgid="4815455344600932173">"Borrar valores predeterminados en la página de configuración de la pantalla de inicio del teléfono &gt; Aplicaciones &gt; Administrar aplicaciones\"."</string>
     <string name="chooseActivity" msgid="1009246475582238425">"Seleccionar una acción"</string>
+    <string name="chooseUsbActivity" msgid="7892597146032121735">"Seleccionar una aplicación para el dispositivo USB"</string>
     <string name="noApplications" msgid="1691104391758345586">"Ninguna aplicación puede realizar esta acción."</string>
     <string name="aerr_title" msgid="653922989522758100">"Lo sentimos."</string>
     <string name="aerr_application" msgid="4683614104336409186">"La aplicación <xliff:g id="APPLICATION">%1$s</xliff:g> (proceso <xliff:g id="PROCESS">%2$s</xliff:g>) se ha interrumpido inesperadamente. Inténtalo de nuevo."</string>
@@ -974,7 +975,7 @@
     <string name="tethered_notification_message" msgid="3067108323903048927">"Toca para iniciar la configuración."</string>
     <string name="back_button_label" msgid="2300470004503343439">"Atrás"</string>
     <string name="next_button_label" msgid="1080555104677992408">"Siguiente"</string>
-    <string name="skip_button_label" msgid="1275362299471631819">"Omitir"</string>
+    <string name="skip_button_label" msgid="1275362299471631819">"Saltar"</string>
     <string name="throttle_warning_notification_title" msgid="4890894267454867276">"Uso elevado datos móviles"</string>
     <string name="throttle_warning_notification_message" msgid="2609734763845705708">"Más información sobre uso de datos"</string>
     <string name="throttled_notification_title" msgid="6269541897729781332">"Límite datos superado"</string>
diff --git a/core/res/res/values-fa/strings.xml b/core/res/res/values-fa/strings.xml
index fa74391..1f3ca7e 100644
--- a/core/res/res/values-fa/strings.xml
+++ b/core/res/res/values-fa/strings.xml
@@ -361,8 +361,8 @@
     <string name="permdesc_vibrate" msgid="2886677177257789187">"به برنامه کاربردی اجازه می دهد لرزاننده را کنترل کند."</string>
     <string name="permlab_flashlight" msgid="2155920810121984215">"کنترل چراغ قوه"</string>
     <string name="permdesc_flashlight" msgid="6433045942283802309">"به برنامه کاربردی اجازه می دهد چراغ قوه را کنترل کند."</string>
-    <string name="permlab_accessUsb" msgid="7362327818655760496">"دسترسی به دستگاه های USB"</string>
-    <string name="permdesc_accessUsb" msgid="2414271762914049292">"به برنامه کاربردی اجازه می دهد به دستگاه های USB دسترسی پیدا کند."</string>
+    <string name="permlab_manageUsb" msgid="1113453430645402723">"مدیریت تنظیمات برگزیده و مجوزها برای دستگاه های USB"</string>
+    <string name="permdesc_manageUsb" msgid="6148489202092166164">"به برنامه کاربردی جهت مدیریت تنظیمات برگزیده و مجوزها برای دستگاه های USB اجازه می دهد."</string>
     <string name="permlab_accessMtp" msgid="4953468676795917042">"اعمال پروتکل MTP"</string>
     <string name="permdesc_accessMtp" msgid="6532961200486791570">"دسترسی به درایور کرنل MTP جهت اعمال پروتکل MTP USB را اجازه می دهد."</string>
     <string name="permlab_hardware_test" msgid="4148290860400659146">"تست سخت افزار"</string>
@@ -484,8 +484,8 @@
     <string name="policydesc_wipeData" product="default" msgid="7669895333814222586">"پاک کردن داده های گوشی بدون هشدار با انجام یک عملکرد بازنشانی داده های کارخانه"</string>
     <string name="policylab_setGlobalProxy" msgid="2784828293747791446">"تنظیم پروکسی جهانی دستگاه"</string>
     <string name="policydesc_setGlobalProxy" msgid="6387497466660154931">"پروکسی جهانی دستگاه مورد نظر را جهت استفاده هنگام فعال بودن خط مشی تنظیم کنید. فقط اولین سرپرست دستگاه پروکسی جهانی مفید را تنظیم می کند."</string>
-    <!-- outdated translation 4740941403188940274 -->     <string name="policylab_expirePassword" msgid="885279151847254056">"تنظیم زمان انقضای رمز ورود"</string>
-    <!-- outdated translation 6626724939177185949 -->     <string name="policydesc_expirePassword" msgid="4844430354224822074">"کنترل مدت زمانی که رمز ورود صفحه قفل قبل از تغییر یافتن لازم دارد"</string>
+    <string name="policylab_expirePassword" msgid="885279151847254056">"تنظیم زمان انقضای رمز ورود قفل صفحه"</string>
+    <string name="policydesc_expirePassword" msgid="4844430354224822074">"کنترل تعداد دفعات تغییر رمز ورود قفل صفحه"</string>
     <string name="policylab_encryptedStorage" msgid="8901326199909132915">"تنظیم رمزگذاری حافظه"</string>
     <string name="policydesc_encryptedStorage" msgid="2504984732631479399">"نیاز به رمزگذاری داده های برنامه کاربردی ذخیره شده دارد"</string>
   <string-array name="phoneTypes">
@@ -814,6 +814,7 @@
     <string name="alwaysUse" msgid="4583018368000610438">"استفاده به صورت پیش فرض برای این عملکرد."</string>
     <string name="clearDefaultHintMsg" msgid="4815455344600932173">"پاک کردن موارد پیش فرض در تنظیمات صفحه اصلی &gt; برنامه های کاربردی &gt; مدیریت برنامه ها."</string>
     <string name="chooseActivity" msgid="1009246475582238425">"انتخاب یک عملکرد"</string>
+    <string name="chooseUsbActivity" msgid="7892597146032121735">"انتخاب یک برنامه کاربردی برای دستگاه USB"</string>
     <string name="noApplications" msgid="1691104391758345586">"هیچ برنامه ای نمی تواند این عملکرد را اجرا کند."</string>
     <string name="aerr_title" msgid="653922989522758100">"متأسفیم!"</string>
     <string name="aerr_application" msgid="4683614104336409186">"برنامه کاربردی <xliff:g id="APPLICATION">%1$s</xliff:g> ( فرآیند <xliff:g id="PROCESS">%2$s</xliff:g>) به طور غیر منتظره ای متوقف شد. لطفاً دوباره امتحان کنید."</string>
diff --git a/core/res/res/values-fi/strings.xml b/core/res/res/values-fi/strings.xml
index 9c525cf..c9b6826 100644
--- a/core/res/res/values-fi/strings.xml
+++ b/core/res/res/values-fi/strings.xml
@@ -361,8 +361,8 @@
     <string name="permdesc_vibrate" msgid="2886677177257789187">"Antaa sovelluksen hallita värinää."</string>
     <string name="permlab_flashlight" msgid="2155920810121984215">"hallitse taskulamppua"</string>
     <string name="permdesc_flashlight" msgid="6433045942283802309">"Antaa sovelluksen hallita lamppua."</string>
-    <string name="permlab_accessUsb" msgid="7362327818655760496">"käytä USB-tiloja"</string>
-    <string name="permdesc_accessUsb" msgid="2414271762914049292">"Antaa sovelluksen käyttää USB-tiloja."</string>
+    <string name="permlab_manageUsb" msgid="1113453430645402723">"hallinnoi USB-laitteiden asetuksia ja käyttöoikeuksia"</string>
+    <string name="permdesc_manageUsb" msgid="6148489202092166164">"Antaa sovelluksen hallinnoida USB-laitteiden asetuksia ja käyttöoikeuksia"</string>
     <string name="permlab_accessMtp" msgid="4953468676795917042">"ota käyttöön MTP-protokolla"</string>
     <string name="permdesc_accessMtp" msgid="6532961200486791570">"Antaa sovelluksen käyttää kernel-MTP-ajuria ja ottaa käyttöön MTP USB-protokollan."</string>
     <string name="permlab_hardware_test" msgid="4148290860400659146">"testaa laitteistoa"</string>
@@ -484,8 +484,8 @@
     <string name="policydesc_wipeData" product="default" msgid="7669895333814222586">"Tyhjennä puhelimen tiedot varoituksetta palauttamalla tehdasasetukset."</string>
     <string name="policylab_setGlobalProxy" msgid="2784828293747791446">"Aseta laitteen yleinen välityspalvelin"</string>
     <string name="policydesc_setGlobalProxy" msgid="6387497466660154931">"Aseta laitteen yleinen välityspalvelin käyttöön, kun käytäntö on käytössä. Vain ensimmäinen laitteen järjestelmänhallitsija voi asettaa käytettävän yleisen välityspalvelimen."</string>
-    <!-- outdated translation 4740941403188940274 -->     <string name="policylab_expirePassword" msgid="885279151847254056">"Aseta salasanan voimassaoloaika"</string>
-    <!-- outdated translation 6626724939177185949 -->     <string name="policydesc_expirePassword" msgid="4844430354224822074">"Valitse, kuinka pian ruudunlukituksen poiston salasana tulee vaihtaa"</string>
+    <string name="policylab_expirePassword" msgid="885279151847254056">"Aseta ruudunlukituksen salasanan voimassaoloaika"</string>
+    <string name="policydesc_expirePassword" msgid="4844430354224822074">"Määritä, miten usein ruudunlukituksen salasana tulee vaihtaa"</string>
     <string name="policylab_encryptedStorage" msgid="8901326199909132915">"Aseta tallennustilan salaus"</string>
     <string name="policydesc_encryptedStorage" msgid="2504984732631479399">"Pakota tallennettujen sovellustietojen salaus"</string>
   <string-array name="phoneTypes">
@@ -814,6 +814,7 @@
     <string name="alwaysUse" msgid="4583018368000610438">"Käytä oletuksena tälle toiminnolle."</string>
     <string name="clearDefaultHintMsg" msgid="4815455344600932173">"Tyhjennä oletusasetus kohdassa Etusivun asetukset &gt; Sovellukset &gt; Hallinnoi sovelluksia."</string>
     <string name="chooseActivity" msgid="1009246475582238425">"Valitse toiminto"</string>
+    <string name="chooseUsbActivity" msgid="7892597146032121735">"Valitse sovellus USB-laitteelle"</string>
     <string name="noApplications" msgid="1691104391758345586">"Yksikään sovellus ei voi suorittaa tätä toimintoa."</string>
     <string name="aerr_title" msgid="653922989522758100">"Pahoittelemme!"</string>
     <string name="aerr_application" msgid="4683614104336409186">"Sovellus <xliff:g id="APPLICATION">%1$s</xliff:g> (prosessi <xliff:g id="PROCESS">%2$s</xliff:g>) pysähtyi yllättäen. Yritä uudelleen."</string>
diff --git a/core/res/res/values-fr/strings.xml b/core/res/res/values-fr/strings.xml
index 39276af..7e7b24e 100644
--- a/core/res/res/values-fr/strings.xml
+++ b/core/res/res/values-fr/strings.xml
@@ -126,7 +126,7 @@
     <string name="contentServiceSyncNotificationTitle" msgid="397743349191901458">"Synchronisation"</string>
     <string name="contentServiceTooManyDeletesNotificationDesc" msgid="8100981435080696431">"Trop de contenus supprimés (<xliff:g id="CONTENT_TYPE">%s</xliff:g>)."</string>
     <string name="low_memory" product="tablet" msgid="2292820184396262278">"La mémoire de la tablette est pleine. Supprimez des fichiers pour libérer de l\'espace."</string>
-    <string name="low_memory" product="default" msgid="6632412458436461203">"La mémoire du téléphone est pleine ! Supprimez des fichiers pour libérer de l\'espace."</string>
+    <string name="low_memory" product="default" msgid="6632412458436461203">"La mémoire du téléphone est pleine. Supprimez des fichiers pour libérer de l\'espace."</string>
     <string name="me" msgid="6545696007631404292">"Moi"</string>
     <string name="power_dialog" product="tablet" msgid="8545351420865202853">"Options de la tablette"</string>
     <string name="power_dialog" product="default" msgid="1319919075463988638">"Options du téléphone"</string>
@@ -159,8 +159,8 @@
     <string name="permgrouplab_messages" msgid="7521249148445456662">"Vos messages"</string>
     <string name="permgroupdesc_messages" msgid="7045736972019211994">"Permet de lire et rédiger vos SMS, e-mails et autres messages."</string>
     <string name="permgrouplab_personalInfo" msgid="3519163141070533474">"Vos informations personnelles"</string>
-    <string name="permgroupdesc_personalInfo" product="tablet" msgid="6975389054186265786">"Accéder directement aux contacts et à l\'agenda stockés sur la tablette"</string>
-    <string name="permgroupdesc_personalInfo" product="default" msgid="5488050357388806068">"Accédez directement aux contacts et à l\'agenda enregistrés sur votre téléphone."</string>
+    <string name="permgroupdesc_personalInfo" product="tablet" msgid="6975389054186265786">"Accéder directement aux contacts et à l\'agenda enregistrés sur la tablette"</string>
+    <string name="permgroupdesc_personalInfo" product="default" msgid="5488050357388806068">"Accéder directement aux contacts et à l\'agenda enregistrés sur votre téléphone"</string>
     <string name="permgrouplab_location" msgid="635149742436692049">"Votre position"</string>
     <string name="permgroupdesc_location" msgid="2430258821648348660">"Suivre votre position géographique"</string>
     <string name="permgrouplab_network" msgid="5808983377727109831">"Communications réseau"</string>
@@ -177,7 +177,7 @@
     <string name="permgroupdesc_developmentTools" msgid="9056431193893809814">"Ces fonctionnalités sont réservées aux développeurs d\'applications."</string>
     <string name="permgrouplab_storage" msgid="1971118770546336966">"Stockage"</string>
     <string name="permgroupdesc_storage" product="nosdcard" msgid="7442318502446874999">"Accéder à la  mémoire de stockage USB"</string>
-    <string name="permgroupdesc_storage" product="default" msgid="9203302214915355774">"Accès à la carte SD"</string>
+    <string name="permgroupdesc_storage" product="default" msgid="9203302214915355774">"Accéder à la carte SD"</string>
     <string name="permlab_statusBar" msgid="7417192629601890791">"Désactivation ou modification de la barre d\'état"</string>
     <string name="permdesc_statusBar" msgid="1365473595331989732">"Permet à une application de désactiver la barre d\'état ou d\'ajouter/supprimer des icônes système."</string>
     <string name="permlab_statusBarService" msgid="7247281911387931485">"barre d\'état"</string>
@@ -193,7 +193,7 @@
     <string name="permlab_sendSms" msgid="5600830612147671529">"Envoi de messages SMS"</string>
     <string name="permdesc_sendSms" msgid="1946540351763502120">"Permet aux applications d\'envoyer des messages SMS. Des applications malveillantes peuvent entraîner des frais en envoyant des messages sans vous en demander la confirmation."</string>
     <string name="permlab_readSms" msgid="4085333708122372256">"Lecture des SMS ou MMS"</string>
-    <string name="permdesc_readSms" product="tablet" msgid="5836710350295631545">"Permet à l\'application de lire les SMS stockés dans la mémoire de votre tablette ou sur votre carte SIM. Des applications malveillantes peuvent lire vos messages confidentiels."</string>
+    <string name="permdesc_readSms" product="tablet" msgid="5836710350295631545">"Permet à l\'application de lire les SMS enregistrés dans la mémoire de votre tablette ou sur votre carte SIM. Des applications malveillantes peuvent lire vos messages confidentiels."</string>
     <string name="permdesc_readSms" product="default" msgid="3002170087197294591">"Permet à l\'application de lire les SMS enregistrés dans la mémoire de votre téléphone ou sur votre carte SIM. Des applications malveillantes peuvent lire vos messages confidentiels."</string>
     <string name="permlab_writeSms" msgid="6881122575154940744">"Modification de SMS ou de MMS"</string>
     <string name="permdesc_writeSms" product="tablet" msgid="5332124772918835437">"Permet à une application de modifier des messages SMS stockés sur votre tablette ou sur votre carte SIM. Des applications malveillantes peuvent ainsi supprimer vos messages."</string>
@@ -258,7 +258,7 @@
     <string name="permlab_bindRemoteViews" msgid="5697987759897367099">"associer à un service widget"</string>
     <string name="permdesc_bindRemoteViews" msgid="2930855984822926963">"Permet à l\'application autorisée de s\'associer à l\'interface de plus haut niveau d\'un service widget. Les applications standard ne doivent jamais avoir recours à cette fonctionnalité."</string>
     <string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"interagir avec l\'administrateur du périphérique"</string>
-    <string name="permdesc_bindDeviceAdmin" msgid="8714424333082216979">"Permet à l\'application d\'envoyer des intentions à l\'administrateur du périphérique. Les applications standard ne devraient jamais avoir recours à cette fonctionnalité."</string>
+    <string name="permdesc_bindDeviceAdmin" msgid="8714424333082216979">"Permet à l\'application d\'envoyer des intentions à l\'administrateur de l\'appareil. Les applications standard ne devraient jamais avoir recours à cette fonctionnalité."</string>
     <string name="permlab_setOrientation" msgid="3365947717163866844">"Changement d\'orientation de l\'écran"</string>
     <string name="permdesc_setOrientation" msgid="6335814461615851863">"Permet à une application de modifier la rotation de l\'écran à tout moment. Les applications normales ne devraient jamais avoir recours à cette fonctionnalité."</string>
     <string name="permlab_signalPersistentProcesses" msgid="4255467255488653854">"Envoi de signaux Linux aux applications"</string>
@@ -309,10 +309,10 @@
     <string name="permdesc_writeContacts" product="tablet" msgid="7782689510038568495">"Permet à une application de modifier les données (adresses) associées à vos contacts et stockées sur votre tablette. Des applications malveillantes peuvent utiliser cette fonctionnalité pour effacer ou modifier les données de vos contacts."</string>
     <string name="permdesc_writeContacts" product="default" msgid="3924383579108183601">"Permet à une application de modifier toutes les données de contact (adresses) enregistrées sur le téléphone. Des applications malveillantes peuvent utiliser cette fonctionnalité pour effacer ou modifier vos données de contact."</string>
     <string name="permlab_readCalendar" msgid="6898987798303840534">"lire des événements de l\'agenda"</string>
-    <string name="permdesc_readCalendar" product="tablet" msgid="5905870265734599678">"Permet à une application de lire tous les événements d\'agenda stockés sur votre tablette. Des applications malveillantes peuvent exploiter cette fonctionnalité pour envoyer les événements de votre agenda à d\'autres personnes."</string>
-    <string name="permdesc_readCalendar" product="default" msgid="5533029139652095734">"Permet à une application de lire tous les événements de l\'agenda enregistrés sur votre téléphone. Des applications malveillantes peuvent utiliser cette fonctionnalité pour envoyer les événements de votre agenda à d\'autres personnes."</string>
+    <string name="permdesc_readCalendar" product="tablet" msgid="5905870265734599678">"Permet à une application de lire tous les événements de l\'agenda enregistrés sur votre tablette. Des applications malveillantes peuvent exploiter cette fonctionnalité pour envoyer les événements de votre agenda à d\'autres personnes."</string>
+    <string name="permdesc_readCalendar" product="default" msgid="5533029139652095734">"Permet à une application de lire tous les événements de l\'agenda enregistrés sur votre téléphone. Des applications malveillantes peuvent exploiter cette fonctionnalité pour envoyer les événements de votre agenda à d\'autres personnes."</string>
     <string name="permlab_writeCalendar" msgid="3894879352594904361">"ajouter ou modifier des événements d\'agenda et envoyer des e-mails aux invités"</string>
-    <string name="permdesc_writeCalendar" msgid="2988871373544154221">"Autorise les applications à ajouter ou à modifier des événements dans votre agenda, qui pourra envoyer des e-mails aux invités. Des logiciels malveillants peuvent utiliser cette fonctionnalité pour supprimer ou modifier des événements de l\'agenda ou envoyer des e-mails aux invités."</string>
+    <string name="permdesc_writeCalendar" msgid="2988871373544154221">"Permet aux applications d\'ajouter ou de modifier des événements dans votre agenda, qui est susceptible d\'envoyer des e-mails aux invités. Des applications malveillantes peuvent exploiter cette fonctionnalité pour supprimer ou modifier des événements de l\'agenda ou envoyer des e-mails aux invités."</string>
     <string name="permlab_accessMockLocation" msgid="8688334974036823330">"Création de sources de localisation fictives à des fins de test"</string>
     <string name="permdesc_accessMockLocation" msgid="7648286063459727252">"Permet de créer des sources de localisation fictives à des fins de test. Des applications malveillantes peuvent utiliser cette fonctionnalité pour remplacer la position géographique et/ou l\'état fournis par des sources réelles comme le GPS ou les fournisseurs d\'accès."</string>
     <string name="permlab_accessLocationExtraCommands" msgid="2836308076720553837">"Accès aux commandes de fournisseur de position géographique supplémentaires"</string>
@@ -321,10 +321,10 @@
     <string name="permdesc_installLocationProvider" msgid="5449175116732002106">"Créer des sources de données de localisation factices à des fins de test. Les applications malveillantes peuvent exploiter cette fonction pour remplacer la position géographique et/ou l\'état renvoyé par les sources de données de localisation réelles, telles que le GPS ou les fournisseurs réseau, ou pour surveiller et transmettre votre position géographique à une source externe."</string>
     <string name="permlab_accessFineLocation" msgid="8116127007541369477">"Localisation OK (GPS)"</string>
     <string name="permdesc_accessFineLocation" product="tablet" msgid="243973693233359681">"Permet d\'accéder à des sources de localisation précises telles que le système GPS de la tablette, lorsque ces services sont disponibles. Des applications malveillantes peuvent exploiter cette fonctionnalité pour déterminer votre position, ce qui peut entraîner une utilisation accrue de la batterie."</string>
-    <string name="permdesc_accessFineLocation" product="default" msgid="7411213317434337331">"Permet d\'accéder à des sources de localisation précises comme le Global Positioning System (GPS) sur le téléphone, lorsque ces services sont disponibles. Des applications malveillantes peuvent utiliser cette fonctionnalité pour déterminer l\'endroit où vous vous trouvez et augmenter la consommation de la batterie de votre téléphone."</string>
+    <string name="permdesc_accessFineLocation" product="default" msgid="7411213317434337331">"Permet d\'accéder à des sources de localisation précises telles que le système GPS du téléphone, lorsque ces services sont disponibles. Des applications malveillantes peuvent exploiter cette fonctionnalité pour déterminer votre position, ce qui peut entraîner une utilisation accrue de la batterie."</string>
     <string name="permlab_accessCoarseLocation" msgid="4642255009181975828">"Position géo. approximative (selon le réseau)"</string>
     <string name="permdesc_accessCoarseLocation" product="tablet" msgid="3704633168985466045">"Permet d\'accéder à des sources de localisation approximatives telles que des bases de données de réseaux mobiles pour déterminer la position géographique de la tablette lorsque celle-ci est disponible. Des applications malveillantes peuvent exploiter cette fonctionnalité pour déterminer votre position approximative."</string>
-    <string name="permdesc_accessCoarseLocation" product="default" msgid="8235655958070862293">"Accès à des sources de localisation approximative (par ex. des bases de données de réseaux mobiles) pour déterminer la position géographique du téléphone, lorsque cette option est disponible. Des applications malveillantes peuvent utiliser cette fonctionnalité pour déterminer approximativement l\'endroit où vous vous trouvez."</string>
+    <string name="permdesc_accessCoarseLocation" product="default" msgid="8235655958070862293">"Permet d\'accéder à des sources de localisation approximatives telles que des bases de données de réseaux mobiles pour déterminer la position géographique du téléphone, lorsque cette option est disponible. Des applications malveillantes peuvent exploiter cette fonctionnalité pour déterminer votre position approximative."</string>
     <string name="permlab_accessSurfaceFlinger" msgid="2363969641792388947">"Accès à SurfaceFlinger"</string>
     <string name="permdesc_accessSurfaceFlinger" msgid="6805241830020733025">"Permet à certaines applications d\'utiliser les fonctionnalités SurfaceFlinger de bas niveau."</string>
     <string name="permlab_readFrameBuffer" msgid="6690504248178498136">"Lecture de la mémoire tampon graphique"</string>
@@ -336,33 +336,33 @@
     <string name="permlab_camera" msgid="3616391919559751192">"prendre des photos et enregistrer des vidéos"</string>
     <string name="permdesc_camera" msgid="6004878235852154239">"Permet de prendre des photos et d\'enregistrer des vidéos avec l\'appareil photo. Cette fonctionnalité permet à l\'application de récupérer à tout moment les images perçues par l\'appareil."</string>
     <string name="permlab_brick" product="tablet" msgid="2961292205764488304">"désactiver définitivement la tablette"</string>
-    <string name="permlab_brick" product="default" msgid="8337817093326370537">"Désactivation définitive du téléphone"</string>
+    <string name="permlab_brick" product="default" msgid="8337817093326370537">"désactiver définitivement le téléphone"</string>
     <string name="permdesc_brick" product="tablet" msgid="7379164636920817963">"Permet à l\'application de désactiver définitivement la tablette. Cette fonctionnalité est très dangereuse."</string>
     <string name="permdesc_brick" product="default" msgid="5569526552607599221">"Permet à l\'application de désactiver définitivement le téléphone. Cette fonctionnalité est très dangereuse."</string>
     <string name="permlab_reboot" product="tablet" msgid="3436634972561795002">"forcer le redémarrage de la tablette"</string>
-    <string name="permlab_reboot" product="default" msgid="2898560872462638242">"Redémarrage forcé du téléphone"</string>
+    <string name="permlab_reboot" product="default" msgid="2898560872462638242">"forcer le redémarrage du téléphone"</string>
     <string name="permdesc_reboot" product="tablet" msgid="4555793623560701557">"Permet à l\'application de forcer le redémarrage de la tablette."</string>
     <string name="permdesc_reboot" product="default" msgid="7914933292815491782">"Permet à l\'application de forcer le redémarrage du téléphone."</string>
-    <string name="permlab_mount_unmount_filesystems" msgid="1761023272170956541">"Monter et démonter des systèmes de fichiers"</string>
-    <string name="permdesc_mount_unmount_filesystems" msgid="6253263792535859767">"Permet à l\'application de monter et démonter des systèmes de fichiers pour des périphériques de stockage amovibles."</string>
+    <string name="permlab_mount_unmount_filesystems" msgid="1761023272170956541">"Installer et désinstaller des systèmes de fichiers"</string>
+    <string name="permdesc_mount_unmount_filesystems" msgid="6253263792535859767">"Permet à l\'application d\'installer et de désinstaller des systèmes de fichiers pour des périphériques de stockage amovibles."</string>
     <string name="permlab_mount_format_filesystems" msgid="5523285143576718981">"Formatage du périphérique de stockage externe"</string>
     <string name="permdesc_mount_format_filesystems" msgid="574060044906047386">"Permet à l\'application de formater le périphérique de stockage amovible."</string>
     <string name="permlab_asec_access" msgid="3411338632002193846">"obtenir des informations sur la mémoire de stockage interne"</string>
-    <string name="permdesc_asec_access" msgid="8820326551687285439">"Permet à l\'application d\'obtenir des informations sur le stockage interne."</string>
-    <string name="permlab_asec_create" msgid="6414757234789336327">"créer un stockage interne"</string>
+    <string name="permdesc_asec_access" msgid="8820326551687285439">"Permet à l\'application d\'obtenir des informations sur la mémoire de stockage interne."</string>
+    <string name="permlab_asec_create" msgid="6414757234789336327">"créer une mémoire de stockage interne"</string>
     <string name="permdesc_asec_create" msgid="2621346764995731250">"Permet à l\'application de créer une mémoire de stockage interne."</string>
     <string name="permlab_asec_destroy" msgid="526928328301618022">"détruire la mémoire de stockage interne"</string>
-    <string name="permdesc_asec_destroy" msgid="2746706889208066256">"Permet à l\'application de détruire le stockage interne."</string>
+    <string name="permdesc_asec_destroy" msgid="2746706889208066256">"Permet à l\'application de détruire la mémoire de stockage interne."</string>
     <string name="permlab_asec_mount_unmount" msgid="2456287623689029744">"installer/désinstaller la mémoire de stockage interne"</string>
     <string name="permdesc_asec_mount_unmount" msgid="5934375590189368200">"Permet l\'installation ou la désinstallation de la mémoire de stockage interne par l\'application."</string>
     <string name="permlab_asec_rename" msgid="7496633954080472417">"renommer la mémoire de stockage interne"</string>
-    <string name="permdesc_asec_rename" msgid="2152829985238876790">"Permet à l\'application de renommer le stockage interne."</string>
+    <string name="permdesc_asec_rename" msgid="2152829985238876790">"Permet à l\'application de renommer la mémoire de stockage interne."</string>
     <string name="permlab_vibrate" msgid="7768356019980849603">"Contrôle du vibreur"</string>
     <string name="permdesc_vibrate" msgid="2886677177257789187">"Permet à l\'application de contrôler le vibreur."</string>
     <string name="permlab_flashlight" msgid="2155920810121984215">"Contrôle de la lampe de poche"</string>
     <string name="permdesc_flashlight" msgid="6433045942283802309">"Permet à l\'application de contrôler la lampe de poche."</string>
-    <string name="permlab_accessUsb" msgid="7362327818655760496">"accéder aux périphériques USB"</string>
-    <string name="permdesc_accessUsb" msgid="2414271762914049292">"Autorise l\'application à accéder aux périphériques USB"</string>
+    <string name="permlab_manageUsb" msgid="1113453430645402723">"gérer les préférences et les autorisations des périphériques USB"</string>
+    <string name="permdesc_manageUsb" msgid="6148489202092166164">"Permet à l\'application de gérer les préférences et les autorisations des périphériques USB."</string>
     <string name="permlab_accessMtp" msgid="4953468676795917042">"mettre en œuvre le protocole MTP"</string>
     <string name="permdesc_accessMtp" msgid="6532961200486791570">"Permet l\'accès au pilote MTP du noyau à des fins de mise en œuvre du protocole USB MTP."</string>
     <string name="permlab_hardware_test" msgid="4148290860400659146">"Tests du matériel"</string>
@@ -385,16 +385,16 @@
     <string name="permlab_readPhoneState" msgid="2326172951448691631">"Lire l\'état et l\'identité du téléphone"</string>
     <string name="permdesc_readPhoneState" msgid="188877305147626781">"Permet à l\'application d\'accéder aux fonctionnalités d\'appel du téléphone. L\'application peut alors déterminer le numéro de téléphone et le numéro de série de l\'appareil, savoir si un appel est en cours, identifier le numéro appelé, etc."</string>
     <string name="permlab_wakeLock" product="tablet" msgid="1531731435011495015">"empêcher la tablette de passer en mode veille"</string>
-    <string name="permlab_wakeLock" product="default" msgid="573480187941496130">"Arrêt du mode veille sur le téléphone"</string>
-    <string name="permdesc_wakeLock" product="tablet" msgid="4032181488045338551">"Permet à une application d\'empêcher votre tablette de passer en mode veille."</string>
-    <string name="permdesc_wakeLock" product="default" msgid="7584036471227467099">"Permet à une application d\'empêcher votre téléphone de passer en mode veille."</string>
+    <string name="permlab_wakeLock" product="default" msgid="573480187941496130">"empêcher le téléphone de passer en mode veille"</string>
+    <string name="permdesc_wakeLock" product="tablet" msgid="4032181488045338551">"Permet à une application d\'empêcher la tablette de passer en mode veille."</string>
+    <string name="permdesc_wakeLock" product="default" msgid="7584036471227467099">"Permet à une application d\'empêcher le téléphone de passer en mode veille."</string>
     <string name="permlab_devicePower" product="tablet" msgid="2787034722616350417">"éteindre ou allumer la tablette"</string>
     <string name="permlab_devicePower" product="default" msgid="4928622470980943206">"Éteindre ou allumer le téléphone"</string>
     <string name="permdesc_devicePower" product="tablet" msgid="3853773100100451905">"Permet à l\'application d\'éteindre et d\'allumer la tablette."</string>
     <string name="permdesc_devicePower" product="default" msgid="4577331933252444818">"Permet à l\'application d\'éteindre et d\'allumer le téléphone."</string>
     <string name="permlab_factoryTest" msgid="3715225492696416187">"Exécution en mode Test d\'usine"</string>
     <string name="permdesc_factoryTest" product="tablet" msgid="3952059318359653091">"Permet d\'exécuter une application en mode test fabricant de faible niveau, autorisant ainsi l\'accès complet à la tablette. Cette fonctionnalité est uniquement disponible lorsque la tablette est en mode test fabricant."</string>
-    <string name="permdesc_factoryTest" product="default" msgid="8136644990319244802">"Permet d\'exécuter en tant que test fabricant de faible niveau en autorisant l\'accès au matériel du téléphone. Cette fonctionnalité est uniquement disponible lorsque le téléphone est en mode de test fabricant."</string>
+    <string name="permdesc_factoryTest" product="default" msgid="8136644990319244802">"Permet d\'exécuter une application en mode test fabricant de faible niveau en autorisant ainsi l\'accès au téléphone. Cette fonctionnalité est uniquement disponible lorsque le téléphone est en mode test fabricant."</string>
     <string name="permlab_setWallpaper" msgid="6627192333373465143">"Configuration du fond d\'écran"</string>
     <string name="permdesc_setWallpaper" msgid="6417041752170585837">"Permet à une application de définir le fond d\'écran du système."</string>
     <string name="permlab_setWallpaperHints" msgid="3600721069353106851">"Sélection de la la taille du fond d\'écran"</string>
@@ -437,13 +437,13 @@
     <string name="permlab_changeWifiMulticastState" msgid="1368253871483254784">"autoriser la réception de données en Wi-Fi multidiffusion"</string>
     <string name="permdesc_changeWifiMulticastState" msgid="8199464507656067553">"Autorise une application à recevoir des paquets qui ne sont pas directement adressés à votre mobile. Cela peut être utile pour la recherche de services disponibles à proximité. Consomme plus que le mode non multidiffusion."</string>
     <string name="permlab_bluetoothAdmin" msgid="1092209628459341292">"Gestion Bluetooth"</string>
-    <string name="permdesc_bluetoothAdmin" product="tablet" msgid="3511795757324345837">"Permet à une application de configurer la tablette Bluetooth locale, de trouver des périphériques distants et de les associer à la tablette."</string>
+    <string name="permdesc_bluetoothAdmin" product="tablet" msgid="3511795757324345837">"Permet à une application de configurer la tablette Bluetooth locale, d\'identifier des appareils distants et de les associer à la tablette."</string>
     <string name="permdesc_bluetoothAdmin" product="default" msgid="7256289774667054555">"Permet à une application de configurer le téléphone Bluetooth local, d\'identifier des périphériques distants et de les associer au téléphone."</string>
     <string name="permlab_bluetooth" msgid="8361038707857018732">"Création de connexions Bluetooth"</string>
     <string name="permdesc_bluetooth" product="tablet" msgid="4191941825910543803">"Permet à une application d\'obtenir la configuration de la tablette Bluetooth locale, de se connecter à des appareils associés et d\'accepter leur connexion."</string>
-    <string name="permdesc_bluetooth" product="default" msgid="762515380679392945">"Permet à une application d\'obtenir la configuration du téléphone Bluetooth local et de créer et accepter des connexions à des appareils associés."</string>
+    <string name="permdesc_bluetooth" product="default" msgid="762515380679392945">"Permet à une application d\'obtenir la configuration du téléphone Bluetooth local, de se connecter à des appareils associés et d\'accepter leur connexion."</string>
     <string name="permlab_nfc" msgid="4423351274757876953">"contrôler la communication en champ proche"</string>
-    <string name="permdesc_nfc" msgid="9171401851954407226">"Autorise une application à communiquer avec des tags, cartes et lecteurs prenant en charge la communication en champ proche (NFC)."</string>
+    <string name="permdesc_nfc" msgid="9171401851954407226">"Permet à une application de communiquer avec des tags, cartes et lecteurs prenant en charge la communication en champ proche (NFC)."</string>
     <string name="permlab_disableKeyguard" msgid="4977406164311535092">"Désactivation du verrouillage des touches"</string>
     <string name="permdesc_disableKeyguard" msgid="3189763479326302017">"Permet à une application de désactiver le verrouillage des touches et toute sécurité par mot de passe. Exemple : Votre téléphone désactive le verrouillage du clavier lorsque vous recevez un appel, puis le réactive lorsque vous raccrochez."</string>
     <string name="permlab_readSyncSettings" msgid="6201810008230503052">"Lecture des paramètres de synchronisation"</string>
@@ -460,11 +460,11 @@
     <string name="permdesc_readDictionary" msgid="1082972603576360690">"Permet à une application de lire tous les mots, noms et expressions que l\'utilisateur a pu enregistrer dans son dictionnaire personnel."</string>
     <string name="permlab_writeDictionary" msgid="6703109511836343341">"Enregistrement dans le dictionnaire défini par l\'utilisateur"</string>
     <string name="permdesc_writeDictionary" msgid="2241256206524082880">"Permet à une application d\'enregistrer de nouveaux mots dans le dictionnaire personnel de l\'utilisateur."</string>
-    <string name="permlab_sdcardWrite" product="nosdcard" msgid="85430876310764752">"modifier/supprimer le contenu de la mémoire de stockage USB"</string>
-    <string name="permlab_sdcardWrite" product="default" msgid="8079403759001777291">"Modifier/supprimer le contenu de la carte SD"</string>
+    <string name="permlab_sdcardWrite" product="nosdcard" msgid="85430876310764752">"modif./suppr. contenu mémoire USB"</string>
+    <string name="permlab_sdcardWrite" product="default" msgid="8079403759001777291">"modifier/supprimer le contenu de la carte SD"</string>
     <string name="permdesc_sdcardWrite" product="nosdcard" msgid="6594393334785738252">"Autorise une application à écrire sur la mémoire USB."</string>
     <string name="permdesc_sdcardWrite" product="default" msgid="6643963204976471878">"Autorise une application à écrire sur la carte SD."</string>
-    <string name="permlab_mediaStorageWrite" product="default" msgid="6859839199706879015">"modif./suppr. contenu mémoire interne support"</string>
+    <string name="permlab_mediaStorageWrite" product="default" msgid="6859839199706879015">"modif./suppr. contenu mémoire interne"</string>
     <string name="permdesc_mediaStorageWrite" product="default" msgid="8232008512478316233">"Permet à une application de modifier le contenu de la mémoire de stockage interne du support."</string>
     <string name="permlab_cache_filesystem" msgid="5656487264819669824">"accéder au système de fichiers en cache"</string>
     <string name="permdesc_cache_filesystem" msgid="1624734528435659906">"Permet à une application de lire et d\'écrire dans le système de fichiers en cache."</string>
@@ -474,18 +474,18 @@
     <string name="policydesc_limitPassword" msgid="9083400080861728056">"Gérer le nombre et le type de caractères autorisés dans les mots de passe de déverrouillage de l\'écran"</string>
     <string name="policylab_watchLogin" msgid="914130646942199503">"Gérer les tentatives de déverrouillage de l\'écran"</string>
     <string name="policydesc_watchLogin" product="tablet" msgid="933601759466308092">"Surveiller le nombre de mots de passe incorrects saisis lors du déverrouillage de l\'écran et verrouiller la tablette ou effacer toutes ses données après un certain nombre de tentatives."</string>
-    <string name="policydesc_watchLogin" product="default" msgid="7227578260165172673">"Gérer le nombre de mots de passe incorrects saisis lors du déverrouillage de l\'écran et verrouiller le téléphone ou effacer toutes ses données après un certain nombre de tentatives"</string>
+    <string name="policydesc_watchLogin" product="default" msgid="7227578260165172673">"Surveiller le nombre de mots de passe incorrects saisis lors du déverrouillage de l\'écran et verrouiller le téléphone ou effacer toutes ses données après un certain nombre de tentatives"</string>
     <string name="policylab_resetPassword" msgid="2620077191242688955">"Modifier le mot de passe de déverrouillage de l\'écran"</string>
     <string name="policydesc_resetPassword" msgid="5391240616981297361">"Modifier le mot de passe de déverrouillage de l\'écran"</string>
     <string name="policylab_forceLock" msgid="2274085384704248431">"Verrouiller l\'écran"</string>
     <string name="policydesc_forceLock" msgid="5696964126226028442">"Gérer le mode et les conditions de verrouillage de l\'écran"</string>
     <string name="policylab_wipeData" msgid="3910545446758639713">"Effacer toutes les données"</string>
-    <string name="policydesc_wipeData" product="tablet" msgid="314455232799486222">"Effacer les données de la tablette sans avertissement, en réinitialisant la configuration usine"</string>
-    <string name="policydesc_wipeData" product="default" msgid="7669895333814222586">"Effacer les données du téléphone sans avertissement, en restaurant les valeurs d\'usine"</string>
+    <string name="policydesc_wipeData" product="tablet" msgid="314455232799486222">"Effacer les données de la tablette sans avertissement, en restaurant la configuration usine"</string>
+    <string name="policydesc_wipeData" product="default" msgid="7669895333814222586">"Effacer les données du téléphone sans avertissement, en restaurant la configuration usine"</string>
     <string name="policylab_setGlobalProxy" msgid="2784828293747791446">"Définir le proxy global du mobile"</string>
-    <string name="policydesc_setGlobalProxy" msgid="6387497466660154931">"Indiquez le proxy global à utiliser pour ce mobile lorsque les règles sont activées. Seul l\'administrateur principal du mobile peut définir le proxy global utilisé."</string>
-    <!-- outdated translation 4740941403188940274 -->     <string name="policylab_expirePassword" msgid="885279151847254056">"Définir la date d\'expiration du mot de passe"</string>
-    <!-- outdated translation 6626724939177185949 -->     <string name="policydesc_expirePassword" msgid="4844430354224822074">"Définir la fréquence de changement du mot de passe de verrouillage d\'écran"</string>
+    <string name="policydesc_setGlobalProxy" msgid="6387497466660154931">"Indiquer le proxy global à utiliser pour ce mobile lorsque les règles sont activées. Seul l\'administrateur principal du mobile peut définir le proxy global utilisé."</string>
+    <string name="policylab_expirePassword" msgid="885279151847254056">"Définir exp. mot passe verr."</string>
+    <string name="policydesc_expirePassword" msgid="4844430354224822074">"Contrôler la fréquence de modification du mot de passe de verrouillage de l\'écran"</string>
     <string name="policylab_encryptedStorage" msgid="8901326199909132915">"Définir cryptage du stockage"</string>
     <string name="policydesc_encryptedStorage" msgid="2504984732631479399">"Exiger que les données d\'application stockées soient cryptées"</string>
   <string-array name="phoneTypes">
@@ -606,11 +606,11 @@
     <string name="keyguard_password_enter_password_code" msgid="9138158344813213754">"Saisissez le mot de passe pour procéder au déverrouillage."</string>
     <string name="keyguard_password_enter_pin_password_code" msgid="638347075625491514">"Saisissez le code PIN pour procéder au déverrouillage."</string>
     <string name="keyguard_password_wrong_pin_code" msgid="1295984114338107718">"Le code PIN est incorrect !"</string>
-    <string name="keyguard_label_text" msgid="861796461028298424">"Pour débloquer le clavier, appuyez sur \"Menu\" puis sur 0."</string>
+    <string name="keyguard_label_text" msgid="861796461028298424">"Pour déverrouiller le clavier, appuyez sur \"Menu\" puis sur 0."</string>
     <string name="emergency_call_dialog_number_for_display" msgid="696192103195090970">"Numéro d\'urgence"</string>
     <string name="lockscreen_carrier_default" msgid="8812714795156374435">"(Aucun service)"</string>
     <string name="lockscreen_screen_locked" msgid="7288443074806832904">"Écran verrouillé"</string>
-    <string name="lockscreen_instructions_when_pattern_enabled" msgid="46154051614126049">"Appuyez sur \"Menu\" pour débloquer le téléphone ou appeler un numéro d\'urgence"</string>
+    <string name="lockscreen_instructions_when_pattern_enabled" msgid="46154051614126049">"Appuyez sur \"Menu\" pour déverrouiller le téléphone ou appeler un numéro d\'urgence"</string>
     <string name="lockscreen_instructions_when_pattern_disabled" msgid="686260028797158364">"Appuyez sur \"Menu\" pour déverrouiller le téléphone."</string>
     <string name="lockscreen_pattern_instructions" msgid="7478703254964810302">"Dessinez un schéma pour déverrouiller le téléphone"</string>
     <string name="lockscreen_emergency_call" msgid="5347633784401285225">"Appel d\'urgence"</string>
@@ -635,8 +635,8 @@
     <string name="lockscreen_too_many_failed_attempts_dialog_message" msgid="3514742106066877476">"Vous avez mal reproduit le schéma de déverrouillage <xliff:g id="NUMBER_0">%d</xliff:g> fois. "\n\n"Veuillez réessayer dans <xliff:g id="NUMBER_1">%d</xliff:g> secondes."</string>
     <string name="lockscreen_too_many_failed_password_attempts_dialog_message" msgid="4906034376425175381">"Vous avez saisi un mot de passe incorrect à <xliff:g id="NUMBER_0">%d</xliff:g> reprises. "\n\n"Veuillez réessayer dans <xliff:g id="NUMBER_1">%d</xliff:g> secondes."</string>
     <string name="lockscreen_too_many_failed_pin_attempts_dialog_message" msgid="6827749231465145590">"Vous avez saisi un code PIN incorrect à <xliff:g id="NUMBER_0">%d</xliff:g> reprises. "\n\n"Veuillez réessayer dans <xliff:g id="NUMBER_1">%d</xliff:g> secondes."</string>
-    <string name="lockscreen_failed_attempts_almost_glogin" product="tablet" msgid="8687762517114904651">"Vous avez saisi un schéma de déverrouillage incorrect à <xliff:g id="NUMBER_0">%d</xliff:g> reprises. Si vous échouez encore <xliff:g id="NUMBER_1">%d</xliff:g> fois, vous devrez débloquer votre tablette à l\'aide de votre identifiant Google."\n\n" Veuillez réessayer dans <xliff:g id="NUMBER_2">%d</xliff:g> secondes."</string>
-    <string name="lockscreen_failed_attempts_almost_glogin" product="default" msgid="3351013842320127827">"Vous avez mal saisi le schéma de déverrouillage <xliff:g id="NUMBER_0">%d</xliff:g> fois. Au bout de <xliff:g id="NUMBER_1">%d</xliff:g> tentatives supplémentaires, vous devrez débloquer votre téléphone à l\'aide de votre identifiant Google."\n\n"Merci de réessayer dans <xliff:g id="NUMBER_2">%d</xliff:g> secondes."</string>
+    <string name="lockscreen_failed_attempts_almost_glogin" product="tablet" msgid="8687762517114904651">"Vous avez saisi un schéma de déverrouillage incorrect à <xliff:g id="NUMBER_0">%d</xliff:g> reprises. Si vous échouez encore <xliff:g id="NUMBER_1">%d</xliff:g> fois, vous devrez déverrouiller votre tablette à l\'aide de votre identifiant Google."\n\n" Veuillez réessayer dans <xliff:g id="NUMBER_2">%d</xliff:g> secondes."</string>
+    <string name="lockscreen_failed_attempts_almost_glogin" product="default" msgid="3351013842320127827">"Vous avez mal saisi le schéma de déverrouillage <xliff:g id="NUMBER_0">%d</xliff:g> fois. Au bout de <xliff:g id="NUMBER_1">%d</xliff:g> tentatives supplémentaires, vous devrez déverrouiller votre téléphone à l\'aide de votre identifiant Google."\n\n"Merci de réessayer dans <xliff:g id="NUMBER_2">%d</xliff:g> secondes."</string>
     <string name="lockscreen_too_many_failed_attempts_countdown" msgid="6251480343394389665">"Réessayez dans <xliff:g id="NUMBER">%d</xliff:g> secondes."</string>
     <string name="lockscreen_forgot_pattern_button_text" msgid="2626999449610695930">"Schéma oublié ?"</string>
     <string name="lockscreen_glogin_forgot_pattern" msgid="2588521501166032747">"Déverrouillage du compte"</string>
@@ -648,7 +648,7 @@
     <string name="lockscreen_glogin_invalid_input" msgid="1364051473347485908">"Nom d\'utilisateur ou mot de passe incorrect."</string>
     <string name="lockscreen_glogin_account_recovery_hint" msgid="8253152905532900548">"Vous avez oublié votre nom d\'utilisateur ou votre mot de passe ?"\n"Accédez à la page "<b>"google.com/accounts/recovery"</b></string>
     <string name="lockscreen_glogin_checking_password" msgid="6758890536332363322">"Vérification..."</string>
-    <string name="lockscreen_unlock_label" msgid="737440483220667054">"Débloquer"</string>
+    <string name="lockscreen_unlock_label" msgid="737440483220667054">"Déverrouiller"</string>
     <string name="lockscreen_sound_on_label" msgid="9068877576513425970">"Son activé"</string>
     <string name="lockscreen_sound_off_label" msgid="996822825154319026">"Son désactivé"</string>
     <string name="password_keyboard_label_symbol_key" msgid="992280756256536042">"?123"</string>
@@ -674,8 +674,8 @@
     <string name="permlab_readHistoryBookmarks" msgid="1284843728203412135">"lire l\'historique et les favoris du navigateur"</string>
     <string name="permdesc_readHistoryBookmarks" msgid="4981489815467617191">"Autorise l\'application à lire toutes les URL auxquelles le navigateur a accédé et tous ses favoris."</string>
     <string name="permlab_writeHistoryBookmarks" msgid="9009434109836280374">"écrire dans l\'historique et les favoris du navigateur"</string>
-    <string name="permdesc_writeHistoryBookmarks" product="tablet" msgid="7193514090469945307">"Permet à une application de modifier l\'historique du navigateur ou les favoris stockés sur votre tablette. Des applications malveillantes peuvent utiliser cette fonctionnalité pour effacer ou modifier les données de votre navigateur."</string>
-    <string name="permdesc_writeHistoryBookmarks" product="default" msgid="945571990357114950">"Autorise une application à modifier l\'historique du navigateur ou les favoris enregistrés sur votre téléphone. Des applications malveillantes peuvent utiliser cette fonction pour effacer ou modifier les données de votre navigateur."</string>
+    <string name="permdesc_writeHistoryBookmarks" product="tablet" msgid="7193514090469945307">"Permet à une application de modifier l\'historique du navigateur ou les favoris enregistrés sur votre tablette. Des applications malveillantes peuvent exploiter cette fonctionnalité pour effacer ou modifier les données de votre navigateur."</string>
+    <string name="permdesc_writeHistoryBookmarks" product="default" msgid="945571990357114950">"Permet à une application de modifier l\'historique du navigateur ou les favoris enregistrés sur votre téléphone. Des applications malveillantes peuvent exploiter cette fonction pour effacer ou modifier les données de votre navigateur."</string>
     <string name="permlab_setAlarm" msgid="5924401328803615165">"régler le réveil"</string>
     <string name="permdesc_setAlarm" msgid="5966966598149875082">"Permet à l\'application de définir une alarme dans un utilitaire faisant office de réveil. Certains réveils risquent ne pas prendre en charge cette fonctionnalité."</string>
     <string name="permlab_writeGeolocationPermissions" msgid="4715212655598275532">"Modifier les autorisations de géolocalisation du navigateur"</string>
@@ -814,6 +814,7 @@
     <string name="alwaysUse" msgid="4583018368000610438">"Utiliser cette application par défaut pour cette action"</string>
     <string name="clearDefaultHintMsg" msgid="4815455344600932173">"Effacer les paramètres par défaut dans les Paramètres de page d\'accueil &gt; Applications &gt; Gérer les applications."</string>
     <string name="chooseActivity" msgid="1009246475582238425">"Sélectionner une action"</string>
+    <string name="chooseUsbActivity" msgid="7892597146032121735">"Sélectionnez une application pour le périphérique USB"</string>
     <string name="noApplications" msgid="1691104391758345586">"Aucune application ne peut effectuer cette action."</string>
     <string name="aerr_title" msgid="653922989522758100">"Désolé !"</string>
     <string name="aerr_application" msgid="4683614104336409186">"Fermeture soudaine de l\'application <xliff:g id="APPLICATION">%1$s</xliff:g> (du processus <xliff:g id="PROCESS">%2$s</xliff:g>). Merci de réessayer."</string>
@@ -912,22 +913,22 @@
     <string name="ext_media_checking_notification_message" msgid="8287319882926737053">"Recherche d\'erreurs"</string>
     <string name="ext_media_nofs_notification_title" product="nosdcard" msgid="7788040745686229307">"Mémoire de stockage USB vide"</string>
     <string name="ext_media_nofs_notification_title" product="default" msgid="780477838241212997">"Carte SD vide"</string>
-    <string name="ext_media_nofs_notification_message" product="nosdcard" msgid="8623130522556087311">"Le stockage USB est vide ou son système de fichiers n\'est pas pris en charge."</string>
+    <string name="ext_media_nofs_notification_message" product="nosdcard" msgid="8623130522556087311">"La mémoire de stockage USB est vide ou son système de fichiers n\'est pas pris en charge."</string>
     <string name="ext_media_nofs_notification_message" product="default" msgid="3817704088027829380">"La carte SD est vide ou son système de fichiers n\'est pas pris en charge."</string>
-    <string name="ext_media_unmountable_notification_title" product="nosdcard" msgid="2090046769532713563">"Stockage USB endommagé"</string>
+    <string name="ext_media_unmountable_notification_title" product="nosdcard" msgid="2090046769532713563">"Mémoire de stockage USB endommagée"</string>
     <string name="ext_media_unmountable_notification_title" product="default" msgid="6410723906019100189">"Carte SD endommagée"</string>
     <string name="ext_media_unmountable_notification_message" product="nosdcard" msgid="529021299294450667">"La mémoire de stockage USB est endommagée. Un reformatage est peut-être nécessaire."</string>
     <string name="ext_media_unmountable_notification_message" product="default" msgid="6902531775948238989">"La carte SD est endommagée. Vous devrez peut-être la reformater."</string>
     <string name="ext_media_badremoval_notification_title" product="nosdcard" msgid="1661683031330951073">"Mémoire USB retirée inopinément"</string>
     <string name="ext_media_badremoval_notification_title" product="default" msgid="6872152882604407837">"Carte SD retirée inopinément"</string>
     <string name="ext_media_badremoval_notification_message" product="nosdcard" msgid="4329848819865594241">"Désinstaller la mémoire de stockage USB avant de la retirer pour éviter toute perte de données."</string>
-    <string name="ext_media_badremoval_notification_message" product="default" msgid="7260183293747448241">"Désactiver la carte SD avant de la retirer pour éviter toute perte de données."</string>
-    <string name="ext_media_safe_unmount_notification_title" product="nosdcard" msgid="3967973893270360230">"Retirez la mémoire USB en toute sécurité."</string>
+    <string name="ext_media_badremoval_notification_message" product="default" msgid="7260183293747448241">"Désinstaller la carte SD avant de la retirer pour éviter toute perte de données."</string>
+    <string name="ext_media_safe_unmount_notification_title" product="nosdcard" msgid="3967973893270360230">"Vous pouvez retirer la mémoire USB."</string>
     <string name="ext_media_safe_unmount_notification_title" product="default" msgid="6729801130790616200">"La carte SD peut être retirée en toute sécurité"</string>
-    <string name="ext_media_safe_unmount_notification_message" product="nosdcard" msgid="6142195361606493530">"La mémoire de stockage USB peut être retirée en toute sécurité."</string>
+    <string name="ext_media_safe_unmount_notification_message" product="nosdcard" msgid="6142195361606493530">"Vous pouvez retirer la mémoire de stockage USB en toute sécurité."</string>
     <string name="ext_media_safe_unmount_notification_message" product="default" msgid="568841278138377604">"Vous pouvez retirer la carte SD en toute sécurité."</string>
     <string name="ext_media_nomedia_notification_title" product="nosdcard" msgid="4486377230140227651">"Mémoire de stockage USB retirée"</string>
-    <string name="ext_media_nomedia_notification_title" product="default" msgid="8902518030404381318">"Carte SD manquante"</string>
+    <string name="ext_media_nomedia_notification_title" product="default" msgid="8902518030404381318">"Carte SD retirée"</string>
     <string name="ext_media_nomedia_notification_message" product="nosdcard" msgid="6921126162580574143">"Mémoire de stockage USB retirée. Insérez un nouveau support."</string>
     <string name="ext_media_nomedia_notification_message" product="default" msgid="3870120652983659641">"La carte SD a été retirée. Insérez-en une autre."</string>
     <string name="activity_list_empty" msgid="4168820609403385789">"Aucune activité correspondante trouvée"</string>
@@ -988,7 +989,7 @@
     <string name="action_mode_done" msgid="7217581640461922289">"OK"</string>
     <string name="progress_unmounting" product="nosdcard" msgid="535863554318797377">"Désinstallation de la mémoire de stockage USB..."</string>
     <string name="progress_unmounting" product="default" msgid="5556813978958789471">"Désinstallation de la carte SD..."</string>
-    <string name="progress_erasing" product="nosdcard" msgid="4183664626203056915">"Effacement de la  mémoire de stockage USB..."</string>
+    <string name="progress_erasing" product="nosdcard" msgid="4183664626203056915">"Effacement de la mémoire de stockage USB..."</string>
     <string name="progress_erasing" product="default" msgid="2115214724367534095">"Effacement de la carte SD..."</string>
     <string name="format_error" product="nosdcard" msgid="4320339096529911637">"Impossible d\'effacer la mémoire de stockage USB"</string>
     <string name="format_error" product="default" msgid="1343380371925238343">"Impossible d\'effacer la carte SD"</string>
diff --git a/core/res/res/values-hr/strings.xml b/core/res/res/values-hr/strings.xml
index 2fd6d19..25e66b4 100644
--- a/core/res/res/values-hr/strings.xml
+++ b/core/res/res/values-hr/strings.xml
@@ -361,8 +361,8 @@
     <string name="permdesc_vibrate" msgid="2886677177257789187">"Aplikaciji omogućuje nadzor nad vibracijom."</string>
     <string name="permlab_flashlight" msgid="2155920810121984215">"nadzor bljeskalice"</string>
     <string name="permdesc_flashlight" msgid="6433045942283802309">"Aplikaciji omogućuje nadzor nad bljeskalicom."</string>
-    <string name="permlab_accessUsb" msgid="7362327818655760496">"pristupi USB uređajima"</string>
-    <string name="permdesc_accessUsb" msgid="2414271762914049292">"Omogućuje aplikaciji pristup USB uređajima."</string>
+    <string name="permlab_manageUsb" msgid="1113453430645402723">"upravljanje postavkama i dozvolama za USB uređaje"</string>
+    <string name="permdesc_manageUsb" msgid="6148489202092166164">"Aplikaciji omogućuje upravljanje postavkama i dozvolama za USB uređaje."</string>
     <string name="permlab_accessMtp" msgid="4953468676795917042">"Primjena MTP protokola"</string>
     <string name="permdesc_accessMtp" msgid="6532961200486791570">"Omogućuje pristup upravljačkom programu jezgre MTP-a radi implementacije MTP USB protokola."</string>
     <string name="permlab_hardware_test" msgid="4148290860400659146">"testiranje hardvera"</string>
@@ -484,8 +484,8 @@
     <string name="policydesc_wipeData" product="default" msgid="7669895333814222586">"Izbriši podatke telefona bez upozorenja vraćanjem u tvorničko stanje"</string>
     <string name="policylab_setGlobalProxy" msgid="2784828293747791446">"postavi globalni proxy uređaja"</string>
     <string name="policydesc_setGlobalProxy" msgid="6387497466660154931">"Postavi globalni proxy uređaja za upotrebu dok su pravila omogućena. Samo prvi administrator uređaja postavlja djelotvoran globalni proxy."</string>
-    <!-- outdated translation 4740941403188940274 -->     <string name="policylab_expirePassword" msgid="885279151847254056">"Postavi istek zaporke"</string>
-    <!-- outdated translation 6626724939177185949 -->     <string name="policydesc_expirePassword" msgid="4844430354224822074">"Nadzirite za koliko vremena zaporka za zaključani zaslon treba biti promijenjena"</string>
+    <string name="policylab_expirePassword" msgid="885279151847254056">"Post. istek zap. zaklj. zasl."</string>
+    <string name="policydesc_expirePassword" msgid="4844430354224822074">"Nadzirite koliko se često mora mijenjati zaporka za zaključavanje zaslona"</string>
     <string name="policylab_encryptedStorage" msgid="8901326199909132915">"Postavi enkripciju za pohranu"</string>
     <string name="policydesc_encryptedStorage" msgid="2504984732631479399">"Zahtijevaj da pohranjeni podaci aplikacije budu kriptirani"</string>
   <string-array name="phoneTypes">
@@ -814,6 +814,7 @@
     <string name="alwaysUse" msgid="4583018368000610438">"Koristi se kao zadana postavka za ovu lokaciju."</string>
     <string name="clearDefaultHintMsg" msgid="4815455344600932173">"Izbrišite zadane postavke u izborniku Početne postavke &gt; Aplikacije &gt; Upravljanje aplikacijama."</string>
     <string name="chooseActivity" msgid="1009246475582238425">"Odaberite radnju"</string>
+    <string name="chooseUsbActivity" msgid="7892597146032121735">"Odaberite aplikaciju za USB uređaj"</string>
     <string name="noApplications" msgid="1691104391758345586">"Tu radnju ne može izvesti nijedna aplikacija."</string>
     <string name="aerr_title" msgid="653922989522758100">"Žao nam je."</string>
     <string name="aerr_application" msgid="4683614104336409186">"Aplikacija <xliff:g id="APPLICATION">%1$s</xliff:g> (postupak <xliff:g id="PROCESS">%2$s</xliff:g>) neočekivano je zaustavljen. Pokušajte ponovo."</string>
diff --git a/core/res/res/values-hu/strings.xml b/core/res/res/values-hu/strings.xml
index aa4af42..ea4f81f 100644
--- a/core/res/res/values-hu/strings.xml
+++ b/core/res/res/values-hu/strings.xml
@@ -361,8 +361,8 @@
     <string name="permdesc_vibrate" msgid="2886677177257789187">"Lehetővé teszi az alkalmazás számára a rezgés vezérlését."</string>
     <string name="permlab_flashlight" msgid="2155920810121984215">"vaku vezérlése"</string>
     <string name="permdesc_flashlight" msgid="6433045942283802309">"Lehetővé teszi az alkalmazás számára a vaku vezérlését."</string>
-    <string name="permlab_accessUsb" msgid="7362327818655760496">"USB-eszközök elérése"</string>
-    <string name="permdesc_accessUsb" msgid="2414271762914049292">"Lehetővé teszi az alkalmazások számára az USB-eszközök elérését."</string>
+    <string name="permlab_manageUsb" msgid="1113453430645402723">"USB-eszközök preferenciáinak és engedélyeinek kezelése"</string>
+    <string name="permdesc_manageUsb" msgid="6148489202092166164">"Lehetővé teszi, hogy az alkalmazás kezelje az USB-eszközök preferenciáit és engedélyeit."</string>
     <string name="permlab_accessMtp" msgid="4953468676795917042">"MTP-protokoll megvalósítása"</string>
     <string name="permdesc_accessMtp" msgid="6532961200486791570">"Hozzáférést biztosít a kernel MTP illesztőprogramjához az MTP USB-protokoll megvalósításának céljából."</string>
     <string name="permlab_hardware_test" msgid="4148290860400659146">"hardver tesztelése"</string>
@@ -484,8 +484,8 @@
     <string name="policydesc_wipeData" product="default" msgid="7669895333814222586">"Figyelmeztetés nélkül törli a telefon összes adatát, visszaállítva a gyári adatokat"</string>
     <string name="policylab_setGlobalProxy" msgid="2784828293747791446">"Az eszköz globális proxyjának beállítása"</string>
     <string name="policydesc_setGlobalProxy" msgid="6387497466660154931">"Az eszköz globális proxyja lesz használatban, amíg az irányelv engedélyezve van. Csak az eszköz első rendszergazdája állíthatja be a tényleges globális proxyt."</string>
-    <!-- outdated translation 4740941403188940274 -->     <string name="policylab_expirePassword" msgid="885279151847254056">"Jelszó lejáratának beállítása"</string>
-    <!-- outdated translation 6626724939177185949 -->     <string name="policydesc_expirePassword" msgid="4844430354224822074">"Azt vezérli, mennyi időnként kell módosítani a képernyőt zároló jelszót"</string>
+    <string name="policylab_expirePassword" msgid="885279151847254056">"Képernyőjelszó érvényessége"</string>
+    <string name="policydesc_expirePassword" msgid="4844430354224822074">"Adja meg, hogy milyen gyakran kell módosítani a képernyőzár jelszavát"</string>
     <string name="policylab_encryptedStorage" msgid="8901326199909132915">"Tárhelytitkosítás beállítása"</string>
     <string name="policydesc_encryptedStorage" msgid="2504984732631479399">"Megköveteli a tárolt alkalmazásadatok titkosítását"</string>
   <string-array name="phoneTypes">
@@ -814,6 +814,7 @@
     <string name="alwaysUse" msgid="4583018368000610438">"Ez legyen az alapértelmezett program ehhez a művelethez."</string>
     <string name="clearDefaultHintMsg" msgid="4815455344600932173">"Az alapértelmezés törlése a Főoldal beállításai &gt; Alkalmazások &gt; Alkalmazások kezelése menüben lehetséges."</string>
     <string name="chooseActivity" msgid="1009246475582238425">"Válasszon műveletet"</string>
+    <string name="chooseUsbActivity" msgid="7892597146032121735">"Válasszon egy alkalmazást az USB-eszköz számára"</string>
     <string name="noApplications" msgid="1691104391758345586">"Egyik alkalmazás sem tudja végrehajtani ezt a műveletet."</string>
     <string name="aerr_title" msgid="653922989522758100">"Sajnáljuk!"</string>
     <string name="aerr_application" msgid="4683614104336409186">"A(z) <xliff:g id="APPLICATION">%1$s</xliff:g> alkalmazás <xliff:g id="PROCESS">%2$s</xliff:g> folyamata váratlanul leállt. Kérjük, próbálja újra."</string>
diff --git a/core/res/res/values-in/strings.xml b/core/res/res/values-in/strings.xml
index eb14169..4d5352a 100644
--- a/core/res/res/values-in/strings.xml
+++ b/core/res/res/values-in/strings.xml
@@ -361,8 +361,8 @@
     <string name="permdesc_vibrate" msgid="2886677177257789187">"Mengizinkan aplikasi mengontrol penggetar."</string>
     <string name="permlab_flashlight" msgid="2155920810121984215">"mengontrol lampu senter"</string>
     <string name="permdesc_flashlight" msgid="6433045942283802309">"Mengizinkan aplikasi mengontrol lampu senter."</string>
-    <string name="permlab_accessUsb" msgid="7362327818655760496">"akses perangkat USB"</string>
-    <string name="permdesc_accessUsb" msgid="2414271762914049292">"Mengizinkan aplikasi untuk perangkat USB."</string>
+    <string name="permlab_manageUsb" msgid="1113453430645402723">"kelola preferensi dan izin untuk perangkat USB"</string>
+    <string name="permdesc_manageUsb" msgid="6148489202092166164">"Membiarkan aplikasi mengelola preferensi dan izin untuk perangkat USB."</string>
     <string name="permlab_accessMtp" msgid="4953468676795917042">"implementasikan protokol MTP"</string>
     <string name="permdesc_accessMtp" msgid="6532961200486791570">"Izinkan akses pada driver MTP kernel untuk mengimplementasikan protokol USB MTP."</string>
     <string name="permlab_hardware_test" msgid="4148290860400659146">"uji perangkat keras"</string>
@@ -484,8 +484,8 @@
     <string name="policydesc_wipeData" product="default" msgid="7669895333814222586">"Hapus data ponsel tanpa peringatan, dengan menyetel ulang data pabrik"</string>
     <string name="policylab_setGlobalProxy" msgid="2784828293747791446">"Setel proxy global perangkat"</string>
     <string name="policydesc_setGlobalProxy" msgid="6387497466660154931">"Setel proxy global perangkat yang akandigunakan ketika kebijakan diaktifkan. Hanya admin perangkat pertama yang menyetel procy global yang berlaku."</string>
-    <!-- outdated translation 4740941403188940274 -->     <string name="policylab_expirePassword" msgid="885279151847254056">"Setel waktu kedaluwarsa sandi"</string>
-    <!-- outdated translation 6626724939177185949 -->     <string name="policydesc_expirePassword" msgid="4844430354224822074">"Kontrol berapa lama sebelum sandi penguncian layar perlu diubah"</string>
+    <string name="policylab_expirePassword" msgid="885279151847254056">"Setel kedaluwarsa sandi pengunci layar"</string>
+    <string name="policydesc_expirePassword" msgid="4844430354224822074">"Kontrol seberapa sering sandi pengunci layar harus diganti"</string>
     <string name="policylab_encryptedStorage" msgid="8901326199909132915">"Setel enkripsi penyimpanan"</string>
     <string name="policydesc_encryptedStorage" msgid="2504984732631479399">"Mengharuskan data aplikasi yang disimpan untuk dienkripsi"</string>
   <string-array name="phoneTypes">
@@ -814,6 +814,7 @@
     <string name="alwaysUse" msgid="4583018368000610438">"Gunakan secara bawaan untuk tindakan ini."</string>
     <string name="clearDefaultHintMsg" msgid="4815455344600932173">"Bersihkan bawaan pada Setelan Beranda &gt; Aplikasi &gt; Kelola aplikasi."</string>
     <string name="chooseActivity" msgid="1009246475582238425">"Pilih tindakan"</string>
+    <string name="chooseUsbActivity" msgid="7892597146032121735">"Pilih sebuah aplikasi untuk perangkat USB"</string>
     <string name="noApplications" msgid="1691104391758345586">"Tidak ada aplikasi dapat melakukan tindakan ini."</string>
     <string name="aerr_title" msgid="653922989522758100">"Maaf!"</string>
     <string name="aerr_application" msgid="4683614104336409186">"<xliff:g id="APPLICATION">%1$s</xliff:g> aplikasi (<xliff:g id="PROCESS">%2$s</xliff:g> proses) berhenti tiba-tiba. Harap coba lagi."</string>
diff --git a/core/res/res/values-it/strings.xml b/core/res/res/values-it/strings.xml
index 1507467..3196dbe 100644
--- a/core/res/res/values-it/strings.xml
+++ b/core/res/res/values-it/strings.xml
@@ -361,8 +361,8 @@
     <string name="permdesc_vibrate" msgid="2886677177257789187">"Consente all\'applicazione di controllare la vibrazione."</string>
     <string name="permlab_flashlight" msgid="2155920810121984215">"controllo flash"</string>
     <string name="permdesc_flashlight" msgid="6433045942283802309">"Consente all\'applicazione di controllare il flash."</string>
-    <string name="permlab_accessUsb" msgid="7362327818655760496">"accesso a dispositivi USB"</string>
-    <string name="permdesc_accessUsb" msgid="2414271762914049292">"Consente all\'applicazione di accedere ai dispositivi USB"</string>
+    <string name="permlab_manageUsb" msgid="1113453430645402723">"gestione preferenze e autorizzazioni per dispositivi USB"</string>
+    <string name="permdesc_manageUsb" msgid="6148489202092166164">"Consente all\'applicazione di gestire le preferenze e le autorizzazioni relative ai dispositivi USB."</string>
     <string name="permlab_accessMtp" msgid="4953468676795917042">"implementa protocollo MTP"</string>
     <string name="permdesc_accessMtp" msgid="6532961200486791570">"Consente di accedere al driver MTP del kernel per implementare il protocollo USB MTP."</string>
     <string name="permlab_hardware_test" msgid="4148290860400659146">"esecuzione test hardware"</string>
@@ -484,8 +484,8 @@
     <string name="policydesc_wipeData" product="default" msgid="7669895333814222586">"Cancella i dati del telefono senza preavviso eseguendo un ripristino dati di fabbrica"</string>
     <string name="policylab_setGlobalProxy" msgid="2784828293747791446">"Imposta il proxy globale del dispositivo"</string>
     <string name="policydesc_setGlobalProxy" msgid="6387497466660154931">"Imposta il proxy globale del dispositivo in modo da utilizzarlo mentre la norma è attiva. Il proxy globale effettivo è impostabile solo dal primo amministratore del dispositivo."</string>
-    <!-- outdated translation 4740941403188940274 -->     <string name="policylab_expirePassword" msgid="885279151847254056">"Imposta scadenza password"</string>
-    <!-- outdated translation 6626724939177185949 -->     <string name="policydesc_expirePassword" msgid="4844430354224822074">"Stabilisci la scadenza della password di blocco dello schermo"</string>
+    <string name="policylab_expirePassword" msgid="885279151847254056">"Imposta scadenza password blocco schermo"</string>
+    <string name="policydesc_expirePassword" msgid="4844430354224822074">"Stabilisci la frequenza di modifica della password di blocco dello schermo"</string>
     <string name="policylab_encryptedStorage" msgid="8901326199909132915">"Imposta crittografia archivio"</string>
     <string name="policydesc_encryptedStorage" msgid="2504984732631479399">"Richiede la crittografia dei dati applicazione memorizzati"</string>
   <string-array name="phoneTypes">
@@ -814,6 +814,7 @@
     <string name="alwaysUse" msgid="4583018368000610438">"Usa come predefinita per questa azione."</string>
     <string name="clearDefaultHintMsg" msgid="4815455344600932173">"Cancella predefinita in Home &gt; Impostazioni &gt; Applicazioni &gt; Gestisci applicazioni."</string>
     <string name="chooseActivity" msgid="1009246475582238425">"Seleziona un\'azione"</string>
+    <string name="chooseUsbActivity" msgid="7892597146032121735">"Seleziona un\'applicazione per il dispositivo USB"</string>
     <string name="noApplications" msgid="1691104391758345586">"Nessuna applicazione è in grado di svolgere questa azione."</string>
     <string name="aerr_title" msgid="653922989522758100">"Spiacenti."</string>
     <string name="aerr_application" msgid="4683614104336409186">"Interruzione imprevista dell\'applicazione <xliff:g id="APPLICATION">%1$s</xliff:g> (processo <xliff:g id="PROCESS">%2$s</xliff:g>). Riprova."</string>
diff --git a/core/res/res/values-iw/strings.xml b/core/res/res/values-iw/strings.xml
index 7aa7b30..07fab9e 100644
--- a/core/res/res/values-iw/strings.xml
+++ b/core/res/res/values-iw/strings.xml
@@ -361,8 +361,8 @@
     <string name="permdesc_vibrate" msgid="2886677177257789187">"מאפשר ליישום לשלוט ברטט."</string>
     <string name="permlab_flashlight" msgid="2155920810121984215">"שליטה בפנס"</string>
     <string name="permdesc_flashlight" msgid="6433045942283802309">"מאפשר ליישום לשלוט בפנס."</string>
-    <string name="permlab_accessUsb" msgid="7362327818655760496">"גישה להתקני USB"</string>
-    <string name="permdesc_accessUsb" msgid="2414271762914049292">"מאפשר ליישום גישה להתקני USB."</string>
+    <string name="permlab_manageUsb" msgid="1113453430645402723">"נהל העדפות ואישורים עבור התקני USB"</string>
+    <string name="permdesc_manageUsb" msgid="6148489202092166164">"מאפשר ליישום לנהל העדפות ואישורים עבור התקני USB."</string>
     <string name="permlab_accessMtp" msgid="4953468676795917042">"יישם פרוטוקול MTP"</string>
     <string name="permdesc_accessMtp" msgid="6532961200486791570">"מאפשר גישה למנהל התקן MTP של הליבה כדי ליישם פרוטוקול USB של MTP."</string>
     <string name="permlab_hardware_test" msgid="4148290860400659146">"בדוק חומרה"</string>
@@ -484,8 +484,8 @@
     <string name="policydesc_wipeData" product="default" msgid="7669895333814222586">"מחק את נתוני הטלפון ללא אזהרה, על ידי ביצוע איפוס נתוני יצרן"</string>
     <string name="policylab_setGlobalProxy" msgid="2784828293747791446">"הגדר את שרת ה-proxy הגלובלי של ההתקן"</string>
     <string name="policydesc_setGlobalProxy" msgid="6387497466660154931">"הגדר את שרת proxy הגלובלי של ההתקן לשימוש כאשר המדיניות מופעלת. רק מנהל ההתקן הראשון מגדיר את שרת ה-proxy הגלובלי הפעיל."</string>
-    <!-- outdated translation 4740941403188940274 -->     <string name="policylab_expirePassword" msgid="885279151847254056">"הגדר תפוגת תוקף של סיסמה"</string>
-    <!-- outdated translation 6626724939177185949 -->     <string name="policydesc_expirePassword" msgid="4844430354224822074">"שלוט בפרק הזמן הדרוש לשינוי הסיסמה של נעילת המסך"</string>
+    <string name="policylab_expirePassword" msgid="885279151847254056">"הגדר תאריך תפוגה לסיסמה של נעילת המסך"</string>
+    <string name="policydesc_expirePassword" msgid="4844430354224822074">"שלוט בתדירות שבה הסיסמה של נעילת המסך חייבת להשתנות"</string>
     <string name="policylab_encryptedStorage" msgid="8901326199909132915">"הגדר הצפנת אחסון"</string>
     <string name="policydesc_encryptedStorage" msgid="2504984732631479399">"דורש שנתוני היישום המאוחסנים יהיו מוצפנים"</string>
   <string-array name="phoneTypes">
@@ -814,6 +814,7 @@
     <string name="alwaysUse" msgid="4583018368000610438">"השתמש כברירת מחדל עבור פעולה זו."</string>
     <string name="clearDefaultHintMsg" msgid="4815455344600932173">"נקה את ברירת המחדל ב\'הגדרות דף הבית\' &gt; \'יישומים\' &gt; \'נהל יישומים\'."</string>
     <string name="chooseActivity" msgid="1009246475582238425">"בחר פעולה"</string>
+    <string name="chooseUsbActivity" msgid="7892597146032121735">"בחר יישום עבור התקן ה-USB"</string>
     <string name="noApplications" msgid="1691104391758345586">"אין יישומים שיכולים לבצע פעולה זו."</string>
     <string name="aerr_title" msgid="653922989522758100">"מצטערים!"</string>
     <string name="aerr_application" msgid="4683614104336409186">"היישום <xliff:g id="APPLICATION">%1$s</xliff:g> (תהליך <xliff:g id="PROCESS">%2$s</xliff:g>) הופסק באופן לא צפוי. נסה שוב."</string>
diff --git a/core/res/res/values-ja/strings.xml b/core/res/res/values-ja/strings.xml
index af2e4d4..c6a5f95 100644
--- a/core/res/res/values-ja/strings.xml
+++ b/core/res/res/values-ja/strings.xml
@@ -361,8 +361,8 @@
     <string name="permdesc_vibrate" msgid="2886677177257789187">"バイブレーションの制御をアプリケーションに許可します。"</string>
     <string name="permlab_flashlight" msgid="2155920810121984215">"ライトのコントロール"</string>
     <string name="permdesc_flashlight" msgid="6433045942283802309">"ライトの制御をアプリケーションに許可します。"</string>
-    <string name="permlab_accessUsb" msgid="7362327818655760496">"USBデバイスへのアクセス"</string>
-    <string name="permdesc_accessUsb" msgid="2414271762914049292">"USBデバイスへのアクセスをアプリケーションに許可します。"</string>
+    <string name="permlab_manageUsb" msgid="1113453430645402723">"USBデバイスの設定と許可の管理"</string>
+    <string name="permdesc_manageUsb" msgid="6148489202092166164">"USBデバイスの設定と許可の管理をアプリケーションに許可します。"</string>
     <string name="permlab_accessMtp" msgid="4953468676795917042">"MTPプロトコルの実装"</string>
     <string name="permdesc_accessMtp" msgid="6532961200486791570">"カーネルMTPドライバにアクセスしてMTP USBプロトコルを実装することを許可します。"</string>
     <string name="permlab_hardware_test" msgid="4148290860400659146">"ハードウェアのテスト"</string>
@@ -484,8 +484,8 @@
     <string name="policydesc_wipeData" product="default" msgid="7669895333814222586">"警告せずにデータの初期化を実行して端末内のデータを消去します。"</string>
     <string name="policylab_setGlobalProxy" msgid="2784828293747791446">"端末のグローバルプロキシを設定"</string>
     <string name="policydesc_setGlobalProxy" msgid="6387497466660154931">"ポリシーが有効になっている場合は端末のグローバルプロキシが使用されるように設定します。有効なグローバルプロキシを設定できるのは最初のデバイス管理者だけです。"</string>
-    <!-- outdated translation 4740941403188940274 -->     <string name="policylab_expirePassword" msgid="885279151847254056">"パスワードの有効期限の設定"</string>
-    <!-- outdated translation 6626724939177185949 -->     <string name="policydesc_expirePassword" msgid="4844430354224822074">"画面ロックパスワードの変更が必要になるまでの期間を指定します"</string>
+    <string name="policylab_expirePassword" msgid="885279151847254056">"解除パスワードの有効期限の設定"</string>
+    <string name="policydesc_expirePassword" msgid="4844430354224822074">"ロック解除パスワードの変更が必要になる頻度を指定します"</string>
     <string name="policylab_encryptedStorage" msgid="8901326199909132915">"ストレージ暗号化の設定"</string>
     <string name="policydesc_encryptedStorage" msgid="2504984732631479399">"保存したアプリケーションデータが暗号化されるようにする"</string>
   <string-array name="phoneTypes">
@@ -814,6 +814,7 @@
     <string name="alwaysUse" msgid="4583018368000610438">"常にこの操作で使用する"</string>
     <string name="clearDefaultHintMsg" msgid="4815455344600932173">"ホームの[設定]&gt;[アプリケーション]&gt;[アプリケーションの管理]でデフォルト設定をクリアします。"</string>
     <string name="chooseActivity" msgid="1009246475582238425">"操作の選択"</string>
+    <string name="chooseUsbActivity" msgid="7892597146032121735">"USBデバイス用アプリケーションを選択"</string>
     <string name="noApplications" msgid="1691104391758345586">"この操作を実行できるアプリケーションはありません。"</string>
     <string name="aerr_title" msgid="653922989522758100">"エラー"</string>
     <string name="aerr_application" msgid="4683614104336409186">"<xliff:g id="APPLICATION">%1$s</xliff:g>(<xliff:g id="PROCESS">%2$s</xliff:g>)が予期せず停止しました。やり直してください。"</string>
diff --git a/core/res/res/values-ko/strings.xml b/core/res/res/values-ko/strings.xml
index 6d1423c..1b7051e 100644
--- a/core/res/res/values-ko/strings.xml
+++ b/core/res/res/values-ko/strings.xml
@@ -361,8 +361,8 @@
     <string name="permdesc_vibrate" msgid="2886677177257789187">"애플리케이션이 진동을 제어할 수 있도록 합니다."</string>
     <string name="permlab_flashlight" msgid="2155920810121984215">"카메라 플래시 제어"</string>
     <string name="permdesc_flashlight" msgid="6433045942283802309">"애플리케이션이 카메라 플래시를 제어할 수 있도록 합니다."</string>
-    <string name="permlab_accessUsb" msgid="7362327818655760496">"USB 장치 액세스"</string>
-    <string name="permdesc_accessUsb" msgid="2414271762914049292">"애플리케이션이 USB 장치에 액세스하도록 허용합니다."</string>
+    <string name="permlab_manageUsb" msgid="1113453430645402723">"USB 기기에 대한 환경설정 및 권한 관리"</string>
+    <string name="permdesc_manageUsb" msgid="6148489202092166164">"애플리케이션이 USB 기기에 대한 환경설정 및 권한을 관리하도록 허용합니다."</string>
     <string name="permlab_accessMtp" msgid="4953468676795917042">"MTP 프로토콜 구현"</string>
     <string name="permdesc_accessMtp" msgid="6532961200486791570">"커널 MTP 드라이버에 액세스하여 MTP USB 프로토콜을 구현할 수 있도록 허용합니다."</string>
     <string name="permlab_hardware_test" msgid="4148290860400659146">"하드웨어 테스트"</string>
@@ -484,8 +484,8 @@
     <string name="policydesc_wipeData" product="default" msgid="7669895333814222586">"공장 초기화를 수행하여 경고 없이 휴대전화 데이터를 지웁니다."</string>
     <string name="policylab_setGlobalProxy" msgid="2784828293747791446">"기기 전체 프록시 설정"</string>
     <string name="policydesc_setGlobalProxy" msgid="6387497466660154931">"정책이 사용 설정되어 있는 동안 사용될 기기 전체 프록시를 설정합니다. 첫 번째 기기 관리자가 설정한 전체 프록시만 유효합니다."</string>
-    <!-- outdated translation 4740941403188940274 -->     <string name="policylab_expirePassword" msgid="885279151847254056">"비밀번호 만료 설정"</string>
-    <!-- outdated translation 6626724939177185949 -->     <string name="policydesc_expirePassword" msgid="4844430354224822074">"화면 잠금 비밀번호를 변경해야 하는 기간 변경"</string>
+    <string name="policylab_expirePassword" msgid="885279151847254056">"화면 잠금 비밀번호 만료 설정"</string>
+    <string name="policydesc_expirePassword" msgid="4844430354224822074">"화면 잠금 비밀번호 변경 빈도 설정"</string>
     <string name="policylab_encryptedStorage" msgid="8901326199909132915">"저장소 암호화 설정"</string>
     <string name="policydesc_encryptedStorage" msgid="2504984732631479399">"저장한 애플리케이션 데이터를 암호화해야 합니다."</string>
   <string-array name="phoneTypes">
@@ -814,6 +814,7 @@
     <string name="alwaysUse" msgid="4583018368000610438">"이 작업에 대해 기본값으로 사용"</string>
     <string name="clearDefaultHintMsg" msgid="4815455344600932173">"홈 설정 &gt; 애플리케이션 &gt; 애플리케이션 관리에서 기본값을 지웁니다."</string>
     <string name="chooseActivity" msgid="1009246475582238425">"작업 선택"</string>
+    <string name="chooseUsbActivity" msgid="7892597146032121735">"USB 기기에 대한 애플리케이션 선택"</string>
     <string name="noApplications" msgid="1691104391758345586">"작업을 수행할 수 있는 애플리케이션이 없습니다."</string>
     <string name="aerr_title" msgid="653922989522758100">"죄송합니다."</string>
     <string name="aerr_application" msgid="4683614104336409186">"<xliff:g id="APPLICATION">%1$s</xliff:g> 애플리케이션(<xliff:g id="PROCESS">%2$s</xliff:g> 프로세스)이 예상치 않게 중지되었습니다. 다시 시도해 주세요."</string>
diff --git a/core/res/res/values-large/dimens.xml b/core/res/res/values-large/dimens.xml
index 5691548..cd1847f 100644
--- a/core/res/res/values-large/dimens.xml
+++ b/core/res/res/values-large/dimens.xml
@@ -19,4 +19,7 @@
 <resources>
     <item type="dimen" name="dialog_min_width_major">55%</item>
     <item type="dimen" name="dialog_min_width_minor">80%</item>
+
+    <!-- Preference UI dimensions for larger screens. -->
+    <dimen name="preference_widget_width">56dp</dimen>
 </resources>
diff --git a/core/res/res/values-large/styles.xml b/core/res/res/values-large/styles.xml
new file mode 100644
index 0000000..96a8c84
--- /dev/null
+++ b/core/res/res/values-large/styles.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2011 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<resources>
+    <style name="Widget.Holo.PreferenceFrameLayout">
+        <item name="android:borderTop">0dip</item>
+        <item name="android:borderBottom">48dip</item>
+        <item name="android:borderLeft">32dip</item>
+        <item name="android:borderRight">32dip</item>
+    </style>
+</resources>
diff --git a/core/res/res/values-lt/strings.xml b/core/res/res/values-lt/strings.xml
index b0148154..850a6c9 100644
--- a/core/res/res/values-lt/strings.xml
+++ b/core/res/res/values-lt/strings.xml
@@ -361,8 +361,8 @@
     <string name="permdesc_vibrate" msgid="2886677177257789187">"Leidžia programai valdyti vibratorių."</string>
     <string name="permlab_flashlight" msgid="2155920810121984215">"valdyti šviesos signalą"</string>
     <string name="permdesc_flashlight" msgid="6433045942283802309">"Leidžia programai valdyti šviesos signalą."</string>
-    <string name="permlab_accessUsb" msgid="7362327818655760496">"pasiekti USB įrenginius"</string>
-    <string name="permdesc_accessUsb" msgid="2414271762914049292">"Leidžiama programai pasiekti USB įrenginius."</string>
+    <string name="permlab_manageUsb" msgid="1113453430645402723">"valdyti USB įrenginių nuostatas ir leidimus"</string>
+    <string name="permdesc_manageUsb" msgid="6148489202092166164">"Leidžiama programai valdyti USB įrenginių nuostatas ir leidimus."</string>
     <string name="permlab_accessMtp" msgid="4953468676795917042">"taikyti MTP protokolą"</string>
     <string name="permdesc_accessMtp" msgid="6532961200486791570">"Leidžiama prieiga prie pagrindinės MTP tvarkyklės taikyti MTP USB protokolą."</string>
     <string name="permlab_hardware_test" msgid="4148290860400659146">"bandyti aparatinę įrangą"</string>
@@ -484,8 +484,8 @@
     <string name="policydesc_wipeData" product="default" msgid="7669895333814222586">"Be įspėjimo ištrinti telefono duomenis iš naujo nustatant gamyklinius duomenis"</string>
     <string name="policylab_setGlobalProxy" msgid="2784828293747791446">"Nustatyti įrenginio bendrąjį tarpinį serverį"</string>
     <string name="policydesc_setGlobalProxy" msgid="6387497466660154931">"Nustatyti įrenginio bendrąjį tarpinį serverį, kad būtų naudojamas, kol įgalinta politika. Tik pirmasis įrenginio administratorius nustato efektyvų bendrąjį tarpinį serverį."</string>
-    <!-- outdated translation 4740941403188940274 -->     <string name="policylab_expirePassword" msgid="885279151847254056">"Nustatyti slaptažodžio galiojimo pabaigą"</string>
-    <!-- outdated translation 6626724939177185949 -->     <string name="policydesc_expirePassword" msgid="4844430354224822074">"Valdyti, per kiek laiko iki ekrano užrakinimo turi būti pakeistas slaptažodis"</string>
+    <string name="policylab_expirePassword" msgid="885279151847254056">"Nust. ekr. užr. slapt. gal. pab."</string>
+    <string name="policydesc_expirePassword" msgid="4844430354224822074">"Valdykite, kaip dažnai reikia keisti ekrano užrakto slaptažodį"</string>
     <string name="policylab_encryptedStorage" msgid="8901326199909132915">"Nustatyti atmintinės šifruotę"</string>
     <string name="policydesc_encryptedStorage" msgid="2504984732631479399">"Saugomos programos duomenys turi būti šifruoti"</string>
   <string-array name="phoneTypes">
@@ -814,6 +814,7 @@
     <string name="alwaysUse" msgid="4583018368000610438">"Šiam veiksmui tai naudoti pagal numatytuosius nustatymus."</string>
     <string name="clearDefaultHintMsg" msgid="4815455344600932173">"Išvalykite numatytuosius nustatymus apsilankę „Pagrindiniai nustatymai“ &gt; „Programos“ &gt; „Valdyti programas“."</string>
     <string name="chooseActivity" msgid="1009246475582238425">"pasirinkti veiksmą"</string>
+    <string name="chooseUsbActivity" msgid="7892597146032121735">"Pasirinkti programą USB įrenginiui"</string>
     <string name="noApplications" msgid="1691104391758345586">"Šio veiksmo negali atlikti jokios programos."</string>
     <string name="aerr_title" msgid="653922989522758100">"Apgailestaujame!"</string>
     <string name="aerr_application" msgid="4683614104336409186">"Programa <xliff:g id="APPLICATION">%1$s</xliff:g> (<xliff:g id="PROCESS">%2$s</xliff:g> procesas) netikėtai sustojo. Bandykite dar kartą."</string>
diff --git a/core/res/res/values-lv/strings.xml b/core/res/res/values-lv/strings.xml
index 3f69434..a4936ac 100644
--- a/core/res/res/values-lv/strings.xml
+++ b/core/res/res/values-lv/strings.xml
@@ -361,8 +361,8 @@
     <string name="permdesc_vibrate" msgid="2886677177257789187">"Ļauj lietojumprogrammai kontrolēt vibrozvanu."</string>
     <string name="permlab_flashlight" msgid="2155920810121984215">"kontrolēt uzliesmojumu"</string>
     <string name="permdesc_flashlight" msgid="6433045942283802309">"Ļauj lietojumprogrammai kontrolēt uzliesmojumu."</string>
-    <string name="permlab_accessUsb" msgid="7362327818655760496">"piekļuve USB ierīcēm"</string>
-    <string name="permdesc_accessUsb" msgid="2414271762914049292">"Ļauj lietojumprogrammai piekļūt USB ierīcēm."</string>
+    <string name="permlab_manageUsb" msgid="1113453430645402723">"USB ierīču preferenču un atļauju pārvaldība"</string>
+    <string name="permdesc_manageUsb" msgid="6148489202092166164">"Ļauj lietojumprogrammai pārvaldīt preferences un atļaujas saistībā ar USB ierīcēm."</string>
     <string name="permlab_accessMtp" msgid="4953468676795917042">"Ieviests MTP protokols"</string>
     <string name="permdesc_accessMtp" msgid="6532961200486791570">"Ļauj piekļūt kodola MTP dzinim, lai ieviestu MTP USB protokolu."</string>
     <string name="permlab_hardware_test" msgid="4148290860400659146">"pārbaudīt aparatūru"</string>
@@ -484,8 +484,8 @@
     <string name="policydesc_wipeData" product="default" msgid="7669895333814222586">"Dzēš tālruņa datus bez brīdinājuma, veicot rūpnīcas datu atiestatīšanu"</string>
     <string name="policylab_setGlobalProxy" msgid="2784828293747791446">"Iestatīt ierīces globālo starpniekserveri"</string>
     <string name="policydesc_setGlobalProxy" msgid="6387497466660154931">"Iestatiet izmantojamo ierīces globālo starpniekserveri, kad ir iespējota politika. Spēkā esošo globālo starpniekserveri iestata tikai pirmās ierīces administrators."</string>
-    <!-- outdated translation 4740941403188940274 -->     <string name="policylab_expirePassword" msgid="885279151847254056">"Paroles beigu termiņa iestatīšana"</string>
-    <!-- outdated translation 6626724939177185949 -->     <string name="policydesc_expirePassword" msgid="4844430354224822074">"Kontrolē ekrāna bloķēšanas paroles maiņas intervālu"</string>
+    <string name="policylab_expirePassword" msgid="885279151847254056">"Ekr. bloķ. paroles term. iest."</string>
+    <string name="policydesc_expirePassword" msgid="4844430354224822074">"Kontrolē, cik bieži ir jāmaina ekrāna bloķēšanas parole."</string>
     <string name="policylab_encryptedStorage" msgid="8901326199909132915">"Skatīt atmiņas šifrējumu"</string>
     <string name="policydesc_encryptedStorage" msgid="2504984732631479399">"Pieprasīt, lai saglabātie lietojumprogrammas dati tiktu šifrēti"</string>
   <string-array name="phoneTypes">
@@ -814,6 +814,7 @@
     <string name="alwaysUse" msgid="4583018368000610438">"Pēc noklusējuma izmantot šai darbībai."</string>
     <string name="clearDefaultHintMsg" msgid="4815455344600932173">"Notīriet noklusējumu šeit: Sākuma iestatījumi &gt; Lietojumprogrammas &gt; Lietojumprogrammu pārvaldība."</string>
     <string name="chooseActivity" msgid="1009246475582238425">"Atlasiet darbību"</string>
+    <string name="chooseUsbActivity" msgid="7892597146032121735">"Atlasīt lietojumprogrammu USB ierīcei"</string>
     <string name="noApplications" msgid="1691104391758345586">"Šo darbību nevar veikt neviena lietojumprogramma."</string>
     <string name="aerr_title" msgid="653922989522758100">"Atvainojiet!"</string>
     <string name="aerr_application" msgid="4683614104336409186">"Lietojumprogrammas <xliff:g id="APPLICATION">%1$s</xliff:g> (process <xliff:g id="PROCESS">%2$s</xliff:g>) darbība neparedzēti tika apturēta. Lūdzu, mēģiniet vēlreiz."</string>
diff --git a/core/res/res/values-nb/strings.xml b/core/res/res/values-nb/strings.xml
index 09a2cd4..3b15f88 100644
--- a/core/res/res/values-nb/strings.xml
+++ b/core/res/res/values-nb/strings.xml
@@ -361,8 +361,8 @@
     <string name="permdesc_vibrate" msgid="2886677177257789187">"Lar applikasjonen kontrollere vibratoren."</string>
     <string name="permlab_flashlight" msgid="2155920810121984215">"kontrollere lommelykten"</string>
     <string name="permdesc_flashlight" msgid="6433045942283802309">"Lar applikasjonen kontrollere lommelykten."</string>
-    <string name="permlab_accessUsb" msgid="7362327818655760496">"tilgang til USB-enheter"</string>
-    <string name="permdesc_accessUsb" msgid="2414271762914049292">"Tillater programmet å få tilgang til USB-enheter."</string>
+    <string name="permlab_manageUsb" msgid="1113453430645402723">"administrere innstillinger og tillatelser for USB-enheter"</string>
+    <string name="permdesc_manageUsb" msgid="6148489202092166164">"Tillater at programmet administrerer innstillinger og tillatelser for USB-enheter."</string>
     <string name="permlab_accessMtp" msgid="4953468676795917042">"implementer MTP-protokoll"</string>
     <string name="permdesc_accessMtp" msgid="6532961200486791570">"Tillater tilgang til kjerne-MTP-driver for implementering av MTP USB-protokollen."</string>
     <string name="permlab_hardware_test" msgid="4148290860400659146">"teste maskinvare"</string>
@@ -484,8 +484,8 @@
     <string name="policydesc_wipeData" product="default" msgid="7669895333814222586">"Tilbakestill telefonens data uten advarsel ved å utføre tilbakestilling til fabrikkstandard"</string>
     <string name="policylab_setGlobalProxy" msgid="2784828293747791446">"Angi enhetens globale mellomtjener"</string>
     <string name="policydesc_setGlobalProxy" msgid="6387497466660154931">"Angir den globale mellomtjeneren på enheten som skal brukes når regelen er aktivert. Kun den opprinnelige administratoren av enheten kan angi den globale mellomtjeneren."</string>
-    <!-- outdated translation 4740941403188940274 -->     <string name="policylab_expirePassword" msgid="885279151847254056">"Angi utløpsdato for passordet"</string>
-    <!-- outdated translation 6626724939177185949 -->     <string name="policydesc_expirePassword" msgid="4844430354224822074">"Velg hvor lenge det skal gå før passordet til låseskjermen må byttes"</string>
+    <string name="policylab_expirePassword" msgid="885279151847254056">"Angi utløpsdato for skjermlåspassordet"</string>
+    <string name="policydesc_expirePassword" msgid="4844430354224822074">"Velg hvor lenge det skal gå før passordet til skjermlåsen må byttes"</string>
     <string name="policylab_encryptedStorage" msgid="8901326199909132915">"Angi lagringskryptering"</string>
     <string name="policydesc_encryptedStorage" msgid="2504984732631479399">"Krever at lagrede programdata krypteres"</string>
   <string-array name="phoneTypes">
@@ -814,6 +814,7 @@
     <string name="alwaysUse" msgid="4583018368000610438">"Bruk som standardvalg."</string>
     <string name="clearDefaultHintMsg" msgid="4815455344600932173">"Fjern standardvalg i Innstillinger &gt; Applikasjoner &gt; Installerte applikasjoner."</string>
     <string name="chooseActivity" msgid="1009246475582238425">"Velg en aktivitet"</string>
+    <string name="chooseUsbActivity" msgid="7892597146032121735">"Velg et program for USB-enheten"</string>
     <string name="noApplications" msgid="1691104391758345586">"Ingen applikasjoner kan gjøre dette."</string>
     <string name="aerr_title" msgid="653922989522758100">"Beklager!"</string>
     <string name="aerr_application" msgid="4683614104336409186">"Applikasjonen <xliff:g id="APPLICATION">%1$s</xliff:g> (prosess <xliff:g id="PROCESS">%2$s</xliff:g>) stoppet uventet. Prøv igjen."</string>
@@ -918,11 +919,11 @@
     <string name="ext_media_unmountable_notification_title" product="default" msgid="6410723906019100189">"Skadet minnekort"</string>
     <string name="ext_media_unmountable_notification_message" product="nosdcard" msgid="529021299294450667">"USB-lagring er skadet. Det kan være nødvendig å formatere enheten på nytt."</string>
     <string name="ext_media_unmountable_notification_message" product="default" msgid="6902531775948238989">"Minnekortet er skadet. Du må kanskje formatere det."</string>
-    <string name="ext_media_badremoval_notification_title" product="nosdcard" msgid="1661683031330951073">"USB-lagring fjernet uventet"</string>
+    <string name="ext_media_badremoval_notification_title" product="nosdcard" msgid="1661683031330951073">"USB-enhet fjernet uventet"</string>
     <string name="ext_media_badremoval_notification_title" product="default" msgid="6872152882604407837">"Minnekortet ble tatt ut uventet"</string>
-    <string name="ext_media_badremoval_notification_message" product="nosdcard" msgid="4329848819865594241">"Koble fra USB-lagring før enheten tas ut av maskinen for å unngå tap av data."</string>
+    <string name="ext_media_badremoval_notification_message" product="nosdcard" msgid="4329848819865594241">"Koble fra USB-enheten før du tar den ut for å unngå tap av data."</string>
     <string name="ext_media_badremoval_notification_message" product="default" msgid="7260183293747448241">"Avmonter minnekortet før det tas ut, for å unngå datatap."</string>
-    <string name="ext_media_safe_unmount_notification_title" product="nosdcard" msgid="3967973893270360230">"USB-lagring kan trygt fjernes"</string>
+    <string name="ext_media_safe_unmount_notification_title" product="nosdcard" msgid="3967973893270360230">"USB-enheten kan trygt fjernes"</string>
     <string name="ext_media_safe_unmount_notification_title" product="default" msgid="6729801130790616200">"Trygt å ta ut minnekort"</string>
     <string name="ext_media_safe_unmount_notification_message" product="nosdcard" msgid="6142195361606493530">"Det er trygt å ta ut enheten for USB-lagring."</string>
     <string name="ext_media_safe_unmount_notification_message" product="default" msgid="568841278138377604">"Det er trygt å ta ut minnekortet."</string>
diff --git a/core/res/res/values-nl/strings.xml b/core/res/res/values-nl/strings.xml
index 85a7a2d..5ca1e4d 100644
--- a/core/res/res/values-nl/strings.xml
+++ b/core/res/res/values-nl/strings.xml
@@ -361,8 +361,8 @@
     <string name="permdesc_vibrate" msgid="2886677177257789187">"Hiermee kan de app de trilstand beheren."</string>
     <string name="permlab_flashlight" msgid="2155920810121984215">"zaklamp bedienen"</string>
     <string name="permdesc_flashlight" msgid="6433045942283802309">"Hiermee kan de app de zaklamp bedienen."</string>
-    <string name="permlab_accessUsb" msgid="7362327818655760496">"toegang krijgen tot USB-apparaten"</string>
-    <string name="permdesc_accessUsb" msgid="2414271762914049292">"Hiermee kan de app toegang krijgen tot USB-apparaten."</string>
+    <string name="permlab_manageUsb" msgid="1113453430645402723">"voorkeuren en rechten voor USB-apparaten beheren"</string>
+    <string name="permdesc_manageUsb" msgid="6148489202092166164">"Hiermee kan de app voorkeuren en rechten voor USB-apparaten beheren."</string>
     <string name="permlab_accessMtp" msgid="4953468676795917042">"MTP-protocol implementeren"</string>
     <string name="permdesc_accessMtp" msgid="6532961200486791570">"Staat toegang tot de kernel van de MTP-driver toe voor het implementeren van het MTP-USB-protocol."</string>
     <string name="permlab_hardware_test" msgid="4148290860400659146">"hardware testen"</string>
@@ -484,8 +484,8 @@
     <string name="policydesc_wipeData" product="default" msgid="7669895333814222586">"De gegevens van de telefoon zonder waarschuwing wissen door de fabrieksinstellingen te herstellen"</string>
     <string name="policylab_setGlobalProxy" msgid="2784828293747791446">"Algemene proxy voor het apparaat instellen"</string>
     <string name="policydesc_setGlobalProxy" msgid="6387497466660154931">"Stel de algemene proxy voor het apparaat in die moet worden gebruikt terwijl het beleid is geactiveerd. Alleen de eerste apparaatbeheerder stelt de algemene proxy in."</string>
-    <!-- outdated translation 4740941403188940274 -->     <string name="policylab_expirePassword" msgid="885279151847254056">"Verval wachtwoord instellen"</string>
-    <!-- outdated translation 6626724939177185949 -->     <string name="policydesc_expirePassword" msgid="4844430354224822074">"Beheren hoe lang het duurt voordat het wachtwoord voor schermvergrendeling moet worden gewijzigd"</string>
+    <string name="policylab_expirePassword" msgid="885279151847254056">"Verval wachtwoord instellen"</string>
+    <string name="policydesc_expirePassword" msgid="4844430354224822074">"Beheren hoe vaak het wachtwoord voor schermvergrendeling moet worden gewijzigd"</string>
     <string name="policylab_encryptedStorage" msgid="8901326199909132915">"Codering voor opslag instellen"</string>
     <string name="policydesc_encryptedStorage" msgid="2504984732631479399">"Vereisen dat opgeslagen toepassingsgegevens kunnen worden gecodeerd"</string>
   <string-array name="phoneTypes">
@@ -814,6 +814,7 @@
     <string name="alwaysUse" msgid="4583018368000610438">"Standaard gebruiken voor deze actie."</string>
     <string name="clearDefaultHintMsg" msgid="4815455344600932173">"Wis standaardinstelling via startscherm: \'Instellingen\' &gt; \'Toepassingen\' &gt; \'Toepassingen beheren\'."</string>
     <string name="chooseActivity" msgid="1009246475582238425">"Een actie selecteren"</string>
+    <string name="chooseUsbActivity" msgid="7892597146032121735">"Selecteer een app voor het USB-apparaat"</string>
     <string name="noApplications" msgid="1691104391758345586">"Geen enkele app kan deze actie uitvoeren."</string>
     <string name="aerr_title" msgid="653922989522758100">"Helaas!"</string>
     <string name="aerr_application" msgid="4683614104336409186">"De app <xliff:g id="APPLICATION">%1$s</xliff:g> (proces <xliff:g id="PROCESS">%2$s</xliff:g>) is onverwachts gestopt. Probeer het opnieuw."</string>
diff --git a/core/res/res/values-pl/strings.xml b/core/res/res/values-pl/strings.xml
index 99f723c..de44e72 100644
--- a/core/res/res/values-pl/strings.xml
+++ b/core/res/res/values-pl/strings.xml
@@ -361,8 +361,8 @@
     <string name="permdesc_vibrate" msgid="2886677177257789187">"Pozwala aplikacjom na kontrolowanie wibracji."</string>
     <string name="permlab_flashlight" msgid="2155920810121984215">"kontrolowanie latarki"</string>
     <string name="permdesc_flashlight" msgid="6433045942283802309">"Pozwala aplikacji kontrolować latarkę."</string>
-    <string name="permlab_accessUsb" msgid="7362327818655760496">"dostęp do urządzeń USB"</string>
-    <string name="permdesc_accessUsb" msgid="2414271762914049292">"Zezwala aplikacji na dostęp do urządzeń USB."</string>
+    <string name="permlab_manageUsb" msgid="1113453430645402723">"zarządzanie ustawieniami i uprawnieniami urządzeń USB"</string>
+    <string name="permdesc_manageUsb" msgid="6148489202092166164">"Umożliwia aplikacji zarządzanie ustawieniami i uprawnieniami urządzeń USB."</string>
     <string name="permlab_accessMtp" msgid="4953468676795917042">"implementowanie protokołu MTP"</string>
     <string name="permdesc_accessMtp" msgid="6532961200486791570">"Zezwala na dostęp do sterownika MTP jądra w celu implementacji protokołu USB MTP."</string>
     <string name="permlab_hardware_test" msgid="4148290860400659146">"testowanie sprzętu"</string>
@@ -464,7 +464,7 @@
     <string name="permlab_sdcardWrite" product="default" msgid="8079403759001777291">"modyfikowanie/usuwanie zawartości karty SD"</string>
     <string name="permdesc_sdcardWrite" product="nosdcard" msgid="6594393334785738252">"Umożliwia zapis na nośnik USB."</string>
     <string name="permdesc_sdcardWrite" product="default" msgid="6643963204976471878">"Umożliwia aplikacji zapis na karcie SD."</string>
-    <string name="permlab_mediaStorageWrite" product="default" msgid="6859839199706879015">"modyf./usuw. zawartości pam. wewn."</string>
+    <string name="permlab_mediaStorageWrite" product="default" msgid="6859839199706879015">"modyfikowanie/usuwanie zawartości pamięci wew."</string>
     <string name="permdesc_mediaStorageWrite" product="default" msgid="8232008512478316233">"Zezwala aplikacji na modyfikowanie zawartości pamięci wewnętrznej."</string>
     <string name="permlab_cache_filesystem" msgid="5656487264819669824">"dostęp do systemu plików pamięci podręcznej"</string>
     <string name="permdesc_cache_filesystem" msgid="1624734528435659906">"Zezwala aplikacji na odczyt i zapis w systemie plików pamięci podręcznej."</string>
@@ -484,8 +484,8 @@
     <string name="policydesc_wipeData" product="default" msgid="7669895333814222586">"Wymazywanie danych z telefonu bez ostrzeżenia, przez przywrócenie danych fabrycznych"</string>
     <string name="policylab_setGlobalProxy" msgid="2784828293747791446">"Ustaw globalny serwer proxy urządzenia"</string>
     <string name="policydesc_setGlobalProxy" msgid="6387497466660154931">"Ustaw globalny serwer proxy urządzenia do wykorzystywania przy włączonych zasadach. Tylko pierwszy administrator urządzenia ustawia obowiązujący globalny serwer proxy."</string>
-    <!-- outdated translation 4740941403188940274 -->     <string name="policylab_expirePassword" msgid="885279151847254056">"Ustaw wygasanie hasła"</string>
-    <!-- outdated translation 6626724939177185949 -->     <string name="policydesc_expirePassword" msgid="4844430354224822074">"Kontrola czasu, po którym należy zmienić hasło blokowania ekranu"</string>
+    <string name="policylab_expirePassword" msgid="885279151847254056">"Ustaw wygasanie hasła blokady"</string>
+    <string name="policydesc_expirePassword" msgid="4844430354224822074">"Kontrola częstości zmian hasła ekranu blokady"</string>
     <string name="policylab_encryptedStorage" msgid="8901326199909132915">"Ustaw szyfrowanie pamięci"</string>
     <string name="policydesc_encryptedStorage" msgid="2504984732631479399">"Wymaga szyfrowania danych zapisanych aplikacji"</string>
   <string-array name="phoneTypes">
@@ -666,7 +666,7 @@
     <string name="save_password_label" msgid="6860261758665825069">"Potwierdź"</string>
     <string name="double_tap_toast" msgid="1068216937244567247">"Wskazówka: dotknij dwukrotnie, aby powiększyć lub pomniejszyć."</string>
     <string name="autofill_this_form" msgid="1272247532604569872">"Autouzupełnianie"</string>
-    <string name="setup_autofill" msgid="8154593408885654044">"Konfiguruj autouzupełnianie"</string>
+    <string name="setup_autofill" msgid="8154593408885654044">"Opcje autouzupełniania"</string>
     <string name="autofill_address_name_separator" msgid="2504700673286691795">" "</string>
     <string name="autofill_address_summary_name_format" msgid="3268041054899214945">"$1$2$3"</string>
     <string name="autofill_address_summary_separator" msgid="7483307893170324129">", "</string>
@@ -814,6 +814,7 @@
     <string name="alwaysUse" msgid="4583018368000610438">"Używaj domyślnie dla tej czynności."</string>
     <string name="clearDefaultHintMsg" msgid="4815455344600932173">"Wyczyść domyślne w: Ustawienia strony głównej &gt; Aplikacje &gt; Zarządzaj aplikacjami."</string>
     <string name="chooseActivity" msgid="1009246475582238425">"Wybierz czynność"</string>
+    <string name="chooseUsbActivity" msgid="7892597146032121735">"Wybierz aplikację dla urządzenia USB"</string>
     <string name="noApplications" msgid="1691104391758345586">"Żadna z aplikacji nie może wykonać tej czynności."</string>
     <string name="aerr_title" msgid="653922989522758100">"Przepraszamy!"</string>
     <string name="aerr_application" msgid="4683614104336409186">"Aplikacja <xliff:g id="APPLICATION">%1$s</xliff:g> (proces <xliff:g id="PROCESS">%2$s</xliff:g>) została niespodziewanie zatrzymana. Spróbuj ponownie."</string>
diff --git a/core/res/res/values-pt-rPT/strings.xml b/core/res/res/values-pt-rPT/strings.xml
index 9c069c4..1e2bd22 100644
--- a/core/res/res/values-pt-rPT/strings.xml
+++ b/core/res/res/values-pt-rPT/strings.xml
@@ -361,8 +361,8 @@
     <string name="permdesc_vibrate" msgid="2886677177257789187">"Permite à aplicação controlar o vibrador."</string>
     <string name="permlab_flashlight" msgid="2155920810121984215">"controlar lanterna"</string>
     <string name="permdesc_flashlight" msgid="6433045942283802309">"Permite à aplicação controlar a lanterna."</string>
-    <string name="permlab_accessUsb" msgid="7362327818655760496">"aceder a dispositivos USB"</string>
-    <string name="permdesc_accessUsb" msgid="2414271762914049292">"Permite à aplicação aceder a dispositivos USB."</string>
+    <string name="permlab_manageUsb" msgid="1113453430645402723">"gerir preferências e permissões para dispositivos USB"</string>
+    <string name="permdesc_manageUsb" msgid="6148489202092166164">"Permite à aplicação gerir as preferências e permissões para dispositivos USB."</string>
     <string name="permlab_accessMtp" msgid="4953468676795917042">"implementar protocolo MTP"</string>
     <string name="permdesc_accessMtp" msgid="6532961200486791570">"Permite o acesso ao controlador MTP de kernel para implementar o protocolo MTP USB."</string>
     <string name="permlab_hardware_test" msgid="4148290860400659146">"testar hardware"</string>
@@ -484,8 +484,8 @@
     <string name="policydesc_wipeData" product="default" msgid="7669895333814222586">"Apagar os dados do telefone sem avisar, ao efectuar uma reposição de dados de fábrica"</string>
     <string name="policylab_setGlobalProxy" msgid="2784828293747791446">"Definir o proxy global do aparelho"</string>
     <string name="policydesc_setGlobalProxy" msgid="6387497466660154931">"Definir o proxy global do aparelho a ser utilizado quando a política estiver activada. Só o primeiro administrador do aparelho define o proxy global efectivo."</string>
-    <!-- outdated translation 4740941403188940274 -->     <string name="policylab_expirePassword" msgid="885279151847254056">"Definir tempo de validade da palavra-passe"</string>
-    <!-- outdated translation 6626724939177185949 -->     <string name="policydesc_expirePassword" msgid="4844430354224822074">"Controle com que antecedência é necessário alterar a palavra-passe de bloqueio do ecrã"</string>
+    <string name="policylab_expirePassword" msgid="885279151847254056">"Def. valid. palavra-passe bloq. ecrã"</string>
+    <string name="policydesc_expirePassword" msgid="4844430354224822074">"Controlar a frequência com que a palavra-passe deve ser alterada"</string>
     <string name="policylab_encryptedStorage" msgid="8901326199909132915">"Def. encriptação armazenamento"</string>
     <string name="policydesc_encryptedStorage" msgid="2504984732631479399">"Requerer encriptação dos dados da aplicação armazenados"</string>
   <string-array name="phoneTypes">
@@ -814,6 +814,7 @@
     <string name="alwaysUse" msgid="4583018368000610438">"Utilizar por predefinição para esta acção."</string>
     <string name="clearDefaultHintMsg" msgid="4815455344600932173">"Limpar predefinição em Definições iniciais &gt; Aplicações &gt; Gerir aplicações."</string>
     <string name="chooseActivity" msgid="1009246475582238425">"Seleccionar uma acção"</string>
+    <string name="chooseUsbActivity" msgid="7892597146032121735">"Selecione uma aplicação para o dispositivo USB"</string>
     <string name="noApplications" msgid="1691104391758345586">"Nenhuma aplicação pode efectuar esta acção."</string>
     <string name="aerr_title" msgid="653922989522758100">"Lamentamos."</string>
     <string name="aerr_application" msgid="4683614104336409186">"A aplicação <xliff:g id="APPLICATION">%1$s</xliff:g> (processo <xliff:g id="PROCESS">%2$s</xliff:g>) parou de forma inesperada. Tente novamente."</string>
diff --git a/core/res/res/values-pt/strings.xml b/core/res/res/values-pt/strings.xml
index e8b230f..fd3775a 100644
--- a/core/res/res/values-pt/strings.xml
+++ b/core/res/res/values-pt/strings.xml
@@ -361,8 +361,8 @@
     <string name="permdesc_vibrate" msgid="2886677177257789187">"Permite que o aplicativo controle o vibrador."</string>
     <string name="permlab_flashlight" msgid="2155920810121984215">"controlar lanterna"</string>
     <string name="permdesc_flashlight" msgid="6433045942283802309">"Permite que o aplicativo controle a lanterna."</string>
-    <string name="permlab_accessUsb" msgid="7362327818655760496">"acessar dispositivos USB"</string>
-    <string name="permdesc_accessUsb" msgid="2414271762914049292">"Permitir que o aplicativo acesse dispositivos USB."</string>
+    <string name="permlab_manageUsb" msgid="1113453430645402723">"gerenciar preferências e permissões de aplicativos USB"</string>
+    <string name="permdesc_manageUsb" msgid="6148489202092166164">"Permite que o aplicativo gerencie as preferências e as permissões de aplicativos USB."</string>
     <string name="permlab_accessMtp" msgid="4953468676795917042">"implementar protocolo MTP"</string>
     <string name="permdesc_accessMtp" msgid="6532961200486791570">"Permite acesso ao driver MTP do núcleo para implementar o protocolo USB MTP."</string>
     <string name="permlab_hardware_test" msgid="4148290860400659146">"testar hardware"</string>
@@ -484,8 +484,8 @@
     <string name="policydesc_wipeData" product="default" msgid="7669895333814222586">"Apaga os dados do telefone sem aviso, executando uma redefinição da configuração original"</string>
     <string name="policylab_setGlobalProxy" msgid="2784828293747791446">"Definir o proxy global do dispositivo"</string>
     <string name="policydesc_setGlobalProxy" msgid="6387497466660154931">"Configura o proxy global do dispositivo para ser usado enquanto a política estiver ativada. Somente o primeiro administrador do dispositivo pode configurar um verdadeiro proxy global."</string>
-    <!-- outdated translation 4740941403188940274 -->     <string name="policylab_expirePassword" msgid="885279151847254056">"Definir validade da senha"</string>
-    <!-- outdated translation 6626724939177185949 -->     <string name="policydesc_expirePassword" msgid="4844430354224822074">"Controle quanto tempo uma senha de bloqueio de tela deve ficar ativa antes de ser alterada"</string>
+    <string name="policylab_expirePassword" msgid="885279151847254056">"Definir val. da senha de bloqueio"</string>
+    <string name="policydesc_expirePassword" msgid="4844430354224822074">"Controlar a frequência com que a senha da tela de bloqueio deve ser alterada"</string>
     <string name="policylab_encryptedStorage" msgid="8901326199909132915">"Definir criptografia de armazenamento"</string>
     <string name="policydesc_encryptedStorage" msgid="2504984732631479399">"Exigir que os dados do aplicativo armazenado sejam criptografados"</string>
   <string-array name="phoneTypes">
@@ -814,6 +814,7 @@
     <string name="alwaysUse" msgid="4583018368000610438">"Usar como padrão para esta ação."</string>
     <string name="clearDefaultHintMsg" msgid="4815455344600932173">"Limpar o padrão em Configurações da página inicial &gt; Aplicativos &gt; Gerenciar aplicativos."</string>
     <string name="chooseActivity" msgid="1009246475582238425">"Selecionar uma ação"</string>
+    <string name="chooseUsbActivity" msgid="7892597146032121735">"Selecione um aplicativo para o dispositivo USB"</string>
     <string name="noApplications" msgid="1691104391758345586">"Nenhum aplicativo pode realizar esta ação."</string>
     <string name="aerr_title" msgid="653922989522758100">"Desculpe!"</string>
     <string name="aerr_application" msgid="4683614104336409186">"O aplicativo <xliff:g id="APPLICATION">%1$s</xliff:g> (processo <xliff:g id="PROCESS">%2$s</xliff:g>) parou inesperadamente. Tente novamente."</string>
diff --git a/core/res/res/values-rm/strings.xml b/core/res/res/values-rm/strings.xml
index f3073bd..bc1e133 100644
--- a/core/res/res/values-rm/strings.xml
+++ b/core/res/res/values-rm/strings.xml
@@ -367,8 +367,10 @@
     <string name="permdesc_vibrate" msgid="2886677177257789187">"Permetta a l\'applicaziun da controllar la vibraziun."</string>
     <string name="permlab_flashlight" msgid="2155920810121984215">"controllar la glischina"</string>
     <string name="permdesc_flashlight" msgid="6433045942283802309">"Permetta a l\'applicaziun da controllar la glischina."</string>
-    <string name="permlab_accessUsb" msgid="7362327818655760496">"acceder ad apparats USB"</string>
-    <string name="permdesc_accessUsb" msgid="2414271762914049292">"Permetta a l\'applicaziun dad acceder als apparats periferics USB."</string>
+    <!-- no translation found for permlab_manageUsb (1113453430645402723) -->
+    <skip />
+    <!-- no translation found for permdesc_manageUsb (6148489202092166164) -->
+    <skip />
     <!-- no translation found for permlab_accessMtp (4953468676795917042) -->
     <skip />
     <!-- no translation found for permdesc_accessMtp (6532961200486791570) -->
@@ -865,6 +867,8 @@
     <string name="alwaysUse" msgid="4583018368000610438">"Utilisar questa applicaziun sco standard per questa acziun."</string>
     <string name="clearDefaultHintMsg" msgid="4815455344600932173">"Stizzar ils parameters da standard en Parameters da la pagina da partenza &gt; Applicaziuns &gt; Administrar las applicaziuns."</string>
     <string name="chooseActivity" msgid="1009246475582238425">"Tscherner ina acziun"</string>
+    <!-- no translation found for chooseUsbActivity (7892597146032121735) -->
+    <skip />
     <string name="noApplications" msgid="1691104391758345586">"Nagina applicaziun po exequir questa acziun."</string>
     <string name="aerr_title" msgid="653922989522758100">"Perstgisai!"</string>
     <string name="aerr_application" msgid="4683614104336409186">"L\'applicaziun <xliff:g id="APPLICATION">%1$s</xliff:g> (process <xliff:g id="PROCESS">%2$s</xliff:g>) è vegnida serrada nunspetgadamain. Empruvai anc ina giada."</string>
diff --git a/core/res/res/values-ro/strings.xml b/core/res/res/values-ro/strings.xml
index 217c965..b388128 100644
--- a/core/res/res/values-ro/strings.xml
+++ b/core/res/res/values-ro/strings.xml
@@ -361,8 +361,8 @@
     <string name="permdesc_vibrate" msgid="2886677177257789187">"Permite aplicaţiei să controleze mecanismul de vibrare."</string>
     <string name="permlab_flashlight" msgid="2155920810121984215">"control lanternă"</string>
     <string name="permdesc_flashlight" msgid="6433045942283802309">"Permite aplicaţiei să controleze lanterna."</string>
-    <string name="permlab_accessUsb" msgid="7362327818655760496">"accesare dispozitive USB"</string>
-    <string name="permdesc_accessUsb" msgid="2414271762914049292">"Permite aplicaţiei să acceseze dispozitive USB."</string>
+    <string name="permlab_manageUsb" msgid="1113453430645402723">"gestionaţi preferinţele şi permisiunile pentru dispozitivele USB"</string>
+    <string name="permdesc_manageUsb" msgid="6148489202092166164">"Permite aplicaţiei să gestioneze preferinţele şi permisiunile pentru dispozitivele USB."</string>
     <string name="permlab_accessMtp" msgid="4953468676795917042">"implementare protocol MTP"</string>
     <string name="permdesc_accessMtp" msgid="6532961200486791570">"Permite accesul la driverul MTP al nucleului pentru a implementa protocolul USB pentru MTP."</string>
     <string name="permlab_hardware_test" msgid="4148290860400659146">"testare hardware"</string>
@@ -484,8 +484,8 @@
     <string name="policydesc_wipeData" product="default" msgid="7669895333814222586">"Ştergeţi datele din telefon fără avertisment, efectuând resetarea configurării din fabrică"</string>
     <string name="policylab_setGlobalProxy" msgid="2784828293747791446">"Setaţi serverul proxy global pentru dispozitiv"</string>
     <string name="policydesc_setGlobalProxy" msgid="6387497466660154931">"Setaţi serverul proxy global pentru dispozitiv care să fie utilizat cât timp politica este activă. Numai primul administrator al dispozitivului poate seta serverul proxy global activ."</string>
-    <!-- outdated translation 4740941403188940274 -->     <string name="policylab_expirePassword" msgid="885279151847254056">"Setaţi expirarea parolei"</string>
-    <!-- outdated translation 6626724939177185949 -->     <string name="policydesc_expirePassword" msgid="4844430354224822074">"Controlarea duratei până când parola de blocare a ecranului trebuie modificată"</string>
+    <string name="policylab_expirePassword" msgid="885279151847254056">"Expirare parolă blocare ecran"</string>
+    <string name="policydesc_expirePassword" msgid="4844430354224822074">"Stabiliţi frecvenţa de schimbare a parolei de blocare a ecranului"</string>
     <string name="policylab_encryptedStorage" msgid="8901326199909132915">"Setaţi criptarea stocării"</string>
     <string name="policydesc_encryptedStorage" msgid="2504984732631479399">"Necesită ca datele aplicaţiei stocate să fie criptate"</string>
   <string-array name="phoneTypes">
@@ -814,6 +814,7 @@
     <string name="alwaysUse" msgid="4583018368000610438">"Se utilizează în mod prestabilit pentru această acţiune."</string>
     <string name="clearDefaultHintMsg" msgid="4815455344600932173">"Ştergeţi setările prestabilite din Setări pagină de pornire &gt; Aplicaţii &gt; Gestionare aplicaţii."</string>
     <string name="chooseActivity" msgid="1009246475582238425">"Selectaţi o acţiune"</string>
+    <string name="chooseUsbActivity" msgid="7892597146032121735">"Selectaţi o aplicaţie pentru dispozitivul USB"</string>
     <string name="noApplications" msgid="1691104391758345586">"Această acţiune nu poate fi efectuată de nicio aplicaţie."</string>
     <string name="aerr_title" msgid="653922989522758100">"Ne pare rău!"</string>
     <string name="aerr_application" msgid="4683614104336409186">"Aplicaţia <xliff:g id="APPLICATION">%1$s</xliff:g> (procesul <xliff:g id="PROCESS">%2$s</xliff:g>) s-a oprit în mod neaşteptat. Încercaţi din nou."</string>
diff --git a/core/res/res/values-ru/strings.xml b/core/res/res/values-ru/strings.xml
index 405fbc0..10a2898 100644
--- a/core/res/res/values-ru/strings.xml
+++ b/core/res/res/values-ru/strings.xml
@@ -361,8 +361,8 @@
     <string name="permdesc_vibrate" msgid="2886677177257789187">"Позволяет приложению управлять виброзвонком."</string>
     <string name="permlab_flashlight" msgid="2155920810121984215">"управлять вспышкой"</string>
     <string name="permdesc_flashlight" msgid="6433045942283802309">"Позволяет приложению управлять вспышкой."</string>
-    <string name="permlab_accessUsb" msgid="7362327818655760496">"доступ к USB-устройствам"</string>
-    <string name="permdesc_accessUsb" msgid="2414271762914049292">"Позволяет приложению получать доступ к USB-устройствам."</string>
+    <string name="permlab_manageUsb" msgid="1113453430645402723">"управлять настройками и разрешениями для USB-устройств"</string>
+    <string name="permdesc_manageUsb" msgid="6148489202092166164">"Приложение может управлять настройками и разрешениями для USB-устройств."</string>
     <string name="permlab_accessMtp" msgid="4953468676795917042">"Реализовать протокол MTP"</string>
     <string name="permdesc_accessMtp" msgid="6532961200486791570">"Разрешает доступ к драйверу основного устройства MTP для реализации протокола MTP USB"</string>
     <string name="permlab_hardware_test" msgid="4148290860400659146">"проверять аппаратное обеспечение"</string>
@@ -464,8 +464,8 @@
     <string name="permlab_sdcardWrite" product="default" msgid="8079403759001777291">"изменять/удалять содержимое SD-карты"</string>
     <string name="permdesc_sdcardWrite" product="nosdcard" msgid="6594393334785738252">"Разрешает приложению запись на USB-накопитель."</string>
     <string name="permdesc_sdcardWrite" product="default" msgid="6643963204976471878">"Разрешает приложению запись на SD-карту"</string>
-    <string name="permlab_mediaStorageWrite" product="default" msgid="6859839199706879015">"изм./удал. содерж. мультимедиа"</string>
-    <string name="permdesc_mediaStorageWrite" product="default" msgid="8232008512478316233">"Позволяет приложению изменять содержание внутреннего хранилища мультимедиа."</string>
+    <string name="permlab_mediaStorageWrite" product="default" msgid="6859839199706879015">"изменение/удаление данных из внутреннего хранилища мультимедиа"</string>
+    <string name="permdesc_mediaStorageWrite" product="default" msgid="8232008512478316233">"Приложение сможет изменять содержание внутреннего хранилища мультимедиа."</string>
     <string name="permlab_cache_filesystem" msgid="5656487264819669824">"получать доступ к кэшу файловой системы"</string>
     <string name="permdesc_cache_filesystem" msgid="1624734528435659906">"Разрешает программам доступ для записи и чтения к кэшу файловой системы."</string>
     <string name="permlab_use_sip" msgid="5986952362795870502">"совершать и принимать интернет-вызовы"</string>
@@ -484,8 +484,8 @@
     <string name="policydesc_wipeData" product="default" msgid="7669895333814222586">"Уничтожить все данные на телефоне без предупреждения путем сброса настроек"</string>
     <string name="policylab_setGlobalProxy" msgid="2784828293747791446">"Глобальный прокси-сервер"</string>
     <string name="policydesc_setGlobalProxy" msgid="6387497466660154931">"Настройте глобальный прокси-сервер устройства, который будет использоваться при активной политике. Глобальный прокси-сервер должен настроить первый администратор устройства."</string>
-    <!-- outdated translation 4740941403188940274 -->     <string name="policylab_expirePassword" msgid="885279151847254056">"Задать время действия пароля"</string>
-    <!-- outdated translation 6626724939177185949 -->     <string name="policydesc_expirePassword" msgid="4844430354224822074">"Задать время действия пароля перед появлением экрана блокировки"</string>
+    <string name="policylab_expirePassword" msgid="885279151847254056">"Задать срок действия пароля"</string>
+    <string name="policydesc_expirePassword" msgid="4844430354224822074">"Укажите, как часто следует менять пароль блокировки экрана"</string>
     <string name="policylab_encryptedStorage" msgid="8901326199909132915">"Настроить шифрование хранилища"</string>
     <string name="policydesc_encryptedStorage" msgid="2504984732631479399">"Требует шифровать данные приложений, находящиеся в хранилище."</string>
   <string-array name="phoneTypes">
@@ -619,7 +619,7 @@
     <string name="lockscreen_pattern_wrong" msgid="4817583279053112312">"Повторите попытку"</string>
     <string name="lockscreen_password_wrong" msgid="6237443657358168819">"Повторите попытку"</string>
     <string name="lockscreen_plugged_in" msgid="613343852842944435">"Идет зарядка (<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>)"</string>
-    <string name="lockscreen_charged" msgid="4938930459620989972">"Заряжена."</string>
+    <string name="lockscreen_charged" msgid="4938930459620989972">"Батарея заряжена"</string>
     <string name="lockscreen_battery_short" msgid="3617549178603354656">"<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
     <string name="lockscreen_low_battery" msgid="1482873981919249740">"Подключите зарядное устройство."</string>
     <string name="lockscreen_missing_sim_message_short" msgid="7381499217732227295">"Нет SIM-карты."</string>
@@ -814,6 +814,7 @@
     <string name="alwaysUse" msgid="4583018368000610438">"По умолчанию для этого действия"</string>
     <string name="clearDefaultHintMsg" msgid="4815455344600932173">"Удалить настройки по умолчанию: главный экран &gt; \"Настройки\" &gt; \"Приложения\" &gt; \"Управление приложениями\"."</string>
     <string name="chooseActivity" msgid="1009246475582238425">"Выберите действие"</string>
+    <string name="chooseUsbActivity" msgid="7892597146032121735">"Выбор приложения для USB-устройства"</string>
     <string name="noApplications" msgid="1691104391758345586">"Это действие не может выполнять ни одно приложение."</string>
     <string name="aerr_title" msgid="653922989522758100">"Ошибка приложения!"</string>
     <string name="aerr_application" msgid="4683614104336409186">"Произошла неожиданная остановка приложения <xliff:g id="APPLICATION">%1$s</xliff:g> (процесс <xliff:g id="PROCESS">%2$s</xliff:g>). Повторите попытку."</string>
diff --git a/core/res/res/values-sk/strings.xml b/core/res/res/values-sk/strings.xml
index 9605af2..8a37fd1 100644
--- a/core/res/res/values-sk/strings.xml
+++ b/core/res/res/values-sk/strings.xml
@@ -361,8 +361,8 @@
     <string name="permdesc_vibrate" msgid="2886677177257789187">"Umožňuje aplikácii ovládať vibrácie."</string>
     <string name="permlab_flashlight" msgid="2155920810121984215">"ovládanie kontrolky"</string>
     <string name="permdesc_flashlight" msgid="6433045942283802309">"Umožňuje aplikácii ovládať kontrolku."</string>
-    <string name="permlab_accessUsb" msgid="7362327818655760496">"prístup k zariadeniam USB"</string>
-    <string name="permdesc_accessUsb" msgid="2414271762914049292">"Umožní aplikácii prístup k zariadeniam USB."</string>
+    <string name="permlab_manageUsb" msgid="1113453430645402723">"spravovať predvoľby a povolenia zariadení USB"</string>
+    <string name="permdesc_manageUsb" msgid="6148489202092166164">"Povolí aplikácii spravovať predvoľby a povolenia zariadení USB."</string>
     <string name="permlab_accessMtp" msgid="4953468676795917042">"implementovať protokol MTP"</string>
     <string name="permdesc_accessMtp" msgid="6532961200486791570">"Povoľuje prístup k ovládaču kernel MTP na implementáciu protokolu MTP USB."</string>
     <string name="permlab_hardware_test" msgid="4148290860400659146">"testovanie hardvéru"</string>
@@ -484,8 +484,8 @@
     <string name="policydesc_wipeData" product="default" msgid="7669895333814222586">"Bez predchádzajúceho upozornenia zmazať všetky údaje tým, že sa obnovia továrenské nastavenia telefónu"</string>
     <string name="policylab_setGlobalProxy" msgid="2784828293747791446">"Nastaviť globálny server proxy zariadenia"</string>
     <string name="policydesc_setGlobalProxy" msgid="6387497466660154931">"Vyberte globálny server proxy, ktorý sa bude používať po aktivácii pravidiel. Platný globálny server proxy nastavuje iba prvý správca zariadenia."</string>
-    <!-- outdated translation 4740941403188940274 -->     <string name="policylab_expirePassword" msgid="885279151847254056">"Nastaviť dátum vypršania platnosti hesla"</string>
-    <!-- outdated translation 6626724939177185949 -->     <string name="policydesc_expirePassword" msgid="4844430354224822074">"Ovládanie doby, po uplynutí ktorej treba zmeniť heslo na odomknutie obrazovky"</string>
+    <string name="policylab_expirePassword" msgid="885279151847254056">"Nastav. koniec platnosti hesla"</string>
+    <string name="policydesc_expirePassword" msgid="4844430354224822074">"Nastavte, ako často sa musí zmeniť heslo na uzamknutie obrazovky"</string>
     <string name="policylab_encryptedStorage" msgid="8901326199909132915">"Nastaviť šifr. ukl. priestoru"</string>
     <string name="policydesc_encryptedStorage" msgid="2504984732631479399">"Vyžaduje šifrovanie uložených údajov aplikácií"</string>
   <string-array name="phoneTypes">
@@ -814,6 +814,7 @@
     <string name="alwaysUse" msgid="4583018368000610438">"Použiť ako predvolené nastavenie pre túto akciu."</string>
     <string name="clearDefaultHintMsg" msgid="4815455344600932173">"Vymazanie predvolených hodnôt v časti Nastavenia plochy &gt; Aplikácie &gt; Správa aplikácií."</string>
     <string name="chooseActivity" msgid="1009246475582238425">"Vyberte akciu"</string>
+    <string name="chooseUsbActivity" msgid="7892597146032121735">"Vyberte aplikáciu pre zariadenia USB"</string>
     <string name="noApplications" msgid="1691104391758345586">"Túto akciu nemôžu vykonávať žiadne aplikácie."</string>
     <string name="aerr_title" msgid="653922989522758100">"Je nám ľúto!"</string>
     <string name="aerr_application" msgid="4683614104336409186">"Aplikácia <xliff:g id="APPLICATION">%1$s</xliff:g> (proces <xliff:g id="PROCESS">%2$s</xliff:g>) bola neočakávane zastavená. Skúste to znova."</string>
diff --git a/core/res/res/values-sl/strings.xml b/core/res/res/values-sl/strings.xml
index a460627..6ee4ac0 100644
--- a/core/res/res/values-sl/strings.xml
+++ b/core/res/res/values-sl/strings.xml
@@ -361,8 +361,8 @@
     <string name="permdesc_vibrate" msgid="2886677177257789187">"Programu dovoljuje nadzor vibriranja."</string>
     <string name="permlab_flashlight" msgid="2155920810121984215">"nadzor svetilke"</string>
     <string name="permdesc_flashlight" msgid="6433045942283802309">"Programu dovoljuje nadzor svetilke."</string>
-    <string name="permlab_accessUsb" msgid="7362327818655760496">"dostop do naprav USB"</string>
-    <string name="permdesc_accessUsb" msgid="2414271762914049292">"Programu omogoča dostop do naprav USB."</string>
+    <string name="permlab_manageUsb" msgid="1113453430645402723">"upravljanje nastavitev in dovoljenj za naprave USB"</string>
+    <string name="permdesc_manageUsb" msgid="6148489202092166164">"Omogoči programu upravljanje nastavitev in dovoljenj za naprave USB."</string>
     <string name="permlab_accessMtp" msgid="4953468676795917042">"uveljavitev protokola MTP"</string>
     <string name="permdesc_accessMtp" msgid="6532961200486791570">"Omogoča dostop do gonilnika jedra MTP za uveljavitev protokola MTP USB."</string>
     <string name="permlab_hardware_test" msgid="4148290860400659146">"preskušanje strojne opreme"</string>
@@ -484,8 +484,8 @@
     <string name="policydesc_wipeData" product="default" msgid="7669895333814222586">"Brisanje (s tovarniško ponastavitvijo) vseh podatkov v telefonu brez opozorila"</string>
     <string name="policylab_setGlobalProxy" msgid="2784828293747791446">"Nastavitev globalnega strežnika proxy za napravo"</string>
     <string name="policydesc_setGlobalProxy" msgid="6387497466660154931">"Nastavite globalni strežnik proxy naprave, ki bo v uporabi, ko je pravilnik omogočen. Samo skrbnik prve naprave lahko nastavi veljaven globalni strežnik proxy."</string>
-    <!-- outdated translation 4740941403188940274 -->     <string name="policylab_expirePassword" msgid="885279151847254056">"Nastavitev poteka gesla"</string>
-    <!-- outdated translation 6626724939177185949 -->     <string name="policydesc_expirePassword" msgid="4844430354224822074">"Nastavite, koliko časa prej je treba spremeniti geslo za odklepanje zaslona"</string>
+    <string name="policylab_expirePassword" msgid="885279151847254056">"Nastavitev poteka gesla za zaklepanje zaslona"</string>
+    <string name="policydesc_expirePassword" msgid="4844430354224822074">"Določite, kako pogosto je treba spremeniti geslo za zaklepanje zaslona"</string>
     <string name="policylab_encryptedStorage" msgid="8901326199909132915">"Nastavitev šifriranja shrambe"</string>
     <string name="policydesc_encryptedStorage" msgid="2504984732631479399">"Shranjeni podatki programa morajo biti šifrirani"</string>
   <string-array name="phoneTypes">
@@ -814,6 +814,7 @@
     <string name="alwaysUse" msgid="4583018368000610438">"Privzeta uporaba za to dejanje."</string>
     <string name="clearDefaultHintMsg" msgid="4815455344600932173">"Počistite privzete nastavitve v razdelku Osnovne nastavitve &gt; Programi &gt; Upravljanje programov."</string>
     <string name="chooseActivity" msgid="1009246475582238425">"Izberite dejanje"</string>
+    <string name="chooseUsbActivity" msgid="7892597146032121735">"Izberite program za napravo USB"</string>
     <string name="noApplications" msgid="1691104391758345586">"Tega dejanja ne more izvesti noben program."</string>
     <string name="aerr_title" msgid="653922989522758100">"Oprostite."</string>
     <string name="aerr_application" msgid="4683614104336409186">"Program <xliff:g id="APPLICATION">%1$s</xliff:g> (postopek <xliff:g id="PROCESS">%2$s</xliff:g>) se je nepričakovano ustavil. Poskusite znova."</string>
diff --git a/core/res/res/values-sr/strings.xml b/core/res/res/values-sr/strings.xml
index a6f1e5f..6faf9da 100644
--- a/core/res/res/values-sr/strings.xml
+++ b/core/res/res/values-sr/strings.xml
@@ -361,8 +361,8 @@
     <string name="permdesc_vibrate" msgid="2886677177257789187">"Омогућава да апликација контролише вибрације."</string>
     <string name="permlab_flashlight" msgid="2155920810121984215">"контрола осветљења"</string>
     <string name="permdesc_flashlight" msgid="6433045942283802309">"Омогућава да апликација контролише осветљење."</string>
-    <string name="permlab_accessUsb" msgid="7362327818655760496">"приступ USB уређајима"</string>
-    <string name="permdesc_accessUsb" msgid="2414271762914049292">"Омогућава апликацији приступ USB уређајима."</string>
+    <string name="permlab_manageUsb" msgid="1113453430645402723">"управљање подешавањима и дозволама за USB уређаје"</string>
+    <string name="permdesc_manageUsb" msgid="6148489202092166164">"Омогућава да апликација управља подешавањима и дозволама за USB уређаје."</string>
     <string name="permlab_accessMtp" msgid="4953468676795917042">"примени MTP протокол"</string>
     <string name="permdesc_accessMtp" msgid="6532961200486791570">"Омогућава приступ основном MTP управљачком програму ради примене MTP USB протокола."</string>
     <string name="permlab_hardware_test" msgid="4148290860400659146">"тестирање хардвера"</string>
@@ -484,8 +484,8 @@
     <string name="policydesc_wipeData" product="default" msgid="7669895333814222586">"Брисање података на телефону без упозорења враћањем фабричких података"</string>
     <string name="policylab_setGlobalProxy" msgid="2784828293747791446">"Подесите глобални прокси сервер уређаја"</string>
     <string name="policydesc_setGlobalProxy" msgid="6387497466660154931">"Подесите глобални прокси сервер уређаја који ће се користити док су омогућене смернице. Само први администратор уређаја поставља ефективни глобални прокси сервер."</string>
-    <!-- outdated translation 4740941403188940274 -->     <string name="policylab_expirePassword" msgid="885279151847254056">"Подеси време истека лозинке"</string>
-    <!-- outdated translation 6626724939177185949 -->     <string name="policydesc_expirePassword" msgid="4844430354224822074">"Контролишите време када лозинка за закључавање екрана треба да се промени"</string>
+    <string name="policylab_expirePassword" msgid="885279151847254056">"Подешавање истека лозинке екрана"</string>
+    <string name="policydesc_expirePassword" msgid="4844430354224822074">"Контролишите колико често лозинка за закључавање екрана мора да се мења"</string>
     <string name="policylab_encryptedStorage" msgid="8901326199909132915">"Подешавање шифровања складишта"</string>
     <string name="policydesc_encryptedStorage" msgid="2504984732631479399">"Захтева да сачувани подаци апликације буду шифровани"</string>
   <string-array name="phoneTypes">
@@ -814,6 +814,7 @@
     <string name="alwaysUse" msgid="4583018368000610438">"Подразумевано користи за ову радњу."</string>
     <string name="clearDefaultHintMsg" msgid="4815455344600932173">"Обришите подразумевана подешавања у оквиру ставки Подешавања почетне странице &gt; Апликације &gt; Управљање апликацијама."</string>
     <string name="chooseActivity" msgid="1009246475582238425">"Избор радње"</string>
+    <string name="chooseUsbActivity" msgid="7892597146032121735">"Избор апликације за USB уређај"</string>
     <string name="noApplications" msgid="1691104391758345586">"Ниједна апликација не може да изврши ову радњу."</string>
     <string name="aerr_title" msgid="653922989522758100">"Жао нам је!"</string>
     <string name="aerr_application" msgid="4683614104336409186">"Апликација <xliff:g id="APPLICATION">%1$s</xliff:g> (процес <xliff:g id="PROCESS">%2$s</xliff:g>) је неочекивано заустављена. Покушајте поново."</string>
diff --git a/core/res/res/values-sv/strings.xml b/core/res/res/values-sv/strings.xml
index 1c234c2..fcc1fdd 100644
--- a/core/res/res/values-sv/strings.xml
+++ b/core/res/res/values-sv/strings.xml
@@ -361,8 +361,8 @@
     <string name="permdesc_vibrate" msgid="2886677177257789187">"Tillåter att programmet styr vibratorn."</string>
     <string name="permlab_flashlight" msgid="2155920810121984215">"styra lampa"</string>
     <string name="permdesc_flashlight" msgid="6433045942283802309">"Tillåter att programmet styr lampan."</string>
-    <string name="permlab_accessUsb" msgid="7362327818655760496">"åtkomst till USB-enheter"</string>
-    <string name="permdesc_accessUsb" msgid="2414271762914049292">"Tillåter att programmet använder USB-enheter."</string>
+    <string name="permlab_manageUsb" msgid="1113453430645402723">"hantera inställningar och behörighet för USB-enheter"</string>
+    <string name="permdesc_manageUsb" msgid="6148489202092166164">"Tillåter att programmet hanterar inställningar och behörigheter för USB-enheter."</string>
     <string name="permlab_accessMtp" msgid="4953468676795917042">"implementera MTP-protokoll"</string>
     <string name="permdesc_accessMtp" msgid="6532961200486791570">"Ger åtkomst till MTP-kerneldrivrutinen för att implementera MTP/USB-protokollet."</string>
     <string name="permlab_hardware_test" msgid="4148290860400659146">"testa maskinvara"</string>
@@ -484,8 +484,8 @@
     <string name="policydesc_wipeData" product="default" msgid="7669895333814222586">"Ta bort data från telefonen utan förvarning genom att återställa standardinställningarna"</string>
     <string name="policylab_setGlobalProxy" msgid="2784828293747791446">"Ange global proxyserver"</string>
     <string name="policydesc_setGlobalProxy" msgid="6387497466660154931">"Ange vilken global proxyserver som ska användas när policyn är aktiverad. Endast den första enhetsadministratören anger den faktiska globala proxyservern."</string>
-    <!-- outdated translation 4740941403188940274 -->     <string name="policylab_expirePassword" msgid="885279151847254056">"Ange lösenordets utgångsdatum"</string>
-    <!-- outdated translation 6626724939177185949 -->     <string name="policydesc_expirePassword" msgid="4844430354224822074">"Se hur långt det är kvar till du måste ändra lösenordet till låsningsskärmen"</string>
+    <string name="policylab_expirePassword" msgid="885279151847254056">"Ange lösenordets utgångsdatum"</string>
+    <string name="policydesc_expirePassword" msgid="4844430354224822074">"Styr hur ofta lösenordet till skärmlåset måste ändras"</string>
     <string name="policylab_encryptedStorage" msgid="8901326199909132915">"Ange krypterad lagring"</string>
     <string name="policydesc_encryptedStorage" msgid="2504984732631479399">"Kräv att sparade applikationsdata krypteras."</string>
   <string-array name="phoneTypes">
@@ -814,6 +814,7 @@
     <string name="alwaysUse" msgid="4583018368000610438">"Använd som standard för denna åtgärd."</string>
     <string name="clearDefaultHintMsg" msgid="4815455344600932173">"Rensa standardinställning i Startinställningar &gt; Appar &gt; Hantera appar."</string>
     <string name="chooseActivity" msgid="1009246475582238425">"Välj en åtgärd"</string>
+    <string name="chooseUsbActivity" msgid="7892597146032121735">"Välj ett program för USB-enheten"</string>
     <string name="noApplications" msgid="1691104391758345586">"Inga appar kan utföra den här åtgärden."</string>
     <string name="aerr_title" msgid="653922989522758100">"Tyvärr!"</string>
     <string name="aerr_application" msgid="4683614104336409186">"Processen <xliff:g id="PROCESS">%2$s</xliff:g> för programmet <xliff:g id="APPLICATION">%1$s</xliff:g> stoppades oväntat. Försök igen."</string>
diff --git a/core/res/res/values-th/strings.xml b/core/res/res/values-th/strings.xml
index 90747d7..fae3853 100644
--- a/core/res/res/values-th/strings.xml
+++ b/core/res/res/values-th/strings.xml
@@ -361,8 +361,8 @@
     <string name="permdesc_vibrate" msgid="2886677177257789187">"อนุญาตให้แอปพลิเคชันควบคุมการสั่นเตือน"</string>
     <string name="permlab_flashlight" msgid="2155920810121984215">"ควบคุมไฟฉาย"</string>
     <string name="permdesc_flashlight" msgid="6433045942283802309">"อนุญาตให้แอปพลิเคชันควบคุมไฟฉาย"</string>
-    <string name="permlab_accessUsb" msgid="7362327818655760496">"เข้าถึงอุปกรณ์ USB"</string>
-    <string name="permdesc_accessUsb" msgid="2414271762914049292">"อนุญาตให้แอปพลิเคชันเข้าถึงอุปกรณ์ USB"</string>
+    <string name="permlab_manageUsb" msgid="1113453430645402723">"จัดการค่ากำหนดและการอนุญาตสำหรับอุปกรณ์ USB"</string>
+    <string name="permdesc_manageUsb" msgid="6148489202092166164">"อนุญาตให้แอปพลิเคชันจัดการค่ากำหนดและการอนุญาตสำหรับอุปกรณ์ USB"</string>
     <string name="permlab_accessMtp" msgid="4953468676795917042">"ใช้โปรโตคอล MTP"</string>
     <string name="permdesc_accessMtp" msgid="6532961200486791570">"อนุญาตการเข้าถึงไดรเวอร์ Kernel MTP เพื่อใช้โปรโตคอล MTP USB"</string>
     <string name="permlab_hardware_test" msgid="4148290860400659146">"ทดสอบฮาร์ดแวร์"</string>
@@ -484,8 +484,8 @@
     <string name="policydesc_wipeData" product="default" msgid="7669895333814222586">"ลบข้อมูลของโทรศัพท์โดยไม่มีการเตือน ด้วยการดำเนินการรีเซ็ตข้อมูลเป็นค่าเริ่มต้น"</string>
     <string name="policylab_setGlobalProxy" msgid="2784828293747791446">"ตั้งค่าพร็อกซีส่วนกลางของอุปกรณ์"</string>
     <string name="policydesc_setGlobalProxy" msgid="6387497466660154931">"ตั้งค่าพร็อกซีส่วนกลางของอุปกรณ์ที่จะใช้ขณะเปิดการใช้งานนโยบาย เฉพาะผู้ดูแลอุปกรณ์คนแรกเท่านั้นที่ตั้งค่าพร็อกซีส่วนกลางที่มีผลบังคับ"</string>
-    <!-- outdated translation 4740941403188940274 -->     <string name="policylab_expirePassword" msgid="885279151847254056">"ตั้งค่าการหมดอายุของรหัสผ่าน"</string>
-    <!-- outdated translation 6626724939177185949 -->     <string name="policydesc_expirePassword" msgid="4844430354224822074">"ควบคุมระยะเวลาก่อนที่จะต้องเปลี่ยนรหัสผ่านการล็อกหน้าจอ"</string>
+    <string name="policylab_expirePassword" msgid="885279151847254056">"ตั้งค่าวันหมดอายุของรหัสผ่านล็อกหน้าจอ"</string>
+    <string name="policydesc_expirePassword" msgid="4844430354224822074">"ควบคุมความถี่ในการเปลี่ยนรหัสผ่านล็อกหน้าจอ"</string>
     <string name="policylab_encryptedStorage" msgid="8901326199909132915">"ตั้งค่าการเข้ารหัสที่เก็บข้อมูล"</string>
     <string name="policydesc_encryptedStorage" msgid="2504984732631479399">"กำหนดว่าแอปพลิเคชันที่จัดเก็บต้องมีการเข้ารหัส"</string>
   <string-array name="phoneTypes">
@@ -814,6 +814,7 @@
     <string name="alwaysUse" msgid="4583018368000610438">"ใช้ค่าเริ่มต้นสำหรับการทำงานนี้"</string>
     <string name="clearDefaultHintMsg" msgid="4815455344600932173">"ล้างข้อมูลค่าเริ่มต้นในการตั้งค่าหน้าแรก &gt; แอปพลิเคชัน &gt; จัดการแอปพลิเคชัน"</string>
     <string name="chooseActivity" msgid="1009246475582238425">"เลือกการทำงาน"</string>
+    <string name="chooseUsbActivity" msgid="7892597146032121735">"เลือกแอปพลิเคชันสำหรับอุปกรณ์ USB"</string>
     <string name="noApplications" msgid="1691104391758345586">"ไม่มีแอปพลิเคชันใดทำงานนี้ได้"</string>
     <string name="aerr_title" msgid="653922989522758100">"ขออภัย!"</string>
     <string name="aerr_application" msgid="4683614104336409186">"แอปพลิเคชัน <xliff:g id="APPLICATION">%1$s</xliff:g> (กระบวนการ <xliff:g id="PROCESS">%2$s</xliff:g> หยุดทำงานโดยไม่คาดหมาย โปรดลองอีกครั้ง"</string>
diff --git a/core/res/res/values-tl/strings.xml b/core/res/res/values-tl/strings.xml
index 713fca9..5d4a916 100644
--- a/core/res/res/values-tl/strings.xml
+++ b/core/res/res/values-tl/strings.xml
@@ -361,8 +361,8 @@
     <string name="permdesc_vibrate" msgid="2886677177257789187">"Pinapayagan ang application na kontrolin ang vibrator."</string>
     <string name="permlab_flashlight" msgid="2155920810121984215">"kontrolin ang flashlight"</string>
     <string name="permdesc_flashlight" msgid="6433045942283802309">"Pinapayagan ang application na kontrolin ang flashlight."</string>
-    <string name="permlab_accessUsb" msgid="7362327818655760496">"i-access ang mga USB device"</string>
-    <string name="permdesc_accessUsb" msgid="2414271762914049292">"Pinapayagan ang application na i-access ang mga USB device."</string>
+    <string name="permlab_manageUsb" msgid="1113453430645402723">"pamahalaan ang mga kagustuhan at pahintulot para sa mga USB device"</string>
+    <string name="permdesc_manageUsb" msgid="6148489202092166164">"Pinapayagan ang application na pamahalaan ang mga kagustuhan at pahintulot para sa mga USB device."</string>
     <string name="permlab_accessMtp" msgid="4953468676795917042">"ipatupad ang MTP protocol"</string>
     <string name="permdesc_accessMtp" msgid="6532961200486791570">"Pinapayagan ang access sa kernel MTP driver upang maipatupad ang MTP USB protocol."</string>
     <string name="permlab_hardware_test" msgid="4148290860400659146">"subukan ang hardware"</string>
@@ -484,8 +484,8 @@
     <string name="policydesc_wipeData" product="default" msgid="7669895333814222586">"Burahin ang data ng telepono nang walang babala, sa pamamagitan ng pagsasagawa ng pag-reset sa data ng factory"</string>
     <string name="policylab_setGlobalProxy" msgid="2784828293747791446">"Itakda ang pandaigdigang proxy ng device"</string>
     <string name="policydesc_setGlobalProxy" msgid="6387497466660154931">"Itakda ang pandaigdigang proxy ng device na gagamitin habang pinagana ang patakaran. Tanging ang unang admin ng device ang magtatakda sa may bisang pandaigdigang proxy."</string>
-    <!-- outdated translation 4740941403188940274 -->     <string name="policylab_expirePassword" msgid="885279151847254056">"Itakda pag-expire ng password"</string>
-    <!-- outdated translation 6626724939177185949 -->     <string name="policydesc_expirePassword" msgid="4844430354224822074">"Kontrolin kung gaano katagal bago kailangang palitan ang password sa pag-lock ng screen"</string>
+    <string name="policylab_expirePassword" msgid="885279151847254056">"Itakda expire password pag-lock scr"</string>
+    <string name="policydesc_expirePassword" msgid="4844430354224822074">"Kontrolin kung gaano kadalas dapat na mapalitan ang password sa pag-lock ng screen"</string>
     <string name="policylab_encryptedStorage" msgid="8901326199909132915">"Itakda pag-encrypt ng imbakan"</string>
     <string name="policydesc_encryptedStorage" msgid="2504984732631479399">"Hinging naka-encrypt ang nakaimbak na data ng application"</string>
   <string-array name="phoneTypes">
@@ -814,6 +814,7 @@
     <string name="alwaysUse" msgid="4583018368000610438">"Gamitin bilang default para sa pagkilos na ito."</string>
     <string name="clearDefaultHintMsg" msgid="4815455344600932173">"I-clear ang default sa Mga Setting ng Home &gt; Mga Application &gt; Pamahalaan ang mga application."</string>
     <string name="chooseActivity" msgid="1009246475582238425">"Pumili ng pagkilos"</string>
+    <string name="chooseUsbActivity" msgid="7892597146032121735">"Pumili ng application para sa USB device"</string>
     <string name="noApplications" msgid="1691104391758345586">"Walang mga application ang makakapagsagawa ng pagkilos na ito."</string>
     <string name="aerr_title" msgid="653922989522758100">"Paumanhin!"</string>
     <string name="aerr_application" msgid="4683614104336409186">"Hindi inaasahang humito ang <xliff:g id="APPLICATION">%1$s</xliff:g> (proseso <xliff:g id="PROCESS">%2$s</xliff:g>) ng application. Pakisubukang muli."</string>
diff --git a/core/res/res/values-tr/strings.xml b/core/res/res/values-tr/strings.xml
index d7a5008..58b681e 100644
--- a/core/res/res/values-tr/strings.xml
+++ b/core/res/res/values-tr/strings.xml
@@ -361,8 +361,8 @@
     <string name="permdesc_vibrate" msgid="2886677177257789187">"Uygulamanın titreşimi denetlemesine izin verir."</string>
     <string name="permlab_flashlight" msgid="2155920810121984215">"flaşı denetle"</string>
     <string name="permdesc_flashlight" msgid="6433045942283802309">"Uygulamaların flaş ışığını denetlemesine izin verir."</string>
-    <string name="permlab_accessUsb" msgid="7362327818655760496">"USB cihazlarına erişme"</string>
-    <string name="permdesc_accessUsb" msgid="2414271762914049292">"Uygulamaların USB cihazlarına erişimine izin verir"</string>
+    <string name="permlab_manageUsb" msgid="1113453430645402723">"USB cihazları için tercihleri ve izinleri yönet"</string>
+    <string name="permdesc_manageUsb" msgid="6148489202092166164">"Uygulamanın USB cihazları için tercihleri ve izinleri yönetmesine izin verir."</string>
     <string name="permlab_accessMtp" msgid="4953468676795917042">"MTP protokolünü uygula"</string>
     <string name="permdesc_accessMtp" msgid="6532961200486791570">"MTP USB protokolünü uygulamak için çekirdekteki MTP sürücüsüne erişim izni ver."</string>
     <string name="permlab_hardware_test" msgid="4148290860400659146">"donanımı test et"</string>
@@ -484,8 +484,8 @@
     <string name="policydesc_wipeData" product="default" msgid="7669895333814222586">"Fabrika verilerine sıfırlama işlemi gerçekleştirerek telefondaki verileri uyarıda bulunmadan silin"</string>
     <string name="policylab_setGlobalProxy" msgid="2784828293747791446">"Cihaz genelinde geçerli proxy\'i ayarla"</string>
     <string name="policydesc_setGlobalProxy" msgid="6387497466660154931">"Politika etkin olduğunda kullanılacak cihaz genelinde geçerli proxy\'yi ayarlayın. Etkin genel proxy\'yi yalnızca ilk cihaz yöneticisi ayarlar."</string>
-    <!-- outdated translation 4740941403188940274 -->     <string name="policylab_expirePassword" msgid="885279151847254056">"Şifre süre sonu tarihi ayarla"</string>
-    <!-- outdated translation 6626724939177185949 -->     <string name="policydesc_expirePassword" msgid="4844430354224822074">"Ekran kilitleme şifresinin ne kadar süre sonra değiştirilmesi gerekeceğini denetleyin."</string>
+    <string name="policylab_expirePassword" msgid="885279151847254056">"Ekr kilt şifr süre sonu ayarla"</string>
+    <string name="policydesc_expirePassword" msgid="4844430354224822074">"Ekran kilitleme şifresinin hangi sıklıkla değiştirilmesi gerektiğini denetleyin"</string>
     <string name="policylab_encryptedStorage" msgid="8901326199909132915">"Deplm şifrelemesini ayarla"</string>
     <string name="policydesc_encryptedStorage" msgid="2504984732631479399">"Depolanan uygulama verisinin şifrelenmiş olmasını gerektir"</string>
   <string-array name="phoneTypes">
@@ -814,6 +814,7 @@
     <string name="alwaysUse" msgid="4583018368000610438">"Varsayılan olarak bu işlem için kullan."</string>
     <string name="clearDefaultHintMsg" msgid="4815455344600932173">"Giriş Ayarları &gt; Uygulamalar &gt; Uygulamaları yönet\'te varsayılanı temizleyin."</string>
     <string name="chooseActivity" msgid="1009246475582238425">"İşlem seç"</string>
+    <string name="chooseUsbActivity" msgid="7892597146032121735">"USB cihazı için bir uygulama seçin"</string>
     <string name="noApplications" msgid="1691104391758345586">"Hiçbir uygulama bu işlemi yapamaz."</string>
     <string name="aerr_title" msgid="653922989522758100">"Üzgünüz!"</string>
     <string name="aerr_application" msgid="4683614104336409186">"<xliff:g id="APPLICATION">%1$s</xliff:g> uygulaması (<xliff:g id="PROCESS">%2$s</xliff:g> işlemi) beklenmedik biçimde durdu. Lütfen yeniden deneyin."</string>
@@ -824,7 +825,7 @@
     <string name="anr_application_process" msgid="4185842666452210193">"<xliff:g id="APPLICATION">%1$s</xliff:g> uygulaması (<xliff:g id="PROCESS">%2$s</xliff:g> işleminde) yanıt vermiyor."</string>
     <string name="anr_process" msgid="1246866008169975783">"<xliff:g id="PROCESS">%1$s</xliff:g> işlemi yanıt vermiyor."</string>
     <string name="force_close" msgid="3653416315450806396">"Kapanmaya zorla"</string>
-    <string name="report" msgid="4060218260984795706">"Rapor"</string>
+    <string name="report" msgid="4060218260984795706">"Bildir"</string>
     <string name="wait" msgid="7147118217226317732">"Bekle"</string>
     <string name="launch_warning_title" msgid="8323761616052121936">"Uygulama yönlendirildi"</string>
     <string name="launch_warning_replace" msgid="6202498949970281412">"<xliff:g id="APP_NAME">%1$s</xliff:g> şimdi çalışıyor."</string>
diff --git a/core/res/res/values-uk/strings.xml b/core/res/res/values-uk/strings.xml
index 7c329c5..60cea7b 100644
--- a/core/res/res/values-uk/strings.xml
+++ b/core/res/res/values-uk/strings.xml
@@ -361,8 +361,8 @@
     <string name="permdesc_vibrate" msgid="2886677177257789187">"Дозволяє програмі контролювати вібросигнал."</string>
     <string name="permlab_flashlight" msgid="2155920810121984215">"контр. блим. світло"</string>
     <string name="permdesc_flashlight" msgid="6433045942283802309">"Дозволяє програмі контролювати світловий сигнал."</string>
-    <string name="permlab_accessUsb" msgid="7362327818655760496">"отр.дост.до прист.USB"</string>
-    <string name="permdesc_accessUsb" msgid="2414271762914049292">"Дозволяє програмі отрим. доступ до пристр. USB."</string>
+    <string name="permlab_manageUsb" msgid="1113453430645402723">"керувати налаштуваннями та дозволами для пристроїв USB"</string>
+    <string name="permdesc_manageUsb" msgid="6148489202092166164">"Дозволяє програмі керувати налаштуваннями та дозволами для пристроїв USB."</string>
     <string name="permlab_accessMtp" msgid="4953468676795917042">"впроваджувати протокол MTP"</string>
     <string name="permdesc_accessMtp" msgid="6532961200486791570">"Дозволяє доступ до драйвера ядра MTP для впровадження протоколу MTP (USB)."</string>
     <string name="permlab_hardware_test" msgid="4148290860400659146">"тест-ти обладн."</string>
@@ -484,8 +484,8 @@
     <string name="policydesc_wipeData" product="default" msgid="7669895333814222586">"Видаляє дані телефону без попередження, відновлюючи заводські налаштування"</string>
     <string name="policylab_setGlobalProxy" msgid="2784828293747791446">"Установ. глоб. проксі пристрою"</string>
     <string name="policydesc_setGlobalProxy" msgid="6387497466660154931">"Устан. використ. глоб. проксі, коли ввімкнено політику. Лише адміністратор першого пристрою встановлює активний глоб. проксі."</string>
-    <!-- outdated translation 4740941403188940274 -->     <string name="policylab_expirePassword" msgid="885279151847254056">"Установити термін дії пароля"</string>
-    <!-- outdated translation 6626724939177185949 -->     <string name="policydesc_expirePassword" msgid="4844430354224822074">"Регулює, за скільки часу перед блокуванням екрана треба змінювати пароль"</string>
+    <string name="policylab_expirePassword" msgid="885279151847254056">"Установити термін дії пароля блокування екрана"</string>
+    <string name="policydesc_expirePassword" msgid="4844430354224822074">"Контролювати частоту зміни пароля блокування екрана"</string>
     <string name="policylab_encryptedStorage" msgid="8901326199909132915">"Установити шифрування носія"</string>
     <string name="policydesc_encryptedStorage" msgid="2504984732631479399">"Потрібно, щоб дані збереженої програми були зашифровані"</string>
   <string-array name="phoneTypes">
@@ -814,6 +814,7 @@
     <string name="alwaysUse" msgid="4583018368000610438">"Використ. за умовч. для цієї дії."</string>
     <string name="clearDefaultHintMsg" msgid="4815455344600932173">"Очист. налашт. за умовч. у Дом. налашт. &gt; Програми &gt; Керув. програмами."</string>
     <string name="chooseActivity" msgid="1009246475582238425">"Виберіть дію"</string>
+    <string name="chooseUsbActivity" msgid="7892597146032121735">"Виберіть програму для пристрою USB"</string>
     <string name="noApplications" msgid="1691104391758345586">"Жодна програма не може виконати цю дію."</string>
     <string name="aerr_title" msgid="653922989522758100">"Помилка!"</string>
     <string name="aerr_application" msgid="4683614104336409186">"Програма <xliff:g id="APPLICATION">%1$s</xliff:g> (процес <xliff:g id="PROCESS">%2$s</xliff:g>) несподівано зупинилася. Спробуйте ще."</string>
diff --git a/core/res/res/values-vi/strings.xml b/core/res/res/values-vi/strings.xml
index 49c9e44..8070767 100644
--- a/core/res/res/values-vi/strings.xml
+++ b/core/res/res/values-vi/strings.xml
@@ -361,8 +361,8 @@
     <string name="permdesc_vibrate" msgid="2886677177257789187">"Cho phép ứng dụng kiểm soát bộ rung."</string>
     <string name="permlab_flashlight" msgid="2155920810121984215">"kiểm soát đèn nháy"</string>
     <string name="permdesc_flashlight" msgid="6433045942283802309">"Cho phép ứng dụng kiểm soát đèn nháy."</string>
-    <string name="permlab_accessUsb" msgid="7362327818655760496">"truy cập bộ nhớ USB"</string>
-    <string name="permdesc_accessUsb" msgid="2414271762914049292">"Cho phép ứng dụng truy cập thiết bị USB."</string>
+    <string name="permlab_manageUsb" msgid="1113453430645402723">"quản lý các tùy chọn và quyền dành cho thiết bị USB"</string>
+    <string name="permdesc_manageUsb" msgid="6148489202092166164">"Cho phép ứng dụng quản lý các tùy chọn và quyền dành cho thiết bị USB."</string>
     <string name="permlab_accessMtp" msgid="4953468676795917042">"triển khai giao thức MTP"</string>
     <string name="permdesc_accessMtp" msgid="6532961200486791570">"Cho phép truy cập tới trình điều khiển MTP nhân hệ điều hành để triển khai giao thức MTP USB."</string>
     <string name="permlab_hardware_test" msgid="4148290860400659146">"kiểm tra phần cứng"</string>
@@ -484,8 +484,8 @@
     <string name="policydesc_wipeData" product="default" msgid="7669895333814222586">"Xóa dữ liệu trên điện thoại mà không cần cảnh báo, bằng cách thực hiện đặt lại về dữ liệu gốc"</string>
     <string name="policylab_setGlobalProxy" msgid="2784828293747791446">"Đặt proxy chung của điện thoại"</string>
     <string name="policydesc_setGlobalProxy" msgid="6387497466660154931">"Đặt proxy chung của điện thoại được sử dụng trong khi chính sách được bật. Chỉ quản trị viên đầu tiên của điện thoại mới có thể đặt proxy chung hiệu quả."</string>
-    <!-- outdated translation 4740941403188940274 -->     <string name="policylab_expirePassword" msgid="885279151847254056">"Đặt hết hạn mật khẩu"</string>
-    <!-- outdated translation 6626724939177185949 -->     <string name="policydesc_expirePassword" msgid="4844430354224822074">"Kiểm soát thời lượng trước khi mật khẩu khóa màn hình cần được thay đổi"</string>
+    <string name="policylab_expirePassword" msgid="885279151847254056">"Đặt hết hạn mật khẩu khóa màn hình"</string>
+    <string name="policydesc_expirePassword" msgid="4844430354224822074">"Kiểm soát tần suất bắt buộc phải thay đổi mật khẩu khóa màn hình"</string>
     <string name="policylab_encryptedStorage" msgid="8901326199909132915">"Đặt mã hóa dung lượng lưu trữ"</string>
     <string name="policydesc_encryptedStorage" msgid="2504984732631479399">"Yêu cầu dữ liệu ứng dụng được lưu trữ phải được mã hóa"</string>
   <string-array name="phoneTypes">
@@ -814,6 +814,7 @@
     <string name="alwaysUse" msgid="4583018368000610438">"Sử dụng theo mặc định đối với tác vụ này."</string>
     <string name="clearDefaultHintMsg" msgid="4815455344600932173">"Xoá mặc định trong Cài đặt Màn hình trang chủ &gt; Ứng dụng&gt; Quản lý ứng dụng."</string>
     <string name="chooseActivity" msgid="1009246475582238425">"Chọn tác vụ"</string>
+    <string name="chooseUsbActivity" msgid="7892597146032121735">"Chọn ứng dụng cho thiết bị USB"</string>
     <string name="noApplications" msgid="1691104391758345586">"Không ứng dụng nào có thể thực hiện tác vụ này."</string>
     <string name="aerr_title" msgid="653922989522758100">"Rất tiếc!"</string>
     <string name="aerr_application" msgid="4683614104336409186">"Ứng dụng <xliff:g id="APPLICATION">%1$s</xliff:g> (quá trình <xliff:g id="PROCESS">%2$s</xliff:g>) đã dừng đột ngột. Vui lòng thử lại."</string>
diff --git a/core/res/res/values-xlarge/styles.xml b/core/res/res/values-xlarge/styles.xml
index dd78920..a39d9d6 100644
--- a/core/res/res/values-xlarge/styles.xml
+++ b/core/res/res/values-xlarge/styles.xml
@@ -36,6 +36,22 @@
         <item name="android:textColor">?android:attr/textColorPrimary</item>
     </style>
 
+    <style name="TextAppearance.Holo.Widget.TabWidget">
+        <item name="android:textSize">18sp</item>
+        <item name="android:textStyle">normal</item>
+        <item name="android:textColor">@android:color/tab_indicator_text</item>
+    </style>
+    
+    <style name="Widget.Holo.TabWidget" parent="Widget.TabWidget">
+        <item name="android:textAppearance">@style/TextAppearance.Holo.Widget.TabWidget</item>
+        <item name="android:tabStripLeft">@null</item>
+        <item name="android:tabStripRight">@null</item>
+        <item name="android:tabStripEnabled">false</item>
+        <item name="android:divider">@null</item>
+        <item name="android:gravity">left|center_vertical</item>
+        <item name="android:tabLayout">@android:layout/tab_indicator_holo_large</item>
+    </style>
+    
     <style name="PreferencePanel">
         <item name="android:layout_marginLeft">@dimen/preference_screen_side_margin</item>
         <item name="android:layout_marginRight">@dimen/preference_screen_side_margin</item>
diff --git a/core/res/res/values-zh-rCN/strings.xml b/core/res/res/values-zh-rCN/strings.xml
index 640b9bc..fce5fca 100644
--- a/core/res/res/values-zh-rCN/strings.xml
+++ b/core/res/res/values-zh-rCN/strings.xml
@@ -361,8 +361,8 @@
     <string name="permdesc_vibrate" msgid="2886677177257789187">"允许应用程序控制振动器。"</string>
     <string name="permlab_flashlight" msgid="2155920810121984215">"控制闪光灯"</string>
     <string name="permdesc_flashlight" msgid="6433045942283802309">"允许应用程序控制闪光灯。"</string>
-    <string name="permlab_accessUsb" msgid="7362327818655760496">"访问 USB 设备"</string>
-    <string name="permdesc_accessUsb" msgid="2414271762914049292">"允许应用程序访问 USB 设备。"</string>
+    <string name="permlab_manageUsb" msgid="1113453430645402723">"管理 USB 设备的偏好设置和权限"</string>
+    <string name="permdesc_manageUsb" msgid="6148489202092166164">"允许应用程序管理 USB 设备的偏好设置和权限。"</string>
     <string name="permlab_accessMtp" msgid="4953468676795917042">"应用 MTP 协议"</string>
     <string name="permdesc_accessMtp" msgid="6532961200486791570">"允许访问内核 MTP 驱动程序,以便应用 MTP USB 协议。"</string>
     <string name="permlab_hardware_test" msgid="4148290860400659146">"测试硬件"</string>
@@ -484,8 +484,8 @@
     <string name="policydesc_wipeData" product="default" msgid="7669895333814222586">"恢复出厂设置时,将擦除手机上的数据而不发送警告"</string>
     <string name="policylab_setGlobalProxy" msgid="2784828293747791446">"设置设备全局代理"</string>
     <string name="policydesc_setGlobalProxy" msgid="6387497466660154931">"请设置在启用政策的情况下要使用的设备全局代理。只有第一设备管理员才可设置有效的全局代理。"</string>
-    <!-- outdated translation 4740941403188940274 -->     <string name="policylab_expirePassword" msgid="885279151847254056">"设置密码有效期"</string>
-    <!-- outdated translation 6626724939177185949 -->     <string name="policydesc_expirePassword" msgid="4844430354224822074">"控制屏幕锁定密码的使用期限"</string>
+    <string name="policylab_expirePassword" msgid="885279151847254056">"设置锁定屏幕密码的有效期"</string>
+    <string name="policydesc_expirePassword" msgid="4844430354224822074">"控制锁定屏幕密码的更改频率"</string>
     <string name="policylab_encryptedStorage" msgid="8901326199909132915">"设置存储设备加密"</string>
     <string name="policydesc_encryptedStorage" msgid="2504984732631479399">"需要对存储的应用程序数据进行加密"</string>
   <string-array name="phoneTypes">
@@ -814,6 +814,7 @@
     <string name="alwaysUse" msgid="4583018368000610438">"默认使用此方式发送。"</string>
     <string name="clearDefaultHintMsg" msgid="4815455344600932173">"通过主屏幕上的“设置”&gt;“应用程序”&gt;“管理应用程序”清除默认设置。"</string>
     <string name="chooseActivity" msgid="1009246475582238425">"选择一项操作"</string>
+    <string name="chooseUsbActivity" msgid="7892597146032121735">"选择适用于 USB 设备的应用程序"</string>
     <string name="noApplications" msgid="1691104391758345586">"没有应用程序可执行此操作。"</string>
     <string name="aerr_title" msgid="653922989522758100">"很抱歉!"</string>
     <string name="aerr_application" msgid="4683614104336409186">"应用程序 <xliff:g id="APPLICATION">%1$s</xliff:g>(进程:<xliff:g id="PROCESS">%2$s</xliff:g>)意外停止,请重试。"</string>
diff --git a/core/res/res/values-zh-rTW/strings.xml b/core/res/res/values-zh-rTW/strings.xml
index fe1d78d..141ed01 100644
--- a/core/res/res/values-zh-rTW/strings.xml
+++ b/core/res/res/values-zh-rTW/strings.xml
@@ -361,8 +361,8 @@
     <string name="permdesc_vibrate" msgid="2886677177257789187">"允許應用程式控制震動。"</string>
     <string name="permlab_flashlight" msgid="2155920810121984215">"控制閃光燈"</string>
     <string name="permdesc_flashlight" msgid="6433045942283802309">"允許應用程式控制閃光燈。"</string>
-    <string name="permlab_accessUsb" msgid="7362327818655760496">"存取 USB 裝置"</string>
-    <string name="permdesc_accessUsb" msgid="2414271762914049292">"允許應用程式存取 USB 裝置。"</string>
+    <string name="permlab_manageUsb" msgid="1113453430645402723">"管理 USB 裝置的偏好設定和權限"</string>
+    <string name="permdesc_manageUsb" msgid="6148489202092166164">"允許應用程式管理 USB 裝置的偏好設定和權限。"</string>
     <string name="permlab_accessMtp" msgid="4953468676795917042">"執行 MTP 通訊協定"</string>
     <string name="permdesc_accessMtp" msgid="6532961200486791570">"允許存取核心 MTP 驅動程式,以執行 MTP USB 通訊協定。"</string>
     <string name="permlab_hardware_test" msgid="4148290860400659146">"測試硬體"</string>
@@ -484,8 +484,8 @@
     <string name="policydesc_wipeData" product="default" msgid="7669895333814222586">"執行重設為原廠設定時,系統會直接清除手機資料而不提出警告"</string>
     <string name="policylab_setGlobalProxy" msgid="2784828293747791446">"設定裝置全域 Proxy"</string>
     <string name="policydesc_setGlobalProxy" msgid="6387497466660154931">"設定政策啟用時所要使用的裝置全域 Proxy,只有第一個裝置管理員所設定的全域 Proxy 具有效力。"</string>
-    <!-- outdated translation 4740941403188940274 -->     <string name="policylab_expirePassword" msgid="885279151847254056">"設定密碼到期日"</string>
-    <!-- outdated translation 6626724939177185949 -->     <string name="policydesc_expirePassword" msgid="4844430354224822074">"控制螢幕鎖定密碼的使用期限"</string>
+    <string name="policylab_expirePassword" msgid="885279151847254056">"設定螢幕上鎖密碼到期日"</string>
+    <string name="policydesc_expirePassword" msgid="4844430354224822074">"控制螢幕上鎖密碼的變更頻率"</string>
     <string name="policylab_encryptedStorage" msgid="8901326199909132915">"設定儲存裝置加密"</string>
     <string name="policydesc_encryptedStorage" msgid="2504984732631479399">"必須為儲存的應用程式資料加密"</string>
   <string-array name="phoneTypes">
@@ -814,6 +814,7 @@
     <string name="alwaysUse" msgid="4583018368000610438">"以此為本操作預設值。"</string>
     <string name="clearDefaultHintMsg" msgid="4815455344600932173">"清除首頁設定 (應用程式) 管理應用程式的預設值。"</string>
     <string name="chooseActivity" msgid="1009246475582238425">"選取一項操作"</string>
+    <string name="chooseUsbActivity" msgid="7892597146032121735">"選取要以 USB 裝置存取的應用程式"</string>
     <string name="noApplications" msgid="1691104391758345586">"沒有應用程式可執行此項操作。"</string>
     <string name="aerr_title" msgid="653922989522758100">"很抱歉!"</string>
     <string name="aerr_application" msgid="4683614104336409186">"<xliff:g id="APPLICATION">%1$s</xliff:g> 應用程式 (程序:<xliff:g id="PROCESS">%2$s</xliff:g>) 異常終止。請再試一次。"</string>
diff --git a/core/res/res/values/arrays.xml b/core/res/res/values/arrays.xml
index fa33b0a..9073531 100644
--- a/core/res/res/values/arrays.xml
+++ b/core/res/res/values/arrays.xml
@@ -242,15 +242,15 @@
        <item>@drawable/action_bar_background</item>
        <item>@drawable/action_bar_divider</item>
        <item>@drawable/ic_menu_close_clear_cancel</item>
-       <item>@drawable/ic_menu_copy_dark</item>
-       <item>@drawable/ic_menu_copy_light</item>
-       <item>@drawable/ic_menu_cut_dark</item>
-       <item>@drawable/ic_menu_cut_light</item>
+       <item>@drawable/ic_menu_copy_holo_dark</item>
+       <item>@drawable/ic_menu_copy_holo_light</item>
+       <item>@drawable/ic_menu_cut_holo_dark</item>
+       <item>@drawable/ic_menu_cut_holo_light</item>
        <item>@drawable/ic_menu_more</item>
        <item>@drawable/ic_menu_moreoverflow_holo_dark</item>
        <item>@drawable/ic_menu_moreoverflow_holo_light</item>
-       <item>@drawable/ic_menu_paste_dark</item>
-       <item>@drawable/ic_menu_paste_light</item>
+       <item>@drawable/ic_menu_paste_holo_dark</item>
+       <item>@drawable/ic_menu_paste_holo_light</item>
        <item>@drawable/dialog_bottom_holo_dark</item>
        <item>@drawable/dialog_bottom_holo_light</item>
        <item>@drawable/dialog_full_holo_dark</item>
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index d3b1062..c81f8c0 100755
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -610,6 +610,12 @@
         <attr name="actionModeCopyDrawable" format="reference" />
         <!-- Drawable to use for the Paste action button in Contextual Action Bar -->
         <attr name="actionModePasteDrawable" format="reference" />
+        <!-- Drawable to use for the Share action button in WebView selection action modes -->
+        <attr name="actionModeShareDrawable" format="reference" />
+        <!-- Drawable to use for the Find action button in WebView selection action modes -->
+        <attr name="actionModeFindDrawable" format="reference" />
+        <!-- Drawable to use for the Web Search action button in WebView selection action modes -->
+        <attr name="actionModeWebSearchDrawable" format="reference" />
 
         <!-- PopupWindow style to use for action modes when showing as a window overlay. -->
         <attr name="actionModePopupWindowStyle" format="reference" />
@@ -723,6 +729,10 @@
         <attr name="searchViewEditQuery" format="reference" />
         <!-- SearchView query refinement icon background -->
         <attr name="searchViewEditQueryBackground" format="reference" />
+        <!-- SearchView text field background for the left section -->
+        <attr name="searchViewTextField" format="reference" />
+        <!-- SearchView text field background for the right section -->
+        <attr name="searchViewTextFieldRight" format="reference" />
 
         <!-- Specifies a drawable to use for the 'home as up' indicator. -->
         <attr name="homeAsUpIndicator" format="reference" />
@@ -1364,6 +1374,9 @@
         <enum name="KEYCODE_BUTTON_14" value="201" />
         <enum name="KEYCODE_BUTTON_15" value="202" />
         <enum name="KEYCODE_BUTTON_16" value="203" />
+        <enum name="KEYCODE_LANGUAGE_SWITCH" value="204" />
+        <enum name="KEYCODE_MANNER_MODE" value="205" />
+        <enum name="KEYCODE_3D_MODE" value="206" />
     </attr>
 
     <!-- ***************************************************************** -->
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
old mode 100644
new mode 100755
index c815758..56bc1d3
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -138,9 +138,9 @@
         <item>"mobile_mms,2,0,2"</item>
         <item>"mobile_supl,3,0,2"</item>
         <item>"mobile_hipri,5,0,3"</item>
-        <item>"mobile_fota,8,0,2"</item>
-        <item>"mobile_ims,9,0,2"</item>
-        <item>"mobile_cbs,10,0,2"</item>
+        <item>"mobile_fota,10,0,2"</item>
+        <item>"mobile_ims,11,0,2"</item>
+        <item>"mobile_cbs,12,0,2"</item>
     </string-array>
 
     <!-- This string array should be overridden by the device to present a list of radio
@@ -544,6 +544,9 @@
          which typically is /data/data/com.android.providers.downloads/files -->
     <integer name="config_downloadDataDirSize">100</integer>
 
+    <!-- Max number of downloads allowed to proceed concurrently -->
+    <integer name="config_MaxConcurrentDownloadsAllowed">5</integer>
+
     <!-- When the free space available in DownloadManager's data dir falls
          below the percentage value specified by this param, DownloadManager
          starts removing files to try to make percentage of available
@@ -571,4 +574,27 @@
 
     <!-- The VoiceMail default value is displayed to my own number if it is true -->
     <bool name="config_telephony_use_own_number_for_voicemail">false</bool>
+
+    <!-- If this value is true, Sms encoded as octet is decoded by utf8 decoder.
+         If false, decoded by Latin decoder. -->
+    <bool name="config_sms_utf8_support">false</bool>
+
+    <!-- If this value is true, The mms content-disposition field is supported correctly.
+         If false, Content-disposition fragments are ignored -->
+    <bool name="config_mms_content_disposition_support">true</bool>
+
+    <!-- If this value is true, the carrier supports sms delivery reports.
+         If false, sms delivery reports are not supported and the preference
+         option to enable/disable delivery reports is removed in the Messaging app. -->
+    <bool name="config_sms_delivery_reports_support">true</bool>
+
+    <!-- If this value is true, the carrier supports mms delivery reports.
+         If false, mms delivery reports are not supported and the preference
+         option to enable/disable delivery reports is removed in the Messaging app. -->
+    <bool name="config_mms_delivery_reports_support">true</bool>
+
+    <!-- If this value is true, the carrier supports mms read reports.
+         If false, mms read reports are not supported and the preference
+         option to enable/disable read reports is removed in the Messaging app. -->
+    <bool name="config_mms_read_reports_support">true</bool>
 </resources>
diff --git a/core/res/res/values/dimens.xml b/core/res/res/values/dimens.xml
index 8a590cd..cca7d8b 100644
--- a/core/res/res/values/dimens.xml
+++ b/core/res/res/values/dimens.xml
@@ -52,12 +52,13 @@
     <dimen name="password_keyboard_key_height_numeric">56dip</dimen>
     <!-- Default correction for the space key in the password keyboard -->
     <dimen name="password_keyboard_spacebar_vertical_correction">4dip</dimen>
+
     <!-- Preference activity side margins -->
     <dimen name="preference_screen_side_margin">0dp</dimen>
     <!-- Preference activity side margins negative-->
     <dimen name="preference_screen_side_margin_negative">0dp</dimen>
     <!-- Preference widget area width (to the left of the text) -->
-    <dimen name="preference_widget_width">56dp</dimen>
+    <dimen name="preference_widget_width">8dp</dimen>
 
     <!-- The platform's desired minimum size for a dialog's width when it
          is along the major axis (that is the screen is landscape).  This may
diff --git a/core/res/res/values/styles.xml b/core/res/res/values/styles.xml
index 72f1801..f7d3c3f 100644
--- a/core/res/res/values/styles.xml
+++ b/core/res/res/values/styles.xml
@@ -982,7 +982,7 @@
     <eat-comment />
 
     <style name="MediaButton">
-        <item name="android:background">@android:drawable/media_button_background</item>
+        <item name="android:background">@null</item>
         <item name="android:layout_width">71dip</item>
         <item name="android:layout_height">52dip</item>
     </style>
@@ -1214,8 +1214,10 @@
         <item name="android:textColor">?textColorPrimary</item>
     </style>
 
+    <!-- This style is for smaller screens; values-xlarge defines a version
+         for larger screens. -->
     <style name="TextAppearance.Holo.Widget.TabWidget">
-        <item name="android:textSize">18sp</item>
+        <item name="android:textSize">14sp</item>
         <item name="android:textStyle">normal</item>
         <item name="android:textColor">@android:color/tab_indicator_text</item>
     </style>
@@ -1611,6 +1613,8 @@
         <item name="android:thumb">@android:drawable/scrubber_control_selector_holo</item>
         <item name="android:thumbOffset">16dip</item>
         <item name="android:focusable">true</item>
+        <item name="android:paddingLeft">16dip</item>
+        <item name="android:paddingRight">16dip</item>
     </style>
 
     <style name="Widget.Holo.RatingBar" parent="Widget.RatingBar">
@@ -1662,6 +1666,9 @@
         <item name="android:button">@android:drawable/btn_star_holo_dark</item>
     </style>
 
+    <!-- The holo style for smaller screens actually uses the non-holo layout,
+         which is more compact.  values-xlarge defines an alternative version
+         for the real holo look on a large screen. -->
     <style name="Widget.Holo.TabWidget" parent="Widget.TabWidget">
         <item name="android:textAppearance">@style/TextAppearance.Holo.Widget.TabWidget</item>
         <item name="android:tabStripLeft">@null</item>
@@ -2177,8 +2184,8 @@
 
     <style name="Widget.Holo.PreferenceFrameLayout">
         <item name="android:borderTop">0dip</item>
-        <item name="android:borderBottom">48dip</item>
-        <item name="android:borderLeft">32dip</item>
-        <item name="android:borderRight">32dip</item>
+        <item name="android:borderBottom">0dip</item>
+        <item name="android:borderLeft">0dip</item>
+        <item name="android:borderRight">0dip</item>
     </style>
 </resources>
diff --git a/core/res/res/values/themes.xml b/core/res/res/values/themes.xml
index 82164e5..b127747 100644
--- a/core/res/res/values/themes.xml
+++ b/core/res/res/values/themes.xml
@@ -260,9 +260,12 @@
         <item name="actionOverflowButtonStyle">@android:style/Widget.ActionButton.Overflow</item>
         <item name="actionModeBackground">@android:drawable/cab_background_dark</item>
         <item name="actionModeCloseDrawable">@android:drawable/ic_menu_close_clear_cancel</item>
-        <item name="actionModeCutDrawable">@android:drawable/ic_menu_cut_dark</item>
-        <item name="actionModeCopyDrawable">@android:drawable/ic_menu_copy_dark</item>
-        <item name="actionModePasteDrawable">@android:drawable/ic_menu_paste_dark</item>
+        <item name="actionModeCutDrawable">@android:drawable/ic_menu_cut_holo_dark</item>
+        <item name="actionModeCopyDrawable">@android:drawable/ic_menu_copy_holo_dark</item>
+        <item name="actionModePasteDrawable">@android:drawable/ic_menu_paste_holo_dark</item>
+        <item name="actionModeShareDrawable">@android:drawable/ic_menu_share_holo_dark</item>
+        <item name="actionModeFindDrawable">@android:drawable/ic_menu_find_holo_dark</item>
+        <item name="actionModeWebSearchDrawable">@android:drawable/ic_menu_search</item>
         <item name="actionBarTabStyle">@style/Widget.ActionBarView_TabView</item>
         <item name="actionBarTabBarStyle">@style/Widget.ActionBarView_TabBar</item>
         <item name="actionBarTabTextStyle">@style/Widget.ActionBarView_TabText</item>
@@ -282,6 +285,8 @@
 
         <!-- SearchView attributes -->
         <item name="searchDropdownBackground">@android:drawable/spinner_dropdown_background</item>
+        <item name="searchViewTextField">@drawable/textfield_searchview_holo_dark</item>
+        <item name="searchViewTextFieldRight">@drawable/textfield_searchview_right_holo_dark</item>
         <item name="searchViewCloseIcon">@android:drawable/ic_clear</item>
         <item name="searchViewSearchIcon">@android:drawable/ic_search</item>
         <item name="searchViewGoIcon">@android:drawable/ic_go</item>
@@ -380,13 +385,18 @@
         <item name="progressBarStyleInverse">@android:style/Widget.ProgressBar</item>
         <item name="progressBarStyleSmallInverse">@android:style/Widget.ProgressBar.Small</item>
         <item name="progressBarStyleLargeInverse">@android:style/Widget.ProgressBar.Large</item>
-        <item name="actionModeCutDrawable">@android:drawable/ic_menu_cut_light</item>
-        <item name="actionModeCopyDrawable">@android:drawable/ic_menu_copy_light</item>
-        <item name="actionModePasteDrawable">@android:drawable/ic_menu_paste_light</item>
+        <item name="actionModeCutDrawable">@android:drawable/ic_menu_cut_holo_light</item>
+        <item name="actionModeCopyDrawable">@android:drawable/ic_menu_copy_holo_light</item>
+        <item name="actionModePasteDrawable">@android:drawable/ic_menu_paste_holo_light</item>
+        <item name="actionModeShareDrawable">@android:drawable/ic_menu_share_holo_light</item>
+        <item name="actionModeFindDrawable">@android:drawable/ic_menu_find_holo_light</item>
+        <item name="actionModeWebSearchDrawable">@android:drawable/ic_menu_search_holo_light</item>
         <item name="actionModeBackground">@android:drawable/cab_background_light</item>
 
         <!-- SearchView attributes -->
         <item name="searchDropdownBackground">@android:drawable/search_dropdown_light</item>
+        <item name="searchViewTextField">@drawable/textfield_searchview_holo_light</item>
+        <item name="searchViewTextFieldRight">@drawable/textfield_searchview_right_holo_light</item>
         <item name="searchViewCloseIcon">@android:drawable/ic_clear_holo_light</item>
         <item name="searchViewSearchIcon">@android:drawable/ic_search_api_holo_light</item>
         <item name="searchViewGoIcon">@android:drawable/ic_go_search_api_holo_light</item>
@@ -994,6 +1004,13 @@
         <item name="actionBarSize">56dip</item>
         <item name="actionModePopupWindowStyle">@android:style/Widget.Holo.PopupWindow.ActionMode</item>
 
+        <item name="actionModeCutDrawable">@android:drawable/ic_menu_cut_holo_dark</item>
+        <item name="actionModeCopyDrawable">@android:drawable/ic_menu_copy_holo_dark</item>
+        <item name="actionModePasteDrawable">@android:drawable/ic_menu_paste_holo_dark</item>
+        <item name="actionModeShareDrawable">@android:drawable/ic_menu_share_holo_dark</item>
+        <item name="actionModeFindDrawable">@android:drawable/ic_menu_find_holo_dark</item>
+        <item name="actionModeWebSearchDrawable">@android:drawable/ic_menu_search_holo_dark</item>
+
         <item name="dividerVertical">?android:attr/listDivider</item>
         <item name="dividerHorizontal">?android:attr/listDivider</item>
         <item name="buttonBarStyle">@android:style/Holo.ButtonBar</item>
@@ -1270,6 +1287,13 @@
         <item name="actionBarSize">56dip</item>
         <item name="actionModePopupWindowStyle">@android:style/Widget.Holo.Light.PopupWindow.ActionMode</item>
 
+        <item name="actionModeCutDrawable">@android:drawable/ic_menu_cut_holo_light</item>
+        <item name="actionModeCopyDrawable">@android:drawable/ic_menu_copy_holo_light</item>
+        <item name="actionModePasteDrawable">@android:drawable/ic_menu_paste_holo_light</item>
+        <item name="actionModeShareDrawable">@android:drawable/ic_menu_share_holo_light</item>
+        <item name="actionModeFindDrawable">@android:drawable/ic_menu_find_holo_light</item>
+        <item name="actionModeWebSearchDrawable">@android:drawable/ic_menu_search_holo_light</item>
+
         <item name="dividerVertical">?android:attr/listDivider</item>
         <item name="dividerHorizontal">?android:attr/listDivider</item>
         <item name="buttonBarStyle">@android:style/Holo.Light.ButtonBar</item>
diff --git a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/ConnectivityManagerStressTestRunner.java b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/ConnectivityManagerStressTestRunner.java
index 5b76e39..d23dfd3 100644
--- a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/ConnectivityManagerStressTestRunner.java
+++ b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/ConnectivityManagerStressTestRunner.java
@@ -19,6 +19,7 @@
 import android.os.Bundle;
 import android.test.InstrumentationTestRunner;
 import android.test.InstrumentationTestSuite;
+
 import com.android.connectivitymanagertest.stress.WifiApStress;
 import com.android.connectivitymanagertest.stress.WifiStressTest;
 
@@ -44,8 +45,13 @@
     @Override
     public TestSuite getAllTests() {
         TestSuite suite = new InstrumentationTestSuite(this);
-        suite.addTestSuite(WifiApStress.class);
-        suite.addTestSuite(WifiStressTest.class);
+        if (!UtilHelper.isWifiOnly()) {
+            suite.addTestSuite(WifiApStress.class);
+            suite.addTestSuite(WifiStressTest.class);
+        } else {
+            // only the wifi stress tests
+            suite.addTestSuite(WifiStressTest.class);
+        }
         return suite;
     }
 
@@ -57,11 +63,13 @@
     @Override
     public void onCreate(Bundle icicle) {
         super.onCreate(icicle);
-        String valueStr = (String) icicle.get("softap_iterations");
-        if (valueStr != null) {
-            int iteration = Integer.parseInt(valueStr);
-            if (iteration > 0) {
-                mSoftapIterations = iteration;
+        if (!UtilHelper.isWifiOnly()) {
+            String valueStr = (String) icicle.get("softap_iterations");
+            if (valueStr != null) {
+                int iteration = Integer.parseInt(valueStr);
+                if (iteration > 0) {
+                    mSoftapIterations = iteration;
+                }
             }
         }
 
diff --git a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/ConnectivityManagerTestRunner.java b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/ConnectivityManagerTestRunner.java
index 3d4dc3d..20aae47 100644
--- a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/ConnectivityManagerTestRunner.java
+++ b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/ConnectivityManagerTestRunner.java
@@ -19,7 +19,7 @@
 import android.os.Bundle;
 import android.test.InstrumentationTestRunner;
 import android.test.InstrumentationTestSuite;
-import android.util.Log;
+
 import com.android.connectivitymanagertest.functional.ConnectivityManagerMobileTest;
 import com.android.connectivitymanagertest.functional.WifiConnectionTest;
 
@@ -35,10 +35,24 @@
  */
 
 public class ConnectivityManagerTestRunner extends InstrumentationTestRunner {
+    public String TEST_SSID = null;
+
     @Override
     public TestSuite getAllTests() {
         TestSuite suite = new InstrumentationTestSuite(this);
-        suite.addTestSuite(ConnectivityManagerMobileTest.class);
+        if (!UtilHelper.isWifiOnly()) {
+            suite.addTestSuite(ConnectivityManagerMobileTest.class);
+        } else {
+            // create a new test suite
+            suite.setName("ConnectivityManagerWifiOnlyFunctionalTests");
+            String[] methodNames = {"testConnectToWifi", "testConnectToWifWithKnownAP",
+                    "testDisconnectWifi", "testDataConnectionOverAMWithWifi",
+                    "testDataConnectionWithWifiToAMToWifi", "testWifiStateChange"};
+            Class<ConnectivityManagerMobileTest> testClass = ConnectivityManagerMobileTest.class;
+            for (String method: methodNames) {
+                suite.addTest(TestSuite.createTest(testClass, method));
+            }
+        }
         suite.addTestSuite(WifiConnectionTest.class);
         return suite;
     }
@@ -56,6 +70,4 @@
             TEST_SSID = testSSID;
         }
     }
-
-    public String TEST_SSID = null;
 }
diff --git a/core/java/android/nfc/INfcSecureElement.aidl b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/UtilHelper.java
old mode 100755
new mode 100644
similarity index 64%
rename from core/java/android/nfc/INfcSecureElement.aidl
rename to core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/UtilHelper.java
index aa98dd2..1b966bf
--- a/core/java/android/nfc/INfcSecureElement.aidl
+++ b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/UtilHelper.java
@@ -14,15 +14,14 @@
  * limitations under the License.
  */
 
-package android.nfc;
+package com.android.connectivitymanagertest;
 
-/**
- * {@hide}
- */
-interface INfcSecureElement {
-    int openSecureElementConnection();
-    int closeSecureElementConnection(int nativeHandle);
-    byte[] exchangeAPDU(int nativeHandle, in byte[] data);
-    int[] getSecureElementTechList(int nativeHandle);
-    byte[] getSecureElementUid(int nativeHandle);
-}
\ No newline at end of file
+import android.os.SystemProperties;
+
+public class UtilHelper {
+    public static boolean isWifiOnly() {
+        return "wifi-only".equals(SystemProperties.get("ro.carrier"));
+    }
+
+
+}
diff --git a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/functional/ConnectivityManagerMobileTest.java b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/functional/ConnectivityManagerMobileTest.java
index b87021a..d9b770a 100644
--- a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/functional/ConnectivityManagerMobileTest.java
+++ b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/functional/ConnectivityManagerMobileTest.java
@@ -17,6 +17,7 @@
 package com.android.connectivitymanagertest.functional;
 
 import com.android.connectivitymanagertest.ConnectivityManagerTestActivity;
+import com.android.connectivitymanagertest.UtilHelper;
 
 import android.content.Intent;
 import android.content.Context;
@@ -48,7 +49,7 @@
     private WakeLock wl;
 
     public ConnectivityManagerMobileTest() {
-        super(PKG_NAME, ConnectivityManagerTestActivity.class);
+        super(ConnectivityManagerTestActivity.class);
     }
 
     @Override
@@ -68,13 +69,15 @@
             Log.v(LOG_TAG, "airplane is not disabled, disable it.");
             cmActivity.setAirplaneMode(getInstrumentation().getContext(), false);
         }
-        if (!cmActivity.waitForNetworkState(ConnectivityManager.TYPE_MOBILE, State.CONNECTED,
-                ConnectivityManagerTestActivity.LONG_TIMEOUT)) {
-            // Note: When the test fails in setUp(), tearDown is not called. In that case,
-            // the activity is destroyed which blocks the next test at "getActivity()".
-            // tearDown() is called here to avoid that situation.
-            tearDown();
-            fail("Device is not connected to Mobile, setUp failed");
+        if (!UtilHelper.isWifiOnly()) {
+            if (!cmActivity.waitForNetworkState(ConnectivityManager.TYPE_MOBILE, State.CONNECTED,
+                    ConnectivityManagerTestActivity.LONG_TIMEOUT)) {
+                // Note: When the test fails in setUp(), tearDown is not called. In that case,
+                // the activity is destroyed which blocks the next test at "getActivity()".
+                // tearDown() is called here to avoid that situation.
+                tearDown();
+                fail("Device is not connected to Mobile, setUp failed");
+            }
         }
     }
 
@@ -128,8 +131,8 @@
         // As Wifi stays in DISCONNETED, Mobile statys in CONNECTED,
         // the connectivity manager will not broadcast any network connectivity event for Wifi
         NetworkInfo networkInfo = cmActivity.mCM.getNetworkInfo(ConnectivityManager.TYPE_MOBILE);
-        cmActivity.setStateTransitionCriteria(ConnectivityManager.TYPE_MOBILE, networkInfo.getState(),
-                NetworkState.DO_NOTHING, State.CONNECTED);
+        cmActivity.setStateTransitionCriteria(ConnectivityManager.TYPE_MOBILE,
+                networkInfo.getState(), NetworkState.DO_NOTHING, State.CONNECTED);
         networkInfo = cmActivity.mCM.getNetworkInfo(ConnectivityManager.TYPE_WIFI);
         cmActivity.setStateTransitionCriteria(ConnectivityManager.TYPE_WIFI, networkInfo.getState(),
                 NetworkState.DO_NOTHING, State.DISCONNECTED);
@@ -162,10 +165,13 @@
     @LargeTest
     public void testConnectToWifi() {
         assertNotNull("SSID is null", TEST_ACCESS_POINT);
-        //Prepare for connectivity verification
-        NetworkInfo networkInfo = cmActivity.mCM.getNetworkInfo(ConnectivityManager.TYPE_MOBILE);
-        cmActivity.setStateTransitionCriteria(ConnectivityManager.TYPE_MOBILE, networkInfo.getState(),
-                NetworkState.TO_DISCONNECTION, State.DISCONNECTED);
+        NetworkInfo networkInfo;
+        if (!UtilHelper.isWifiOnly()) {
+            //Prepare for connectivity verification
+            networkInfo = cmActivity.mCM.getNetworkInfo(ConnectivityManager.TYPE_MOBILE);
+            cmActivity.setStateTransitionCriteria(ConnectivityManager.TYPE_MOBILE,
+                    networkInfo.getState(), NetworkState.TO_DISCONNECTION, State.DISCONNECTED);
+        }
         networkInfo = cmActivity.mCM.getNetworkInfo(ConnectivityManager.TYPE_WIFI);
         cmActivity.setStateTransitionCriteria(ConnectivityManager.TYPE_WIFI, networkInfo.getState(),
                 NetworkState.TO_CONNECTION, State.CONNECTED);
@@ -179,8 +185,10 @@
         Log.v(LOG_TAG, "wifi state is enabled");
         assertTrue(cmActivity.waitForNetworkState(ConnectivityManager.TYPE_WIFI, State.CONNECTED,
                 ConnectivityManagerTestActivity.LONG_TIMEOUT));
-        assertTrue(cmActivity.waitForNetworkState(ConnectivityManager.TYPE_MOBILE, State.DISCONNECTED,
-                ConnectivityManagerTestActivity.LONG_TIMEOUT));
+        if (!UtilHelper.isWifiOnly()) {
+            assertTrue(cmActivity.waitForNetworkState(ConnectivityManager.TYPE_MOBILE,
+                    State.DISCONNECTED, ConnectivityManagerTestActivity.LONG_TIMEOUT));
+        }
 
         // validate states
         if (!cmActivity.validateNetworkStates(ConnectivityManager.TYPE_WIFI)) {
@@ -189,11 +197,13 @@
                     cmActivity.getTransitionFailureReason(ConnectivityManager.TYPE_WIFI));
             assertTrue(false);
         }
-        if (!cmActivity.validateNetworkStates(ConnectivityManager.TYPE_MOBILE)) {
-            Log.v(LOG_TAG, "Mobile state transition validation failed.");
-            Log.v(LOG_TAG, "reason: " +
-                    cmActivity.getTransitionFailureReason(ConnectivityManager.TYPE_MOBILE));
-            assertTrue(false);
+        if (!UtilHelper.isWifiOnly()) {
+            if (!cmActivity.validateNetworkStates(ConnectivityManager.TYPE_MOBILE)) {
+                Log.v(LOG_TAG, "Mobile state transition validation failed.");
+                Log.v(LOG_TAG, "reason: " +
+                        cmActivity.getTransitionFailureReason(ConnectivityManager.TYPE_MOBILE));
+                assertTrue(false);
+            }
         }
     }
 
@@ -225,16 +235,21 @@
         // Wait for the Wifi state to be DISABLED
         assertTrue(cmActivity.waitForWifiState(WifiManager.WIFI_STATE_DISABLED,
                 ConnectivityManagerTestActivity.LONG_TIMEOUT));
-        assertTrue(cmActivity.waitForNetworkState(ConnectivityManager.TYPE_WIFI, State.DISCONNECTED,
-                ConnectivityManagerTestActivity.LONG_TIMEOUT));
-        assertTrue(cmActivity.waitForNetworkState(ConnectivityManager.TYPE_MOBILE, State.CONNECTED,
-                ConnectivityManagerTestActivity.LONG_TIMEOUT));
+        assertTrue(cmActivity.waitForNetworkState(ConnectivityManager.TYPE_WIFI,
+                State.DISCONNECTED, ConnectivityManagerTestActivity.LONG_TIMEOUT));
+        if (!UtilHelper.isWifiOnly()) {
+            assertTrue(cmActivity.waitForNetworkState(ConnectivityManager.TYPE_MOBILE,
+                    State.CONNECTED, ConnectivityManagerTestActivity.LONG_TIMEOUT));
+        }
 
-        //Prepare for connectivity state verification
-        NetworkInfo networkInfo = cmActivity.mCM.getNetworkInfo(ConnectivityManager.TYPE_MOBILE);
-        cmActivity.setStateTransitionCriteria(ConnectivityManager.TYPE_MOBILE,
-                                              networkInfo.getState(), NetworkState.DO_NOTHING,
-                                              State.DISCONNECTED);
+        NetworkInfo networkInfo;
+        if (!UtilHelper.isWifiOnly()) {
+            //Prepare for connectivity state verification
+            networkInfo = cmActivity.mCM.getNetworkInfo(ConnectivityManager.TYPE_MOBILE);
+            cmActivity.setStateTransitionCriteria(ConnectivityManager.TYPE_MOBILE,
+                                                  networkInfo.getState(), NetworkState.DO_NOTHING,
+                                                  State.DISCONNECTED);
+        }
         networkInfo = cmActivity.mCM.getNetworkInfo(ConnectivityManager.TYPE_WIFI);
         cmActivity.setStateTransitionCriteria(ConnectivityManager.TYPE_WIFI, networkInfo.getState(),
                 NetworkState.TO_CONNECTION, State.CONNECTED);
@@ -246,8 +261,10 @@
         // Wait for Wifi to be connected and mobile to be disconnected
         assertTrue(cmActivity.waitForNetworkState(ConnectivityManager.TYPE_WIFI, State.CONNECTED,
                 ConnectivityManagerTestActivity.LONG_TIMEOUT));
-        assertTrue(cmActivity.waitForNetworkState(ConnectivityManager.TYPE_MOBILE, State.DISCONNECTED,
-                ConnectivityManagerTestActivity.LONG_TIMEOUT));
+        if (!UtilHelper.isWifiOnly()) {
+            assertTrue(cmActivity.waitForNetworkState(ConnectivityManager.TYPE_MOBILE,
+                    State.DISCONNECTED, ConnectivityManagerTestActivity.LONG_TIMEOUT));
+        }
 
         // validate wifi states
         if (!cmActivity.validateNetworkStates(ConnectivityManager.TYPE_WIFI)) {
@@ -277,11 +294,14 @@
             Log.v(LOG_TAG, "exception: " + e.toString());
         }
 
-        NetworkInfo networkInfo = cmActivity.mCM.getNetworkInfo(ConnectivityManager.TYPE_MOBILE);
-        cmActivity.setStateTransitionCriteria(ConnectivityManager.TYPE_MOBILE,
-                                              networkInfo.getState(),
-                                              NetworkState.TO_CONNECTION,
-                                              State.CONNECTED);
+        NetworkInfo networkInfo;
+        if (!UtilHelper.isWifiOnly()) {
+            networkInfo = cmActivity.mCM.getNetworkInfo(ConnectivityManager.TYPE_MOBILE);
+            cmActivity.setStateTransitionCriteria(ConnectivityManager.TYPE_MOBILE,
+                                                  networkInfo.getState(),
+                                                  NetworkState.TO_CONNECTION,
+                                                  State.CONNECTED);
+        }
         networkInfo = cmActivity.mCM.getNetworkInfo(ConnectivityManager.TYPE_WIFI);
         cmActivity.setStateTransitionCriteria(ConnectivityManager.TYPE_WIFI, networkInfo.getState(),
                 NetworkState.TO_DISCONNECTION, State.DISCONNECTED);
@@ -291,8 +311,10 @@
 
         assertTrue(cmActivity.waitForNetworkState(ConnectivityManager.TYPE_WIFI, State.DISCONNECTED,
                 ConnectivityManagerTestActivity.LONG_TIMEOUT));
-        assertTrue(cmActivity.waitForNetworkState(ConnectivityManager.TYPE_MOBILE, State.CONNECTED,
-                ConnectivityManagerTestActivity.LONG_TIMEOUT));
+        if (!UtilHelper.isWifiOnly()) {
+            assertTrue(cmActivity.waitForNetworkState(ConnectivityManager.TYPE_MOBILE,
+                    State.CONNECTED, ConnectivityManagerTestActivity.LONG_TIMEOUT));
+        }
 
         // validate states
         if (!cmActivity.validateNetworkStates(ConnectivityManager.TYPE_WIFI)) {
@@ -301,11 +323,13 @@
                     cmActivity.getTransitionFailureReason(ConnectivityManager.TYPE_WIFI));
             assertTrue(false);
         }
-        if (!cmActivity.validateNetworkStates(ConnectivityManager.TYPE_MOBILE)) {
-            Log.v(LOG_TAG, "Mobile state transition validation failed.");
-            Log.v(LOG_TAG, "reason: " +
-                    cmActivity.getTransitionFailureReason(ConnectivityManager.TYPE_MOBILE));
-            assertTrue(false);
+        if (!UtilHelper.isWifiOnly()) {
+            if (!cmActivity.validateNetworkStates(ConnectivityManager.TYPE_MOBILE)) {
+                Log.v(LOG_TAG, "Mobile state transition validation failed.");
+                Log.v(LOG_TAG, "reason: " +
+                        cmActivity.getTransitionFailureReason(ConnectivityManager.TYPE_MOBILE));
+                assertTrue(false);
+            }
         }
     }
 
@@ -377,14 +401,16 @@
         // Eanble airplane mode
         cmActivity.setAirplaneMode(getInstrumentation().getContext(), true);
 
-        assertTrue(cmActivity.waitForNetworkState(ConnectivityManager.TYPE_MOBILE, State.DISCONNECTED,
-                ConnectivityManagerTestActivity.LONG_TIMEOUT));
-
-        NetworkInfo networkInfo = cmActivity.mCM.getNetworkInfo(ConnectivityManager.TYPE_MOBILE);
-        cmActivity.setStateTransitionCriteria(ConnectivityManager.TYPE_MOBILE,
-                                              networkInfo.getState(),
-                                              NetworkState.DO_NOTHING,
-                                              State.DISCONNECTED);
+        NetworkInfo networkInfo;
+        if (!UtilHelper.isWifiOnly()) {
+            assertTrue(cmActivity.waitForNetworkState(ConnectivityManager.TYPE_MOBILE,
+                    State.DISCONNECTED, ConnectivityManagerTestActivity.LONG_TIMEOUT));
+            networkInfo = cmActivity.mCM.getNetworkInfo(ConnectivityManager.TYPE_MOBILE);
+            cmActivity.setStateTransitionCriteria(ConnectivityManager.TYPE_MOBILE,
+                                                  networkInfo.getState(),
+                                                  NetworkState.DO_NOTHING,
+                                                  State.DISCONNECTED);
+        }
         networkInfo = cmActivity.mCM.getNetworkInfo(ConnectivityManager.TYPE_WIFI);
         cmActivity.setStateTransitionCriteria(ConnectivityManager.TYPE_WIFI, networkInfo.getState(),
                                               NetworkState.TO_CONNECTION, State.CONNECTED);
@@ -402,11 +428,13 @@
                     cmActivity.getTransitionFailureReason(ConnectivityManager.TYPE_WIFI));
             assertTrue("State validation failed", false);
         }
-        if (!cmActivity.validateNetworkStates(ConnectivityManager.TYPE_MOBILE)) {
-            Log.v(LOG_TAG, "state validation for Mobile failed");
-            Log.v(LOG_TAG, "reason: " +
-                    cmActivity.getTransitionFailureReason(ConnectivityManager.TYPE_MOBILE));
-            assertTrue("state validation failed", false);
+        if (!UtilHelper.isWifiOnly()) {
+            if (!cmActivity.validateNetworkStates(ConnectivityManager.TYPE_MOBILE)) {
+                Log.v(LOG_TAG, "state validation for Mobile failed");
+                Log.v(LOG_TAG, "reason: " +
+                        cmActivity.getTransitionFailureReason(ConnectivityManager.TYPE_MOBILE));
+                assertTrue("state validation failed", false);
+            }
         }
         cmActivity.setAirplaneMode(getInstrumentation().getContext(), false);
     }
@@ -452,8 +480,10 @@
 
         assertTrue(cmActivity.waitForNetworkState(ConnectivityManager.TYPE_WIFI, State.CONNECTED,
                             ConnectivityManagerTestActivity.LONG_TIMEOUT));
-        assertTrue(cmActivity.waitForNetworkState(ConnectivityManager.TYPE_MOBILE, State.DISCONNECTED,
-                            ConnectivityManagerTestActivity.LONG_TIMEOUT));
+        if (!UtilHelper.isWifiOnly()) {
+            assertTrue(cmActivity.waitForNetworkState(ConnectivityManager.TYPE_MOBILE,
+                    State.DISCONNECTED, ConnectivityManagerTestActivity.LONG_TIMEOUT));
+        }
 
         // validate the state transition
         if (!cmActivity.validateNetworkStates(ConnectivityManager.TYPE_WIFI)) {
diff --git a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/stress/WifiStressTest.java b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/stress/WifiStressTest.java
index 2f2a283..7578e67 100644
--- a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/stress/WifiStressTest.java
+++ b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/stress/WifiStressTest.java
@@ -18,6 +18,7 @@
 
 import com.android.connectivitymanagertest.ConnectivityManagerStressTestRunner;
 import com.android.connectivitymanagertest.ConnectivityManagerTestActivity;
+import com.android.connectivitymanagertest.UtilHelper;
 
 import android.content.Context;
 import android.net.ConnectivityManager;
@@ -264,18 +265,22 @@
             assertTrue("Wait for Wi-Fi to idle timeout",
                     mAct.waitForNetworkState(ConnectivityManager.TYPE_WIFI, State.DISCONNECTED,
                     6 * ConnectivityManagerTestActivity.SHORT_TIMEOUT));
-            // use long timeout as the pppd startup may take several retries.
-            assertTrue("Wait for cellular connection timeout",
-                    mAct.waitForNetworkState(ConnectivityManager.TYPE_MOBILE, State.CONNECTED,
-                    ConnectivityManagerTestActivity.LONG_TIMEOUT));
+            if (!UtilHelper.isWifiOnly()) {
+                // use long timeout as the pppd startup may take several retries.
+                assertTrue("Wait for cellular connection timeout",
+                        mAct.waitForNetworkState(ConnectivityManager.TYPE_MOBILE, State.CONNECTED,
+                        ConnectivityManagerTestActivity.LONG_TIMEOUT));
+            }
             sleep(mWifiSleepTime + WIFI_IDLE_DELAY, "Interrupted while device is in sleep mode");
             // Verify the wi-fi is still off and data connection is on
             assertEquals("Wi-Fi is reconnected", State.DISCONNECTED,
                     mAct.mCM.getNetworkInfo(ConnectivityManager.TYPE_WIFI).getState());
-            assertEquals("Cellular connection is down", State.CONNECTED,
-                    mAct.mCM.getNetworkInfo(ConnectivityManager.TYPE_MOBILE).getState());
 
-            assertTrue("Mobile is connected, but no data connection.", mAct.pingTest(null));
+            if (!UtilHelper.isWifiOnly()) {
+                assertEquals("Cellular connection is down", State.CONNECTED,
+                             mAct.mCM.getNetworkInfo(ConnectivityManager.TYPE_MOBILE).getState());
+                assertTrue("Mobile is connected, but no data connection.", mAct.pingTest(null));
+            }
 
             // Turn screen on again
             mAct.turnScreenOn();
diff --git a/core/tests/coretests/src/android/bluetooth/BluetoothStressTest.java b/core/tests/coretests/src/android/bluetooth/BluetoothStressTest.java
index 5dedd4a..7f13791 100644
--- a/core/tests/coretests/src/android/bluetooth/BluetoothStressTest.java
+++ b/core/tests/coretests/src/android/bluetooth/BluetoothStressTest.java
@@ -60,6 +60,7 @@
         }
 
         BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
+        mTestUtils.disable(adapter);
 
         for (int i = 0; i < iterations; i++) {
             mTestUtils.writeOutput("enable iteration " + (i + 1) + " of " + iterations);
@@ -78,7 +79,9 @@
         }
 
         BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
+        mTestUtils.disable(adapter);
         mTestUtils.enable(adapter);
+        mTestUtils.undiscoverable(adapter);
 
         for (int i = 0; i < iterations; i++) {
             mTestUtils.writeOutput("discoverable iteration " + (i + 1) + " of " + iterations);
@@ -99,7 +102,9 @@
         }
 
         BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
+        mTestUtils.disable(adapter);
         mTestUtils.enable(adapter);
+        mTestUtils.stopScan(adapter);
 
         for (int i = 0; i < iterations; i++) {
             mTestUtils.writeOutput("scan iteration " + (i + 1) + " of " + iterations);
@@ -116,7 +121,9 @@
     public void testEnablePan() {
         int iterations = BluetoothTestRunner.sEnablePanIterations;
         BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
+        mTestUtils.disable(adapter);
         mTestUtils.enable(adapter);
+        mTestUtils.disablePan(adapter);
 
         for (int i = 0; i < iterations; i++) {
             mTestUtils.writeOutput("testEnablePan iteration " + (i + 1) + " of "
@@ -141,13 +148,15 @@
         }
 
         BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
-        BluetoothDevice device = adapter.getRemoteDevice(BluetoothTestRunner.sPairAddress);
+        BluetoothDevice device = adapter.getRemoteDevice(BluetoothTestRunner.sDeviceAddress);
+        mTestUtils.disable(adapter);
         mTestUtils.enable(adapter);
+        mTestUtils.unpair(adapter, device);
 
         for (int i = 0; i < iterations; i++) {
             mTestUtils.writeOutput("pair iteration " + (i + 1) + " of " + iterations);
-            mTestUtils.pair(adapter, device, BluetoothTestRunner.sPairPasskey,
-                    BluetoothTestRunner.sPairPin);
+            mTestUtils.pair(adapter, device, BluetoothTestRunner.sDevicePairPasskey,
+                    BluetoothTestRunner.sDevicePairPin);
             mTestUtils.unpair(adapter, device);
         }
         mTestUtils.disable(adapter);
@@ -162,13 +171,15 @@
     public void testAcceptPair() {
         int iterations = BluetoothTestRunner.sPairIterations;
         BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
-        BluetoothDevice device = adapter.getRemoteDevice(BluetoothTestRunner.sPairAddress);
+        BluetoothDevice device = adapter.getRemoteDevice(BluetoothTestRunner.sDeviceAddress);
+        mTestUtils.disable(adapter);
         mTestUtils.enable(adapter);
+        mTestUtils.unpair(adapter, device);
 
         for (int i = 0; i < iterations; i++) {
             mTestUtils.writeOutput("acceptPair iteration " + (i + 1) + " of " + iterations);
-            mTestUtils.acceptPair(adapter, device, BluetoothTestRunner.sPairPasskey,
-                    BluetoothTestRunner.sPairPin);
+            mTestUtils.acceptPair(adapter, device, BluetoothTestRunner.sDevicePairPasskey,
+                    BluetoothTestRunner.sDevicePairPin);
             mTestUtils.unpair(adapter, device);
         }
         mTestUtils.disable(adapter);
@@ -187,15 +198,20 @@
         }
 
         BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
-        BluetoothDevice device = adapter.getRemoteDevice(BluetoothTestRunner.sA2dpAddress);
+        BluetoothDevice device = adapter.getRemoteDevice(BluetoothTestRunner.sDeviceAddress);
+        mTestUtils.disable(adapter);
         mTestUtils.enable(adapter);
-        mTestUtils.pair(adapter, device, BluetoothTestRunner.sPairPasskey,
-                BluetoothTestRunner.sPairPin);
+        mTestUtils.unpair(adapter, device);
+        mTestUtils.pair(adapter, device, BluetoothTestRunner.sDevicePairPasskey,
+                BluetoothTestRunner.sDevicePairPin);
+        mTestUtils.disconnectProfile(adapter, device, BluetoothProfile.A2DP, null);
 
         for (int i = 0; i < iterations; i++) {
             mTestUtils.writeOutput("connectA2dp iteration " + (i + 1) + " of " + iterations);
-            mTestUtils.connectProfile(adapter, device, BluetoothProfile.A2DP);
-            mTestUtils.disconnectProfile(adapter, device, BluetoothProfile.A2DP);
+            mTestUtils.connectProfile(adapter, device, BluetoothProfile.A2DP,
+                    String.format("connectA2dp(device=%s)", device));
+            mTestUtils.disconnectProfile(adapter, device, BluetoothProfile.A2DP,
+                    String.format("disconnectA2dp(device=%s)", device));
         }
 
         mTestUtils.unpair(adapter, device);
@@ -215,15 +231,20 @@
         }
 
         BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
-        BluetoothDevice device = adapter.getRemoteDevice(BluetoothTestRunner.sHeadsetAddress);
+        BluetoothDevice device = adapter.getRemoteDevice(BluetoothTestRunner.sDeviceAddress);
+        mTestUtils.disable(adapter);
         mTestUtils.enable(adapter);
-        mTestUtils.pair(adapter, device, BluetoothTestRunner.sPairPasskey,
-                BluetoothTestRunner.sPairPin);
+        mTestUtils.unpair(adapter, device);
+        mTestUtils.pair(adapter, device, BluetoothTestRunner.sDevicePairPasskey,
+                BluetoothTestRunner.sDevicePairPin);
+        mTestUtils.disconnectProfile(adapter, device, BluetoothProfile.HEADSET, null);
 
         for (int i = 0; i < iterations; i++) {
             mTestUtils.writeOutput("connectHeadset iteration " + (i + 1) + " of " + iterations);
-            mTestUtils.connectProfile(adapter, device, BluetoothProfile.HEADSET);
-            mTestUtils.disconnectProfile(adapter, device, BluetoothProfile.HEADSET);
+            mTestUtils.connectProfile(adapter, device, BluetoothProfile.HEADSET,
+                    String.format("connectHeadset(device=%s)", device));
+            mTestUtils.disconnectProfile(adapter, device, BluetoothProfile.HEADSET,
+                    String.format("disconnectHeadset(device=%s)", device));
         }
 
         mTestUtils.unpair(adapter, device);
@@ -243,15 +264,20 @@
         }
 
         BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
-        BluetoothDevice device = adapter.getRemoteDevice(BluetoothTestRunner.sInputAddress);
+        BluetoothDevice device = adapter.getRemoteDevice(BluetoothTestRunner.sDeviceAddress);
+        mTestUtils.disable(adapter);
         mTestUtils.enable(adapter);
-        mTestUtils.pair(adapter, device, BluetoothTestRunner.sPairPasskey,
-                BluetoothTestRunner.sPairPin);
+        mTestUtils.unpair(adapter, device);
+        mTestUtils.pair(adapter, device, BluetoothTestRunner.sDevicePairPasskey,
+                BluetoothTestRunner.sDevicePairPin);
+        mTestUtils.disconnectProfile(adapter, device, BluetoothProfile.INPUT_DEVICE, null);
 
         for (int i = 0; i < iterations; i++) {
             mTestUtils.writeOutput("connectInput iteration " + (i + 1) + " of " + iterations);
-            mTestUtils.connectProfile(adapter, device, BluetoothProfile.INPUT_DEVICE);
-            mTestUtils.disconnectProfile(adapter, device, BluetoothProfile.INPUT_DEVICE);
+            mTestUtils.connectProfile(adapter, device, BluetoothProfile.INPUT_DEVICE,
+                    String.format("connectInput(device=%s)", device));
+            mTestUtils.disconnectProfile(adapter, device, BluetoothProfile.INPUT_DEVICE,
+                    String.format("disconnectInput(device=%s)", device));
         }
 
         mTestUtils.unpair(adapter, device);
@@ -271,10 +297,12 @@
         }
 
         BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
-        BluetoothDevice device = adapter.getRemoteDevice(BluetoothTestRunner.sPanAddress);
+        BluetoothDevice device = adapter.getRemoteDevice(BluetoothTestRunner.sDeviceAddress);
+        mTestUtils.disable(adapter);
         mTestUtils.enable(adapter);
-        mTestUtils.pair(adapter, device, BluetoothTestRunner.sPairPasskey,
-                BluetoothTestRunner.sPairPin);
+        mTestUtils.unpair(adapter, device);
+        mTestUtils.pair(adapter, device, BluetoothTestRunner.sDevicePairPasskey,
+                BluetoothTestRunner.sDevicePairPin);
 
         for (int i = 0; i < iterations; i++) {
             mTestUtils.writeOutput("connectPan iteration " + (i + 1) + " of " + iterations);
@@ -299,11 +327,14 @@
         }
 
         BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
-        BluetoothDevice device = adapter.getRemoteDevice(BluetoothTestRunner.sPanAddress);
+        BluetoothDevice device = adapter.getRemoteDevice(BluetoothTestRunner.sDeviceAddress);
+        mTestUtils.disable(adapter);
         mTestUtils.enable(adapter);
+        mTestUtils.disablePan(adapter);
         mTestUtils.enablePan(adapter);
-        mTestUtils.acceptPair(adapter, device, BluetoothTestRunner.sPairPasskey,
-                BluetoothTestRunner.sPairPin);
+        mTestUtils.unpair(adapter, device);
+        mTestUtils.acceptPair(adapter, device, BluetoothTestRunner.sDevicePairPasskey,
+                BluetoothTestRunner.sDevicePairPin);
 
         for (int i = 0; i < iterations; i++) {
             mTestUtils.writeOutput("incomingPanConnection iteration " + (i + 1) + " of "
@@ -330,11 +361,15 @@
         }
 
         BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
-        BluetoothDevice device = adapter.getRemoteDevice(BluetoothTestRunner.sHeadsetAddress);
+        BluetoothDevice device = adapter.getRemoteDevice(BluetoothTestRunner.sDeviceAddress);
+        mTestUtils.disable(adapter);
         mTestUtils.enable(adapter);
-        mTestUtils.pair(adapter, device, BluetoothTestRunner.sPairPasskey,
-                BluetoothTestRunner.sPairPin);
-        mTestUtils.connectProfile(adapter, device, BluetoothProfile.HEADSET);
+        mTestUtils.unpair(adapter, device);
+        mTestUtils.pair(adapter, device, BluetoothTestRunner.sDevicePairPasskey,
+                BluetoothTestRunner.sDevicePairPin);
+        mTestUtils.disconnectProfile(adapter, device, BluetoothProfile.HEADSET, null);
+        mTestUtils.connectProfile(adapter, device, BluetoothProfile.HEADSET, null);
+        mTestUtils.stopSco(adapter, device);
 
         for (int i = 0; i < iterations; i++) {
             mTestUtils.writeOutput("startStopSco iteration " + (i + 1) + " of " + iterations);
@@ -342,7 +377,7 @@
             mTestUtils.stopSco(adapter, device);
         }
 
-        mTestUtils.disconnectProfile(adapter, device, BluetoothProfile.HEADSET);
+        mTestUtils.disconnectProfile(adapter, device, BluetoothProfile.HEADSET, null);
         mTestUtils.unpair(adapter, device);
         mTestUtils.disable(adapter);
     }
diff --git a/core/tests/coretests/src/android/bluetooth/BluetoothTestRunner.java b/core/tests/coretests/src/android/bluetooth/BluetoothTestRunner.java
index 1febc5c..64d2c12 100644
--- a/core/tests/coretests/src/android/bluetooth/BluetoothTestRunner.java
+++ b/core/tests/coretests/src/android/bluetooth/BluetoothTestRunner.java
@@ -65,14 +65,9 @@
     public static int sConnectPanIterations = 100;
     public static int sStartStopScoIterations = 100;
 
-    public static String sPairAddress = "";
-    public static String sHeadsetAddress = "";
-    public static String sA2dpAddress = "";
-    public static String sInputAddress = "";
-    public static String sPanAddress = "";
-
-    public static byte[] sPairPin = {'1', '2', '3', '4'};
-    public static int sPairPasskey = 123456;
+    public static String sDeviceAddress = "";
+    public static byte[] sDevicePairPin = {'1', '2', '3', '4'};
+    public static int sDevicePairPasskey = 123456;
 
     @Override
     public TestSuite getAllTests() {
@@ -177,40 +172,24 @@
                 // Invalid argument, fall back to default value
             }
         }
-        val = arguments.getString("pair_address");
+
+        val = arguments.getString("device_address");
         if (val != null) {
-            sPairAddress = val;
+            sDeviceAddress = val;
         }
 
-        val = arguments.getString("headset_address");
+        val = arguments.getString("device_pair_pin");
         if (val != null) {
-            sHeadsetAddress = val;
+            byte[] pin = BluetoothDevice.convertPinToBytes(val);
+            if (pin != null) {
+                sDevicePairPin = pin;
+            }
         }
 
-        val = arguments.getString("a2dp_address");
-        if (val != null) {
-            sA2dpAddress = val;
-        }
-
-        val = arguments.getString("input_address");
-        if (val != null) {
-            sInputAddress = val;
-        }
-
-        val = arguments.getString("pan_address");
-        if (val != null) {
-            sPanAddress = val;
-        }
-
-        val = arguments.getString("pair_pin");
-        if (val != null) {
-            sPairPin = BluetoothDevice.convertPinToBytes(val);
-        }
-
-        val = arguments.getString("pair_passkey");
+        val = arguments.getString("device_pair_passkey");
         if (val != null) {
             try {
-                sPairPasskey = Integer.parseInt(val);
+                sDevicePairPasskey = Integer.parseInt(val);
             } catch (NumberFormatException e) {
                 // Invalid argument, fall back to default value
             }
@@ -225,13 +204,9 @@
         Log.i(TAG, String.format("connect_input_iterations=%d", sConnectInputIterations));
         Log.i(TAG, String.format("connect_pan_iterations=%d", sConnectPanIterations));
         Log.i(TAG, String.format("start_stop_sco_iterations=%d", sStartStopScoIterations));
-        Log.i(TAG, String.format("pair_address=%s", sPairAddress));
-        Log.i(TAG, String.format("a2dp_address=%s", sA2dpAddress));
-        Log.i(TAG, String.format("headset_address=%s", sHeadsetAddress));
-        Log.i(TAG, String.format("input_address=%s", sInputAddress));
-        Log.i(TAG, String.format("pan_address=%s", sPanAddress));
-        Log.i(TAG, String.format("pair_pin=%s", new String(sPairPin)));
-        Log.i(TAG, String.format("pair_passkey=%d", sPairPasskey));
+        Log.i(TAG, String.format("device_address=%s", sDeviceAddress));
+        Log.i(TAG, String.format("device_pair_pin=%s", new String(sDevicePairPin)));
+        Log.i(TAG, String.format("device_pair_passkey=%d", sDevicePairPasskey));
 
         // Call onCreate last since we want to set the static variables first.
         super.onCreate(arguments);
diff --git a/core/tests/coretests/src/android/bluetooth/BluetoothTestUtils.java b/core/tests/coretests/src/android/bluetooth/BluetoothTestUtils.java
index 1741119..f1dd8fe 100644
--- a/core/tests/coretests/src/android/bluetooth/BluetoothTestUtils.java
+++ b/core/tests/coretests/src/android/bluetooth/BluetoothTestUtils.java
@@ -37,44 +37,21 @@
 
 public class BluetoothTestUtils extends Assert {
 
-    /**
-     * Timeout for enable/disable in ms.
-     */
+    /** Timeout for enable/disable in ms. */
     private static final int ENABLE_DISABLE_TIMEOUT = 20000;
-
-    /**
-     * Timeout for discoverable/undiscoverable in ms.
-     */
+    /** Timeout for discoverable/undiscoverable in ms. */
     private static final int DISCOVERABLE_UNDISCOVERABLE_TIMEOUT = 5000;
-
-    /**
-     * Timeout for starting/stopping a scan in ms.
-     */
+    /** Timeout for starting/stopping a scan in ms. */
     private static final int START_STOP_SCAN_TIMEOUT = 5000;
-
-    /**
-     * Timeout for pair/unpair in ms.
-     */
+    /** Timeout for pair/unpair in ms. */
     private static final int PAIR_UNPAIR_TIMEOUT = 20000;
-
-    /**
-     * Timeout for connecting/disconnecting a profile in ms.
-     */
+    /** Timeout for connecting/disconnecting a profile in ms. */
     private static final int CONNECT_DISCONNECT_PROFILE_TIMEOUT = 20000;
-
-    /**
-     * Timeout to connect a profile proxy in ms.
-     */
-    private static final int CONNECT_PROXY_TIMEOUT = 5000;
-
-    /**
-     * Timeout to start or stop a SCO channel in ms.
-     */
+    /** Timeout to start or stop a SCO channel in ms. */
     private static final int START_STOP_SCO_TIMEOUT = 10000;
-
-    /**
-     * Time between polls in ms.
-     */
+    /** Timeout to connect a profile proxy in ms. */
+    private static final int CONNECT_PROXY_TIMEOUT = 5000;
+    /** Time between polls in ms. */
     private static final int POLL_TIME = 100;
 
     private abstract class FlagReceiver extends BroadcastReceiver {
@@ -249,6 +226,9 @@
                 case BluetoothProfile.INPUT_DEVICE:
                     mConnectionAction = BluetoothInputDevice.ACTION_CONNECTION_STATE_CHANGED;
                     break;
+                case BluetoothProfile.PAN:
+                    mConnectionAction = BluetoothPan.ACTION_CONNECTION_STATE_CHANGED;
+                    break;
                 default:
                     mConnectionAction = null;
             }
@@ -281,47 +261,22 @@
         }
     }
 
-    private class ConnectPanReceiver extends FlagReceiver {
-        private static final int STATE_DISCONNECTED_FLAG = 1;
-        private static final int STATE_CONNECTING_FLAG = 1 << 1;
-        private static final int STATE_CONNECTED_FLAG = 1 << 2;
-        private static final int STATE_DISCONNECTING_FLAG = 1 << 3;
-
-        private BluetoothDevice mDevice;
+    private class ConnectPanReceiver extends ConnectProfileReceiver {
         private int mRole;
 
         public ConnectPanReceiver(BluetoothDevice device, int role, int expectedFlags) {
-            super (expectedFlags);
+            super(device, BluetoothProfile.PAN, expectedFlags);
 
-            mDevice = device;
             mRole = role;
         }
 
         @Override
         public void onReceive(Context context, Intent intent) {
-            if (!mDevice.equals(intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE))
-                    || mRole != intent.getIntExtra(BluetoothPan.EXTRA_LOCAL_ROLE, -1)) {
+            if (mRole != intent.getIntExtra(BluetoothPan.EXTRA_LOCAL_ROLE, -1)) {
                 return;
             }
 
-            if (BluetoothPan.ACTION_CONNECTION_STATE_CHANGED.equals(intent.getAction())) {
-                int state = intent.getIntExtra(BluetoothPan.EXTRA_STATE, -1);
-                assertNotSame(-1, state);
-                switch (state) {
-                    case BluetoothPan.STATE_DISCONNECTED:
-                        setFiredFlag(STATE_DISCONNECTED_FLAG);
-                        break;
-                    case BluetoothPan.STATE_CONNECTING:
-                        setFiredFlag(STATE_CONNECTING_FLAG);
-                        break;
-                    case BluetoothPan.STATE_CONNECTED:
-                        setFiredFlag(STATE_CONNECTED_FLAG);
-                        break;
-                    case BluetoothPan.STATE_DISCONNECTING:
-                        setFiredFlag(STATE_DISCONNECTING_FLAG);
-                        break;
-                }
-            }
+            super.onReceive(context, intent);
         }
     }
 
@@ -353,6 +308,7 @@
 
     private BluetoothProfile.ServiceListener mServiceListener =
             new BluetoothProfile.ServiceListener() {
+        @Override
         public void onServiceConnected(int profile, BluetoothProfile proxy) {
             synchronized (this) {
                 switch (profile) {
@@ -372,6 +328,7 @@
             }
         }
 
+        @Override
         public void onServiceDisconnected(int profile) {
             synchronized (this) {
                 switch (profile) {
@@ -399,10 +356,10 @@
     private String mOutputFile;
 
     private Context mContext;
-    private BluetoothA2dp mA2dp;
-    private BluetoothHeadset mHeadset;
-    private BluetoothInputDevice mInput;
-    private BluetoothPan mPan;
+    private BluetoothA2dp mA2dp = null;
+    private BluetoothHeadset mHeadset = null;
+    private BluetoothInputDevice mInput = null;
+    private BluetoothPan mPan = null;
 
     /**
      * Creates a utility instance for testing Bluetooth.
@@ -818,10 +775,15 @@
             byte[] pin, boolean shouldPair) {
         int mask = PairReceiver.STATE_BONDING_FLAG | PairReceiver.STATE_BONDED_FLAG;
         long start = -1;
-        String methodName = shouldPair ? "pair()" : "acceptPair()";
+        String methodName;
+        if (shouldPair) {
+            methodName = String.format("pair(device=%s)", device);
+        } else {
+            methodName = String.format("acceptPair(device=%s)", device);
+        }
 
         if (!adapter.isEnabled()) {
-            fail(methodName + " bluetooth not enabled");
+            fail(String.format("%s bluetooth not enabled", methodName));
         }
 
         PairReceiver receiver = getPairReceiver(device, passkey, pin, mask);
@@ -843,8 +805,7 @@
                 return;
             default:
                 removeReceiver(receiver);
-                fail(String.format("%s invalid state: device=%s, state=%d", methodName, device,
-                        state));
+                fail(String.format("%s invalid state: state=%d", methodName, state));
         }
 
         long s = System.currentTimeMillis();
@@ -854,10 +815,10 @@
                 assertTrue(adapter.getBondedDevices().contains(device));
                 long finish = receiver.getCompletedTime();
                 if (start != -1 && finish != -1) {
-                    writeOutput(String.format("%s completed in %d ms: device=%s", methodName,
-                            (finish - start), device));
+                    writeOutput(String.format("%s completed in %d ms", methodName,
+                            (finish - start)));
                 } else {
-                    writeOutput(String.format("%s completed: device=%s", methodName, device));
+                    writeOutput(String.format("%s completed", methodName));
                 }
                 removeReceiver(receiver);
                 return;
@@ -867,9 +828,8 @@
 
         int firedFlags = receiver.getFiredFlags();
         removeReceiver(receiver);
-        fail(String.format("%s timeout: device=%s, state=%d (expected %d), "
-                + "flags=0x%x (expected 0x%x)", methodName, device, state,
-                BluetoothDevice.BOND_BONDED, firedFlags, mask));
+        fail(String.format("%s timeout: state=%d (expected %d), flags=0x%x (expected 0x%x)",
+                methodName, state, BluetoothDevice.BOND_BONDED, firedFlags, mask));
     }
 
     /**
@@ -882,9 +842,10 @@
     public void unpair(BluetoothAdapter adapter, BluetoothDevice device) {
         int mask = PairReceiver.STATE_NONE_FLAG;
         long start = -1;
+        String methodName = String.format("unpair(device=%s)", device);
 
         if (!adapter.isEnabled()) {
-            fail("unpair() bluetooth not enabled");
+            fail(String.format("%s bluetooth not enabled", methodName));
         }
 
         PairReceiver receiver = getPairReceiver(device, 0, null, mask);
@@ -906,7 +867,7 @@
                 break;
             default:
                 removeReceiver(receiver);
-                fail(String.format("unpair() invalid state: device=%s, state=%d", device, state));
+                fail(String.format("%s invalid state: state=%d", methodName, state));
         }
 
         long s = System.currentTimeMillis();
@@ -916,10 +877,10 @@
                 assertFalse(adapter.getBondedDevices().contains(device));
                 long finish = receiver.getCompletedTime();
                 if (start != -1 && finish != -1) {
-                    writeOutput(String.format("unpair() completed in %d ms: device=%s",
-                            (finish - start), device));
+                    writeOutput(String.format("%s completed in %d ms", methodName,
+                            (finish - start)));
                 } else {
-                    writeOutput(String.format("unpair() completed: device=%s", device));
+                    writeOutput(String.format("%s completed", methodName));
                 }
                 removeReceiver(receiver);
                 return;
@@ -928,9 +889,8 @@
 
         int firedFlags = receiver.getFiredFlags();
         removeReceiver(receiver);
-        fail(String.format("unpair() timeout: device=%s, state=%d (expected %d), "
-                + "flags=0x%x (expected 0x%x)", device, state, BluetoothDevice.BOND_BONDED,
-                firedFlags, mask));
+        fail(String.format("%s timeout: state=%d (expected %d), flags=0x%x (expected 0x%x)",
+                methodName, state, BluetoothDevice.BOND_BONDED, firedFlags, mask));
     }
 
     /**
@@ -939,29 +899,30 @@
      *
      * @param adapter The BT adapter.
      * @param device The remote device.
-     * @param profile The profile to connect. One of {@link BluetoothProfile#A2DP} or
-     *        {@link BluetoothProfile#HEADSET}.
+     * @param profile The profile to connect. One of {@link BluetoothProfile#A2DP},
+     * {@link BluetoothProfile#HEADSET}, or {@link BluetoothProfile#INPUT_DEVICE}.
+     * @param methodName The method name to printed in the logs.  If null, will be
+     * "connectProfile(profile=&lt;profile&gt;, device=&lt;device&gt;)"
      */
-    public void connectProfile(BluetoothAdapter adapter, BluetoothDevice device, int profile) {
+    public void connectProfile(BluetoothAdapter adapter, BluetoothDevice device, int profile,
+            String methodName) {
+        if (methodName == null) {
+            methodName = String.format("connectProfile(profile=%d, device=%s)", profile, device);
+        }
         int mask = (ConnectProfileReceiver.STATE_CONNECTING_FLAG
                 | ConnectProfileReceiver.STATE_CONNECTED_FLAG);
         long start = -1;
 
         if (!adapter.isEnabled()) {
-            fail(String.format("connectProfile() bluetooth not enabled: device=%s, profile=%d",
-                    device, profile));
+            fail(String.format("%s bluetooth not enabled", methodName));
         }
 
         if (!adapter.getBondedDevices().contains(device)) {
-            fail(String.format("connectProfile() device not paired: device=%s, profile=%d",
-                    device, profile));
+            fail(String.format("%s device not paired", methodName));
         }
 
         BluetoothProfile proxy = connectProxy(adapter, profile);
-        if (proxy == null) {
-            fail(String.format("connectProfile() unknown profile: device=%s, profile=%d",
-                    device, profile));
-        }
+        assertNotNull(proxy);
 
         ConnectProfileReceiver receiver = getConnectProfileReceiver(device, profile, mask);
 
@@ -980,8 +941,7 @@
                 break;
             default:
                 removeReceiver(receiver);
-                fail(String.format("connectProfile() invalid state: device=%s, profile=%d, "
-                        + "state=%d", device, profile, state));
+                fail(String.format("%s invalid state: state=%d", methodName, state));
         }
 
         long s = System.currentTimeMillis();
@@ -991,11 +951,10 @@
                     && (receiver.getFiredFlags() & mask) == mask) {
                 long finish = receiver.getCompletedTime();
                 if (start != -1 && finish != -1) {
-                    writeOutput(String.format("connectProfile() completed in %d ms: "
-                            + "device=%s, profile=%d", (finish - start), device, profile));
+                    writeOutput(String.format("%s completed in %d ms", methodName,
+                            (finish - start)));
                 } else {
-                    writeOutput(String.format("connectProfile() completed: device=%s, "
-                            + "profile=%d", device, profile));
+                    writeOutput(String.format("%s completed", methodName));
                 }
                 removeReceiver(receiver);
                 return;
@@ -1005,9 +964,8 @@
 
         int firedFlags = receiver.getFiredFlags();
         removeReceiver(receiver);
-        fail(String.format("connectProfile() timeout: device=%s, profile=%s, "
-                + "state=%d (expected %d), flags=0x%x (expected 0x%x)", device, profile, state,
-                BluetoothProfile.STATE_CONNECTED, firedFlags, mask));
+        fail(String.format("%s timeout: state=%d (expected %d), flags=0x%x (expected 0x%x)",
+                methodName, state, BluetoothProfile.STATE_CONNECTED, firedFlags, mask));
     }
 
     /**
@@ -1016,29 +974,30 @@
      *
      * @param adapter The BT adapter.
      * @param device The remote device.
-     * @param profile The profile to disconnect. One of {@link BluetoothProfile#A2DP} or
-     *        {@link BluetoothProfile#HEADSET}.
+     * @param profile The profile to disconnect. One of {@link BluetoothProfile#A2DP},
+     * {@link BluetoothProfile#HEADSET}, or {@link BluetoothProfile#INPUT_DEVICE}.
+     * @param methodName The method name to printed in the logs.  If null, will be
+     * "connectProfile(profile=&lt;profile&gt;, device=&lt;device&gt;)"
      */
-    public void disconnectProfile(BluetoothAdapter adapter, BluetoothDevice device, int profile) {
+    public void disconnectProfile(BluetoothAdapter adapter, BluetoothDevice device, int profile,
+            String methodName) {
+        if (methodName == null) {
+            methodName = String.format("disconnectProfile(profile=%d, device=%s)", profile, device);
+        }
         int mask = (ConnectProfileReceiver.STATE_DISCONNECTING_FLAG
                 | ConnectProfileReceiver.STATE_DISCONNECTED_FLAG);
         long start = -1;
 
         if (!adapter.isEnabled()) {
-            fail(String.format("disconnectProfile() bluetooth not enabled: device=%s, profile=%d",
-                    device, profile));
+            fail(String.format("%s bluetooth not enabled", methodName));
         }
 
         if (!adapter.getBondedDevices().contains(device)) {
-            fail(String.format("disconnectProfile() device not paired: device=%s, profile=%d",
-                    device, profile));
+            fail(String.format("%s device not paired", methodName));
         }
 
         BluetoothProfile proxy = connectProxy(adapter, profile);
-        if (proxy == null) {
-            fail(String.format("disconnectProfile() unknown profile: device=%s, profile=%d",
-                    device, profile));
-        }
+        assertNotNull(proxy);
 
         ConnectProfileReceiver receiver = getConnectProfileReceiver(device, profile, mask);
 
@@ -1057,8 +1016,7 @@
                 break;
             default:
                 removeReceiver(receiver);
-                fail(String.format("disconnectProfile() invalid state: device=%s, profile=%d, "
-                        + "state=%d", device, profile, state));
+                fail(String.format("%s invalid state: state=%d", methodName, state));
         }
 
         long s = System.currentTimeMillis();
@@ -1068,11 +1026,10 @@
                     && (receiver.getFiredFlags() & mask) == mask) {
                 long finish = receiver.getCompletedTime();
                 if (start != -1 && finish != -1) {
-                    writeOutput(String.format("disconnectProfile() completed in %d ms: "
-                            + "device=%s, profile=%d", (finish - start), device, profile));
+                    writeOutput(String.format("%s completed in %d ms", methodName,
+                            (finish - start)));
                 } else {
-                    writeOutput(String.format("disconnectProfile() completed: device=%s, "
-                            + "profile=%d", device, profile));
+                    writeOutput(String.format("%s completed", methodName));
                 }
                 removeReceiver(receiver);
                 return;
@@ -1082,9 +1039,8 @@
 
         int firedFlags = receiver.getFiredFlags();
         removeReceiver(receiver);
-        fail(String.format("disconnectProfile() timeout: device=%s, profile=%s, "
-                + "state=%d (expected %d), flags=0x%x (expected 0x%x)", device, profile, state,
-                BluetoothProfile.STATE_DISCONNECTED, firedFlags, mask));
+        fail(String.format("%s timeout: state=%d (expected %d), flags=0x%x (expected 0x%x)",
+                methodName, state, BluetoothProfile.STATE_DISCONNECTED, firedFlags, mask));
     }
 
     /**
@@ -1125,25 +1081,25 @@
         String methodName;
 
         if (connect) {
-            methodName = "connectPan()";
-            mask = (ConnectPanReceiver.STATE_CONNECTED_FLAG |
-                    ConnectPanReceiver.STATE_CONNECTING_FLAG);
+            methodName = String.format("connectPan(device=%s)", device);
+            mask = (ConnectProfileReceiver.STATE_CONNECTED_FLAG |
+                    ConnectProfileReceiver.STATE_CONNECTING_FLAG);
             role = BluetoothPan.LOCAL_PANU_ROLE;
         } else {
-            methodName = "incomingPanConnection()";
-            mask = ConnectPanReceiver.STATE_CONNECTED_FLAG;
+            methodName = String.format("incomingPanConnection(device=%s)", device);
+            mask = ConnectProfileReceiver.STATE_CONNECTED_FLAG;
             role = BluetoothPan.LOCAL_NAP_ROLE;
         }
 
         if (!adapter.isEnabled()) {
-            fail(String.format("%s bluetooth not enabled: device=%s", methodName, device));
+            fail(String.format("%s bluetooth not enabled", methodName));
         }
 
         if (!adapter.getBondedDevices().contains(device)) {
-            fail(String.format("%s device not paired: device=%s", methodName, device));
+            fail(String.format("%s device not paired", methodName));
         }
 
-        if (mPan == null) mPan = (BluetoothPan) connectProxy(adapter, BluetoothProfile.PAN);
+        mPan = (BluetoothPan) connectProxy(adapter, BluetoothProfile.PAN);
         assertNotNull(mPan);
         ConnectPanReceiver receiver = getConnectPanReceiver(device, role, mask);
 
@@ -1165,8 +1121,7 @@
                 break;
             default:
                 removeReceiver(receiver);
-                fail(String.format("%s invalid state: device=%s, state=%d", methodName, device,
-                        state));
+                fail(String.format("%s invalid state: state=%d", methodName, state));
         }
 
         long s = System.currentTimeMillis();
@@ -1176,10 +1131,10 @@
                     && (receiver.getFiredFlags() & mask) == mask) {
                 long finish = receiver.getCompletedTime();
                 if (start != -1 && finish != -1) {
-                    writeOutput(String.format("%s completed in %d ms: device=%s", methodName,
-                            (finish - start), device));
+                    writeOutput(String.format("%s completed in %d ms", methodName,
+                            (finish - start)));
                 } else {
-                    writeOutput(String.format("%s completed: device=%s", methodName, device));
+                    writeOutput(String.format("%s completed", methodName));
                 }
                 removeReceiver(receiver);
                 return;
@@ -1189,9 +1144,8 @@
 
         int firedFlags = receiver.getFiredFlags();
         removeReceiver(receiver);
-        fail(String.format("%s timeout: device=%s, state=%d (expected %d), "
-                + "flags=0x%x (expected 0x%s)", methodName, device, state,
-                BluetoothPan.STATE_CONNECTED, firedFlags, mask));
+        fail(String.format("%s timeout: state=%d (expected %d), flags=0x%x (expected 0x%s)",
+                methodName, state, BluetoothPan.STATE_CONNECTED, firedFlags, mask));
     }
 
     /**
@@ -1232,25 +1186,25 @@
         String methodName;
 
         if (disconnect) {
-            methodName = "disconnectPan()";
-            mask = (ConnectPanReceiver.STATE_DISCONNECTED_FLAG |
-                    ConnectPanReceiver.STATE_DISCONNECTING_FLAG);
+            methodName = String.format("disconnectPan(device=%s)", device);
+            mask = (ConnectProfileReceiver.STATE_DISCONNECTED_FLAG |
+                    ConnectProfileReceiver.STATE_DISCONNECTING_FLAG);
             role = BluetoothPan.LOCAL_PANU_ROLE;
         } else {
-            methodName = "incomingPanDisconnection()";
-            mask = ConnectPanReceiver.STATE_DISCONNECTED_FLAG;
+            methodName = String.format("incomingPanDisconnection(device=%s)", device);
+            mask = ConnectProfileReceiver.STATE_DISCONNECTED_FLAG;
             role = BluetoothPan.LOCAL_NAP_ROLE;
         }
 
         if (!adapter.isEnabled()) {
-            fail(String.format("%s bluetooth not enabled: device=%s", methodName, device));
+            fail(String.format("%s bluetooth not enabled", methodName));
         }
 
         if (!adapter.getBondedDevices().contains(device)) {
-            fail(String.format("%s device not paired: device=%s", methodName, device));
+            fail(String.format("%s device not paired", methodName));
         }
 
-        if (mPan == null) mPan = (BluetoothPan) connectProxy(adapter, BluetoothProfile.PAN);
+        mPan = (BluetoothPan) connectProxy(adapter, BluetoothProfile.PAN);
         assertNotNull(mPan);
         ConnectPanReceiver receiver = getConnectPanReceiver(device, role, mask);
 
@@ -1271,8 +1225,7 @@
                 break;
             default:
                 removeReceiver(receiver);
-                fail(String.format("%s invalid state: device=%s, state=%d", methodName, device,
-                        state));
+                fail(String.format("%s invalid state: state=%d", methodName, state));
         }
 
         long s = System.currentTimeMillis();
@@ -1282,10 +1235,10 @@
                     && (receiver.getFiredFlags() & mask) == mask) {
                 long finish = receiver.getCompletedTime();
                 if (start != -1 && finish != -1) {
-                    writeOutput(String.format("%s completed in %d ms: device=%s", methodName,
-                            (finish - start), device));
+                    writeOutput(String.format("%s completed in %d ms", methodName,
+                            (finish - start)));
                 } else {
-                    writeOutput(String.format("%s completed: device=%s", methodName, device));
+                    writeOutput(String.format("%s completed", methodName));
                 }
                 removeReceiver(receiver);
                 return;
@@ -1295,9 +1248,8 @@
 
         int firedFlags = receiver.getFiredFlags();
         removeReceiver(receiver);
-        fail(String.format("%s timeout: device=%s, state=%d (expected %d), "
-                + "flags=0x%x (expected 0x%s)", methodName, device, state,
-                BluetoothInputDevice.STATE_DISCONNECTED, firedFlags, mask));
+        fail(String.format("%s timeout: state=%d (expected %d), flags=0x%x (expected 0x%s)",
+                methodName, state, BluetoothInputDevice.STATE_DISCONNECTED, firedFlags, mask));
     }
 
     /**
@@ -1335,29 +1287,26 @@
         String methodName;
 
         if (isStart) {
-            methodName = "startSco()";
+            methodName = String.format("startSco(device=%s)", device);
             mask = StartStopScoReceiver.STATE_CONNECTED_FLAG;
         } else {
-            methodName = "stopSco()";
+            methodName = String.format("stopSco(device=%s)", device);
             mask = StartStopScoReceiver.STATE_DISCONNECTED_FLAG;
         }
 
         if (!adapter.isEnabled()) {
-            fail(String.format("%s bluetooth not enabled: device=%s, start=%b", methodName, device,
-                    isStart));
+            fail(String.format("%s bluetooth not enabled", methodName));
         }
 
         if (!adapter.getBondedDevices().contains(device)) {
-            fail(String.format("%s device not paired: device=%s, start=%b", methodName, device,
-                    isStart));
+            fail(String.format("%s device not paired", methodName));
         }
 
         AudioManager manager = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE);
         assertNotNull(manager);
 
         if (!manager.isBluetoothScoAvailableOffCall()) {
-            fail(String.format("%s device does not support SCO: device=%s, start=%b", methodName,
-                    device, isStart));
+            fail(String.format("%s device does not support SCO", methodName));
         }
 
         boolean isScoOn = manager.isBluetoothScoOn();
@@ -1376,8 +1325,7 @@
         long s = System.currentTimeMillis();
         while (System.currentTimeMillis() - s < START_STOP_SCO_TIMEOUT) {
             isScoOn = manager.isBluetoothScoOn();
-            if ((isStart == isScoOn) &&
-                    (receiver.getFiredFlags() & mask) == mask) {
+            if (isStart == isScoOn && (receiver.getFiredFlags() & mask) == mask) {
                 long finish = receiver.getCompletedTime();
                 if (start != -1 && finish != -1) {
                     writeOutput(String.format("%s completed in %d ms", methodName,
@@ -1393,7 +1341,7 @@
 
         int firedFlags = receiver.getFiredFlags();
         removeReceiver(receiver);
-        fail(String.format("%s timeout: start=%b (expected %b), flags=0x%x (expected 0x%x)",
+        fail(String.format("%s timeout: on=%b (expected %b), flags=0x%x (expected 0x%x)",
                 methodName, isScoOn, isStart, firedFlags, mask));
     }
 
@@ -1478,6 +1426,30 @@
     }
 
     private BluetoothProfile connectProxy(BluetoothAdapter adapter, int profile) {
+        switch (profile) {
+            case BluetoothProfile.A2DP:
+                if (mA2dp != null) {
+                    return mA2dp;
+                }
+                break;
+            case BluetoothProfile.HEADSET:
+                if (mHeadset != null) {
+                    return mHeadset;
+                }
+                break;
+            case BluetoothProfile.INPUT_DEVICE:
+                if (mInput != null) {
+                    return mInput;
+                }
+                break;
+            case BluetoothProfile.PAN:
+                if (mPan != null) {
+                    return mPan;
+                }
+                break;
+            default:
+                return null;
+        }
         adapter.getProfileProxy(mContext, mServiceListener, profile);
         long s = System.currentTimeMillis();
         switch (profile) {
diff --git a/core/tests/coretests/src/android/database/sqlite/SQLiteDatabaseTest.java b/core/tests/coretests/src/android/database/sqlite/SQLiteDatabaseTest.java
index 39258ae..5ef8d11 100644
--- a/core/tests/coretests/src/android/database/sqlite/SQLiteDatabaseTest.java
+++ b/core/tests/coretests/src/android/database/sqlite/SQLiteDatabaseTest.java
@@ -31,9 +31,11 @@
 import android.test.suitebuilder.annotation.SmallTest;
 import android.test.suitebuilder.annotation.Suppress;
 import android.util.Log;
+import android.util.Pair;
 
 import java.io.File;
 import java.util.ArrayList;
+import java.util.List;
 
 public class SQLiteDatabaseTest extends AndroidTestCase {
     private static final String TAG = "DatabaseGeneralTest";
@@ -892,6 +894,49 @@
         c.close();
     }
 
+    @SmallTest
+    public void testAttachDb() {
+        String newDb = "/sdcard/mydata.db";
+        File f = new File(newDb);
+        if (f.exists()) {
+            f.delete();
+        }
+        assertFalse(f.exists());
+        SQLiteDatabase db = SQLiteDatabase.openOrCreateDatabase(newDb, null);
+        db.execSQL("create table test1 (i int);");
+        db.execSQL("insert into test1 values(1);");
+        db.execSQL("insert into test1 values(11);");
+        Cursor c = null;
+        try {
+            c = db.rawQuery("select * from test1", null);
+            int count = c.getCount();
+            Log.i(TAG, "count: " + count);
+            assertEquals(2, count);
+        } finally {
+            c.close();
+            db.close();
+            c = null;
+        }
+
+        mDatabase.execSQL("attach database ? as newDb" , new String[]{newDb});
+        Cursor c1 = null;
+        try {
+            c1 = mDatabase.rawQuery("select * from newDb.test1", null);
+            assertEquals(2, c1.getCount());
+        } catch (Exception e) {
+            fail("unexpected exception: " + e.getMessage());
+        } finally {
+            if (c1 != null) {
+                c1.close();
+            }
+        }
+        List<Pair<String, String>> dbs = mDatabase.getAttachedDbs();
+        for (Pair<String, String> p: dbs) {
+            Log.i(TAG, "attached dbs: " + p.first + " : " + p.second);
+        }
+        assertEquals(2, dbs.size());
+     }
+
     /**
      * http://b/issue?id=2943028
      * SQLiteOpenHelper maintains a Singleton even if it is in bad state.
diff --git a/core/tests/coretests/src/android/text/TextUtilsTest.java b/core/tests/coretests/src/android/text/TextUtilsTest.java
index e111662..e8e56de 100644
--- a/core/tests/coretests/src/android/text/TextUtilsTest.java
+++ b/core/tests/coretests/src/android/text/TextUtilsTest.java
@@ -16,28 +16,20 @@
 
 package android.text;
 
-import android.graphics.Paint;
+import com.google.android.collect.Lists;
+
+import android.test.MoreAsserts;
 import android.test.suitebuilder.annotation.LargeTest;
 import android.test.suitebuilder.annotation.SmallTest;
-import android.text.Spannable;
-import android.text.SpannableString;
-import android.text.Spanned;
-import android.text.SpannedString;
-import android.text.TextPaint;
-import android.text.TextUtils;
 import android.text.style.StyleSpan;
 import android.text.util.Rfc822Token;
 import android.text.util.Rfc822Tokenizer;
-import android.test.MoreAsserts;
 
-import com.google.android.collect.Lists;
-import com.google.android.collect.Maps;
+import java.util.ArrayList;
+import java.util.List;
 
 import junit.framework.TestCase;
 
-import java.util.List;
-import java.util.Map;
-
 /**
  * TextUtilsTest tests {@link TextUtils}.
  */
@@ -354,6 +346,7 @@
             return mString.charAt(off);
         }
 
+        @Override
         public String toString() {
             return mString.toString();
         }
@@ -362,4 +355,104 @@
             return new Wrapper(mString.subSequence(start, end));
         }
     }
+
+    @LargeTest
+    public void testRemoveEmptySpans() {
+        MockSpanned spanned = new MockSpanned();
+
+        spanned.test();
+        spanned.addSpan().test();
+        spanned.addSpan().test();
+        spanned.addSpan().test();
+        spanned.addEmptySpan().test();
+        spanned.addSpan().test();
+        spanned.addEmptySpan().test();
+        spanned.addEmptySpan().test();
+        spanned.addSpan().test();
+
+        spanned.clear();
+        spanned.addEmptySpan().test();
+        spanned.addEmptySpan().test();
+        spanned.addEmptySpan().test();
+        spanned.addSpan().test();
+        spanned.addEmptySpan().test();
+        spanned.addSpan().test();
+
+        spanned.clear();
+        spanned.addSpan().test();
+        spanned.addEmptySpan().test();
+        spanned.addSpan().test();
+        spanned.addEmptySpan().test();
+        spanned.addSpan().test();
+        spanned.addSpan().test();
+    }
+
+    protected static class MockSpanned implements Spanned {
+
+        private List<Object> allSpans = new ArrayList<Object>();
+        private List<Object> nonEmptySpans = new ArrayList<Object>();
+
+        public void clear() {
+            allSpans.clear();
+            nonEmptySpans.clear();
+        }
+
+        public MockSpanned addSpan() {
+            Object o = new Object();
+            allSpans.add(o);
+            nonEmptySpans.add(o);
+            return this;
+        }
+
+        public MockSpanned addEmptySpan() {
+            Object o = new Object();
+            allSpans.add(o);
+            return this;
+        }
+
+        public void test() {
+            Object[] nonEmpty = TextUtils.removeEmptySpans(allSpans.toArray(), this, Object.class);
+            assertEquals("Mismatched array size", nonEmptySpans.size(), nonEmpty.length);
+            for (int i=0; i<nonEmpty.length; i++) {
+                assertEquals("Span differ", nonEmptySpans.get(i), nonEmpty[i]);
+            }
+        }
+
+        public char charAt(int arg0) {
+            return 0;
+        }
+
+        public int length() {
+            return 0;
+        }
+
+        public CharSequence subSequence(int arg0, int arg1) {
+            return null;
+        }
+
+        @Override
+        public <T> T[] getSpans(int start, int end, Class<T> type) {
+            return null;
+        }
+
+        @Override
+        public int getSpanStart(Object tag) {
+            return 0;
+        }
+
+        @Override
+        public int getSpanEnd(Object tag) {
+            return nonEmptySpans.contains(tag) ? 1 : 0;
+        }
+
+        @Override
+        public int getSpanFlags(Object tag) {
+            return 0;
+        }
+
+        @Override
+        public int nextSpanTransition(int start, int limit, Class type) {
+            return 0;
+        }
+    }
 }
diff --git a/core/tests/coretests/src/android/util/LruCacheTest.java b/core/tests/coretests/src/android/util/LruCacheTest.java
index 7e46e26..5a97158 100644
--- a/core/tests/coretests/src/android/util/LruCacheTest.java
+++ b/core/tests/coretests/src/android/util/LruCacheTest.java
@@ -183,20 +183,15 @@
      * Replacing the value for a key doesn't cause an eviction but it does bring
      * the replaced entry to the front of the queue.
      */
-    public void testPutDoesNotCauseEviction() {
-        final List<String> evictionLog = new ArrayList<String>();
-        List<String> expectedEvictionLog = new ArrayList<String>();
-        LruCache<String, String> cache = new LruCache<String, String>(3) {
-            @Override protected void entryEvicted(String key, String value) {
-                evictionLog.add(key + "=" + value);
-            }
-        };
+    public void testPutCauseEviction() {
+        List<String> log = new ArrayList<String>();
+        LruCache<String, String> cache = newRemovalLogCache(log);
 
         cache.put("a", "A");
         cache.put("b", "B");
         cache.put("c", "C");
         cache.put("b", "B2");
-        assertEquals(expectedEvictionLog, evictionLog);
+        assertEquals(Arrays.asList("b=B>B2"), log);
         assertSnapshot(cache, "a", "A", "c", "C", "b", "B2");
     }
 
diff --git a/core/tests/systemproperties/AndroidManifest.xml b/core/tests/systemproperties/AndroidManifest.xml
index ad0abf4..1608788 100644
--- a/core/tests/systemproperties/AndroidManifest.xml
+++ b/core/tests/systemproperties/AndroidManifest.xml
@@ -24,7 +24,7 @@
     </application>
 
     <instrumentation android:name="android.test.InstrumentationTestRunner"
-            android:targetPackage="com.android.frameworks.coretests"
-            android:label="Frameworks Core Tests" />
+            android:targetPackage="com.android.frameworks.coretests.systemproperties"
+            android:label="Frameworks SystemProperties Core Tests" />
 
 </manifest>
diff --git a/core/tests/systemproperties/run_core_systemproperties_test.sh b/core/tests/systemproperties/run_core_systemproperties_test.sh
index 48880f3..d39adbb 100755
--- a/core/tests/systemproperties/run_core_systemproperties_test.sh
+++ b/core/tests/systemproperties/run_core_systemproperties_test.sh
@@ -16,6 +16,9 @@
 if [[ $rebuild == true ]]; then
   make -j4 FrameworksCoreSystemPropertiesTests
   TESTAPP=${ANDROID_PRODUCT_OUT}/data/app/FrameworksCoreSystemPropertiesTests.apk
+  COMMAND="adb install -r $TESTAPP"
+  echo $COMMAND
+  $COMMAND
 fi
 
 adb shell am instrument -w -e class android.os.SystemPropertiesTest com.android.frameworks.coretests.systemproperties/android.test.InstrumentationTestRunner
diff --git a/core/tests/systemproperties/src/android/os/SystemPropertiesTest.java b/core/tests/systemproperties/src/android/os/SystemPropertiesTest.java
index 243ac38..544a967 100644
--- a/core/tests/systemproperties/src/android/os/SystemPropertiesTest.java
+++ b/core/tests/systemproperties/src/android/os/SystemPropertiesTest.java
@@ -23,8 +23,19 @@
 
 public class SystemPropertiesTest extends TestCase {
     private static final String KEY = "sys.testkey";
+    private static final String PERSIST_KEY = "persist.sys.testkey";
+
     @SmallTest
-    public void testLongSequencialProperties() throws Exception {
+    public void testStressPersistPropertyConsistency() throws Exception {
+        for (int i = 0; i < 100; ++i) {
+            SystemProperties.set(PERSIST_KEY, Long.toString(i));
+            long ret = SystemProperties.getLong(PERSIST_KEY, -1);
+            assertEquals(i, ret);
+        }
+    }
+
+    @SmallTest
+    public void testStressMemoryPropertyConsistency() throws Exception {
         for (int i = 0; i < 100; ++i) {
             SystemProperties.set(KEY, Long.toString(i));
             long ret = SystemProperties.getLong(KEY, -1);
diff --git a/data/fonts/DroidSans-Bold.ttf b/data/fonts/DroidSans-Bold.ttf
index 7ac04b6..d065b64 100644
--- a/data/fonts/DroidSans-Bold.ttf
+++ b/data/fonts/DroidSans-Bold.ttf
Binary files differ
diff --git a/data/fonts/DroidSans.ttf b/data/fonts/DroidSans.ttf
index 767c63a..ad1efca 100644
--- a/data/fonts/DroidSans.ttf
+++ b/data/fonts/DroidSans.ttf
Binary files differ
diff --git a/data/fonts/DroidSansArabic.ttf b/data/fonts/DroidSansArabic.ttf
index 660e2a9..bdefaac 100644
--- a/data/fonts/DroidSansArabic.ttf
+++ b/data/fonts/DroidSansArabic.ttf
Binary files differ
diff --git a/data/fonts/DroidSansFallback.ttf b/data/fonts/DroidSansFallback.ttf
index 8c6fabe..ba9d76f 100644
--- a/data/fonts/DroidSansFallback.ttf
+++ b/data/fonts/DroidSansFallback.ttf
Binary files differ
diff --git a/data/fonts/DroidSansMono.ttf b/data/fonts/DroidSansMono.ttf
index 6e79dad..a007071 100644
--- a/data/fonts/DroidSansMono.ttf
+++ b/data/fonts/DroidSansMono.ttf
Binary files differ
diff --git a/data/fonts/DroidSerif-Bold.ttf b/data/fonts/DroidSerif-Bold.ttf
index 85d6c6b..838d255 100644
--- a/data/fonts/DroidSerif-Bold.ttf
+++ b/data/fonts/DroidSerif-Bold.ttf
Binary files differ
diff --git a/data/fonts/DroidSerif-BoldItalic.ttf b/data/fonts/DroidSerif-BoldItalic.ttf
index 9d8e798..0b1601f 100644
--- a/data/fonts/DroidSerif-BoldItalic.ttf
+++ b/data/fonts/DroidSerif-BoldItalic.ttf
Binary files differ
diff --git a/data/fonts/DroidSerif-Italic.ttf b/data/fonts/DroidSerif-Italic.ttf
index 6acc86d..2972809 100644
--- a/data/fonts/DroidSerif-Italic.ttf
+++ b/data/fonts/DroidSerif-Italic.ttf
Binary files differ
diff --git a/data/fonts/DroidSerif-Regular.ttf b/data/fonts/DroidSerif-Regular.ttf
index 8c1c2c4..5b4fe81 100644
--- a/data/fonts/DroidSerif-Regular.ttf
+++ b/data/fonts/DroidSerif-Regular.ttf
Binary files differ
diff --git a/data/keyboards/Generic.kl b/data/keyboards/Generic.kl
index 33947e7..68a158e 100644
--- a/data/keyboards/Generic.kl
+++ b/data/keyboards/Generic.kl
@@ -426,6 +426,10 @@
 axis 0x03 RX
 axis 0x04 RY
 axis 0x05 RZ
+axis 0x06 THROTTLE
+axis 0x07 RUDDER
+axis 0x08 WHEEL
+axis 0x09 GAS
+axis 0x0a BRAKE
 axis 0x10 HAT_X
 axis 0x11 HAT_Y
- 
\ No newline at end of file
diff --git a/data/keyboards/Vendor_045e_Product_028e.kl b/data/keyboards/Vendor_045e_Product_028e.kl
new file mode 100644
index 0000000..99f046a
--- /dev/null
+++ b/data/keyboards/Vendor_045e_Product_028e.kl
@@ -0,0 +1,46 @@
+# Copyright (C) 2011 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+#
+# XBox 360 USB Controller
+#
+
+key 304   BUTTON_A
+key 305   BUTTON_B
+key 307   BUTTON_X
+key 308   BUTTON_Y
+key 310   BUTTON_L1
+key 311   BUTTON_R1
+key 314   BUTTON_SELECT
+key 315   BUTTON_START
+key 316   BUTTON_MODE
+key 317   BUTTON_THUMBL
+key 318   BUTTON_THUMBR
+
+# Left and right stick.
+# The reported value for flat is 128 out of a range from -32767 to 32768, which is absurd.
+# This confuses applications that rely on the flat value because the joystick actually
+# settles in a flat range of +/- 4096 or so.
+axis 0x00 X flat 4096
+axis 0x01 Y flat 4096
+axis 0x03 Z flat 4096
+axis 0x04 RZ flat 4096
+
+# Triggers.
+axis 0x02 LTRIGGER
+axis 0x05 RTRIGGER
+
+# Hat.
+axis 0x10 HAT_X
+axis 0x11 HAT_Y
diff --git a/data/keyboards/Vendor_046d_Product_c294.kl b/data/keyboards/Vendor_046d_Product_c294.kl
new file mode 100644
index 0000000..5492f49
--- /dev/null
+++ b/data/keyboards/Vendor_046d_Product_c294.kl
@@ -0,0 +1,53 @@
+# Copyright (C) 2011 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+#
+# Logitech G25 Racing Wheel (in Compatibility Mode)
+#
+
+# 4 way buttons above hat
+key 0x121    BUTTON_A
+key 0x123    BUTTON_B
+key 0x120    BUTTON_X
+key 0x122    BUTTON_Y
+
+# Row of buttons under hat
+key 0x12b    BUTTON_1
+key 0x128    BUTTON_2
+key 0x129    BUTTON_3
+key 0x12a    BUTTON_4
+
+# Gear shift positions
+#   0x12a top-left gear (aliased as BUTTON_4)
+#   0x12b bottom-left gear (aliased as BUTTON_1)
+
+# Buttons on wheel
+key 0x127    BUTTON_L1
+key 0x126    BUTTON_R1
+
+# Toggles under wheel
+key 0x125    BUTTON_L2
+key 0x124    BUTTON_R2
+
+# Hat
+axis 0x10    HAT_X
+axis 0x11    HAT_Y
+
+# Steering Wheel
+axis 0x00    WHEEL
+
+# Accelerator / Brake
+#   00..7e : accelerator
+#   80..ff : brake
+axis 0x01    split 0x7f GAS BRAKE
diff --git a/data/keyboards/Vendor_046d_Product_c299.kl b/data/keyboards/Vendor_046d_Product_c299.kl
new file mode 100644
index 0000000..d42963d
--- /dev/null
+++ b/data/keyboards/Vendor_046d_Product_c299.kl
@@ -0,0 +1,62 @@
+# Copyright (C) 2011 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+#
+# Logitech G25 Racing Wheel (in Native Mode)
+#
+
+# 4 way buttons above hat
+key 0x121    BUTTON_A
+key 0x123    BUTTON_B
+key 0x120    BUTTON_X
+key 0x122    BUTTON_Y
+
+# Row of buttons under hat
+key 0x12b    BUTTON_1
+key 0x128    BUTTON_2
+key 0x129    BUTTON_3
+key 0x12a    BUTTON_4
+
+# Gear shift positions
+key 0x12c    BUTTON_5
+key 0x12d    BUTTON_6
+key 0x12e    BUTTON_7
+key 0x12f    BUTTON_8
+key 0x2d0    BUTTON_9
+key 0x2d1    BUTTON_10
+key 0x2d2    BUTTON_11
+
+# Buttons on wheel
+key 0x127    BUTTON_L1
+key 0x126    BUTTON_R1
+
+# Toggles under wheel
+key 0x125    BUTTON_L2
+key 0x124    BUTTON_R2
+
+# Hat
+axis 0x10    HAT_X
+axis 0x11    HAT_Y
+
+# Steering Wheel
+axis 0x00    WHEEL
+
+# Clutch
+axis 0x01    invert GENERIC_1
+
+# Accelerator
+axis 0x02    invert GAS
+
+# Brake
+axis 0x05    invert BRAKE
diff --git a/data/keyboards/common.mk b/data/keyboards/common.mk
index 5b367b9..335298c 100644
--- a/data/keyboards/common.mk
+++ b/data/keyboards/common.mk
@@ -19,7 +19,10 @@
     Generic.kl \
     AVRCP.kl \
     qwerty.kl \
+    Vendor_045e_Product_028e.kl \
     Vendor_046d_Product_c216.kl \
+    Vendor_046d_Product_c294.kl \
+    Vendor_046d_Product_c299.kl \
     Vendor_046d_Product_c532.kl \
     Vendor_054c_Product_0268.kl \
     Vendor_05ac_Product_0239.kl \
diff --git a/docs/html/guide/appendix/faq/commontasks.jd b/docs/html/guide/appendix/faq/commontasks.jd
index 4747379..b0c96b1 100644
--- a/docs/html/guide/appendix/faq/commontasks.jd
+++ b/docs/html/guide/appendix/faq/commontasks.jd
@@ -1,821 +1,8 @@
-page.title=Common Tasks and How to Do Them in Android
-parent.title=FAQs, Tips, and How-to
-parent.link=index.html
 @jd:body
 
-<ul>
-    <li><a href="#neweclipseandroidproject">Creating an Android Application using
-    the Eclipse plugin</a></li>
-    <li><a href="#newandroidprojectnoeclipse">Creating an Android Application without
-    the Eclipse plugin</a></li>
-    <li><a href="#addexternallibrary">Adding an External Library (.jar) using Eclipse</a></li>
-    <li><a href="#implementcallbacks">Implementing Activity callbacks</a> (Android
-        calls your activity at various key moments in its life cycle. You must know
-        how to handle each of these to draw your screen, initialize class members,
-        and acquire data.)</li>
-    <li><a href="#opennewscreen">Opening a new screen</a></li>
-    <li><a href="#listening">Listening for button clicks </a></li>
-    <li><a href="#configurewindowproperties">Configuring general window properties </a></li>
-    <li><a href="#localhostalias">Referring to localhost from the emulated environment</a></li>
-    <li><a href="#appstate">Storing and retrieving state</a></li>
-    <li><a href="{@docRoot}guide/topics/data/data-storage.html#preferences">Storing and retrieving preferences</a></li>
-    <li><a href="#storingandretrieving">Storing and retrieving larger or more complex
-            persistent data</a> (files and data) </li>
-    <li><a href="#playback">Playing audio, video, still, or other media files</a></li>
-    <li><a href="#broadcastreceivers">Listening for and broadcasting global messages
-        and setting alarms</a></li>
-    <li><a href="#alerts">Displaying alerts </a></li>
-    <li><a href="#progressbar">Displaying a progress bar</a> </li>
-    <li><a href="#addmenuitems">Adding items to the screen menu</a> </li>
-    <li><a href="#webpage">Display a web page</a> </li>
-    <li><a href="#binding">Binding to data</a></li>
-    <li><a href="#handle">Getting a Handle to a Screen Element</a></li>
-    <li><a href="#captureimages">Capture images from the phone camera </a></li>
-    <li><a href="#threading">Handling expensive operations in the UI thread</a></li>
-    <li><a href="#selectingtext">Selecting, highlighting, or styling portions of
-            text</a></li>
-    <li><a href="#querymap">Utilizing attributes in a Map query</a></li>
-    <li><a href="#filelist">List of files for an Android application</a></li>
-    <li><a href="#logging">Print messages to a log file</a></li>
-</ul>
-<p>The ApiDemos sample application includes many, many examples of common
-tasks and UI features. See the code inside
-<code>&lt;sdk&gt;samples/ApiDemos</code> and the other sample applications
-under the <code>samples/</code> folder in the SDK.</p>
+<script type="text/javascript">
+  document.location=toRoot+"resources/faq/commontasks.html"
+</script>
 
-
-<h2 id="neweclipseandroidproject">Creating an Android Application using the Eclipse Plugin</h2>
-
-<p>Using the Android Eclipse plugin is the fastest and easiest way
-to start creating a new Android application. The plugin automatically generates
-the correct project structure for your application, and keeps the resources
-compiled for you automatically.</p>
-
-<p>It is still a good idea to know what is going on though. Take a look at <a
-href="{@docRoot}guide/topics/fundamentals.html">Application Fundamentals</a> 
-to understand the basics of how an Android application works.</p> 
-
-<p>You should also take a look at the ApiDemos application and the other sample
-applications included in the SDK, in the <code>&lt;sdk&gt;/samples/</code>
-folder in the SDK.</p>
-
-<p>Finally, a great way to started with Android development in Eclipse is to
-follow both the <a href="{@docRoot}resources/tutorials/hello-world.html">Hello,
-World</a> and <a
-href="{@docRoot}resources/tutorials/notepad/index.html">Notepad</a> code
-tutorials. In particular, the start of the Hello Android tutorial is an
-excellent introduction to creating a new Android application in Eclipse.</p>
-
-<h2 id="newandroidprojectnoeclipse">Creating an Android Application without the Eclipse Plugin</h2>
-
-<p>This topic describes the manual steps in creating an Android application.
-Before reading this, you should read <a
-href="{@docRoot}guide/topics/fundamentals.html">Application Fundamentals</a> 
-to understand the basics of how an Android application works. You might also 
-want to look at the sample code included with the Android SDK, in the 
-<code>&lt;sdk&gt;/samples/</code> directory. </p>
-
-<p>Here is a list of the basic steps in building an application.</p>
-<ol>
-    <li><strong>Create your required resource files</strong> &nbsp;&nbsp;This includes
-        the AndroidManifest.xml global description file, string files that your application
-        needs, and layout files describing your user interface. A full list of optional
-        and required files and syntax details for each is given in <a href="#filelist">File
-        List for an Android Application</a>. </li>
-    <li><strong>Design your user interface</strong> &nbsp;&nbsp;See <a
-    href="{@docRoot}guide/topics/ui/index.html">User Interface</a> for
-    details on elements of the Android screen. </li>
-    <li><strong>Implement your Activity </strong>(this page)<strong>&nbsp;&nbsp; </strong> You
-        will create one class/file for each screen in your application. Screens will
-        inherit from an {@link android.app android.app} class, typically {@link android.app.Activity
-        android.app.Activity} for basic screens, {@link android.app.ListActivity
-        android.app.ListActivity} for list screens, or {@link android.app.Dialog
-        android.app.Dialog} for dialog boxes. You will implement the required callbacks
-        that let you draw your screen, query data, and commit changes, and also perform
-        any required tasks such as opening additional screens or reading data from
-        the device. Common tasks, such as opening a new screen or reading data from
-        the device, are described below.
-        The list of files you'll need for your application are described in <a href="#filelist">List
-        of Files for an Android Application</a>. </li>
-    <li><strong><a href="{@docRoot}guide/developing/other-ide.html#buildingwithant">Build and install your
-                package</a>.</strong> The Android SDK has some nice tools for generating
-                projects and debugging code. </li>
-</ol>
-
-<h2 id="addexternallibrary">Adding an External Library (.jar) using Eclipse</h2>
-<p>
-You can use a third party JAR in your application by adding it to your Eclipse project as follows:
-</p>
-<ol>
-<li>
-In the <strong>Package Explorer</strong> panel, right-click on your project and select <strong>Properties</strong>.
-<li>
-Select <strong>Java Build Path</strong>, then the tab <strong>Libraries</strong>.
-<li>
-Press the <strong>Add External JARs...</strong> button and select the JAR file.
-</ol>
-<p>
-Alternatively, if you want to include third party JARs with your package, create a new directory for them within your project and select <strong>Add Library...</strong> instead.</p>
-<p>
-It is not necessary to put external JARs in the assets folder.
-</p>
-
-<a name="implementcallbacks" id="implementcallbacks"></a>
-<h2>Implementing Activity Callbacks</h2>
-<p>Android calls a number of callbacks to let you draw your screen, store data before
-    pausing, and refresh data after closing. You must implement at least some of
-    these methods. See the <a
-href="{@docRoot}guide/topics/fundamentals/activites.html#Lifecycle">Activities</a>
-    document to learn when and in what order these methods 
-    are called. Here are some of the standard types of screen classes that Android provides:</p>
-<ul>
-    <li>{@link android.app.Activity android.app.Activity} - This is a standard screen,
-        with no specialization.</li>
-    <li>{@link android.app.ListActivity android.app.ListActivity} - This is a screen
-        that is used to display a list of something. It hosts a ListView object,
-        and exposes methods to let you identify the selected item, receive callbacks
-        when the selected item changes, and perform other list-related actions. </li>
-    <li>{@link android.app.Dialog android.app.Dialog} - This is a small, popup dialog-style
-        window that isn't intended to remain in the history stack. (It is not resizeable
-        or moveable by the user.)</li>
-</ul>
-
-<a name="opennewscreen" id="opennewscreen"></a><h2>Opening a New Screen</h2>
-<p>Your Activity will often need to open another Activity screen as it progresses.
-    This new screen can be part of the same application or part of another application,
-    the new screen can be floating or full screen, it can return a result, and you
-    can decide whether to close this screen and remove it from the history stack
-    when you are done with it, or to keep the screen open in history. These next
-    sections describe all these options. </p>
-<h3>Floating or full?<a name="floatingorfull" id="floatingorfull"></a></h3>
-<p>When you open a new screen you can decide whether to make it transparent or floating,
-    or full-screen. The choice of new screen affects the event sequence of events
-    in the old screen (if the new screen obscures the old screen, a different
-    series of events is called in the old screen). See the <a
-    href="{@docRoot}guide/topics/fundamentals/activities.html#Lifecycle">Activities</a> document for
-details. </p> 
-<p>Transparent or floating windows are implemented in three
-    standard ways: </p>
-<ul>
-    <li>Create an {@link android.app.Dialog app.Dialog} class </li>
-    <li>Create an {@link android.app.AlertDialog app.AlertDialog} class </li>
-    <li>Set the {@link android.R.style#Theme_Dialog} <em>theme</em> attribute to <code>&#064;android:style/Theme.Dialog</code>
-        in your AndroidManifest.xml file. For example:    
-    <pre>&lt;activity class=&quot;AddRssItem&quot; android:label=&quot;Add an item&quot; android:theme=&quot;&#064;android:style/Theme.Dialog&quot;/&gt;
-</pre></li>
-</ul>
-<p>Calling startActivity() or startActivityForResult() will open a new screen in whatever
-    way it defines itself (if it uses a floating theme it will be floating,
-    otherwise it will be full screen). </p>
-<h3>Opening a Screen </h3>
-<p>When you want to open a new screen, you can either explicitly specify the activity
-    class to open, or you can let the operating system decide which screen to open,
-    based upon the data and various parameters you pass in. A screen is opened by
-    calling {@link android.app.Activity#startActivity(android.content.Intent) startActivity}
-    and passing in an {@link android.content.Intent Intent} object, which specifies
-    the criteria for the handling screen. To specify a specific screen, call Intent.setClass
-    or setClassName with the exact activity class to open. Otherwise, set a variety
-    of values and data, and let Android decide which screen is appropriate to open.
-    Android will find one or zero Activities that match the specified requirements;
-    it will never open multiple activities for a single request. More information
-    on Intents and how Android resolves them to a specific class is given in the
-    {@link android.content.Intent Intent} topic. </p>
-<a name="intentexamples" id="intentexamples"></a><h3>Some Intent examples </h3>
-<p>The following snippet loads the com.android.samples.Animation1 class, and
-    passes it some arbitrary data.:</p>
-<pre>Intent myIntent = new Intent();
-myIntent.setClassName(&quot;com.android.samples&quot;, &quot;com.android.samples.Animation1&quot;);
-myIntent.putExtra(&quot;com.android.samples.SpecialValue&quot;, &quot;Hello, Joe!&quot;); // key/value pair, where key needs current package prefix.
-startActivity(myIntent);    </pre>
-<p>The next snippet requests that a Web page be opened by specifying the VIEW action,
-    and a URI data string starting with &quot;http://&quot; schema:</p>
-<pre>Intent myIntent = new Intent(Intent.VIEW_ACTION, Uri.parse(&quot;http://www.google.com&quot;));</pre>
-<p>Here is the intent filter from the AndroidManifest.xml file for com.android.browser:</p>
-<pre>&lt;intent-filter&gt;
-    &lt;action android:name=&quot;android.intent.action.VIEW&quot; /&gt;
-    &lt;category android:name=&quot;android.intent.category.DEFAULT&quot; /&gt;
-    &lt;scheme android:name=&quot;http&quot; /&gt;
-    &lt;scheme android:name=&quot;https&quot; /&gt;
-    &lt;scheme android:name=&quot;file&quot; /&gt;
-&lt;/intent-filter&gt; </pre>
-<p>Android defines a number of standard values, for instance the action constants
-    defined by {@link android.content.Intent}. You can define custom values, but
-    both the caller and handler must use them. See the &lt;intent-filter&gt;
-    tag description in <a href="{@docRoot}guide/topics/manifest/manifest-intro.html">The AndroidManifest.xml
-    File</a> for more information on the manifest syntax for the handling
-    application. </p>
-<a name="returningaresult" id="returningaresult"></a><h3>Returning a Result from a Screen</h3>
-<p>A window can return a result after it closes. This result will be passed back
-    into the calling Activity's {@link android.app.Activity#onActivityResult(int,int,android.content.Intent)
-    onActivityResult()} method, which can supply an Intent containing arbitrary data, along with
-    the request code passed to startActivityForResult(). Note that you must call the {@link
-    android.app.Activity#startActivityForResult(android.content.Intent,int) startActivityForResult()}
-    method that accepts a request code parameter to get this callback. The following
-    code demonstrates opening a new screen and retrieving a result. </p>
-<pre>// Open the new screen.
-public void onClick(View v){
-    // Start the activity whose result we want to retrieve.  The
-    // result will come back with request code GET_CODE.
-    Intent intent = new Intent(this, com.example.app.ChooseYourBoxer.class);
-    startActivityForResult(intent, CHOOSE_FIGHTER);
-}
-
-// Listen for results.
-protected void onActivityResult(int requestCode, int resultCode, Intent data){
-    // See which child activity is calling us back.
-    switch (resultCode) {
-        case CHOOSE_FIGHTER:
-            // This is the standard resultCode that is sent back if the
-            // activity crashed or didn't doesn't supply an explicit result.
-            if (resultCode == RESULT_CANCELED){
-                myMessageboxFunction("Fight cancelled");
-            } 
-            else {
-                myFightFunction(data);
-            }
-        default:
-            break;
-    }
-}
-
-// Class SentResult
-// Temporary screen to let the user choose something.
-    private OnClickListener mLincolnListener = new OnClickListener(){
-        public void onClick(View v) {
-            Bundle stats = new Bundle();
-            stats.putString("height","6\'4\""); 
-            stats.putString("weight", "190 lbs");
-            stats.putString("reach", "74\"");
-            setResult(RESULT_OK, "Lincoln", stats);
-            finish();
-        }
-    };
-
-    private OnClickListener mWashingtonListener = new OnClickListener() {
-        public void onClick(View v){
-            Bundle stats = new Bundle();
-            stats.putString("height","6\'2\""); 
-            stats.putString("weight", "190 lbs");
-            stats.putString("reach", "73\"");
-            setResult(RESULT_OK, "Washington", Bundle);
-            finish();
-        }
-    };
-	</pre>
-<h3>Lifetime of the new screen </h3>
-<p>An activity can remove itself from the history stack by calling {@link android.app.Activity#finish()
-    Activity.finish()} on itself, or the activity that opened the screen can call
-    {@link android.app.Activity#finishActivity(int) Activity.finishActivity()}
-    on any screens that it opens to close them. </p>
-<a name="listening" id="listening"></a><h2>Listening for Button Clicks</h2>
-<p>Button click and other UI event capturing are covered in <a href="{@docRoot}guide/topics/ui/ui-events.html">Handling UI Events</a> on the UI Design page.</p>
-<a name="configurewindowproperties" id="configurewindowproperties"></a><h2>Configuring General Window Properties</h2>
-<p>You can set a number of general window properties, such as whether to display
-    a title, whether the window is floating, and whether it displays an icon, by
-    calling methods on the {@link android.view.Window Window} member
-    of the underlying View object for the window. Examples include calling {@link
-    android.app.Activity#getWindow() getWindow().requestFeature()} (or the convenience
-    method {@link android.app.Activity#requestWindowFeature(int) requestWindowFeature(<em>some_feature</em>)})
-    to hide the title. Here is an example of hiding the title bar:</p>
-<pre>//Hide the title bar
-requestWindowFeature(Window.FEATURE_NO_TITLE);
-</pre>
-<p>A better way to achieve the same end is to specify a theme in your Android
-Manifest file:</p>
-<pre>&lt;application android:icon="@drawable/icon" android:theme="@android:style/Theme.NoTitleBar"&gt;
-</pre>
-<p>This is preferable because it tells the system not to show a title bar while
-your application is starting up. With the explicit method call, your application
-will have a title bar visible to the user until <code>onCreate</code> runs.</p>
-<p>(Note that this can be applied to either the <code>&lt;application&gt;</code>
-tag or to individual <code>&lt;activity&gt;</code> tags.)</p>
-<a name="localhostalias" id="localhostalias"></a><h2>Referring to localhost from the emulated environment</h2>
-<p>
-If you need to refer to your host computer's <em>localhost</em>, such as when you 
-want the emulator client to contact a server running on the same host, use the alias 
-<code>10.0.2.2</code> to refer to the host computer's loopback interface. 
-From the emulator's perspective, localhost (<code>127.0.0.1</code>) refers to its own 
-loopback interface.
-</p>
-<a name="appstate" id="appstate"></a><h2>Storing and Retrieving State</h2>
-<p>If your application is dumped from memory because of space concerns, it will lose
-    all user interface state information such as checkbox state and text box values
-    as well as class member values. Android calls {@link android.app.Activity#onSaveInstanceState(android.os.Bundle)
-    Activity.onSaveInstanceState} before it pauses the application. This method hands in a {@link
-    android.os.Bundle Bundle} that can be used to store name/value pairs that will
-    persist and be handed back to the application even if it is dropped from memory.
-    Android will pass this Bundle back to you when it calls {@link android.app.Activity#onCreate(android.os.Bundle)
-    onCreate()}. This Bundle only exists while the application is still in the history
-    stack (whether or not it has been removed from memory) and will be lost when
-    the application is finalized. See the topics for {@link android.app.Activity#onSaveInstanceState} and
-    {@link android.app.Activity#onCreate} for
-    examples of storing and retrieving state.</p>
-<p>Read more about the lifecycle of an activity in <a
-href="{@docRoot}guide/topics/fundamentals/activities.html">Activities</a> document.</p>
-<h3>Storing and Retrieving Larger or More Complex Persistent Data<a name="storingandretrieving" id="storingandretrieving"></a></h3>
-<p>Your application can store files or complex collection objects, and reserve them
-    for private use by itself or other activities in the application, or it can expose
-    its data to all other applications on the device. See <a href="{@docRoot}guide/topics/data/data-storage.html">Storing,
-    Retrieving, and Exposing Data</a> to learn how to store and retrieve private data,
-    how to store and retrieve common data from the device, and how to expose your
-    private data to other applications.</p>
-<a name="playback" id="playback"></a><h2>Playing Media Files</h2>
-<p>Please see the document <a href="{@docRoot}guide/topics/media/index.html">Audio and Video</a> for more details.</p>
-<a name="broadcastreceivers" id="broadcastreceivers"></a><h2>Listening For and Broadcasting Global Messages, and Setting Alarms</h2>
-<p>You can create a listening class that can be notified or even instantiated whenever
-    a specific type of system message is sent. 
-</p>
-<p>The listening classes, called broadcast receivers, extend {@link android.content.BroadcastReceiver
-    BroadcastReceiver}. If you want Android to instantiate the object whenever an appropriate
-    intent notification is sent, define the receiver with a <code>&lt;receiver&gt;</code> element
-    in the AndroidManifest.xml file. If the caller is expected to instantiate the
-    object in preparation to receive a message, this is not required. The receiver
-    will get a call to their {@link android.content.BroadcastReceiver#onReceive(android.content.Context,android.content.Intent)
-    BroadcastReceiver.onReceive()} method. A receiver can define an <code>&lt;intent-filter&gt;</code> tag
-    that describes the types of messages it will receive. Just as Android's IntentResolver
-    will look for appropriate Activity matches for a startActivity() call, it will
-    look for any matching Receivers (but it will send the message to all matching
-    receivers, not to the &quot;best&quot; match). </p>
-<p>To send a notification, the caller creates an {@link android.content.Intent Intent}
-    object and calls {@link android.app.Activity#sendBroadcast(android.content.Intent)
-    Context.sendBroadcast()} with that Intent. Multiple recipients can receive
-    the same message. You can broadcast an Intent message to an intent receiver in
-    any application, not only your own. If the receiving class is not registered
-    using <code>&lt;receiver&gt;</code> in its manifest, you can dynamically instantiate
-    and register a receiver by calling {@link android.content.Context#registerReceiver(android.content.BroadcastReceiver,android.content.IntentFilter)
-    Context.registerReceiver()}. </p>
-<p>Receivers can include intent filters to specify what kinds of intents they are
-    listening for. Alternatively, if you expect a single known caller to contact
-    a single known receiver, the receiver does not specify an intent filter, and
-    the caller specifies the receiver's class name in the Intent by calling {@link
-    android.content.Intent#setClassName(java.lang.String, java.lang.String) Intent.setClassName()}
-    with the recipient's class name. The recipient receives a {@link android.content.Context
-    Context} object that refers to its own package, not to the package of the sender.</p>
-<p><em><strong>Note:</strong></em>&nbsp;&nbsp;&nbsp;If a receiver or broadcaster
-    enforces permissions, your application might need to request permission
-    to send or receive messages from that object. You can request permission by using
-    the &lt;uses-permission&gt; tag in the manifest. </p>
-<p>Here is a code snippet of a sender and receiver. This example does not demonstrate
-    registering receivers dynamically. For a full code example, see the AlarmService
-    class in the ApiDemos project.</p>
-<h3>Sending the message</h3>
-<pre>// We are sending this to a specific recipient, so we will
-// only specify the recipient class name. 
-Intent intent = new Intent(this, AlarmReceiver.class);
-intent.putExtra(&quot;message&quot;,&quot;Wake up.&quot;);
-sendBroadcast(intent);
-</pre>
-<h3>Receiving the message</h3>
-<p><strong>Receiver AndroidManifest.xml </strong>(because there is no intent filter
-    child, this class will only receive a broadcast when the receiver class is specified
-    by name, as is done in this example):</p>
-<pre>
-&lt;receiver class=".AlarmReceiver" /&gt;</pre>
-<p><strong>Receiver Java code: </strong></p>
-<pre>
-public class AlarmReceiver extends BroadcastReceiver{
-    // Display an alert that we've received a message.    
-    &#064;Override 
-    public void onReceive(Context context, Intent intent){
-	    // Send a text notification to the screen.
-        NotificationManager nm = (NotificationManager)
-        context.getSystemService(Context.NOTIFICATION_SERVICE);
-        nm.notifyWithText(R.id.alarm,
-                          &quot;Alarm!!!&quot;,
-                          NotificationManager.LENGTH_SHORT,
-                          null);
-   }
-}   </pre>
-<h3>Other system messages</h3>
-<p>You can listen for other system messages sent by Android as well, such as USB
-    connection/removal messages, SMS arrival messages, and timezone changes. See
-    {@link android.content.Intent} for a list of broadcast messages to listen for.
-    Messages are marked &quot;Broadcast Action&quot; in the documentation. </p>
-<h3>Listening for phone events<a name="phoneevents" id="phoneevents"></a></h3>
-<p>The {@link android.telephony android.telephony} package overview page describes how to
-    register to listen for phone events. </p>
-<a name="alarms" id="alarms"></a><h3>Setting Alarms </h3>
-<p>Android provides an {@link android.app.AlarmManager AlarmManager} service that
-    will let you specify an Intent to send at a designated time. This intent is typically
-    used to start an application at a preset time. (Note: If you want to send
-    a notification to a sleeping or running application, use {@link android.os.Handler
-    Handler} instead.)</p>
-<a name="alerts" id="alerts"></a><h2>Displaying Alerts</h2>
-<p>There are two major kinds of alerts that you may display to the user:
-(1) Normal alerts are displayed in response to a user action, such as
-trying to perform an action that is not allowed.  (2) Out-of-band alerts,
-called notifications, are
-displayed as a result of something happening in the background, such as the
-user receiving new e-mail.</p>
-
-<a name="dialogsandalerts" id="dialogsandalerts"></a><h3>Normal Alerts</h3>
-
-<p>Android provides a number of ways for you to show popup notifications to your
-    user as they interact with your application. </p>
-<table width="100%" border="1">
-    <tr>
-        <th scope="col">Class</th>
-        <th scope="col">Description</th>
-    </tr>
-    <tr>
-        <td>{@link android.app.Dialog app.Dialog}</td>
-        <td>A generic floating dialog box with a layout that you design. </td>
-    </tr>
-    <tr>
-        <td><p>{@link android.app.AlertDialog app.AlertDialog}</p></td>
-        <td>A popup alert dialog with two buttons (typically OK and Cancel) that
-            take callback handlers. See the section after this table for more details. </td>
-    </tr>
-    <tr>
-        <td>{@link android.app.ProgressDialog ProgressDialog} </td>
-        <td>A dialog box used to indicate progress of an operation with a known progress
-            value or an indeterminate length (setProgress(bool)). See <strong>Views</strong> &gt; <strong>Progress Bar</strong> in
-            ApiDemos for examples. </td>
-    </tr>
-    <tr>
-        <td>Activity</td>
-        <td>By setting the theme of an activity to
-            {@link android.R.style#Theme_Dialog 
-            android:theme=&quot;&#064;android:style/Theme.Dialog&quot;}, 
-            your activity will take on
-            the appearance of a normal dialog, floating on top of whatever was
-            underneath it.  You usually set the theme through the
-            {@link android.R.attr#theme android:theme} attribute in your AndroidManifest.xml.
-            The advantage of this
-            over Dialog and AlertDialog is that Application has a much better managed
-            life cycle than dialogs: if a dialog goes to the background and is killed,
-            you cannot recapture state, whereas Application exposes a {@link android.os.Bundle
-            Bundle} of saved values in <code>onCreate()</code> to help you maintain state.</td>
-    </tr>
-</table>
-<h3>AlertDialog</h3>
-<p>This is a basic warning dialog box that lets you configure a message, button text,
-    and callback. You can create one by calling using the {@link 
-    android.app.AlertDialog.Builder} class, as shown here. </p>
-<pre>private Handler mHandler = new Handler() {
-    public void handleMessage(Message msg) {
-        switch (msg.what) {
-            case ACCEPT_CALL:
-            answer(msg.obj);
-            break;
-    
-            case BOUNCE_TO_VOICEMAIL:
-            voicemail(msg.obj);
-            break;
-    
-        }
-    }
-};
-
-
-private void IncomingMotherInLawCall(Connection c) {
-    String Text;
-    
-    // &quot;Answer&quot; callback.
-    Message acceptMsg = Message.obtain();
-    acceptMsg.target = mHandler;
-    acceptMsg.what = ACCEPT_CALL;
-    acceptMsg.obj = c.getCall();
-    
-    // &quot;Cancel&quot; callback.
-    final Message rejectMsg = Message.obtain();
-    rejectMsg.target = mHandler;
-    rejectMsg.what = BOUNCE_TO_VOICEMAIL;
-    rejectMsg.obj = c.getCall();
-
-    new AlertDialog.Builder(this)
-      .setMessage("Phyllis is calling")
-      .setPositiveButton("Answer", acceptMsg)
-      .setOnCancelListener(new OnCancelListener() {
-        public void onCancel(DialogInterface dialog) {
-          rejectMsg.sendToTarget();
-        }});
-      .show();
-}    </pre>
-
-<h3>Notifications</h3>
-
-<p>Out-of-band alerts should always be displayed using the
-{@link android.app.NotificationManager}, which allows you to tell the user
-about something they may be interested in without disrupting what they are
-currently doing.  A notification can be anything from a brief pop-up box
-informing the user of the new information, through displaying a persistent
-icon in the status bar, to vibrating, playing sounds, or flashing lights to
-get the user's attention.  In all cases, the user must explicitly shift their
-focus to the notification before they can interact with it.</p>
-
-<p>The following code demonstrates using NotificationManager to display a basic text
-    popup when a new SMS message arrives in a listening service, and provides the
-    current message count. You can see several more examples in the ApiDemos application,
-    under app/ (named <em>notification</em>*.java).</p>
-<pre>static void setNewMessageIndicator(Context context, int messageCount){
-   // Get the static global NotificationManager object.
-   NotificationManager nm = NotificationManager.getDefault();</p>
-
-   // If we're being called because a new message has been received, 
-   // then display an icon and a count. Otherwise, delete the persistent
-   // message.
-   if (messageCount &gt; 0) {
-      nm.notifyWithText(myApp.NOTIFICATION_GUID,      // ID for this notification.
-                messageCount + &quot; new message&quot; + messageCount &gt; 1 ? &quot;s&quot;:&quot;&quot;, // Text to display.
-                NotificationManager.LENGTH_SHORT); // Show it for a short time only.
-   }
-}</pre>
-<p>To display a notification in the status bar and have it launch an intent when
-    the user selects it (such as the new text message notification does), call {@link
-    android.app.NotificationManager#notify(int, android.app.Notification) NotificationManager.notify()},
-    and pass in vibration patterns, status bar icons, or Intents to associate with
-    the notification. </p>
-<a name="progressbar" id="progressbar"></a><h2>Displaying a Progress Bar</h2>
-<p>An activity can display a progress bar to notify the user that something is happening.
-    To display a progress bar in a screen, call {@link android.app.Activity#requestWindowFeature(int)
-    Activity.requestWindowFeature(Window.FEATURE_PROGRESS)}. To set the value
-    of the progress bar, call {@link android.view.Window#setFeatureInt(int,int)
-    Activity.getWindow().setFeatureInt(Window.FEATURE_PROGRESS, <em>level</em>)}.
-    Progress bar values are from 0 to 9,999, or set the value to 10,000 to make the
-    progress bar invisible. </p>
-<p>You can also use the {@link android.app.ProgressDialog ProgressDialog} class,
-    which enables a  dialog box with an embedded progress bar to send a &quot;I'm working
-    on it&quot; notification to the user. </p>
-<a name="addmenuitems" id="addmenuitems"></a><h2>Adding Items to the Screen Menu</h2>
-<p>See <a href="{@docRoot}guide/topics/ui/menus.html">Creating Menus</a>.</p>
-
-<a name="webpage" id="webpage"></a><h2>Display a Web Page</h2>
-<p>Use the {@link android.webkit.WebView webkit.WebView} object. </p>
-<a name="binding" id="binding"></a><h2>Binding to Data</h2>
-<p>You can bind a ListView to a set of underlying data by using a shim class called
-    {@link android.widget.ListAdapter ListAdapter} (or a subclass). ListAdapter subclasses
-    bind to a variety of data sources, and expose a common set of methods such as
-    getItem() and getView(), and uses them to pick View items to display in its list.
-    You can extend ListAdapter and override getView() to create your own custom list
-    items. There are essentially only two steps you need to perform to bind to data: </p>
-<ol>
-    <li>Create a ListAdapter object and specify its data source</li>
-    <li>Give the ListAdapter to your ListView object.</li>
-</ol>
-<p>That's it!</p>
-<p>Here's an example of binding a ListActivity screen to the results from a cursor
-    query. (Note that the setListAdapter() method shown is a convenience method that
-    gets the page's ListView object and calls setAdapter() on it.)</p>
-<pre>// Run a query and get a Cursor pointing to the results.
-Cursor c = People.query(this.getContentResolver(), null);
-startManagingCursor(c);
-
-// Create the ListAdapter. A SimpleCursorAdapter lets you specify two interesting things:
-// an XML template for your list item, and
-// The column to map to a specific item, by ID, in your template.
-ListAdapter adapter = new SimpleCursorAdapter(this,  
-                android.R.layout.simple_list_item_1,  // Use a template that displays a text view
-                c,                                    // Give the cursor to the list adapter
-                new String[] {People.NAME} ,          // Map the NAME column in the people database to...
-                new String[] {"text1"});              // The "text1" view defined in the XML template
-setListAdapter(adapter);</pre>
-<p>See view/List4 in the ApiDemos project for an example of extending ListAdapter
-    for a new data type. </p>
-
-<a name="handle"></a>
-
-<h2>Getting a Handle to a Screen Element</h2>
-<p>You can get a handle to a screen element by calling {@link
-android.app.Activity#findViewById(int) Activity.findViewById}. You can then use
-the handle to set or retrieve any values exposed by the object. </p>
-<a name="captureimages" id="captureimages"></a><h2>Capture Images from the Phone Camera</h2>
-<p>You can hook into the device's camera onto your own Canvas object by using the
-    {@link android.hardware.Camera Camera} class. See that class's documentation,
-    and the ApiDemos project's Camera Preview application (Graphics/Camera Preview)
-    for example code. </p>
-
-
-<a name="threading" id="threading"></a><h2>Handling Expensive Operations in the UI Thread</h2>
-<p>Avoid performing long-running operations (such as network I/O) directly in the UI thread &mdash; 
-the main thread of an application where the UI is run &mdash; or your application may be blocked 
-and become unresponsive. Here is a brief summary of the recommended approach for handling expensive operations:</p>
-<ol>
-<li>Create a Handler object in your UI thread</li>
-<li>Spawn off worker threads to perform any required expensive operations</li>
-<li>Post results from a worker thread back to the UI thread's handler either through a Runnable or a {@link android.os.Message}</li>
-<li>Update the views on the UI thread as needed</li>
-</ol>
-
-<p>The following outline illustrates a typical implementation:</p>
-
-<pre>
-public class MyActivity extends Activity {
-
-    [ . . . ]
-    // Need handler for callbacks to the UI thread
-    final Handler mHandler = new Handler();
-
-    // Create runnable for posting
-    final Runnable mUpdateResults = new Runnable() {
-        public void run() {
-            updateResultsInUi();
-        }
-    };
-
-    &#64;Override
-    protected void onCreate(Bundle savedInstanceState) {
-        super.onCreate(savedInstanceState);
-
-        [ . . . ]
-    }
-
-    protected void startLongRunningOperation() {
-
-        // Fire off a thread to do some work that we shouldn't do directly in the UI thread
-        Thread t = new Thread() {
-            public void run() {
-                mResults = doSomethingExpensive();
-                mHandler.post(mUpdateResults);
-            }
-        };
-        t.start();
-    }
-
-    private void updateResultsInUi() {
-
-        // Back in the UI thread -- update our UI elements based on the data in mResults
-        [ . . . ]
-    }
-}
-</pre>
-
-<p>For further discussions on this topic, see 
-<a href="{@docRoot}guide/practices/design/responsiveness.html">Designing for Responsiveness</a> 
-and the {@link android.os.Handler} documentation.</p>
-
-<a name="selectingtext" id="selectingtext"></a><h2>Selecting, Highlighting, or Styling Portions of Text</h2>
-<p>You can highlight or style the formatting of strings or substrings of text in
-    a TextView object. There are two ways to do this:</p>
-<ul>
-    <li>If you use a <a href="{@docRoot}guide/topics/resources/available-resources.html#stringresources">string resource</a>,
-        you can add some simple styling, such as bold or italic using HTML notation.
-        The currently supported tags are: <code>B</code> (bold),
-        <code>I</code> (italic), <code>U</code> (underline),
-        <code>TT</code> (monospace), <code>BIG</code>, <code>SMALL</code>,
-        <code>SUP</code> (superscript), <code>SUB</code> (subscript),
-        and <code>STRIKE</code> (strikethrough).
-        So, for example, in res/values/strings.xml you could declare this:<br />
-        <code>&lt;resource&gt;<br />
-        &nbsp;&nbsp;&nbsp;&nbsp;&lt;string&nbsp;id=&quot;@+id/styled_welcome_message&quot;&gt;We
-        are &lt;b&gt;&lt;i&gt;so&lt;/i&gt;&lt;/b&gt; glad to see you.&lt;/string&gt;<br />
-        &lt;/resources&gt;</code></li>
-    <li>To style text on the fly, or to add highlighting or more complex styling,
-        you must use the Spannable object as described next. </li>
-</ul>
-<p>To style text on the fly, you must make sure the TextView is using {@link android.text.Spannable}
-    storage for the text (this will always be true if the TextView is an EditText),
-    retrieve its text with {@link android.widget.TextView#getText}, and call {@link
-    android.text.Spannable#setSpan}, passing in a new style class from the {@link
-    android.text.style} package and the selection range. </p>
-<p>The following code snippet demonstrates creating a string with a highlighted section,
-    italic section, and bold section, and adding it to an EditText object. </p>
-<pre>// Get our EditText object.
-EditText vw = (EditText)findViewById(R.id.text);
-
-// Set the EditText's text.
-vw.setText("Italic, highlighted, bold.");
-
-// If this were just a TextView, we could do:
-// vw.setText("Italic, highlighted, bold.", TextView.BufferType.SPANNABLE);
-// to force it to use Spannable storage so styles can be attached.
-// Or we could specify that in the XML.
-
-// Get the EditText's internal text storage
-Spannable str = vw.getText();
-
-// Create our span sections, and assign a format to each.
-str.setSpan(new StyleSpan(android.graphics.Typeface.ITALIC), 0, 7, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
-str.setSpan(new BackgroundColorSpan(0xFFFFFF00), 8, 19, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
-str.setSpan(new StyleSpan(android.graphics.Typeface.BOLD), 21, str.length() - 1, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
-</pre>
-
-<a name="querymap" id="querymap"></a><h2>Utilizing attributes in a Map query</h2>
-<p>
-When using a search intent to ask the Maps activity to search for something, the Maps activity responds to the following attributes in the optional context bundle:
-</p>
-<pre>
-               float "centerLatitude" default 0.0f
-               float "centerLongitude" default 0.0f
-               float "latitudeSpan" default 0.0f
-               float "longitudeSpan" default 0.0f
-               int "zoomLevel" default 10
-</pre>
-<p>
-This context information is used to center the search result in a particular area, and is equivalent to adjusting the Map activity to the described location and zoom level before issuing the query.
-</p>
-<p>
-If the latitudeSpan, longitudeSpan, and zoomLevel attributes are not consistent, then it is undefined which one takes precedence.
-</p>
-
-<a name="filelist" id="filelist"></a><h2>List of Files for an Android Application</h2>
-<p>The following list describes the structure and files of an Android application.
-    Many of these files can be built for you (or stubbed out) by the android tool
-    shipped in the tools/ menu of the SDK. </p>
-<table width="100%" border="0">
-    <tr>
-        <td width="28%" valign="top">MyApp/<br /></td>
-        <td width="72%" valign="top">&nbsp;</td>
-    </tr>
-    <tr>
-        <td valign="top">&nbsp;&nbsp;&nbsp;&nbsp;AndroidManifest.xml</td>
-        <td valign="top">(<em>required</em>) Advertises the screens that this application provides,
-            where they can be launched (from the main program menu or elsewhere),
-            any content providers it implements and what kind of data they handle,
-            where the implementation classes are, and other application-wide
-            information. Syntax details for this file are described in <a href="{@docRoot}guide/topics/manifest/manifest-intro.html">The AndroidManifest.xml File</a>.</td>
-    </tr>
-    <tr>
-        <td valign="top">&nbsp;&nbsp;&nbsp;&nbsp;src/<br />
-        &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;/<em>myPackagePath</em>/.../<em>MyClass</em>.java</td>
-        <td valign="top">(<em>required</em>) This folder holds all the source code files for your
-            application, inside the appropriate package subfolders. </td>
-    </tr>
-    <tr>
-        <td valign="top">&nbsp;&nbsp;&nbsp;&nbsp;res/</td>
-        <td valign="top">(<em>required</em>) This folder holds all the <em>resources</em> for
-            your application. Resources are external data files or description files
-            that are compiled into your code at build time. Files in different folders
-            are compiled differently, so you must put the proper resource into the
-            proper folder. (See <a href="{@docRoot}guide/topics/resources/resources-i18n.html">Resources</a> for details.)</td>
-    </tr>
-    <tr>
-        <td valign="top">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;anim/<br />
-            &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<em>animation1</em>.xml<br />
-        &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<em>...</em></td>
-        <td valign="top">(<em>optional</em>) Holds any animation XML description files that the
-            application uses. The format of these files is described in <a href="{@docRoot}guide/topics/resources/resources-i18n.html">Resources</a>. </td>
-    </tr>
-    <tr>
-        <td valign="top">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;drawable/<br />
-            &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<em>some_picture</em>.png<br />
-            &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<em>some_stretchable</em>.9.png<br />
-            &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<em>some_background</em>.xml<br />
-        &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;...</td>
-        <td valign="top">(<em>optional</em>) Zero or more files that will be compiled to {@link
-            android.graphics.drawable android.graphics.drawable} resources. Files
-            can be image files (png, gif, or other) or XML files describing other
-            graphics such as bitmaps, stretchable bitmaps, or gradients. Supported
-            bitmap file formats are PNG (preferred), JPG, and GIF (discouraged),
-            as well as the custom 9-patch stretchable bitmap format. These formats
-            are described in <a href="{@docRoot}guide/topics/resources/resources-i18n.html">Resources</a>. </td>
-    </tr>
-    <tr>
-        <td valign="top">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;layout/<br />
-            &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<em>screen_1_layout</em>.xml<br />
-        &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;...<br /></td>
-        <td valign="top">(<em>optional</em>) Holds all the XML files describing screens or parts
-            of screens. Although you could create a screen in Java, defining them
-            in XML files is typically easier. A layout file is similar in concept
-            to an HTML file that describes the screen layout and components. See <a href="{@docRoot}guide/topics/ui/index.html">User Interface</a> for more information about designing screens, and <a href="{@docRoot}guide/topics/resources/available-resources.html#layoutresources">Available Resource Types</a> for the syntax of these files.</td>
-    </tr>
-    <tr>
-        <td valign="top">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;values/<br />
-            &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;arrays<br />
-  &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;          &nbsp;classes.xml<br />
-            &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;colors.xml<br />
-            &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;dimens.xml<br />
-&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;            strings.xml<br />
-        &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;styles.xml<br />
-        &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;values.xml<br /></td>
-        <td valign="top"><p>(<em>optional</em>) XML files describing additional resources
-                such as strings, colors, and styles. The naming, quantity, and number
-                of these files are not enforced--any XML file is compiled, but these
-                are the standard names given to these files. However, the syntax
-                of these files is prescribed by Android, and described in <a href="{@docRoot}guide/topics/resources/resources-i18n.html">Resources</a>. </p>
-        </td>
-    </tr>
-    <tr>
-        <td valign="top">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;xml/</td>
-        <td valign="top">(<em>optional</em>) XML files that can be read at run time on the device. </td>
-    </tr>
-    <tr>
-        <td valign="top">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;raw/</td>
-        <td valign="top">(<em>optional</em>) Any files to be copied directly to the device. </td>
-    </tr>
-</table>
-
-
-<a name="logging" ></a>
-<h2>Print Messages to a Log File</h2>
-
-<p>To write log messages from your application:</p>
-<ol><li>Import <code>android.util.Log</code>.</li>
-    <li>Use <code>Log.v()</code>, <code>Log.d()</code>, <code>Log.i()</code>,
-    <code>Log.w()</code>, or <code>Log.e()</code> to log messages.
-    (See the {@link android.util.Log} class.)<br/> E.g., 
-    <code>Log.e(this.toString(), "error: " + err.toString())</code></li>
-    <li>Launch <a href="{@docRoot}guide/developing/tools/ddms.html">DDMS</a> from a terminal
-    by executing <code>ddms</code> in your Android SDK <code>/tools</code> path.</li>
-    <li>Run your application in the Android emulator.</li>
-    <li>From the DDMS application, select the emulator 
-    (e.g., "emulator-5554") and click <b>Device > Run logcat...</b>
-    to view all the log data.</li>
-</ol>
-<p class="note"><strong>Note:</strong> If you are running Eclipse and 
-encounter a warning about the VM debug port when opening DDMS, you can ignore it
-if you're only interested in logs. However, if you want to further inspect and
-control your processes from DDMS, then you should close Eclipse before launching DDMS so that 
-it may use the VM debugging port.</p>
-
-
+<p>You should have already been redirected by your browser. Please follow
+<a href="{@docRoot}resources/faq/commontasks.html">this link</a>.</p>
\ No newline at end of file
diff --git a/docs/html/guide/appendix/faq/framework.jd b/docs/html/guide/appendix/faq/framework.jd
index 33b69ac..a79686e 100644
--- a/docs/html/guide/appendix/faq/framework.jd
+++ b/docs/html/guide/appendix/faq/framework.jd
@@ -1,197 +1,8 @@
-page.title=Android Application Framework FAQ
-parent.title=FAQs, Tips, and How-to
-parent.link=index.html
 @jd:body
 
-<ul>
-  <li><a href="#1">Do all the Activities and Services of an
-  application run in a single process?</a></li>
-  <li><a href="#2">Do all Activities run in the main thread of
-  an application process?</a></li>
-  <li><a href="#3">How do I pass complicated data structures
-  from one Activity/Service to another?</a></li>
-  <li><a href="#4">How can I check if an Activity is already
-  running before starting it?</a></li>
-  <li><a href="#5">If an Activity starts a remote service, is
-  there any way for the Service to pass a message back to the Activity?</a></li>
-  <li><a href="#6">How to avoid getting the Application not
-  responding dialog?</a></li>
-  <li><a href="#7">How does an application know if a package is
-  added or removed?</a></li>
-</ul>
+<script type="text/javascript">
+  document.location=toRoot+"resources/faq/framework.html"
+</script>
 
-
-<a name="1" id="1"></a>
-
-<h2>Do all the Activities and Services of an application run in a
-single process?</h2>
-
-<p>All Activities and Services in an application run in a single process by
-default. If needed, you can declare an <code>android:process</code> attribute
-in your manifest file, to explicitly place a component (Activity/Service) in
-another process.</p>
-
-
-
-<a name="2" id="2"></a>
-
-<h2>Do all Activities run in the main thread of an application
-process?</h2>
-
-<p>By default, all of the application code in a single process runs
-in the main UI thread. This is the same thread
-that also handles UI events. The only exception is the code that handles
-IPC calls coming in from other processes. The system maintains a
-separate pool of transaction threads in each process to dispatch all
-incoming IPC calls. The developer should create separate threads for any
-long-running code, to avoid blocking the main UI thread.</p>
-
-
-
-<a name="3" id="3"></a>
-
-<h2>How do I pass data between Activities/Services within a single
-application?</h2>
-
-<p>It depends on the type of data that you want to share:</p>
-
-<h3>Primitive Data Types</h3>
-
-<p>To share primitive data between Activities/Services in an
-application, use Intent.putExtras(). For passing primitive data that
-needs to persist use the 
-<a href="{@docRoot}guide/topics/data/data-storage.html#preferences">
-Preferences</a> storage mechanism.</p>
-
-<h3>Non-Persistent Objects</h3>
-
-<p>For sharing complex non-persistent user-defined objects for short
-duration, the following approaches are recommended:
-</p>
-  <h4>The android.app.Application class</h4>
-  <p>The android.app.Application is a base class for those who need to
-maintain global application state. It can be accessed via
-getApplication() from any Activity or Service. It has a couple of
-life-cycle methods and will be instantiated by Android automatically if
-your register it in AndroidManifest.xml.</p>
-
-  <h4>A public static field/method</h4>
-  <p>An alternate way to make data accessible across Activities/Services is to use <em>public static</em>
-fields and/or methods. You can access these static fields from any other
-class in your application. To share an object, the activity which creates your object sets a
-static field to point to this object and any other activity that wants to use
-this object just accesses this static field.</p>
-
-  <h4>A HashMap of WeakReferences to Objects</h4>
-  <p>You can also use a HashMap of WeakReferences to Objects with Long
-keys. When an activity wants to pass an object to another activity, it
-simply puts the object in the map and sends the key (which is a unique
-Long based on a counter or time stamp) to the recipient activity via
-intent extras. The recipient activity retrieves the object using this
-key.</p>
-
-  <h4>A Singleton class</h4>
-  <p>There are advantages to using a static Singleton, such as you can
-refer to them without casting getApplication() to an
-application-specific class, or going to the trouble of hanging an
-interface on all your Application subclasses so that your various
-modules can refer to that interface instead. </p>
-<p>But, the life cycle of a static is not well under your control; so
-to abide by the life-cycle model, the application class should initiate and
-tear down these static objects in the onCreate() and onTerminate() methods
-of the Application Class</p>
-</p>
-
-<h3>Persistent Objects</h3>
-
-<p>Even while an application appears to continue running, the system
-may choose to kill its process and restart it later. If you have data
-that you need to persist from one activity invocation to the next, you
-need to represent that data as state that gets saved by an activity when
-it is informed that it might go away.</p>
-
-<p>For sharing complex persistent user-defined objects, the
-following approaches are recommended:
-<ul>
-  <li>Application Preferences</li>
-  <li>Files</li>
-  <li>contentProviders</li>
-  <li>SQLite DB</li>
-</ul>
-</p>
-
-<p>If the shared data needs to be retained across points where the application
-process can be killed, then place that data in persistent storage like
-Application Preferences, SQLite DB, Files or ContentProviders. Please refer to
-the <a href="{@docRoot}guide/topics/data/data-storage.html">Data Storage</a>
-for further details on how to use these components.</p>
-
-
-
-
-<a name="4" id="4"></a>
-
-<h2>How can I check if an Activity is already running before starting
-it?</h2>
-
-<p>The general mechanism to start a new activity if its not running&mdash;
-or to bring the activity stack to the front if is already running in the
-background&mdash; is the to use the NEW_TASK_LAUNCH flag in the startActivity()
-call.</p>
-
-
-
-<a name="5" id="5"></a>
-
-<h2>If an Activity starts a remote service, is there any way for the
-Service to pass a message back to the Activity?</h2>
-
-<p>The remote service can define a callback interface and register it with the
-clients to callback into the clients. The 
-{@link android.os.RemoteCallbackList RemoteCallbackList} class provides methods to
-register and unregister clients with the service, and send and receive
-messages.</p>
-
-<p>The sample code for remote service callbacks is given in <a
-href="{@docRoot}guide/samples/ApiDemos/src/com/example/android/apis/app/RemoteService.html">ApiDemos/RemoteService</a></p>
-
-
-
-<a name="6" id="6"></a>
-
-<h2>How to avoid getting the Application not responding dialog?</h2>
-
-<p>Please read the <a href="{@docRoot}guide/practices/design/responsiveness.html">Designing for Responsiveness</a> 
-document.</p>
-
-
-
-
-<a name="7" id="7"></a>
-
-<h2>How does an application know if a package is added or removed?
-</h2>
-
-<p>Whenever a package is added, an intent with PACKAGE_ADDED action
-is broadcast by the system. Similarly when a package is removed, an
-intent with PACKAGE_REMOVED action is broadcast. To receive these
-intents, you should write something like this:
-<pre>
-       &lt;receiver android:name ="com.android.samples.app.PackageReceiver"&gt;
-            &lt;intent-filter&gt;
-             &lt;action android:name="android.intent.action.PACKAGE_ADDED"/&gt;
-              &lt;action android:name="android.intent.action.PACKAGE_REMOVED"/&gt;            
-            
-              &lt;data android:scheme="package" /&gt;
-            &lt;/intent-filter&gt;
-        &lt;/receiver&gt;
-  </pre>
-  <br>
-Here PackageReceiver is a BroadcastReceiver class.Its onReceive()
-method is invoked, every time an application package is installed or
-removed.
-
-</p>
-
-
-
+<p>You should have already been redirected by your browser. Please follow
+<a href="{@docRoot}resources/faq/framework.html">this link</a>.</p>
\ No newline at end of file
diff --git a/docs/html/guide/appendix/faq/index.jd b/docs/html/guide/appendix/faq/index.jd
index 90415ae..4194663 100644
--- a/docs/html/guide/appendix/faq/index.jd
+++ b/docs/html/guide/appendix/faq/index.jd
@@ -1,15 +1,8 @@
-page.title=FAQs, Tips, and How-to
 @jd:body
 
-<dl>
-    <dt><a href="commontasks.html">Common Development Tasks and How To Do Them</a></dt>
-    <dd>Quick and to the point &mdash; how-to's for a variety of development tasks you are likely to use.</dd>
-    <dt><a href="framework.html">Application Framework FAQ</a></dt>
-    <dd>Common questions about the Android Application Framework.</dd>
-    <dt><a href="troubleshooting.html">Troubleshooting Tips</a></dt>
-    <dd>Answers to help you troubleshoot common problems.</dd>
-    <dt><a href="licensingandoss.html">Open Source Licensing FAQ</a></dt>
-    <dd>Common topics around licensing and Android Open Source</dd>
-    <dt><a href="security.html">Android Security FAQ</a></dt>
-    <dd>Answers to common questions about Android security.</dd>
-</dl>
+<script type="text/javascript">
+  document.location=toRoot+"resources/faq/index.html"
+</script>
+
+<p>You should have already been redirected by your browser. Please follow
+<a href="{@docRoot}resources/faq/index.html">this link</a>.</p>
\ No newline at end of file
diff --git a/docs/html/guide/appendix/faq/licensingandoss.jd b/docs/html/guide/appendix/faq/licensingandoss.jd
index c267fe81..0da97db 100644
--- a/docs/html/guide/appendix/faq/licensingandoss.jd
+++ b/docs/html/guide/appendix/faq/licensingandoss.jd
@@ -1,19 +1,8 @@
-page.title=Android Open Source Licensing FAQ
-parent.title=FAQs, Tips, and How-to
-parent.link=index.html
 @jd:body
 
-<ul>
-    <li><a href="#mirror">Where can I find the open source components of Android?</a></li>
-    <li><a href="#timeline">When will we see more code released under open source licenses?</a></li>
-    <li><a href="#apache2">Why are you releasing the code under the Apache License instead of GPLv2?</a></li>
-</ul>
+<script type="text/javascript">
+  document.location=toRoot+"resources/faq/licensingandoss.html"
+</script>
 
-<a name="mirror" id="mirror"></a><h2>Where can I find the open source components of Android?</h2>
-<p>The source code for the full Android stack is available from the <a href="http://source.android.com">Android Open Source Project </a> site. 
-
-<p>Other mirrored GPL and LGPL'd components are available at <a href="http://code.google.com/p/android/downloads/list"><code>http://code.google.com/p/android/downloads/list</code></a>.</p>
-<p>Notices for other licenses can be found within the SDK.</p>
-
-<a name="apache2" id="apache2"></a><h2>Why are you releasing the code under the Apache License instead of GPLv2?</h2>
-<p>One of the best explanations for the reasoning behind releasing code under Apache2 can be found in a <a href="http://arstechnica.com/news.ars/post/20071106-why-google-chose-the-apache-software-license-over-gplv2.html">ArsTechnica article</a> by Ryan Paul.</p>
+<p>You should have already been redirected by your browser. Please follow
+<a href="{@docRoot}resources/faq/licensingandoss.html">this link</a>.</p>
\ No newline at end of file
diff --git a/docs/html/guide/appendix/faq/security.jd b/docs/html/guide/appendix/faq/security.jd
index b0d832b..88bcd51 100644
--- a/docs/html/guide/appendix/faq/security.jd
+++ b/docs/html/guide/appendix/faq/security.jd
@@ -1,156 +1,8 @@
-page.title=Android Security FAQ
-parent.title=FAQs, Tips, and How-to
-parent.link=index.html
 @jd:body
 
-<ul>
-    <li><a href="#secure">Is Android Secure?</a></li>
-    <li><a href="#issue">I think I found a security flaw. How do I report
-    it?</a></li>
-    <li><a href="#informed">How can I stay informed of Android security
-    announcements?</a></li>
-    <li><a href="#use">How do I securely use my Android phone?</a></li>
-    <li><a href="#malware">I think I found malicious software being distributed
-    for Android. How can I help?</a></li>
-    <li><a href="#fixes">How will Android-powered devices receive security fixes?</a>
-    </li>
-    <li><a href="#directfix">Can I get a fix directly from the Android Platform
-    Project?</a></li>
-</ul>
+<script type="text/javascript">
+  document.location=toRoot+"resources/faq/security.html"
+</script>
 
-
-<a name="secure" id="secure"></a><h2>Is Android secure?</h2>
-
-<p>The security and privacy of our users' data is of primary importance to the
-Android Open Source Project. We are dedicated to building and maintaining one
-of the most secure mobile platforms available while still fulfilling our goal
-of opening the mobile device space to innovation and competition.</p>
-
-<p>The Android Platform provides a rich <a
-href="http://code.google.com/android/devel/security.html">security model</a>
-that allows developers to request the capabilities, or access, needed by their 
-application and to define new capabilities that other applications can request.
-The Android user can choose to grant or deny an application's request for
-certain capabilities on the handset.</p>
-
-<p>We have made great efforts to secure the Android platform, but it is
-inevitable that security bugs will be found in any system of this complexity.
-Therefore, the Android team works hard to find new bugs internally and responds
-quickly and professionally to vulnerability reports from external researchers.
-</p>
-
-
-<a name="issue" id="issue"></a><h2>I think I found a security flaw. How do I
-report it?</h2>
-
-<p>You can reach the Android security team at <a
-href="mailto:security@android.com">security@android.com</a>. If you like, you
-can protect your message using our <a
-href="http://code.google.com/android/security_at_android_dot_com.txt">PGP
-key</a>.</p>
-
-<p>We appreciate researchers practicing responsible disclosure by emailing us 
-with a detailed summary of the issue and keeping the issue confidential while 
-users are at risk. In return, we will make sure to keep the researcher informed
-of our progress in issuing a fix and will properly credit the reporter(s) when
-we announce the patch. We will always move swiftly to mitigate or fix an 
-externally-reported flaw and will publicly announce the fix once patches are 
-available to users.</p>
-
-
-<a name="informed" id="informed"></a><h2>How can I stay informed of Android
-security announcements?</h2>
-
-<p>An important part of sustainably securing a platform, such as, Android is
-keeping the user and security community informed of bugs and fixes. We will
-publicly announce security bugs when the fixes are available via postings to
-the <a
-href="http://groups.google.com/group/android-security-announce">android-security-announce</a>
-group on Google Groups. You can subscribe to this group as you would a mailing
-list and view the archives here.</p>
-
-<p>For more general discussion of Android platform security, or how to use
-security features in your Android application, please subscribe to <a
-href="http://groups.google.com/group/android-security-discuss">android-security-discuss</a>.
-</p>
-
-
-<a name="use" id="use"></a><h2>How do I securely use my Android phone?</h2>
-
-<p>As an open platform, Android allows users to load software from any
-developer onto a device.  As with a home PC, the user must be
-aware of who is providing the software they are downloading and must decide
-whether they want to grant the application the capabilities it requests.
-This decision can be informed by the user's judgment of the software
-developer's trustworthiness, and where the software came from.</p>
-
-<p>Despite the security protections in Android, it is important
-for users to only download and install software from developers they trust.
-More details on how Android users can make smart security decisions will be
-released when consumer devices become available.</p>
-
-
-<a name="malware" id="malware"></a><h2>I think I found malicious software being
-distributed for Android. How can I help?</h2>
-
-<p>Like any other open platform, it will be possible for unethical developers
-to create malicious software, known as <a
-href="http://en.wikipedia.org/wiki/Malware">malware</a>, for Android. If you
-think somebody is trying to spread malware, please let us know at <a 
-href="mailto:security@android.com">security@android.com</a>. Please include as
-much detail about the application as possible, with the location it is
-being distributed from and why you suspect it of being malicious software.</p>
-
-<p>The term <i>malicious software</i> is subjective, and we cannot make an 
-exhaustive definition.  Some examples of what the Android Security Team believes
-to be malicious software is any application that:
-<ul>
-    <li>drains the device's battery very quickly;</li>
-    <li>shows the user unsolicited messages (especially messages urging the
-    user to buy something);</li>
-    <li>resists (or attempts to resist) the user's effort to uninstall it;</li>
-    <li>attempts to automatically spread itself to other devices;</li>
-    <li>hides its files and/or processes;</li>
-    <li>discloses the user's private information to a third party, without the
-    user's knowledge and consent;</li>
-    <li>destroys the user's data (or the device itself) without the user's
-    knowledge and consent;</li>
-    <li>impersonates the user (such as by sending email or buying things from a
-    web store) without the user's knowledge and consent; or</li>
-    <li>otherwise degrades the user's experience with the device.</li>
-</ul>
-</p>
-
-
-<a name="fixes" id="fixes"></a><h2>How will Android-powered devices receive security
-fixes?</h2>
-
-<p>The manufacturer of each device is responsible for distributing software
-upgrades for it, including security fixes. Many devices will update themselves
-automatically with software downloaded "over the air", while some devices
-require the user to upgrade them manually.</p>
-
-<p>When Android-powered devices are publicly available, this FAQ will provide links how
-Open Handset Alliance members release updates.</p>
-
-<a name="directfix" id="directfix"></a><h2>Can I get a fix directly from the
-Android Platform Project?</h2>
-
-<p>Android is a mobile platform that will be released as open source and
-available for free use by anybody. This means that there will be many
-Android-based products available to consumers, and most of them will be created
-without the knowledge or participation of the Android Open Source Project. Like
-the maintainers of other open source projects, we cannot build and release
-patches for the entire ecosystem of products using Android. Instead, we will
-work diligently to find and fix flaws as quickly as possible and to distribute
-those fixes to the manufacturers of the products.</p>
-
-<p>In addition, We will add security fixes to the open source distribution of
-Android and publicly announce the changes on <a 
-href="http://groups.google.com/group/android-security-announce">android-security-announce</a>.
-</p>
-
-<p>If you are making an Android-powered device and would like to know how you can 
-properly support your customers by keeping abreast of software updates, please
-contact us at <a
-href="mailto:info@openhandsetalliance.com">info@openhandsetalliance.com</a>.</p>
+<p>You should have already been redirected by your browser. Please follow
+<a href="{@docRoot}resources/faq/security.html">this link</a>.</p>
\ No newline at end of file
diff --git a/docs/html/guide/appendix/faq/troubleshooting.jd b/docs/html/guide/appendix/faq/troubleshooting.jd
index 86ab187..e3a9e4182 100755
--- a/docs/html/guide/appendix/faq/troubleshooting.jd
+++ b/docs/html/guide/appendix/faq/troubleshooting.jd
@@ -1,335 +1,8 @@
-page.title=Troubleshooting
-parent.title=FAQs, Tips, and How-to
-parent.link=index.html
 @jd:body
 
+<script type="text/javascript">
+  document.location=toRoot+"resources/faq/troubleshooting.html"
+</script>
 
-<p>Here are some tips and tricks for common Android errors. Don't forget to use the
-    ddms logcat capability to get a deeper view when errors occur. See <a href="{@docRoot}guide/developing/debug-tasks.html">Debugging</a> for more debugging tips. </p>
-<ul>
-    <li><a href="#installeclipsecomponents">ADT Installation Error: "requires plug-in org.eclipse.wst.sse.ui".</a></li>
-    <li><a href="#nodevice">ADB reports &quot;no device&quot; when an emulator is running</a></li>
-    <li><a href="#noapp">My new application/activity isn't showing up in the device application
-        list </a></li>
-    <li><a href="#noupdate">I updated my app, but the updates don't seem to be showing up on
-    the device</a></li>
-    <li><a href="#layout_wilih">I'm getting a &quot;Binary XML file line #2: You must supply a layout_wilih
-    attribute&quot; error when I start an application</a></li>
-    <li><a href="#permission">My request to (<em>make a call, catch an incoming SMS, receive
-        a notification, send an intent to an Android application</em>) is being
-        ignored</a></li>
-    <li><a href="#build">Help! My project won't build in Eclipse</a></li>
-    <li><a href="#eclipse">Eclipse isn't talking to the emulator</a></li>
-    <li><a href="#majorminor">When I go to preferences in Eclipse and select "Android", I get the following error message: Unsupported major.minor version 49.0.</a></li>
-    <li><a href="#apidemosreinstall">I can't install ApiDemos apps in my IDE because of a signing error</a></li>
-    <li><a href="#gesturebuilderinstall">I can't install the GestureBuilder sample
-app in the emulator</a></li>
-    <li><a href="#signingcalendar">I can't compile my app because the build tools generated an expired debug certificate</a></li>
-    <li><a href="#manifestfiles">Unable to view manifest files from within Eclipse</a></li>
-</ul>
-
-<a name="installeclipsecomponents" id="installeclipsecomponents"></a><h2>ADT Installation Error: "requires plug-in org.eclipse.wst.sse.ui".</h2>
-<p>
-The "Android Editors" feature of the ADT Plugin requires specific Eclipse components, such as WST. If you
-encounter this error message during ADT installation, you need to install the
-required Eclipse components and then try the ADT installation again. Follow the steps below to install the required components for the 
-Android Editors feature, based on the version of Eclipse that you are using.</p>
-
-<table style="font-size:100%">
-<tr><th>Eclipse 3.3 (Europa)</th><th>Eclipse 3.4 (Ganymede)</th></tr>
-<tr>
-<td width="50%">
-<ol>
-<li>From the dialog where you select the <strong>Update sites to visit</strong>, select the checkboxes for both the
-ADT site, and the Callisto/Europa/Ganymede Discovery Site (you may want to
-check <strong>Automatically select mirrors</strong> at the bottom).</li>
-<li>Click <strong>Finish</strong>.</li>
-<li>In the <strong>Next</strong> dialog, select the Android Plugins.</li>
-<li>Now, expand the tree item of the discovery site. It seems that if you
-don't do it, it doesn't load the content of the discovery site.</li>
-<li>On the right, click <strong>Select required</strong>. This will select all the components
-that are required to install the Android plugin (wst, emf, etc...).</li>
-<li>Click <strong>Next</strong>, accept the agreement, click <strong>Install All</strong>, and restart Eclipse.</li>
-</ol>
-</td>
-<td>
-<ol>
-    <li>Select <strong>Help</strong> &gt; <strong>Software Updates...</strong></li>
-    <li>Select the <strong>Installed Software</strong> tab.</li>
-    <li>Click <strong>Update...</strong></li>
-    <li>If an update for ADT is available, select it and click <strong>Finish</strong>.</li>
-</ol>
-</td>
-</tr>
-</table>
-
-
-</p>
-<a name="nodevice"></a><h2>ADB reports &quot;no device&quot; when an emulator is running</h2>
-    <p>Try restarting adb by stopping it (<code>adb
-        kill-server</code>) then any other adb command to restart it.</p>
-
-<a name="noapp"></a><h2>My new application/activity isn't showing up in the
-        applications list </h2>
-<ul>
-    <li>You often must restart your device or emulator before a new activity shows
-        up in the applications list. This is particularly true when it is a completely
-        new application with a new AndroidManifest.xml file.</li>
-    <li>If this is for a new activity in an existing AndroidManifest.xml file, did
-        you include an <code>&lt;activity&gt;</code> tag for your app (or a <code>&lt;service&gt;</code>        tag
-        for a service, or a <code>&lt;receiver&gt;</code> tag for a receiver, etc.)? </li>
-    <li>Make sure that your AndroidManifest.xml file is valid. Errors in attribute
-        values, such as the <em>value </em> attribute in <code>&lt;action <em>value</em>=&quot;<em>&lt;something&gt;</em>&quot;&gt;</code>
-        will often not be caught by compilers, but will prevent your application
-        from being displayed because the intent filter will not be matched. Extra
-        spaces or other characters can often sneak into these strings.</li>
-    <li>Did you send your .apk file to the device (<a href="{@docRoot}guide/developing/tools/adb.html#move">adb install</a>)?</li>
-    <li>Run logcat on your device (<code>adb logcat</code>)
-        and then install your .apk file. Check the logcat output to see whether the
-        application is being installed and recognized properly. Here's sample output
-        from a successful installation:
-<pre>I/FileObserver( 414): *** onEvent wfd: 3 mask: 8 path: MyRSSReader.apk
-D/PackageManager( 414): Scanning package: /data/app/MyRSSReader.apk
-D/PackageManager( 414): Adding package com.example.codelab.rssexample
-D/PackageManager( 414): Registered content provider: my_rss_item, className = com.example.codelab.rssexample.RssContentProvider, isSyncable = false
-D/PackageManager( 414): Providers: com.example.codelab.rssexample.RssContentProvider
-D/PackageManager( 414): Activities: com.example.codelab.rssexample.MyRssReader com.example.codelab.rssexample.MyRssReader2 </pre>
-    </li>
-	<li>If logcat shows that the package manager is having problems loading the manifest
-	    file, force your manifest to be recompiled by adding a space in the file and
-	    compiling it.</li>
-</ul>
-<a name="noupdate"></a><h2>I updated my app, but the updates don't seem to be showing up on the device</h2>
-    <p>Did you remember to send your .apk file to the device (<a href="{@docRoot}guide/developing/tools/adb.html#move">adb
-        install</a>)?</p>
-
-<a name="layout_wilih"></a><h2>I'm getting a &quot;Binary XML file line #2: You must supply a layout_wilih
-    attribute&quot; error
-    when I start an application (but I declare a layout_wilih attribute <em>right
-        there!!!</em>)</h2>
-<ul>
-    <li>Make sure that the SDK you are building with is the same version as the Android
-        OS that you are running on. </li>
-    <li>Make sure that you're calling setContentView() early in your onCreate() method.
-        Calling other methods, such as setListAdapter() before calling setContentView()
-        can sometimes create odd errors when Android tries to access screen elements
-        that haven't been set before.</li>
-</ul>
-<a name="permission"></a><h2>My request to (<em>make a call, catch an incoming SMS,
-receive a notification, send an intent to an Android application</em>) is being
-ignored</h2>
-    <p>You might not have permission (or might not have requested permission) to
-        call this activity or receive this intent. Many standard Android activities,
-        such as making a call, have a permission assigned to it to prevent arbitrary
-        applications from sending or receiving requests. See <a
-        href="{@docRoot}guide/topics/security/security.html">Security and
-        Permissions</a> for more information on permissions, and 
-		{@link android.Manifest.permission Manifest.permission} for a list of
-        standard permissions supported by the Android platform.
-</p>
-<a name="build"></a><h2>Help! My project won't build in Eclipse</h2>
-<p>If your project doesn't build, you may notice symptoms such as new
-resources added in the <code>res/</code> sub-folders not showing up in the R class,
-the emulator not being started, not being able to run the application, or even seeming to run an old version of the application.</p>
-<p>To troubleshoot these types of problems, first try:</p>
-<ol>
-  <li>Switch to the DDMS view in Eclipse (if you don't already have it open):
-    <ol type="a">
-      <li>From the menu select <code>Window &gt; Open Perspective &gt; Other</code></li>      
-      <li>Select DDMS from the list and hit OK</li>
-    </ol>
-  </li>
-  <li>In the Devices panel (top right panel by default), click on the down triangle
-  to bring up the panel menu</li>
-  <li>Select <code>Reset ADB</code> from the menu, and then try running the
-  application again</li>
-</ol>
-<p>If the above still doesn't work, you can try these steps:</p>
-<ol>
-  <li>
-    Check the console and problems tabs at the bottom of the Eclipse UI
-  </li>
-  <li>
-    If there are problems listed in either place, they should give you a clue
-    what is wrong
-  </li>
-  <li>
-    If you aren't sure if the problems are fresh or stale, clear the console
-    with a right click &gt; Clear, then clean the project
-  </li>
-  <li>
-    To clean the project (a good idea with any kind of build error), select
-    Project &gt; Clean from the eclipse main menu, then select the project you
-    are working on (or clean all)
-  </li>
-</ol>
-<a name="eclipse"></a><h2>Eclipse isn't talking to the emulator</h2>
-<p>When communication doesn't seem to be happening between Eclipse and the emulator, symptoms can include: nothing happening when you press run, the emulator hanging waiting
-for a debugger to connect, or errors that Eclipse reports about not being able
-to find the emulator or shell. By far the most common symptom is that when you press run, the emulator starts (or
-is already running), but the application doesn't start.</p>
-<p>
-You may find any of these steps will fix the problem and with practice you
-probably can figure out which one you need to do for your particular issue, but
-to start with, the safest option is to run through all of them in order:</p>
-<ol>
-  <li>
-    Quit the emulator if it is running
-  </li>
-  <li>
-    Check that any emulator processes are killed (sometimes they    can hang, use ps on unix or mac, or task manager in the process view on
-    windows).
-  </li>
-  <li>
-    Quit Eclipse
-  </li>
-  <li>
-    From the command line, type: 
-<pre>adb kill-server </pre>
-  </li>
-  <li>
-    Start Eclipse and try again
-  </li>
-</ol>
-
-<a name="majorminor"></a><h2>When I go to preferences in Eclipse and select "Android", I get the following error message: Unsupported major.minor version 49.0.</h2>
-<p>This error is displayed if you are using an older version of the JDK. Please make sure you are using JDK version 5 or 6.</p>
-
-<h2 id="apidemosreinstall">I can't install ApiDemos apps in my IDE because of a signing error</a></h2>
-
-<p>The Android system requires that all applications be signed, as described in 
-	<a href="{@docRoot}guide/publishing/app-signing.html">Signing Your Applications</a>. The ApiDemos 
-applications included with the SDK are preinstalled on the emulator and for that reason have been 
-compiled and signed with a private key.</p>
-
-If you want to modify or run one of the ApiDemos apps from Eclipse/ADT or other IDE, you can do so 
-so only after you uninstall the <em>preinstalled</em> version of the app from the emulator. If 
-you try to run an ApiDemos app from your IDE without removing the preinstalled version first, 
-you will get errors similar to these: </p>
-
-<pre>[2008-08-13 15:14:15 - ApiDemos] Re-installation failed due to different application signatures.
-[2008-08-13 15:14:15 - ApiDemos] You must perform a full uninstall of the application. WARNING: ...This will remove the application data!
-[2008-08-13 15:14:15 - ApiDemos] Please execute 'adb uninstall com.android.samples' in a shell.</pre>
-
-<p>The error occurs because, in this case, you are attempting to install another copy of ApiDemos 
-onto the emulator, a copy that is signed with a different certificate. (The Android IDE tools will 
-have signed the app with a debug certificate, where the existing version was already signed with 
-a private certificate.) The system does not allow this type of reinstallation.  </p>
-
-<p>To resolve the issue, you need to fully uninstall the preinstalled and then reinstall it using 
-the adb tool. Here's how to do that:</p>
-
-<ol>
-  <li>In a terminal, change to the tools directory of the SDK.</li>
-  <li>If no emulator instance is running, start an emulator using using the command <code>emulator &</code>.</li>
-  <li>Uninstall the preinstalled app using the command <code>adb uninstall com.android.samples</code>.</li>
-  <li>Reinstall the app using the command <code>adb install &lt;path to the ApiDemos.apk&gt;</code>. If you are 
-  working in Eclipse/ADT, you can just compile and run the app in the normal way. </li>
-</ol>
-
-<p>Note that if multiple emulator instances are running, you need to direct your uninstall/install 
-commands to the emulator instance that you are targeting. To do that you can add the 
-<code>-s &lt;serialNumber&gt;</code> to the command, for example: </p>
-
-<pre>adb -s emulator-5556 install</pre>
-
-<p>For more information about adb, see the <a href="{@docRoot}guide/developing/tools/adb.html">Android Debug Bridge</a> 
-documentation.</p>
-
-<h2 id="gesturebuilderinstall">I can't install the GestureBuilder sample 
-app in the emulator</a></h2>
-
-<p>This is similar to the ApiDemos problem described above, except that
-you cannot fix it by uninstalling GestureBuilder from the emulator. The 
-GestureBuilder app cannot be uninstalled because it is currently installed 
-within the system files themselves.</p>
-
-<p><strong>Symptoms</strong></p>
-
-<ul><li><p>You cannot run GestureBuilder in the emulator:</p>
-
-<pre>[2009-12-10 14:57:19 - GestureBuilderActivity]Re-installation failed due to different application signatures.
-[2009-12-10 14:57:19 - GestureBuilderActivity]You must perform a full uninstall of the application. WARNING: This will remove the application data!
-[2009-12-10 14:57:19 - GestureBuilderActivity]Please execute 'adb uninstall com.android.gesture.builder' in a shell.</pre>
-</li>
-
-<li><p>Running <code>adb uninstall com.android.gesture.builder</code> fails:</p>
-<pre>$ adb uninstall com.android.gesture.builder
-	Failure</pre>
-</li></ul>
-
-<p>For now, the work-around is to change the sample's package name
-so that the system can install it as a new app rather than as a 
-replacement for the existing GestureBuilder app. To change the 
-package name, open the manifest file and modify the package attribute 
-of the manifest element. Next, update imports and other references to 
-the package name, rebuild the app, and run it in an AVD.</p>
-
-<p>For example, here's how you could do this in Eclipse:</p>
-
-<ol>
-  <li>Right-click on the package name
-(<code>src/com.android.gesture.builder</code>).</li>
-  <li>Select <strong>Refactor &gt; Rename</strong> and change the name, for example to
-<code>com.android.gestureNEW.builder</code>. </li>
-  <li>Open the manifest file. Inside the <code>&lt;manifest&gt;</code>
-tag, change the package name to
-<code>com.android.gestureNEW.builder</code>.</li>
-  <li>Open each of the two Activity files and do Ctrl-Shift-O to add
-missing import packages, then save each file.</li>
-<li>Run the GestureBuilder application on the emulator.</li>
-</ol>
-
-<p>If you get an error message such as "Could not load /sdcard/gestures. 
-Make sure you have a mounted SD card," be sure that your target AVD has an 
-SD card. To create an AVD that has an SD card, use the
-<a href="{@docRoot}guide/developing/tools/avd.html#options"><code>-c</code> 
-option</a> in the <code>android create avd</code> command.</p> 
-
-<h2 id="signingcalendar">I can't compile my app because the build tools generated an expired debug certificate</h2>
-
-<p>If your development machine uses a locale that has a non-Gregorian calendar, you may encounter problems when first trying to compile and run your application. Specifically, you may find that the Android build tools won't compile your application because the debug key is expired. </p>
-
-<p>The problem occurs because the Keytool utility &mdash; included in the JDK and used by the Android build tools &mdash; fails to properly handle non-Gregorian locales and may create validity dates that are in the past. That is, it may generate a debug key that is already expired, which results in the compile error.</p>
-
-<p>If you encounter this problem, follow these steps to work around it: </p>
-
-<ol>
-<li>First, delete the debug keystore/key already generated by the Android build tools. Specifically, delete the <code>debug.keystore</code> file. On Linux/Mac OSX, the file is stored in <code>~/.android</code>. On Windows XP, the file is stored in <code>
-C:\Documents and Settings\&lt;user&gt;\.android</code>. On Windows Vista, the file is stored in <code>
-C:\Users\&lt;user&gt;\.android</code></li>
-<li>Next, you can either
-<ul>
-<li>Temporarily change your development machine's locale (date and time) to one that uses a Gregorian calendar, for example, United States. Once the locale is changed, use the Android build tools to compile and install your app. The build tools will regenerate a new keystore and debug key with valid dates. Once the new debug key is generated, you can reset your development machine to the original locale. </li>
-<li>Alternatively, if you do not want to change your machine's locale settings, you can generate the keystore/key on any machine using the Gregorian calendar, then copy the <code>debug.keystore</code> file from that computer to the proper location on your development machine. </li>
-</ul>
-</li>
-</ol>
-
-<p>This problem has been verified on Windows and may apply to other platforms. </p>
-
-<p>For general information about signing Android applications, see 
-<a href="{@docRoot}guide/publishing/app-signing.html">Signing Your Applications</a>. </p>
-
-<h2 id="manifestfiles">Unable to view manifest files from within
-Eclipse</a></h2>
-
-<p>When you try to open an application's manifest file from within
-Eclipse, you might get an error such as this one:</p>
-<pre>An error has occurred. See error log for more details.
-org.eclipse.wst.sse.ui.StructuredTextEditor.isBlockSelectionModeEnabled()Z</pre>
-
-<p>Try reverting to the 3.0 version of the Eclipse XML Editors and
-Tools. If this does not work, remove the 3.1 version of the tool. To do
-this in Eclipse 3.4:</p>
-
-<ol>
-	<li>Select <strong>Help > Software Updates...</strong></li>
-	<li>Select the <strong>Installed Software</strong> tab.</li>
-	<li>Select <strong>Eclipse XML Editors and Tools</strong>.</li>
-	<li>Click <strong>Uninstall</strong>.</li>
-	<li>Click <strong>Finish</strong>.</li>
-</ol>
-
-<p>When you restart Eclipse, you should be able to view the manifest
-files. </p>
+<p>You should have already been redirected by your browser. Please follow
+<a href="{@docRoot}resources/faq/troubleshooting.html">this link</a>.</p>
\ No newline at end of file
diff --git a/docs/html/guide/developing/device.jd b/docs/html/guide/developing/device.jd
index abfae5d..3127e10 100644
--- a/docs/html/guide/developing/device.jd
+++ b/docs/html/guide/developing/device.jd
@@ -119,7 +119,7 @@
 
 <table>
   <tr>
-    <th>Manufacturer</th><th>USB Vendor ID</th></tr>
+    <th>Company</th><th>USB Vendor ID</th></tr>
   <tr>
     <td>Acer</td>
     <td><code>0502</code></td></tr>
@@ -133,6 +133,9 @@
     <td>Garmin-Asus</td>
     <td><code>091E</code></td></tr>
   <tr>
+    <td>Google</td>
+    <td><code>18d1</code></td></tr>
+  <tr>
     <td>HTC</td>
     <td><code>0bb4</code></td></tr>
   <tr>
diff --git a/docs/html/guide/developing/index.jd b/docs/html/guide/developing/index.jd
index 3a64dbc..4257bf0 100644
--- a/docs/html/guide/developing/index.jd
+++ b/docs/html/guide/developing/index.jd
@@ -23,7 +23,7 @@
       before continuing.</p>
     </li>
 
-    <li>Set up Android Virtual Devices or hardware devices</a>.
+    <li>Set up Android Virtual Devices or hardware devices.
 
       <p>You need to create Android Virtual Devices (AVD) or connect hardware devices on which
       you will install your applications.</p>
@@ -66,8 +66,8 @@
       run tests within an emulator or device.</p>
     </li>
   </ol>
-
-  <h2 id="EssentialTools">Essential command line tools</h2>
+ 
+<h2 id="EssentialTools">Essential command line tools</h2>
 
   <p>When developing in IDEs or editors other than Eclipse, be familiar with
   all of the tools below, because you will have to run them from the command line.</p>
@@ -112,6 +112,43 @@
   Eclipse, such as the <code>adb</code> shell commands. You might also need to call Keytool and Jarsigner to
   sign your applications, but you can set up Eclipse to do this automatically as well.</p>
   
-  <p>For more information on the tools provided with the Android SDK, see the
+<p>For more information on the tools provided with the Android SDK, see the
   <a href="{@docRoot}guide/developing/tools/index.html">Tools</a> section of the documentation.</p>
+  
+<h2 id="ThirdParty">Third-Party Development Tools</h2>
+<p>
+	The tools described in this section are not developed by the Android SDK team. The Android Dev Guide
+	    does not provide documentation for these tools. Please refer to the linked documents in each
+	    section for documentation.
+</p>  
+<h3 id="IntelliJ">Developing in IntelliJ IDEA</h3>
+<div style="float: right">
+<img alt="The IntelliJ graphical user interface" height="500px" src="{@docRoot}images/developing/intellijidea_android_ide.png"/>
+</div>
+<p>
+	IntelliJ IDEA is a powerful Java IDE from JetBrains that provides
+	full-cycle Android development support in both the free Community
+	Edition and the Ultimate edition.
+</p>
+<p>
+	The IDE ensures compatibility with the latest Android SDK and offers a
+	smart code editor with completion, quick navigation between code and
+	resources, a graphical debugger, unit testing support using Android
+	Testing Framework, and the ability to run applications in either the
+	emulator or a USB-connected device.
+</p>
+<p>
+	<strong>Links:</strong>
+</p>
+<ul>
+	<li>
+    	<a href="http://www.jetbrains.com/idea">IntelliJ IDEA official website</a>
+</li>
+	<li>
+    	<a href="http://www.jetbrains.com/idea/features/google_android.html">Android support in IntelliJ IDEA</a>
+</li>
+	<li>
+    	<a href="http://wiki.jetbrains.net/intellij/Android">IntelliJ IDEA Android Tutorials</a>
+	</li>
+</ul> 
 
diff --git a/docs/html/guide/developing/tools/monkeyrunner_concepts.jd b/docs/html/guide/developing/tools/monkeyrunner_concepts.jd
index 97c7c1f..c0795d7 100644
--- a/docs/html/guide/developing/tools/monkeyrunner_concepts.jd
+++ b/docs/html/guide/developing/tools/monkeyrunner_concepts.jd
@@ -128,7 +128,7 @@
 device.press('KEYCODE_MENU','DOWN_AND_UP')
 
 # Takes a screenshot
-result = device.takeSnapShot()
+result = device.takeSnapshot()
 
 # Writes the screenshot to a file
 result.writeToFile('myproject/shot1.png','png')
diff --git a/docs/html/guide/guide_toc.cs b/docs/html/guide/guide_toc.cs
index b13600c..fa588cb 100644
--- a/docs/html/guide/guide_toc.cs
+++ b/docs/html/guide/guide_toc.cs
@@ -310,7 +310,7 @@
             <span class="en">Search</span>
           </a></div>
           <ul>
-            <li><a href="<?cs var:toroot?>guide/topics/search/search-dialog.html">Using the Android Search Dialog</a></li>
+            <li><a href="<?cs var:toroot?>guide/topics/search/search-dialog.html">Creating a Search Interface</a></li>
             <li><a href="<?cs var:toroot?>guide/topics/search/adding-recent-query-suggestions.html">Adding Recent Query Suggestions</a></li>
             <li><a href="<?cs var:toroot?>guide/topics/search/adding-custom-suggestions.html">Adding Custom Suggestions</a></li>
             <li><a href="<?cs var:toroot?>guide/topics/search/searchable-config.html">Searchable Configuration</a></li>
@@ -630,7 +630,7 @@
             <span class="zh-TW" style="display:none">準備發佈</span>
           </a></li>
       <li><a href="<?cs var:toroot ?>guide/publishing/publishing.html">
-            <span class="en">Publishing Your Applications</span>
+            <span class="en">Publishing on Android Market</span>
           </a></li>
     </ul>
   </li>
diff --git a/docs/html/guide/practices/optimizing-for-3.0.jd b/docs/html/guide/practices/optimizing-for-3.0.jd
index a22e69a..5cd519b 100644
--- a/docs/html/guide/practices/optimizing-for-3.0.jd
+++ b/docs/html/guide/practices/optimizing-for-3.0.jd
@@ -5,20 +5,32 @@
 <div id="qv">
 <h2>In this document</h2>
 <ol>
-<li><a href="#Setup">Set Up Your SDK with Android 3.0</a></li>
-<li><a href="#SearchableConfiguration">Optimize Your App for Tablets and Similar Devices</a></li>
-<li><a href="#SearchableActivity">Upgrade or Develop a New App for Tablets and Similar
-Devices</a></li>
+<li><a href="#Setup">Setting Up Your SDK with Android 3.0</a></li>
+<li><a href="#Optimizing">Optimizing Your App for Tablets</a></li>
+<li><a href="#Upgrading">Upgrading or Developing a New App for Tablets</a></li>
+<li><a href="#ManagingAppDist">Managing App Distribution Based on Screen Configuration</a>
+  <ol>
+    <li><a href="#FilteringTabletApps">Filtering a tablet app from mobile devices</a></li>
+    <li><a href="#FilteringMobileApps">Filtering a mobile device app from tablets</a></li>
+  </ol>
+</li>
+<li><a href="#Issues">Other Issues</a>
+  <ol>
+    <li><a href="#Landscape">Adding support for landscape screens</a></li>
+    <li><a href="#Telephony">Using telephony or other variable features</a></li>
+  </ol>
+</li>
 </ol>
 
 </div>
 </div>
 
-<p>If you're developing an Android application, Android 3.0 introduces several features that allow
+<p>Android 3.0 introduces several features that allow
 you to enhance your user's experience on tablets and similar devices. Any application you've already
 published is compatible with devices running Android 3.0, by default, because Android applications
-are forward-compatible. However, there are some simple changes you should make to optimize your
-application for tablet-type devices.</p>
+are forward-compatible. However, new tablet devices running Android 3.0 are now available to the
+public and provide users a new Android experience on a larger screen, so you should make sure
+your application looks and works great on the new platform and new device form-factors.</p>
 
 <p>This document shows how you can optimize your existing application for Android 3.0 and
 maintain compatibility with older versions or upgrade your application completely with new APIs.</p>
@@ -27,18 +39,28 @@
 <p><b>To get started:</b></p>
 
 <ol>
-  <li><a href="#Setup">Set up your SDK with Android 3.0</a>.</li>
-  <li>Then choose to either optimize or upgrade:
+  <li><a href="#Setup">Set up your SDK with Android 3.0</a>.
+    <p>Install the Android 3.0 platform, new tools, and set up a new AVD.</p></li>
+  <li>Choose to either optimize or upgrade:
     <ol type="a">
-      <li><a href="#Optimize">Optimize Your App for Tablets and Similar Devices</a>.
-        <p>When you have an existing application and want to maintain compatibility with
-older versions of Android.</p>
+      <li><a href="#Optimizing">Optimize your app for tablets and similar devices</a>.
+        <p>Read this section if you have an existing application and want to
+maintain compatibility with older versions of Android. All you need to do is update your
+manifest file to declare support for Android 3.0, test your application on the new platform, and
+add extra resources to support extra large screens, as appropriate.</p>
       </li>
-      <li><a href="#Upgrade">Upgrade or Develop a New App for Tablets and Similar Devices</a>.
-        <p>When you want to upgrade your application to use APIs introduced in Android 3.0 or
-    create a new application targeted to tablets and similar devices.</p></li>
+      <li><a href="#Upgrading">Upgrade or develop a new app for tablets and similar devices</a>.
+        <p>Read this section if you want to upgrade your application to use APIs introduced in
+Android 3.0 or create a new application targeted to tablets and similar devices. Compared to
+upgrading to previous versions of Android, there's nothing different about upgrading to Android 3.0.
+This section introduces some of the key features and APIs you should use to make an
+application that's fully enhanced for tablets.</p></li>
     </ol>
   </li>
+  <li>Consider whether you need to <a href="#ManagingAppDist">manage the distribution of your
+application based on screen configuration</a>.</li>
+  <li>Then review some <a href="#Issue">other issues</a> you might encounter when developing
+for tablets and similar devices.</li>
 </ol>
 
 
@@ -66,14 +88,16 @@
   <p>Set the target to "Android 3.0" and the skin to "WXGA" (the default skin).</p></li>
 </ol>
 
+<p>The best way to test your application on Android 3.0 is to use real hardware running Android 3.0,
+such as the <a href="http://www.motorola.com/staticfiles/Consumers/XOOM/index.html">Motorola
+Xoom</a>. Of course, you can also use the Android emulator on your development machine, but because
+the Android emulator must simulate the ARM instruction set on your computer and the WXGA screen is
+significantly larger than a typical virtual device, emulator performance is much slower than a real
+device.</p>
 
 <h3>About emulator performance</h3>
 
-<p>Because the Android emulator must simulate the ARM instruction set on your computer
-and the WXGA screen is significantly larger than a typical virtual device, emulator performance is
-much slower than a real device.</p>
-
-<p>In particular, initializing the emulator can be slow and can take several minutes, depending on
+<p>Initializing the emulator can be slow and can take several minutes, depending on
 your hardware. When the emulator is booting, there is limited user feedback, so please be patient
 and wait until you see the home screen (or lock screen) appear. </p>
 
@@ -82,9 +106,10 @@
 Also see the tip below for information about using a snapshot to drastically reduce startup time
 after the first initialization. </p>
 
-<p>We're working hard to resolve the performance issues and it will improve in future tools
-releases. For the time being, the emulator is still best way to evaluate your application's
-appearance and functionality on Android 3.0 without a real device.</p>
+<p>General performance in the emulator is also slow. We're working hard to resolve the performance
+issues and it will improve in future tools releases. If you don't yet have a real device running
+Android 3.0, the emulator is still best way to evaluate your application's appearance and
+functionality on Android 3.0.</p>
 
 <p class="note"><strong>Tip:</strong> To improve the startup time for the emulator, enable snapshots
 for the AVD when you create it with the SDK and AVD Manager (there's a checkbox in the AVD creator
@@ -97,7 +122,7 @@
 
 
 
-<h2 id="Optimize">Optimize Your Application for Tablets and Similar Devices</h2>
+<h2 id="Optimizing">Optimizing Your App for Tablets</h2>
 
 <p>If you've already developed an application for an earlier version of Android, there are a few
 things you can do to optimize it for a tablet-style experience on Android 3.0 without changing the
@@ -142,21 +167,24 @@
 </pre>
     <p>By targeting the Android 3.0 platform, the system automatically applies the holographic theme
 to each activity when your application runs on an Android 3.0 device. The holographic theme
-provides a new design for widgets, such as buttons and text boxes, and restyles other
-visual elements. This is the standard theme in applications built for Android 3.0, so your
-application will look more at home by enabling the theme.</p>
-    <p>Additionally, the holographic theme enables the <a
-href="{@docRoot}guide/topics/ui/actionbar.html">Action Bar</a> in your activities when running on an
-Android 3.0 device. The Action Bar replaces the traditional title bar at the top of the activity
-window and provides the user access to the activity's Options Menu.</p>
+provides a new design for widgets, such as buttons and text boxes, and new styles for other
+visual elements. This is the standard theme for applications built for Android 3.0, so your
+application will look and feel consistent with the system and other applications when it is
+enabled.</p>
+    <p>Additionally, when an activity uses the holographic theme, the system enables the <a
+href="{@docRoot}guide/topics/ui/actionbar.html">Action Bar</a> for the activity. The Action Bar
+replaces the traditional title bar at the top of the activity window and provides the user access to
+the activity's Options Menu.</p>
       </li>
-      <li>Continue to build your application against the minimum version specified by <a
-href="{@docRoot}guide/topics/manifest/uses-sdk-element.html#min">{@code android:minSdkVersion}</a>,
-but install it on the Android 3.0 AVD. Repeat your tests to be sure that your user interface works
-well with the holographic theme.
+      <li>Build your application against the same version of the Android platform you have been
+using previously (such as the version declared in your <a
+href="{@docRoot}guide/topics/manifest/uses-sdk-element.html#min">{@code android:minSdkVersion}</a>),
+but install it on the Android 3.0 AVD. (You should not build against Android 3.0 unless you are
+using new APIs.) Repeat your tests to be sure that your user interface works well with the
+holographic theme.
         <p class="note"><strong>Note:</strong> If you have applied other themes directly to your
 activities, they will override the inherited holographic theme. To resolve this, you can use
-the <a href="{@docRoot}guide/topics/resources/providing-resources.html#VersionQualifier">system
+the <a href="{@docRoot}guide/topics/resources/providing-resources.html#VersionQualifier">platform
 version qualifier</a> to provide an alternative theme for Android 3.0 devices that's based on the
 holographic theme. For more information, read how to <a
 href="{@docRoot}guide/topics/ui/themes.html#SelectATheme">select a theme based on platform
@@ -177,15 +205,24 @@
 (wide), so you should be sure that your activities offer a layout that's optimized for a wide
 viewing area. <p>You can specify landscape resources with the <code>land</code> resource
 qualifier, but if you want alternative resources for an extra large landscape screen, you
-should use both <code>xlarge</code> and <code>land</code> qualifiers. For example, {@code
+should use both the <code>xlarge</code> and <code>land</code> qualifiers. For example, {@code
 res/layout-xlarge-land/}. The order of the qualifier names is important; see <a
 href="{@docRoot}guide/topics/resources/providing-resources.html#AlternativeResources">
 Providing Alternative Resources</a> for more information.</p></li>
-      <li>Button position: Consider whether the position of the most common buttons in your UI are
-easily accessible while holding a tablet with two hands.</li>
+      <li>Button position and size: Consider whether the position and size of the most common
+buttons in your UI make them easily accessible while holding a tablet with two hands. In some
+cases, you might need to resize buttons, especially if they use {@code "wrap_content"}
+as the width value. To enlarge the buttons, if necessary, you should either: add
+extra padding to the button; specify dimension values with {@code dp} units; or use {@code
+android:layout_weight} when the button is in a <a
+href="{@docRoot}guide/topics/ui/layout-objects.html#linearlayout">linear layout</a>. Use your
+best judgment of proportions for each screen size&mdash;you don't want the buttons to be too big,
+either.</li>
       <li>Font sizes: Be sure your application uses {@code sp} units when setting font
-sizes. This alone should ensure a readable experience on tablet-style devices. In some cases,
-however, you might want to consider larger font sizes for <code>xlarge</code> configurations.</li>
+sizes. This alone should ensure a readable experience on tablet-style devices, because it is a
+scale-independent pixel unit, which will resize as appropriate for the current screen configuration.
+In some cases, however, you still might want to consider larger font sizes for <code>xlarge</code>
+configurations.</li>
     </ul>
     <p>In general, always be sure that your application follows the <a
 href="{@docRoot}guide/practices/screens_support.html#screen-independence">Best Practices
@@ -197,7 +234,29 @@
 
 
 
-<h2 id="Upgrade">Upgrade or Develop a New App for Tablets and Similar Devices</h2>
+
+<h2 id="Upgrading">Upgrading or Developing a New App for Tablets</h2>
+
+<div class="sidebox-wrapper">
+<div class="sidebox">
+  <h3>Use new APIs and remain backward-compatible</h3>
+<p>It is possible for you to upgrade your application with some new
+APIs <em>and</em> remain compatible with older versions of Android. Usually, this requires that you
+use techniques such as reflection to check for the availability of certain APIs at runtime. However,
+to help you add features from Android 3.0 without requiring you to change your <a
+href="{@docRoot}guide/topics/manifest/uses-sdk-element.html#min">{@code android:minSdkVersion}</a>
+or build target, we're providing a static library called the "Android Compatibility package"
+(downloadable from the AVD and SDK Manager).</p>
+<p>This library includes APIs for <a
+href="{@docRoot}guide/topics/fundamentals/fragments.html">fragments</a>, <a
+href="{@docRoot}guide/topics/fundamentals/loaders.html">loaders</a>, and some updated classes. By
+simply adding this library to your Android project, you can use these APIs in your application and
+remain compatible with Android 1.6. For more information, see the blog post, <a
+href="http://android-developers.blogspot.com/2011/03/fragments-for-all.html">Fragments for
+All</a>.</p>
+</div>
+</div>
+
 
 <p>If you want to develop an application that's fully enhanced for tablet-type devices running
 Android 3.0, then you need to use new APIs in Android 3.0. This section introduces some of
@@ -206,9 +265,11 @@
 
 <h3>Declare the minimum system version</h3>
 
-<p>The first thing to do when you create a project for Android 3.0 is set your manifest's <a
-href="{@docRoot}guide/topics/manifest/uses-sdk-element.html#min">{@code android:minSdkVersion}</a>
-to {@code "11"}. For example:</p>
+<p>The first thing to do when you upgrade or create a project for Android 3.0 is set your manifest's
+<a href="{@docRoot}guide/topics/manifest/uses-sdk-element.html#min">{@code
+android:minSdkVersion}</a> to {@code "11"}. This declares that your application uses APIs available
+in Android 3.0 and greater, so it should not be available to devices running an older version of
+Android. For example:</p>
 
 <pre>
 &lt;manifest ... >
@@ -218,9 +279,11 @@
     &lt;application>
 &lt;/manifest>
 </pre>
-   
-<p>By targeting the Android 3.0 platform, the system automatically applies the new holographic theme
-to each of your activities.</p>
+
+<p>Not only is this necessary in order to declare the minimum API level your application requires,
+but it enables the new holographic theme to each of your activities. The holographic theme is the
+standard theme for the Android 3.0 system and all applications designed for it. It includes new
+designs for the system widgets and overall appearance.</p>
 
 <p>Additionally, the holographic theme enables the Action Bar for each activity.</p>
 
@@ -229,13 +292,14 @@
 
 <p>The Action Bar is a widget for activities that replaces the traditional title bar at the top of
 the screen. By default, the Action Bar includes the application logo on the left side, followed by
-the activity title, and any available items from the Options Menu on the right side.</p>
+the activity title, and access to items from the Options Menu in a drop-down list on the right
+side.</p>
 
-<p>You can enable items from your activity's Options Menu to appear directly in the Action Bar as
-"action items" by adding {@code showAsAction="ifRoom"} to specific items in your <a
+<p>You can enable items from the Options Menu to appear directly in the Action Bar as
+"action items" by adding {@code showAsAction="ifRoom"} to specific menu items in your <a
 href="{@docRoot}guide/topics/resources/menu-resource.html">menu resource</a>. You can also add
 navigation features to the Action Bar, such as tabs, and use the application icon to navigate to
-your application's "home" activity or "up" the activity hierarchy.</p>
+your application's "home" activity or to navigate "up" the application's activity hierarchy.</p>
 
 <p>For more information, read <a href="{@docRoot}guide/topics/ui/actionbar.html">Using the
 Action Bar</a>.</p>
@@ -244,11 +308,12 @@
 
 <h3>Divide your activities into fragments</h3>
 
-<p>A fragment represents a behavior or a portion of user interface in an activity. You can combine
-multiple fragments in a single activity to build a multi-pane UI and reuse a fragment in multiple
-activities. You can think of a fragment as a modular section of an activity, which has its own
-lifecycle, receives its own input events, and which you can add or remove while the activity is
-running.</p>
+<p>A fragment represents a behavior or a portion of user interface in an activity. You can think of
+a fragment as a modular section of an activity, which has its own lifecycle, receives its own input
+events, and which you can add or remove while the activity is running. Fragments are an optional
+component for your activities that allow you to build a multi-pane UI and reuse them in multiple
+activities. If you're building an application for tablets, we recommend that you use fragments to
+create activities that offer a more dynamic and flexible user interface.</p>
 
 <p>For example, a news application can use one fragment to show a list of articles on the left and
 another fragment to display an article on the right&mdash;both fragments appear in one activity,
@@ -262,8 +327,8 @@
 
 <h3>Use new animation APIs for transitions</h3>
 
-<p>An all new flexible animation framework allows you to animate arbitrary properties of any object
-(View, Drawable, Fragment, Object, or anything else). You can define several animation aspects
+<p>An all-new animation framework allows you to animate arbitrary properties of any object
+(such as a View, Drawable, Fragment, or anything else). You can define several animation aspects
 (such as duration, repeat, interpolation, and more) for an object's int, float, and hexadecimal
 color values, by default. That is, when an object has a property field for one of these types, you
 can change its value over time to affect an animation.</p>
@@ -279,8 +344,9 @@
 
 <h3>Enable hardware acceleration</h3>
 
-<p>You can now enable the OpenGL renderer for your application by setting {@code
-android:hardwareAccelerated="true"} in your manifest's <a
+<p>Android 3.0 adds a hardware-accelerated OpenGL renderer that gives a performance boost to most 2D
+graphics operations. You can enable hardware-accelerated rendering in your application by setting
+{@code android:hardwareAccelerated="true"} in your manifest's <a
 href="{@docRoot}guide/topics/manifest/application-element.html">{@code &lt;application&gt;}</a>
 element or for individual <a href="{@docRoot}guide/topics/manifest/activity-element.html">{@code
 &lt;activity&gt;}</a> elements. Hardware acceleration results in smoother animations, smoother
@@ -314,48 +380,16 @@
 href="{@docRoot}sdk/android-3.0.html">Android 3.0 Platform</a> document.</p>
 
 
-<h3>Publish your app for extra large screens</h3>
-
-<p>You should also decide whether your application is <em>only</em> for
-tablet-type devices (specifically, <em>xlarge</em> devices) or for all types of screen sizes.</p>
-
-<p>If you want your application to be available to all screen sizes (for example, for all
-phones and tablets), there's nothing you need to do. By default, an application with <a
-href="{@docRoot}guide/topics/manifest/uses-sdk-element.html#min">{@code
-android:minSdkVersion}</a> set to {@code "4"} or higher will resize to fit any screen size.</p>
-
-<p>If your application is <em>only</em> for <em>xlarge</em> screens, include the <a
-href="{@docRoot}guide/topics/manifest/supports-screens-element.html">{@code
-&lt;supports-screens&gt;}</a> element in your manifest and declare that the application supports
-only <em>xlarge</em> screens, by declaring all other sizes {@code "false"}. For example:</p>
-
-<pre>
-&lt;manifest ... >
-    ...
-    &lt;supports-screens android:smallScreens="false"
-                      android:normalScreens="false"
-                      android:largeScreens="false"
-                      android:xlargeScreens="true" /&gt;
-    &lt;application ... >
-        ...
-    &lt;application>
-&lt;/manifest>
-</pre>
-
-<p>With this declaration, you indicate that your application does not support any screen size except
-extra large. External services such as Android Market may then use this information to filter your
-application from devices that do not have an extra large screen.</p>
-
-
 
 <h3>Look at some samples</h3>
 
-<p>Many of the new features and APIs that are described in the <a
-href="{@docRoot}sdk/android-3.0.html#api">Android 3.0 Platform Preview</a> also have accompanying
-samples that can help you understand how to use them. To get the samples, download them from the SDK
-repository using the Android SDK Manager. After downloading the samples ("Samples for SDK API 11"), 
-you can find them in <code>&lt;sdk_root&gt;/samples/android-11/</code>. The links below can help you
-find samples for the features you are interested in:</p>
+<p>Many of the new features and APIs that are described above and in the <a
+href="{@docRoot}sdk/android-3.0.html#api">Android 3.0 Platform</a> document also have accompanying
+samples that allow you to preview the effects and can help you understand how to use them. To get
+the samples, download them from the SDK repository <a href="{@docRoot}sdk/adding-components.html"
+>using the Android SDK and AVD Manager</a>. After downloading the samples ("Samples for SDK API
+11"), you can find them in <code>&lt;sdk_root&gt;/samples/android-11/</code>. The following list
+provides links to the browsable source code for some of the samples:</p>
 
 <ul>
   <li><a href="{@docRoot}resources/samples/HoneycombGallery/index.html">Honeycomb Gallery</a>:
@@ -395,3 +429,248 @@
 graphics.</li>
 </ul>
 
+
+
+<h2 id="ManagingAppDist">Managing App Distribution Based on Screen Configuration</h2>
+
+<p>If your manifest file has either <a
+href="{@docRoot}guide/topics/manifest/uses-sdk-element.html#min">{@code android:minSdkVersion}</a>
+or <a href="{@docRoot}guide/topics/manifest/uses-sdk-element.html#target">{@code
+android:targetSdkVersion}</a> set to {@code "4"} or higher, then the Android system will scale your
+application's layout and assets to fit the current device screen, whether the device screen is
+smaller or larger than the one for which you originally designed your application. As such, you
+should always test your application on real or <a
+href="{@docRoot}guide/developing/devices/index.html">virtual devices</a> with various screen sizes
+and densities.</p>
+
+<p>Although we recommend that you design your application to function properly on multiple
+configurations of screen size and density, you can instead choose to limit the distribution of your
+application to certain types of screens, such as only tablets or only mobile devices. To do so, you
+can add elements to your Android manifest file that enable filtering based on screen configuration
+by external services such as Android Market.</p>
+
+<p>However, before you decide to restrict your application to certain screen configurations, you
+should understand the techniques for <a
+href="{@docRoot}guide/practices/screens_support.html">supporting multiple screens</a> and employ
+them to the best of your ability. By supporting multiple screens, your application can be made
+available to the greatest number of users with different devices.</p>
+
+
+<h3 id="FilteringTabletApps">Filtering a tablet application from mobile devices</h3>
+
+<p>If the system scaling adversely affects your application UI when scaling your application down
+for smaller screens, you should add <a
+href="{@docRoot}guide/topics/resources/providing-resources.html#AlternativeResources">alternative
+layouts</a> for smaller screens to adjust your layout. However, sometimes your layout still might
+not fit a smaller screen or you've explicitly designed your application only for tablets and other
+large devices. In this case, you can manage the availability of your application to smaller screens
+by using the <a href="{@docRoot}guide/topics/manifest/supports-screens-element.html">{@code
+&lt;supports-screens>}</a> manifest element.</p>
+
+<p>For example, if you want your application to be available only to extra large
+screens, you can declare the element in your manifest like this:</p>
+
+<pre>
+&lt;manifest ... >
+    ...
+    &lt;supports-screens android:smallScreens="false"
+                      android:normalScreens="false"
+                      android:largeScreens="false"
+                      android:xlargeScreens="true" /&gt;
+    &lt;application ... >
+        ...
+    &lt;application>
+&lt;/manifest>
+</pre>
+
+<p>External services such as Android Market read this manifest element and use it to ensure that
+your application is available only to devices with an extra large screen.</p>
+
+<p class="note"><strong>Note:</strong> If you use the <a
+href="{@docRoot}guide/topics/manifest/supports-screens-element.html">{@code
+&lt;supports-screens>}</a> element for the reverse scenario (when your application is not compatible
+with <em>larger</em> screens) and set the larger screen size attributes to {@code "false"}, then
+external services such as Android Market <strong>do not</strong> apply filtering. Your application
+will still be available to larger screens, but when it runs, it will not fill the screen&mdash;the
+system will draw it in a "postage stamp" window that's the same relative size as the screen size
+that your application does support. If you want to prevent your application from being downloaded on
+larger screens, see the following section.</p>
+
+
+<h3 id="FilteringMobileApps">Filtering a mobile device application from tablets</h3>
+
+<p>Because Android automatically scales applications to fit larger screens, you shouldn't
+need to filter your application from larger screens. However, you might discover that your
+application can't scale up or perhaps you've decided to publish two versions of your application
+that each deliver different features for different screen configurations, so you don't want
+larger devices to download the version designed for smaller screens. In such a case, you can
+use the <a href="{@docRoot}guide/topics/manifest/compatible-screens-element.html">{@code
+&lt;compatible-screens>}</a> element to manage the distribution of your application based on the
+combination of screen size and density. External services such as
+Android Market uses this information to apply filtering to your application, so that only devices
+that have a screen configuration with which you declare compatibility can download your
+application.</p>
+
+<p>The <a href="{@docRoot}guide/topics/manifest/compatible-screens-element.html">{@code
+&lt;compatible-screens>}</a> element must contain one or more {@code &lt;screen&gt;} elements,
+which each specify a screen configuration with which your application is compatible, using both
+the {@code android:screenSize} and {@code android:screenDensity} attributes. Each {@code
+&lt;screen&gt;} element <strong>must include both attributes</strong> to specify an individual
+screen configuration&mdash;if either attribute is missing, then the element is invalid
+(external services such as Android Market will ignore it).</p>
+
+<p>For example, if your application is compatible with only small and normal screens, regardless
+of screen density, then you must specify eight different {@code &lt;screen&gt;} elements,
+because each screen size has four density configurations. You must declare each one of
+these; any combination of size and density that you do <em>not</em> specify is considered a screen
+configuration with which your application is <em>not</em> compatible. Here's what the manifest
+entry looks like if your application is compatible with only small and normal screens:</p>
+
+<pre>
+&lt;manifest ... >
+    ...
+    &lt;compatible-screens>
+        &lt;!-- all small size screens -->
+        &lt;screen android:screenSize="small" android:screenDensity="ldpi" />
+        &lt;screen android:screenSize="small" android:screenDensity="mdpi" />
+        &lt;screen android:screenSize="small" android:screenDensity="hdpi" />
+        &lt;screen android:screenSize="small" android:screenDensity="xhdpi" />
+        &lt;!-- all normal size screens -->
+        &lt;screen android:screenSize="normal" android:screenDensity="ldpi" />
+        &lt;screen android:screenSize="normal" android:screenDensity="mdpi" />
+        &lt;screen android:screenSize="normal" android:screenDensity="hdpi" />
+        &lt;screen android:screenSize="normal" android:screenDensity="xhdpi" />
+    &lt;/compatible-screens>
+    &lt;application ... >
+        ...
+    &lt;application>
+&lt;/manifest>
+</pre>
+
+<p class="note"><strong>Note:</strong> Although you can also use the <a
+href="{@docRoot}guide/topics/manifest/compatible-screens-element.html">{@code
+&lt;compatible-screens>}</a> element for the reverse scenario (when your application is not
+compatible with smaller screens), it's easier if you instead use the <a
+href="{@docRoot}guide/topics/manifest/supports-screens-element.html">{@code
+&lt;supports-screens>}</a> as discussed in the previous section, because it doesn't require you
+to specify each screen density your application supports.</p>
+
+<p>Remember, you should strive to make your application available to as many devices as possible by
+applying all necessary techniques for <a
+href="{@docRoot}guide/practices/screens_support.html">supporting multiple screens</a>. You should
+then use the <a href="{@docRoot}guide/topics/manifest/compatible-screens-element.html">{@code
+&lt;compatible-screens>}</a> element to filter your application from certain devices only when you
+cannot offer compatibility on all screen configurations or you have decided to provide
+multiple versions of your application, each for a different set of screen configurations.</p>
+
+
+
+<h2 id="Issues">Other Issues</h2>
+
+<p>Whether you decide to optimize or upgrade your application for tablet-type devices, you
+should be aware that the functionality and availability of your application on new devices
+might be affected by the following issues:</p>
+
+<ul>
+  <li><a href="#Landscape">Tablets are often designed for use in the landscape orientation</a>
+  <p>Tablets and similar devices often have a screen that uses the landscape orientation
+by default. If your application assumes a portrait orientation or locks into portrait
+orientation, you should update your application to support landscape.</p></li>
+  <li><a href="#Telephony">Not all devices have telephony or other features</a>
+  <p>If your application declares the {@code "android.hardware.telephony"} feature in the manifest,
+then it will not be available to devices that do not offer telephony (such as tablets), based on
+Android Market filtering. If your application can function properly without telephony, you should
+update your application to gracefully disable the telephony features when not available on a
+device.</p></li>
+</ul>
+
+
+<h3 id="Landscape">Adding support for landscape screens</h3>
+
+<p>Although tablets can rotate to operate in any orientation, they are often designed for
+landscape orientation and that is how most users will use them. So, you should ensure that your
+application can function in landscape. Even if you want to avoid rotating the screen while your
+application is running, you should not assume that portrait is the device's default orientation. You
+should either ensure that your layout is usable in both portrait and landscape orientations or
+provide an <a href="{@docRoot}guide/topics/resources/providing-resources.html#AlternativeResources" 
+>alternative layout resource</a> for landscape orientation.</p>
+
+<p>If you believe your application or game provides its best experience when the screen is tall,
+consider that tablets and similar devices have a screen that's as tall or taller in landscape
+orientation than a phone in portrait orientation. With that in mind, you might be able to add a
+landscape design that adds padding or extra landscape scenery on the left and right sides, so
+the primary screen space still remains taller than it is wide.</p>
+
+<p>Ideally, your application should handle all orientation changes instead of locking into one
+orientation. When the user rotates the screen, the system restarts the current activity by calling
+{@link android.app.Activity#onDestroy onDestroy()} and {@link android.app.Activity#onCreate
+onCreate()}) in immediate succession. You should design your activity to account for these changes
+in the lifecycle, so the activity can save and restore its state. You can learn about the
+necessary lifecycle callback methods and how to save and restore the activity state in the <a
+href="{@docRoot}guide/topics/fundamentals/activities.html#Lifecycle">Activities</a>
+document. If your activity state is more complex and cannot retain it using the normal
+lifecycle callback methods, you can use alternative techniques described in <a
+href="{@docRoot}guide/topics/resources/runtime-changes.html">Handling Runtime Changes</a>.</p>
+
+<p>In the worst-case scenario, however, you can avoid orientation changes by using the <a
+href="{@docRoot}guide/topics/manifest/activity-element.html#screen">{@code
+android:screenOrientation}</a> attribute in the <a
+href="{@docRoot}guide/topics/manifest/activity-element.html">{@code &lt;activity&gt;}</a>
+element. Instead of locking the orientation in landscape or portrait, however, you should
+specify a value of {@code "nosensor"}. This way, your activity uses whatever orientation the
+device specifies as its natural orientation and the screen will not rotate. You should still
+avoid using the <a
+href="{@docRoot}guide/topics/manifest/activity-element.html#screen">{@code
+android:screenOrientation}</a> attribute, but because it's sometimes necessary to lock the
+screen into one orientation, it's best if you do so in a way that uses the device's natural
+orientation instead of assuming one specific orientation.</p>
+
+<p>If your application uses the orientation sensors, such as the accelerometer (with the {@link
+android.hardware.SensorManager} APIs), also be aware that the landscape screen can also cause
+problems, due to false assumptions about which orientation is the natural position. For more
+information about how you should properly handle rotation changes when using the orientation
+sensors, read the blog post, <a
+href="http://android-developers.blogspot.com/2010/09/one-screen-turn-deserves-another.html">One
+Screen Turn Deserves Another</a>.</p>
+
+
+
+<h3 id="Telephony">Using telephony or other variable features</h3>
+
+<p>Tablets and similar devices might not include support for telephony, so they can't make
+traditional phone calls or handle SMS. Some devices might also omit
+other hardware features, such as Bluetooth. If your application uses these features, then your
+manifest file probably already includes (or should include) a declaration of the feature with the <a
+href="{@docRoot}guide/topics/manifest/uses-feature-element.html">{@code &lt;uses-feature&gt;}</a>
+element. Doing so prevents devices that do not declare support for the feature from downloading
+your applications. For example:</p>
+
+<pre>&lt;uses-feature android:name="android.hardware.telephony" /></pre>
+
+<p>By default, this declares that your application <em>requires</em> telephony features. So,
+external services such as Android Market use this information to filter your application from
+devices that do not offer telephony.</p>
+
+<p>If, however, your application uses, but does not require the feature, you should
+add to this element, {@code android:required="false"}. For example:</p>
+
+<pre>&lt;uses-feature android:name="android.hardware.telephony" android:required="false" /></pre>
+
+<p>This indicates that your application uses the feature, but is still functional if the feature is
+not available. So, it should still be available to devices that don't provide telephony hardware
+(or telephony features), such as tablets.</p>
+
+<p>Then in your application code, you must gracefully disable the features that use telephony
+when it's not available. You can check whether the feature is available using {@link
+android.content.pm.PackageManager#hasSystemFeature PackageManager.hasSystemFeature()}. For
+example:</p>
+
+<pre>
+PackageManager pm = getPackageManager();
+boolean hasTelephony = pm.hasSystemFeature(PackageManager.FEATURE_TELEPHONY);
+</pre>
+
+<p>For more information about these
+issues and how to future-proof your application for different hardware, read the blog post <a
+href="http://android-developers.blogspot.com/2010/10/five-steps-to-future-hardware-happiness.html">
+The Five Steps to Future Hardware Happiness</a>.</p>
\ No newline at end of file
diff --git a/docs/html/guide/publishing/app-signing.jd b/docs/html/guide/publishing/app-signing.jd
index 93077a0..df240e2 100644
--- a/docs/html/guide/publishing/app-signing.jd
+++ b/docs/html/guide/publishing/app-signing.jd
@@ -260,8 +260,8 @@
 
 <p>To fix this problem, simply delete the <code>debug.keystore</code> file. 
 The default storage location for AVDs is in <code>~/.android/</code> on OS X and Linux, 
-in <code>C:\Documents and Settings\<user>\.android\</code> on Windows XP, and in
-<code>C:\Users\<user>\.android\</code> on Windows Vista.</p>
+in <code>C:\Documents and Settings\&lt;user>\.android\</code> on Windows XP, and in
+<code>C:\Users\&lt;user>\.android\</code> on Windows Vista and Windows 7.</p>
 
 
 <p>The next time you build, the build tools will regenerate a new keystore and debug key.</p>
diff --git a/docs/html/guide/publishing/publishing.jd b/docs/html/guide/publishing/publishing.jd
index af1ea74..0cbba53 100644
--- a/docs/html/guide/publishing/publishing.jd
+++ b/docs/html/guide/publishing/publishing.jd
@@ -1,4 +1,4 @@
-page.title=Publishing Your Applications
+page.title=Publishing on Android Market
 @jd:body
 
 <div id="qv-wrapper">
@@ -16,22 +16,22 @@
 <h2>In this document</h2>
 
 <ol>
-<li><a href="#overview">Publishing on Android Market</a>
-    <ol>
-    <li><a href="#marketupgrade">Publishing Updates on Android Market</a></li>
-    <li><a href="#marketLicensing">Using Android Market Licensing Service</a></li>
-    <li><a href="#marketintent">Using Intents to Launch the Market Application</a></li>
-    </ol></li>
-<!--
-<li><span style="color:ccc">Publishing on Other Hosted Services</a></li>
-<li><span style="color:ccc">Publishing through a Web Server</a></li>
--->
+<li><a href="#overview">About Android Market</a>
+<li><a href="#marketupgrade">Publishing Updates on Android Market</a></li>
+<li><a href="#marketLicensing">Using Android Market Licensing Service</a></li>
+<li><a href="#marketintent">Linking to Your Apps on Android Market</a>
+  <ol>
+    <li><a href="#OpeningDetails">Opening an app's details page</a></li>
+    <li><a href="#PerformingSearch">Performing a search</a></li>
+    <li><a href="#UriSummary">Summary of URI formats</a></li>
+  </ol>  
+</li>
 </ol>
 
 <h2>See also</h2>
 
 <ol>
-<li><a href="{@docRoot}guide/publishing/licensing.html">Licensing Your Applications</a></li>
+<li><a href="{@docRoot}guide/publishing/licensing.html">Application Licensing</a></li>
 <li><a href="{@docRoot}guide/publishing/preparing.html">Preparing to Publish</a></li>
 </ol>
 
@@ -39,43 +39,45 @@
   <img id="rule" src="{@docRoot}assets/images/grad-rule-qv.png">
   <div id="qv-sub-rule">
     <img src="{@docRoot}assets/images/icon_market.jpg" style="float:left;margin:0;padding:0;">
-    <p style="color:#669999;">Interested in publishing your app on Android Market?</p>
-    <a id="publish-link" href="http://market.android.com/publish">Go to Android Market &raquo;</a>
+    <h2 style="color:#669999;">Interested in publishing your app on Android Market?</h2>
+    <p><a href="http://market.android.com/publish">Go to Android Market</a> to
+create a developer account and upload your application. For more information about the
+required assets, listing details, and options, see <a
+href="http://market.android.com/support/bin/answer.py?answer=113469">Uploading
+applications</a>.</p>
   </div>
 </div>
 
 </div>
 </div>
 
-<p>Publishing an application means testing it, packaging it appropriately, and making 
-it available to users of Android-powered mobile devices for download or sideload.</p>
+<p>If you've followed the steps outlined in <a
+href="{@docRoot}guide/publishing/preparing.html">Preparing to Publish</a>, the result of the process
+is a compiled {@code .apk} file that is signed with your private release key. Your application is
+now ready to be published publicly so users can install it.</p>
 
-<p>If you've followed the steps outlined in 
-<a href="{@docRoot}guide/publishing/preparing.html">Preparing to
-Publish Your Applications</a>, the result of the process is a compiled .apk that
-is signed with your release private key. Inside the .apk, the application is
-properly versioned and any MapView elements reference a Maps API Key that you
-obtained by registering the MD5 fingerprint of the same certificate used to sign
-the .apk. Your application is now ready for publishing. </p>
+<p>You can publish your application and allow users to install it any way you choose, including
+from your own web server. This document provides information about publishing your Android
+application with Android Market.</p>
 
-<p>The sections below provide information about publishing your Android
-application to mobile device users.</p>
 
-<h2 id="overview">Publishing on Android Market</h2>
+<h2 id="overview">About Android Market</h2>
 
-<p>Android Market is a hosted service that makes it easy for users to find and
-download Android applications to their Android-powered devices, and makes it 
-easy for developers to publish their applications to Android users.</p>
+<p>Android Market is a service that makes it easy for users to find and download Android
+applications to their Android-powered devices, either from the Android Market application on their
+device or from the Android Market web site (<a
+href="http://market.android.com">market.android.com</a>). As a developer, you can use Android Market
+to distribute your applications to users on all types of Android-powered devices, all around the
+world.</p>
 
 <p>To publish your application on Android Market, you first need to register
-with the service using your Google account and agree to the terms of service.
+with the service using a Google account and agree to the terms of service.
 Once you are registered, you can upload your application to the service whenever
-you want, as many times as you want, and then publish it when you are ready.
-Once published, users can see your application, download it, and rate it using
-the Market application installed on their Android-powered devices. </p>
+you want, update it as many times as you want, and then publish it when you are ready.
+Once published, users can see your application, download it, and rate it. </p>
 
 <p>To register as an Android Market developer and get started with publishing,
-visit the Android Market: </p>
+visit the Android Market publisher site: </p>
 
 <p style="margin-left:3em;"><a
 href="http://market.android.com/publish">http://market.android.com/publish</a>
@@ -94,22 +96,24 @@
 <code>android:versionName</code> attribute in the
 <a
 href="{@docRoot}guide/topics/manifest/manifest-element.html"><code>&lt;manifest&gt;</code></a>
-element of its manifest. The server uses the <code>android:versionCode</code> as
+element of its manifest file. The server uses the <code>android:versionCode</code> as
 the basis for identifying the application internally and handling updates, and
 it displays the <code>android:versionName</code> to users as the application's
 version.</li>
 <li>Your application must define both an <code>android:icon</code> and an
-<code>android:label</code> attribute in the <code>&lt;application&gt;</code>
-element of its manifest.</li>
+<code>android:label</code> attribute in the <a
+href="{@docRoot}guide/topics/manifest/application-element.html"><code>&lt;application&gt;</code></a>
+element of its manifest file.</li>
 </ol>
 </div>
 
-<h3 id="marketupgrade">Publishing Updates on Android Market</h3>
+
+<h2 id="marketupgrade">Publishing Updates on Android Market</h2>
 
 <p>At any time after publishing an application on Android Market, you can upload
 and publish an update to the same application package. When you publish an
 update to an application, users who have already installed the
-application will automatically receive a notification that an update is
+application may receive a notification that an update is
 available for the application. They can then choose to update the application
 to the latest version.</p>
 
@@ -117,190 +121,231 @@
 the <code>android:versionCode</code> and <code>android:versionName</code>
 attributes in the <a
 href="{@docRoot}guide/topics/manifest/manifest-element.html"><code>&lt;manifest&gt;</code></a>
-element of the manifest file. Also, the package name must be the same and the
-.apk must be signed with the same private key. If the package name and signing
+element of the manifest file. Also, the package name must be the same as the existing version and
+the {@code .apk} file must be signed with the same private key. If the package name and signing
 certificate do <em>not</em> match those of the existing version, Market will
-consider it a new application and will not offer it to users as an update.</p>
+consider it a new application, publish it as such, and will not offer it to existing users as an
+update.</p>
 
 
-<h3 id="marketLicensing">Using Android Market Licensing Service</h3>
+<h2 id="marketLicensing">Using Android Market Licensing Service</h2>
 
 <p>Android Market offers a licensing service that lets you enforce licensing
 policies for paid applications that you publish through Android Market. With
-Android Market Licensing, your applications can query Android Market at run time
-to obtain their licensing status for the current user, then allow or disallow
-further use as appropriate. Using the service, you can apply a flexible
-licensing policy on an application-by-application basis &mdash; each 
+Android Market Licensing, your applications can query Android Market at runtime
+to obtain the licensing status for the current user, then allow or disallow
+further use of the application as appropriate. Using the service, you can apply a flexible
+licensing policy on an application-by-application basis&mdash;each 
 application can enforce its licensing status in the way most appropriate
 for it. </p>
 
 <p>Any application that you publish through Android Market can use the Android
-Market Licensing Service. The service uses no dedicated framework APIs, you can
-add licensing to any legacy application that uses a minimum API level of 3 or
+Market Licensing Service. The service uses no dedicated framework APIs, so you can
+add licensing to any application that uses a minimum API Level of 3 or
 higher.</p>
 
 <p>For complete information about Android Market Licensing Service and how to
-use it in your application, see <a
-href="{@docRoot}guide/publishing/licensing.html">Licensing Your
-Applications</a>.</p>
+use it in your application, read <a
+href="{@docRoot}guide/publishing/licensing.html">Application Licensing</a>.</p>
 
 
-<h3 id="marketintent">Using Intents to Launch the Market Application on 
-a Device</h3>
 
-<p>Android-powered devices include a preinstalled Market application that gives
-users access to the Android Market site. From Market, users can
-browse or search available applications, read ratings and reviews, and
-download/install applications.</p>
+<h2 id="marketintent">Linking to Your Apps on Android Market</h2>
 
-<p>You can launch the Market application from another Android
-application by sending an Intent to the system. You might want to do
-this, for example, to help the user locate and download an update to an
-installed application, or to let the user know about related
-applications that are available for download. </p>
-
-<p>To launch Market, you send an ACTION_VIEW Intent, passing a Market-handled
-URI string as the Intent data. In most cases, your application would call
-startActivity() to send the ACTION_VIEW Intent with the Market-handled URI.</p>
-
-<p>The URI that you supply with the Intent lets the system route the intent
-properly and also expresses the type of action that you want Market to perform
-after launch. Currently, you can have Market take these actions:</p>
+<p>To help users discover your published applications, you can use two special Android Market URIs
+that direct users to your application's details page or perform a search for all of your published
+applications in Android Market. You can use these URIs to do the following:</p>
 
 <ul>
-<li>Initiate a search for applications on Android Market, based on the query
-parameters that you provide, or </li>
-<li>Load the Details page for a specific application on Android Market, based on
-the application's package name.</li>
+  <li>Create a button in your application or a link on a web page that opens one of your
+application's details page in the Android Market application or web site.</li>
+  <li>Create a button in your application or a link on a web page that searches for all your
+published applications in the Android Market application or web site.</li>
 </ul>
 
-<h4>Initiating a search</h4>
+<p>You can launch the Android Market application or web site in the following ways:</p>
+<ul>
+  <li>Initiate an {@link android.content.Intent} from your application that launches the
+Android Market application on the user's device. The intent must use the {@link
+android.content.Intent#ACTION_VIEW} action, and include intent data with the appropriate
+Android Market URI scheme.</li>
+  <li>Provide a hyperlink on a web page that opens the Android Market web site.</li>
+</ul>
 
-<p>Your application can initiate a search on Android Market for applications
-that match the query parameters that you provide. To do so, your application
-sends an ACTION_VIEW Intent that includes a URI and query parameters in this
+<p>In both cases, you need to create a URI that indicates either the application you'd like to view
+in Android Market or the search you'd like to perform. The URI is quite similar whether you want
+to open the application or open the web site. The only difference is the URI prefix.</p>
+
+<p>To open the Android Market application on the device, the prefix for the intent's data URI
+is:</p>
+
+<p style="margin-left:2em"><code>market://</code></p>
+
+<p>To open the Android Market web site, the prefix for the link URI is:</p>
+
+<p style="margin-left:2em"><code>http://market.android.com/</code></p>
+
+<p>To complete each URI, you must append a string that specifies either the
+application for which you want to view or the search to execute. The following sections
+describe how to create a complete URI for each case.</p>
+
+<p class="note"><strong>Note:</strong> If you create a link to open the Android Market web site and
+the user selects it from an Android-powered device, the Android Market application will also resolve
+the link so the user can use the native application instead of the web site. Also, because the
+Android Market application also reads the {@code http://} URIs, you can also use them in an intent,
+but you should usually use the {@code market://} URIs for an intent, so that the native application
+is opened by default. You should use {@code http://} URIs only when creating links from a web
+page.</p>
+
+
+<h3 id="OpeningDetails">Opening an app's details page</h3>
+
+<p>As described above, you can open the details page for a specific application either on the
+Android Market application or the Android Market web site. The details page allows the user to see
+the application description, screenshots, reviews and more, and choose to install it.</p>
+
+<p>The format for the URI that opens the details page is:</p>
+
+<p style="margin-left:2em"><code>&lt;URI_prefix&gt;<b>details?id=</b>&lt;package_name&gt;</code></p>
+
+<p>The <code>&lt;package_name&gt;</code> is a placeholder for the target application's fully
+qualified package name, as declared in the <a
+href="{@docRoot}guide/topics/manifest/manifest-element.html#package">{@code
+package}</a> attribute of the <a href="{@docRoot}guide/topics/manifest/manifest-element.html">{@code
+&lt;manifest&gt;}</a> element in the application's manifest file.</p>
+
+
+<h4>Opening details in the Android Market application</h4>
+
+<p>To open the details page in the Android Market application, create an intent with the
+{@link android.content.Intent#ACTION_VIEW} action and include a data URI in this format:</p>
+
+<p style="margin-left:2em"><code>market://details?id=&lt;package_name&gt;</code></p>
+
+<p>For example, here's how you can create an intent and open an application's details page in the
+Android Market application:</p>
+
+<pre>
+Intent intent = new Intent(Intent.ACTION_VIEW);
+intent.setData(Uri.parse("market://details?id=com.android.example"));
+startActivity(intent);
+</pre>
+
+
+<h4>Opening details on the Android Market web site</h4>
+
+<p>To open the details page on the Android Market web site, create a link with a URI in this
 format:</p>
 
-<p style="margin-left:2em"><code>market://search?q=&lt;paramtype&gt;:&lt;value&gt;</code></p>
+<p style="margin-left:2em">
+  <code>http://market.android.com/details?id=&lt;package_name&gt;</code>
+</p>
 
-<div class="sidebox-wrapper" xstyle="margin-bottom:2em;margin-top:.5em;width:90%;"> 
-  <img id="rule" src="{@docRoot}assets/images/grad-rule-qv.png"> 
-  <div id="qv-sub-rule"> 
-    <img src="{@docRoot}assets/images/icon_market.jpg" style="float:left;margin:0;padding:0;"> 
-    <p style="color:#669999;">Searches on Android Market</p> 
-<p>When you initiate a search, Android Market returns results from matches in
-the public metadata supplied by developers in their Android Market profiles or
-application publishing information, but not from the developer's private account
-or from the certificate used to sign the application. </p>
-  </div> 
-</div>
+<p>For example, here's a link that opens an application's details page on the Android Market web
+site:</p>
 
-<p>Using this URI format, you can search for applications by:</p>
+<pre>
+&lt;a href="http://market.android.com/details?id=com.android.example">App Link&lt;/a>
+</pre>
+
+
+
+<h3 id="PerformingSearch">Performing a search</h3>
+
+<p>To initiate a search in Android Market, the format for the URI is:</p>
+
+<p style="margin-left:2em">
+  <code>&lt;URI_prefix&gt;<b>search?q=</b>&lt;query&gt;</code>
+</p>
+
+<p>The <code>&lt;query&gt;</code> is a placeholder for the search query to execute in Android
+Market. The query can be a raw text string or you can include a parameter that performs a search
+based on the publisher name:</p>
 
 <ul>
-<li>Package name</li>
-<li>Developer name</li>
-<li>String match across application name, developer name, and
-description, or </li>
-<li>Any combination of the above</li>
+  <li>To perform a raw text search, append the query string:
+  <p><code>&lt;URI_prefix&gt;<b>search?q=</b>&lt;search_query&gt;</code></p></li>
+
+  <li>To search based on the publisher name, use the {@code pub:} parameter in the query, followed
+by the publisher name:
+  <p><code>&lt;URI_prefix&gt;<b>search?q=pub:</b>&lt;publisher_name&gt;</code></p>
+  <p>You can use this type of search to show all of your published applications.</p></li>
 </ul>
 
-<p>The table at the bottom of this page specifies the <code>paramtypes</code>
-and <code>values</code> that correspond to each of these types of search. </p>
 
-<p>When you send an intent to initiate a search for applications, Market sends
-the search query to the server and displays the result. To the user, the
-experience is something like this: </p>
+<h4>Searching the Android Market application</h4>
 
-<ol>
-<li>The user presses a link or button in your application.</li>
-<li>The Market application launches and takes control of the screen, displaying
-a progress indicator labeled "Searching" until it receives the search
-results.</li>
-<li>Market receives the search results and displays them. Depending on the query
-parameters, the search results may include a list of one or more applications.
-</li>
-<li>From the results page, the user can select an app to go to its Details page,
-which offers information about the app and lets the user download/purchase the
-app.</li>
-</ol>
+<p>To perform a search in the Android Market application, create an intent with the
+{@link android.content.Intent#ACTION_VIEW} action and include a data URI in this format:</p>
 
-<h4>Loading an application's Details page</h4>
+<p style="margin-left:2em"><code>market://search?q=&lt;query&gt;</code></p>
 
-<p>In Android Market, every application has a Details page that provides an
-overview of the application for users. For example, the page includes a short
-description of the app and screen shots of it in use, if supplied by the
-developer, as well as feedback from users and information about the developer.
-The Details page also includes an "Install" button that lets the user trigger
-the download/purchase of the application.</p>
+<p>The query may include the {@code pub:} parameter described above.</p>
 
-<p>If you want to refer the user to a specific appplication, your application
-can take the user directly to the application's Details page. To do so, your
-application sends an ACTION_VIEW Intent that includes a URI and query parameter
-in this format:</p>
+<p>For example, here's how you can initiate a search in the Android Market application, based on the
+publisher name:</p>
 
-<p style="margin-left:2em"><code>market://details?id=&lt;packagename&gt;</code></p>
+<pre>
+Intent intent = new Intent(Intent.ACTION_VIEW);
+intent.setData(Uri.parse("market://search?q=pub:Your Publisher Name"));
+startActivity(intent);
+</pre>
 
-<p>In this case, the <code>packagename</code> parameter is target application's
-fully qualified package name, as declared in the <code>package</code> attribute
-of the <code>manifest</code> element in the application's manifest file. For example:</p>
+<p>The search result shows all applications published by the publisher and which are compatible with
+the current device.</p>
 
-<p style="margin-left:2em"><code>market://details?id=com.example.android.jetboy</code></p>
 
-<h4>Android Market URIs</h4>
+<h4>Searching the Android Market web site</h4>
 
-<p>The table below provides a list of URIs and actions currently
-supported by the Market application.</p>
+<p>To perform a search on the Android Market web site, create a link with a URI in this
+format:</p>
 
-<p>Note that these URIs work only when passed as Intent data &mdash; you 
-can't currently load the URIs in a web browser, either on a desktop machine or 
-on the device. </p>
+<p style="margin-left:2em">
+  <code>http://market.android.com/search?q=&lt;query&gt;</code>
+</p>
+
+<p>The query may include the {@code pub:} parameter described above.</p>
+
+<p>For example, here's a link that initiates a search on the Android Market web site, based on the
+publisher name:</p>
+
+<pre>
+&lt;a href="http://market.android.com/search?q=pub:Your Publisher Name">Search Link&lt;/a>
+</pre>
+
+<p>The search result shows all applications published by the publisher.</p>
+
+
+
+<h3 id="UriSummary">Summary of URI formats</h3>
+
+<p>The table below provides a summary of the URIs currently supported by the Android Market (both on
+the web and in the Android application), as discussed in the previous sections.</p>
 
 <table>
 <tr>
-<th  width="25%">For this Result</th>
-<th>Pass this URI with the ACTION_VIEW Intent</th>
-<th  width="36%">Comments</th>
-</tr>
-<tr>
-<td>Display the Details screen for a specific application, as identified 
-by the app's fully qualified package name.</td>
-<td><code>http://market.android.com/details?id=&lt;packagename&gt;</code> 
-or<br>
-<code>market://details?id=&lt;packagename&gt;</code></td>
-<td>Note that the package name that you specify is <em>not</em> specific to any 
-version of an application. Therefore, Market always displays the Details page for the 
-latest version of the application.</td>
-</tr>
-<tr>
-<td>Search for an application by its fully qualified Java package name and
-display the result.</td>
-<td><code>http://market.android.com/search?q=pname:&lt;package&gt;</code> or<br>
-<code>market://search?q=pname:&lt;package&gt;</code></td>
-<td>Searches only the Java package name of applications. Returns only exact
-matches.</td>
+<th>For this result</th>
+<th>Use this URI in a web page link</th>
+<th>Or this URI in an {@link android.content.Intent#ACTION_VIEW} intent</th>
 </tr>
 
 <tr>
-<td>Search for applications by developer name and display the results.</td>
-<td><code>http://market.android.com/search?q=pub:&lt;Developer&nbsp;Name&gt;</code>
-or<br> <code>market://search?q=pub:&lt;Developer Name&gt;</code></td>
-<td>Searches only the "Developer Name" fields of Market public profiles. 
-Returns exact matches only. </td>
+<td>Display the details screen for a specific application</td>
+<td><code>http://market.android.com/details?id=&lt;package_name&gt;</code> 
+<td><code>market://details?id=&lt;package_name&gt;</code></td>
 </tr>
 
 <tr>
-<td>Search for applications by substring and display the results.</td>
-<td><code>http://market.android.com/search?q=&lt;substring&gt;</code> or
-<br><code>market://search?q=&lt;substring&gt;</code></td>
-<td>Searches all public fields (application title, developer name, and
-application description) for all applications. Returns exact and partial 
-matches.</td>
+<td>Search for applications using a general string query.</td>
+<td><code>http://market.android.com/search?q=&lt;query&gt;</code></td>
+<td><code>market://search?q=&lt;query&gt;</code></td>
 </tr>
 
 <tr>
-<td>Search using multiple query parameters and display the results.</td>
-<td>Example:<p><code>http://market.android.com/search?q=world pname:com.android.hello pub:Android</code></p></td>
-<td>Returns a list of applications meeting all the supplied parameters. </td>
+<td>Search for applications by publisher name</td>
+<td><nobr><code>http://market.android.com/search?q=pub:&lt;publisher_name&gt;</code></nobr></td>
+<td><nobr><code>market://search?q=pub:&lt;publisher_name&gt;</code></nobr></td>
 </tr>
+
 </table>
+
diff --git a/docs/html/guide/topics/manifest/compatible-screens-element.jd b/docs/html/guide/topics/manifest/compatible-screens-element.jd
index 8669874..5c89869 100644
--- a/docs/html/guide/topics/manifest/compatible-screens-element.jd
+++ b/docs/html/guide/topics/manifest/compatible-screens-element.jd
@@ -101,6 +101,38 @@
     </dd>
   </dl>
 </dd>
+
+<dt>example</dt>
+<dd>
+<p>If your application is compatible with only small and normal screens, regardless
+of screen density, then you must specify eight different {@code &lt;screen&gt;} elements,
+because each screen size has four different density configurations. You must declare each one of
+these; any combination of size and density that you do <em>not</em> specify is considered a screen
+configuration with which your application is <em>not</em> compatible. Here's what the manifest
+entry looks like if your application is compatible with only small and normal screens:</p>
+
+<pre>
+&lt;manifest ... >
+    ...
+    &lt;compatible-screens>
+        &lt;!-- all small size screens -->
+        &lt;screen android:screenSize="small" android:screenDensity="ldpi" />
+        &lt;screen android:screenSize="small" android:screenDensity="mdpi" />
+        &lt;screen android:screenSize="small" android:screenDensity="hdpi" />
+        &lt;screen android:screenSize="small" android:screenDensity="xhdpi" />
+        &lt;!-- all normal size screens -->
+        &lt;screen android:screenSize="normal" android:screenDensity="ldpi" />
+        &lt;screen android:screenSize="normal" android:screenDensity="mdpi" />
+        &lt;screen android:screenSize="normal" android:screenDensity="hdpi" />
+        &lt;screen android:screenSize="normal" android:screenDensity="xhdpi" />
+    &lt;/compatible-screens>
+    &lt;application ... >
+        ...
+    &lt;application>
+&lt;/manifest>
+</pre>
+</dd>
+
 <dt>introduced in:</dt>
 <dd>API Level 9</dd>
 <dt>see also:</dt>
diff --git a/docs/html/guide/topics/resources/menu-resource.jd b/docs/html/guide/topics/resources/menu-resource.jd
index d09790b..5c1eed0 100644
--- a/docs/html/guide/topics/resources/menu-resource.jd
+++ b/docs/html/guide/topics/resources/menu-resource.jd
@@ -250,7 +250,7 @@
               android:icon="@drawable/group_item1_icon" />
         &lt;item android:id="@+id/group_item2"
               android:onClick="onGroupItemClick"
-              android:title="G@string/group_item2"
+              android:title="@string/group_item2"
               android:icon="@drawable/group_item2_icon" />
     &lt;/group>
     &lt;item android:id="@+id/submenu"
diff --git a/docs/html/guide/topics/resources/providing-resources.jd b/docs/html/guide/topics/resources/providing-resources.jd
index 60030f0..1583dee 100644
--- a/docs/html/guide/topics/resources/providing-resources.jd
+++ b/docs/html/guide/topics/resources/providing-resources.jd
@@ -596,7 +596,7 @@
     </tr>
 -->
     <tr id="VersionQualifier">
-      <td>System Version (API Level)</td>
+      <td>Platform Version (API Level)</td>
       <td>Examples:<br/>
         <code>v3</code><br/>
         <code>v4</code><br/>
@@ -609,7 +609,7 @@
 href="{@docRoot}guide/appendix/api-levels.html">Android API Levels</a> document for more information
 about these values.</p>
         <p class="caution"><strong>Caution:</strong> Android 1.5 and 1.6 only match resources
-with this qualifier when it exactly matches the system version. See the section below about <a
+with this qualifier when it exactly matches the platform version. See the section below about <a
 href="#KnownIssues">Known Issues</a> for more information.</p>
       </td>
     </tr>
@@ -975,7 +975,7 @@
 
 <p>The correct behavior is for the system to match resources marked with a <a
 href="#VersionQualifier">version qualifier</a> equal
-to or less than the system version on the device, but on Android 1.5 and 1.6, (API Level 3 and 4),
+to or less than the platform version on the device, but on Android 1.5 and 1.6, (API Level 3 and 4),
 there is a bug that causes the system to match resources marked with the version qualifier
 only when it exactly matches the version on the device.</p>
 
diff --git a/docs/html/guide/topics/search/adding-custom-suggestions.jd b/docs/html/guide/topics/search/adding-custom-suggestions.jd
index c8f06b9..02ee084 100644
--- a/docs/html/guide/topics/search/adding-custom-suggestions.jd
+++ b/docs/html/guide/topics/search/adding-custom-suggestions.jd
@@ -17,8 +17,8 @@
 </li>
 <li><a href="#IntentForSuggestions">Declaring an Intent for Suggestions</a>
   <ol>
-    <li><a href="#IntentAction">Declaring the Intent action</a></li>
-    <li><a href="#IntentData">Declaring the Intent data</a></li>
+    <li><a href="#IntentAction">Declaring the intent action</a></li>
+    <li><a href="#IntentData">Declaring the intent data</a></li>
   </ol>
 </li>
 <li><a href="#HandlingIntent">Handling the Intent</a></li>
@@ -47,8 +47,8 @@
 </div>
 </div>
 
-<p>When using the Android search dialog, you can provide custom search suggestions that are
-created from data in your application. For example, if your application is a word
+<p>When using the Android search dialog or search widget, you can provide custom search suggestions
+that are created from data in your application. For example, if your application is a word
 dictionary, you can suggest words from the
 dictionary that match the text entered so far. These are the most valuable suggestions, because you
 can effectively predict what the user wants and provide instant access to it. Figure 1 shows
@@ -58,9 +58,8 @@
 Search Box, providing access to your content from outside your application.</p>
 
 <p>Before you begin with this guide to add custom suggestions, you need to have implemented the
-Android search dialog for searches in your
-application. If you haven't, see <a href="search-dialog.html">Using the Android Search
-Dialog</a>.</p>
+Android search dialog or a search widget for searches in your
+application. If you haven't, see <a href="search-dialog.html">Creating a Search Interface</a>.</p>
 
 
 <h2 id="TheBasics">The Basics</h2>
@@ -71,11 +70,11 @@
 search suggestions.</p>
 </div>
 
-<p>When the user selects a custom suggestion, the Search Manager sends an {@link
+<p>When the user selects a custom suggestion, the Android system sends an {@link
 android.content.Intent} to
-your searchable Activity. Whereas a normal search query sends an Intent with the {@link
+your searchable activity. Whereas a normal search query sends an intent with the {@link
 android.content.Intent#ACTION_SEARCH} action, you can instead define your custom suggestions to use
-{@link android.content.Intent#ACTION_VIEW} (or any other Intent action), and also include data
+{@link android.content.Intent#ACTION_VIEW} (or any other intent action), and also include data
 that's relevant to the selected suggestion. Continuing
 the dictionary example, when the user selects a suggestion, your application can immediately
 open the definition for that word, instead of searching the dictionary for matches.</p>
@@ -83,8 +82,8 @@
 <p>To provide custom suggestions, do the following:</p>
 
 <ul>
-  <li>Implement a basic searchable Activity, as described in <a
-href="search-dialog.html">Using the Android Search Dialog</a>.</li>
+  <li>Implement a basic searchable activity, as described in <a
+href="search-dialog.html">Creating a Search Interface</a>.</li>
   <li>Modify the searchable configuration with information about the content provider that
 provides custom suggestions.</li>
   <li>Build a table (such as in an {@link android.database.sqlite.SQLiteDatabase}) for your
@@ -96,22 +95,21 @@
 suggestion (including a custom action and custom data). </li>
 </ul>
 
-<p>Just like the Search Manager displays the search dialog, it also displays your search
-suggestions. All you need is a content provider from which the Search Manager can retrieve your
+<p>Just as the Android system displays the search dialog, it also displays your search
+suggestions. All you need is a content provider from which the system can retrieve your
 suggestions. If you're not familiar with creating content
 providers, read the <a href="{@docRoot}guide/topics/providers/content-providers.html">Content
 Providers</a> developer guide before you continue.</p>
 
-<p>When the Search Manager identifies that your Activity is searchable and provides search
-suggestions, the following procedure takes place as soon as the user enters text into the
-search dialog:</p>
+<p>When the system identifies that your activity is searchable and provides search
+suggestions, the following procedure takes place when the user types a query:</p>
 
 <ol>
-  <li>Search Manager takes the search query text (whatever has been typed so far) and performs a
+  <li>The system takes the search query text (whatever has been typed so far) and performs a
 query to your content provider that manages your suggestions.</li>
   <li>Your content provider returns a {@link android.database.Cursor} that points to all
 suggestions that are relevant to the search query text.</li>
-  <li>Search Manager displays the list of suggestions provided by the Cursor.</li>
+  <li>The system displays the list of suggestions provided by the Cursor.</li>
 </ol>
 
 <p>Once the custom suggestions are displayed, the following might happen:</p>
@@ -120,9 +118,9 @@
   <li>If the user types another key, or changes the query in any way, the above steps are repeated
 and the suggestion list is updated as appropriate. </li>
   <li>If the user executes the search, the suggestions are ignored and the search is delivered
-to your searchable Activity using the normal {@link android.content.Intent#ACTION_SEARCH}
-Intent.</li>
-  <li>If the user selects a suggestion, an Intent is sent to your searchable Activity, carrying a
+to your searchable activity using the normal {@link android.content.Intent#ACTION_SEARCH}
+intent.</li>
+  <li>If the user selects a suggestion, an intent is sent to your searchable activity, carrying a
 custom action and custom data so that your application can open the suggested content.</li>
 </ul>
 
@@ -142,7 +140,7 @@
 &lt;/searchable&gt;
 </pre>
 
-<p>You might need some additional attributes, depending on the type of Intent you attach
+<p>You might need some additional attributes, depending on the type of intent you attach
 to each suggestion and how you want to format queries to your content provider. The other optional
 attributes are discussed in the following sections.</p>
 
@@ -155,11 +153,11 @@
 href="{@docRoot}guide/topics/providers/content-providers.html">Content Provider</a> developer
 guide. For the most part, a content provider for custom suggestions is the
 same as any other content provider. However, for each suggestion you provide, the respective row in
-the {@link android.database.Cursor} must include specific columns that the Search Manager
+the {@link android.database.Cursor} must include specific columns that the system
 understands and uses to format the suggestions.</p>
 
-<p>When the user starts typing into the search dialog, the Search Manager queries your content
-provider for suggestions by calling {@link
+<p>When the user starts typing into the search dialog or search widget, the system queries
+your content provider for suggestions by calling {@link
 android.content.ContentProvider#query(Uri,String[],String,String[],String) query()} each time
 a letter is typed. In your implementation of {@link
 android.content.ContentProvider#query(Uri,String[],String,String[],String) query()}, your
@@ -170,22 +168,22 @@
 two sections:</p>
 <dl>
   <dt><a href="#HandlingSuggestionQuery">Handling the suggestion query</a></dt>
-  <dd>How the Search Manager sends requests to your content provider and how to handle them</dd>
+  <dd>How the system sends requests to your content provider and how to handle them</dd>
   <dt><a href="#SuggestionTable">Building a suggestion table</a></dt>
-  <dd>How to define the columns that the Search Manager expects in the {@link
+  <dd>How to define the columns that the system expects in the {@link
 android.database.Cursor} returned with each query</dd>
 </dl>
 
 
 <h3 id="HandlingSuggestionQuery">Handling the suggestion query</h3>
 
-<p>When the Search Manager requests suggestions from your content provider, it calls your content
+<p>When the system requests suggestions from your content provider, it calls your content
 provider's {@link android.content.ContentProvider#query(Uri,String[],String,String[],String)
 query()} method. You must
 implement this method to search your suggestion data and return a
 {@link android.database.Cursor} pointing to the suggestions you deem relevant.</p>
 
-<p>Here's a summary of the parameters that the Search Manager passes to your {@link
+<p>Here's a summary of the parameters that the system passes to your {@link
 android.content.ContentProvider#query(Uri,String[],String,String[],String) query()} method
 (listed in order):</p>
 
@@ -196,7 +194,7 @@
 content://<em>your.authority</em>/<em>optional.suggest.path</em>/<em>{@link
 android.app.SearchManager#SUGGEST_URI_PATH_QUERY}</em>
 </pre>
-<p>The default behavior is for Search Manager to pass this URI and append it with the query text.
+<p>The default behavior is for system to pass this URI and append it with the query text.
 For example:</p>
 <pre class="no-pretty-print">
 content://<em>your.authority</em>/<em>optional.suggest.path</em>/<em>{@link
@@ -233,7 +231,7 @@
   <dd>Always null</dd>
 </dl>
 
-<p>The Search Manager can send you the search query text in two ways. The
+<p>The system can send you the search query text in two ways. The
 default manner is for the query text to be included as the last path of the content
 URI passed in the {@code uri} parameter. However, if you include a selection value in your
 searchable configuration's {@code
@@ -251,8 +249,8 @@
 String query = uri.getLastPathSegment().toLowerCase();
 </pre>
 
-<p>This returns the last segment of the {@link android.net.Uri}, which is the query text entered in
-the search dialog.</p>
+<p>This returns the last segment of the {@link android.net.Uri}, which is the query text entered
+by the user.</p>
 
 
 
@@ -264,7 +262,7 @@
 {@code selection} and {@code selectionArgs} parameters to carry the appropriate values. In such a
 case, add the {@code android:searchSuggestSelection} attribute to your searchable configuration with
 your SQLite selection string. In the selection string, include a question mark ("?") as
-a placeholder for the actual search query. The Search Manager calls {@link
+a placeholder for the actual search query. The system calls {@link
 android.content.ContentProvider#query(Uri,String[],String,String[],String) query()} with the
 selection string as the {@code selection} parameter and the search query as the first
 element in the {@code selectionArgs} array.</p>
@@ -278,15 +276,15 @@
     android:label="@string/app_label"
     android:hint="@string/search_hint"
     android:searchSuggestAuthority="com.example.MyCustomSuggestionProvider"
-    android:searchSuggestIntentAction="android.Intent.action.VIEW"
+    android:searchSuggestIntentAction="android.intent.action.VIEW"
     <b>android:searchSuggestSelection="word MATCH ?"</b>&gt;
 &lt;/searchable&gt;
 </pre>
 
 <p>With this configuration, your {@link
 android.content.ContentProvider#query(Uri,String[],String,String[],String) query()} method
-delivers the {@code selection} parameter as "word MATCH ?" and the {@code selectionArgs}
-parameter as whatever the user entered in the search dialog. When you pass these to an SQLite
+delivers the {@code selection} parameter as {@code "word MATCH ?"} and the {@code selectionArgs}
+parameter as the search query. When you pass these to an SQLite
 {@link android.database.sqlite.SQLiteDatabase#query(String,String[],String,String[],String,String,
 String) query()} method, as their respective arguments, they are synthesized together (the
 question mark is replaced with the query
@@ -296,9 +294,9 @@
 question mark.</p>
 
 <p>Another new attribute in the example above is {@code android:searchSuggestIntentAction}, which
-defines the Intent action sent with each Intent when the user selects a suggestion. It is
+defines the intent action sent with each intent when the user selects a suggestion. It is
 discussed further in the section about <a href="#IntentForSuggestions">Declaring an Intent for
-suggestions</a>.</p>
+Suggestions</a>.</p>
 
 <p class="note"><strong>Tip:</strong> If you don't want to define a selection clause in
 the {@code android:searchSuggestSelection} attribute, but would still like to receive the query
@@ -317,7 +315,7 @@
 <h2>Creating a Cursor without a table</h2>
 <p>If your search suggestions are not stored in a table format (such as an SQLite table) using the
 columns required by the
-Search Manager, then you can search your suggestion data for matches and then format them
+system, then you can search your suggestion data for matches and then format them
 into the necessary table on each request. To do so, create a {@link android.database.MatrixCursor}
 using the required column names and then add a row for each suggestion using {@link
 android.database.MatrixCursor#addRow(Object[])}. Return the final product from your Content
@@ -326,18 +324,18 @@
 </div>
 </div>
 
-<p>When you return suggestions to the Search Manager with a {@link android.database.Cursor}, the
-Search Manager expects specific columns in each row. So, regardless of whether you
+<p>When you return suggestions to the system with a {@link android.database.Cursor}, the
+system expects specific columns in each row. So, regardless of whether you
 decide to store
 your suggestion data in an SQLite database on the device, a database on a web server, or another
 format on the device or web, you must format the suggestions as rows in a table and
-present them with a {@link android.database.Cursor}. The Search
-Manager understands several columns, but only two are required:</p>
+present them with a {@link android.database.Cursor}. The system understands several columns, but
+only two are required:</p>
 
 <dl>
   <dt>{@link android.provider.BaseColumns#_ID}</dt>
-  <dd>A unique integer row ID for each suggestion. The search dialog requires this in order
-to present suggestions in a ListView.</dd>
+  <dd>A unique integer row ID for each suggestion. The system requires this in order
+to present suggestions in a {@link android.widget.ListView}.</dd>
   <dt>{@link android.app.SearchManager#SUGGEST_COLUMN_TEXT_1}</dt>
   <dd>The string that is presented as a suggestion.</dd>
 </dl>
@@ -359,35 +357,35 @@
 all suggestions are provided in an icon-plus-text format with the icon on the right side. This can
 be null or zero to indicate no icon in this row.</dd>
   <dt>{@link android.app.SearchManager#SUGGEST_COLUMN_INTENT_ACTION}</dt>
-  <dd>An Intent action string. If this column exists and contains a value at the given row, the
-action defined here is used when forming the suggestion's Intent. If the element is not
+  <dd>An intent action string. If this column exists and contains a value at the given row, the
+action defined here is used when forming the suggestion's intent. If the element is not
 provided, the action is taken from the {@code android:searchSuggestIntentAction} field in your
 searchable configuration. If your action is the same for all
 suggestions, it is more efficient to specify the action using {@code
 android:searchSuggestIntentAction} and omit this column.</dd>
   <dt>{@link android.app.SearchManager#SUGGEST_COLUMN_INTENT_DATA}</dt>
   <dd>A data URI string. If this column exists and contains a value at the given row, this is the
-data that is used when forming the suggestion's Intent. If the element is not provided, the data is
+data that is used when forming the suggestion's intent. If the element is not provided, the data is
 taken from the {@code android:searchSuggestIntentData} field in your searchable configuration. If
 neither source is provided,
-the Intent's data field is null. If your data is the same for all suggestions, or can be
+the intent's data field is null. If your data is the same for all suggestions, or can be
 described using a constant part and a specific ID, it is more efficient to specify it using {@code
 android:searchSuggestIntentData} and omit this column.
 </dd>
   <dt>{@link android.app.SearchManager#SUGGEST_COLUMN_INTENT_DATA_ID}</dt>
   <dd>A URI path string. If this column exists and contains a value at the given row, then "/" and
-this value is appended to the data field in the Intent. This should only be used if the data field
+this value is appended to the data field in the intent. This should only be used if the data field
 specified
 by the {@code android:searchSuggestIntentData} attribute in the searchable configuration has already
 been set to an appropriate base string.</dd>
   <dt>{@link android.app.SearchManager#SUGGEST_COLUMN_INTENT_EXTRA_DATA}</dt>
   <dd>Arbitrary data. If this column exists and contains a value at a given row, this is the
-<em>extra</em> data used when forming the suggestion's Intent. If not provided, the
-Intent's extra data field is null. This column allows suggestions to provide additional data that is
-included as an extra in the Intent's {@link android.app.SearchManager#EXTRA_DATA_KEY} key.</dd>
+<em>extra</em> data used when forming the suggestion's intent. If not provided, the
+intent's extra data field is null. This column allows suggestions to provide additional data that is
+included as an extra in the intent's {@link android.app.SearchManager#EXTRA_DATA_KEY} key.</dd>
   <dt>{@link android.app.SearchManager#SUGGEST_COLUMN_QUERY}</dt>
   <dd>If this column exists and this element exists at the given row, this is the data that is
-used when forming the suggestion's query, included as an extra in the Intent's {@link
+used when forming the suggestion's query, included as an extra in the intent's {@link
 android.app.SearchManager#QUERY} key. Required if suggestion's action is {@link
 android.content.Intent#ACTION_SEARCH}, optional otherwise.</dd>
   <dt>{@link android.app.SearchManager#SUGGEST_COLUMN_SHORTCUT_ID}</dt>
@@ -410,22 +408,22 @@
 
 
 
-<h2 id="IntentForSuggestions">Declaring an Intent for suggestions</h2>
+<h2 id="IntentForSuggestions">Declaring an Intent for Suggestions</h2>
 
-<p>When the user selects a suggestion from the list that appears below the search dialog, the Search
-Manager sends a custom {@link android.content.Intent} to your searchable Activity. You must define
-the action and data for the Intent.</p>
+<p>When the user selects a suggestion from the list that appears below the search dialog or widget,
+the system sends a custom {@link android.content.Intent} to your searchable activity. You
+must define the action and data for the intent.</p>
 
 
-<h3 id="IntentAction">Declaring the Intent action</h3>
+<h3 id="IntentAction">Declaring the intent action</h3>
 
-<p>The most common Intent action for a custom suggestion is {@link
+<p>The most common intent action for a custom suggestion is {@link
 android.content.Intent#ACTION_VIEW}, which is appropriate when
 you want to open something, like the definition for a word, a person's contact information, or a web
-page. However, the Intent action can be any other action and can even be different for each
+page. However, the intent action can be any other action and can even be different for each
 suggestion.</p>
 
-<p>Depending on whether you want all suggestions to use the same Intent action, you
+<p>Depending on whether you want all suggestions to use the same intent action, you
 can define the action in two ways:</p>
 
 <ol type="a">
@@ -457,34 +455,34 @@
 default, then override this action for some suggestions by declaring a different action in the
 {@link android.app.SearchManager#SUGGEST_COLUMN_INTENT_ACTION} column. If you do not include
 a value in the {@link android.app.SearchManager#SUGGEST_COLUMN_INTENT_ACTION} column, then the
-Intent provided in the {@code android:searchSuggestIntentAction} attribute is used.</p>
+intent provided in the {@code android:searchSuggestIntentAction} attribute is used.</p>
 
 <p class="note"><strong>Note</strong>: If you do not include the
 {@code android:searchSuggestIntentAction} attribute in your searchable configuration, then you
 <em>must</em> include a value in the {@link android.app.SearchManager#SUGGEST_COLUMN_INTENT_ACTION}
-column for every suggestion, or the Intent will fail.</p>
+column for every suggestion, or the intent will fail.</p>
 
 
 
-<h3 id="IntentData">Declaring Intent data</h3>
+<h3 id="IntentData">Declaring intent data</h3>
 
-<p>When the user selects a suggestion, your searchable Activity receives the Intent with the
-action you've defined (as discussed in the previous section), but the Intent must also carry
-data in order for your Activity to identify which suggestion was selected. Specifically,
+<p>When the user selects a suggestion, your searchable activity receives the intent with the
+action you've defined (as discussed in the previous section), but the intent must also carry
+data in order for your activity to identify which suggestion was selected. Specifically,
 the data should be something unique for each suggestion, such as the row ID for the suggestion in
-your SQLite table. When the Intent is received,
+your SQLite table. When the intent is received,
 you can retrieve the attached data with {@link android.content.Intent#getData()} or {@link
 android.content.Intent#getDataString()}.</p>
 
-<p>You can define the data included with the Intent in two ways:</p>
+<p>You can define the data included with the intent in two ways:</p>
 
 <ol type="a">
   <li>Define the data for each suggestion inside the {@link
 android.app.SearchManager#SUGGEST_COLUMN_INTENT_DATA} column of your suggestions table.
 
-<p>Provide all necessary data information for each Intent in the suggestions table by including the
+<p>Provide all necessary data information for each intent in the suggestions table by including the
 {@link android.app.SearchManager#SUGGEST_COLUMN_INTENT_DATA} column and then populating it with
-unique data for each row. The data from this column is attached to the Intent exactly as you
+unique data for each row. The data from this column is attached to the intent exactly as you
 define it in this column. You can then retrieve it with with {@link
 android.content.Intent#getData()} or {@link android.content.Intent#getDataString()}.</p>
 
@@ -498,7 +496,7 @@
   </li>
 
   <li>Fragment a data URI into two pieces: the portion common to all suggestions and the portion
-unique to each suggestion. Place these parts into the {@code android:searchSuggestIntentData}
+unique to each suggestion. Place these parts into the {@code android:searchSuggestintentData}
 attribute of the searchable configuration and the {@link
 android.app.SearchManager#SUGGEST_COLUMN_INTENT_DATA_ID} column of your
 suggestions table, respectively.
@@ -512,14 +510,14 @@
     android:label="@string/app_label"
     android:hint="@string/search_hint"
     android:searchSuggestAuthority="com.example.MyCustomSuggestionProvider"
-    android:searchSuggestIntentAction="android.Intent.action.VIEW"
+    android:searchSuggestIntentAction="android.intent.action.VIEW"
     <b>android:searchSuggestIntentData="content://com.example/datatable"</b> >
 &lt;/searchable>
 </pre>
 
 <p>Then include the final path for each suggestion (the unique part) in the {@link
 android.app.SearchManager#SUGGEST_COLUMN_INTENT_DATA_ID}
-column of your suggestions table. When the user selects a suggestion, the Search Manager takes
+column of your suggestions table. When the user selects a suggestion, the system takes
 the string from {@code android:searchSuggestIntentData}, appends a slash ("/") and then adds the
 respective value from the {@link android.app.SearchManager#SUGGEST_COLUMN_INTENT_DATA_ID} column to
 form a complete content URI. You can then retrieve the {@link android.net.Uri} with with {@link
@@ -530,20 +528,20 @@
 
 <h4>Add more data</h4>
 
-<p>If you need to express even more information with your Intent, you can add another table column,
+<p>If you need to express even more information with your intent, you can add another table column,
 {@link android.app.SearchManager#SUGGEST_COLUMN_INTENT_EXTRA_DATA}, which can store additional
 information about the suggestion. The data saved in this column is placed in {@link
-android.app.SearchManager#EXTRA_DATA_KEY} of the Intent's extra Bundle.</p>
+android.app.SearchManager#EXTRA_DATA_KEY} of the intent's extra Bundle.</p>
 
 
 
 <h2 id="HandlingIntent">Handling the Intent</h2>
 
-<p>Now that your search dialog provides custom search suggestions with custom Intents, you
-need your searchable Activity to handle these Intents when the user selects a
+<p>Now that you provide custom search suggestions with custom intents, you
+need your searchable activity to handle these intents when the user selects a
 suggestion. This is in addition to handling the {@link
-android.content.Intent#ACTION_SEARCH} Intent, which your searchable Activity already does.
-Here's an example of how you can handle the Intents during your Activity {@link
+android.content.Intent#ACTION_SEARCH} intent, which your searchable activity already does.
+Here's an example of how you can handle the intents during your activity {@link
 android.app.Activity#onCreate(Bundle) onCreate()} callback:</p>
 
 <pre>
@@ -559,25 +557,25 @@
 }
 </pre>
 
-<p>In this example, the Intent action is {@link
+<p>In this example, the intent action is {@link
 android.content.Intent#ACTION_VIEW} and the data carries a complete URI pointing to the suggested
 item, as synthesized by the {@code android:searchSuggestIntentData} string and {@link
 android.app.SearchManager#SUGGEST_COLUMN_INTENT_DATA_ID} column. The URI is then passed to the local
 {@code showResult()} method that queries the content provider for the item specified by the URI.</p>
 
-<p class="note"><strong>Note:</strong> You do <em>not</em> need to add an Intent filter to your
-Android manifest file for the Intent action you defined with the {@code
+<p class="note"><strong>Note:</strong> You do <em>not</em> need to add an intent filter to your
+Android manifest file for the intent action you defined with the {@code
 android:searchSuggestIntentAction} attribute or {@link
-android.app.SearchManager#SUGGEST_COLUMN_INTENT_ACTION} column. The Search Manager opens your
-searchable Activity by name to deliver the suggestion's Intent, so the Activity does not need to
+android.app.SearchManager#SUGGEST_COLUMN_INTENT_ACTION} column. The system opens your
+searchable activity by name to deliver the suggestion's intent, so the activity does not need to
 declare the accepted action.</p>
 
 
 <h2 id="RewritingQueryText">Rewriting the query text</h2>
 
-<p>If the user navigates through the suggestions list using the directional controls (trackball or
-d-pad), the text in the search dialog won't change, by default. However, you can temporarily rewrite
-the user's query text as it appears in the text box with
+<p>If the user navigates through the suggestions list using the directional controls (such
+as with a trackball or d-pad), the query text does not update, by default. However, you
+can temporarily rewrite the user's query text as it appears in the text box with
 a query that matches the suggestion currently in focus. This enables the user to see what query is
 being suggested (if appropriate) and then select the search box and edit the query before
 dispatching it as a search.</p>
@@ -654,7 +652,7 @@
     android:label="@string/app_label"
     android:hint="@string/search_hint"
     android:searchSuggestAuthority="com.example.MyCustomSuggestionProvider"
-    android:searchSuggestIntentAction="android.Intent.action.VIEW"
+    android:searchSuggestIntentAction="android.intent.action.VIEW"
     android:includeInGlobalSearch="true"
     <b>android:searchSettingsDescription="@string/search_description"</b> >
 &lt;/searchable>
@@ -676,7 +674,7 @@
 <h3 id="ManagingShortcuts">Managing Quick Search Box suggestion shortcuts</h3>
 
 <p>Suggestions that the user selects from Quick Search Box can be automatically made into shortcuts.
-These are suggestions that the Search Manager has copied from your content provider  so it can
+These are suggestions that the system has copied from your content provider  so it can
 quickly access the suggestion without the need to re-query your content provider. </p>
 
 <p>By default, this is enabled for all suggestions retrieved by Quick Search Box, but if your
diff --git a/docs/html/guide/topics/search/adding-recent-query-suggestions.jd b/docs/html/guide/topics/search/adding-recent-query-suggestions.jd
index cb063a1..2c9a461 100644
--- a/docs/html/guide/topics/search/adding-recent-query-suggestions.jd
+++ b/docs/html/guide/topics/search/adding-recent-query-suggestions.jd
@@ -28,13 +28,15 @@
 </div>
 </div>
 
-<p>When using the Android search dialog, you can provide search suggestions based on recent search
+<p>When using the Android search dialog or search widget, you can provide search suggestions based
+on recent search
 queries. For example, if a user previously searched for "puppies," then that query appears as a
 suggestion once he or she begins typing the same query. Figure 1 shows an example of a search dialog
 with recent query suggestions.</p>
 
-<p>Before you begin, you need to implement the search dialog for basic searches in your application.
-If you haven't, see <a href="search-dialog.html">Using the Android Search Dialog</a>.</p>
+<p>Before you begin, you need to implement the search dialog or a search widget for basic searches
+in your application.
+If you haven't, see <a href="search-dialog.html">Creating a Search Interface</a>.</p>
 
 
 
@@ -47,16 +49,16 @@
 </div>
 
 <p>Recent query suggestions are simply saved searches. When the user selects one of
-the suggestions, your searchable Activity receives a {@link
-android.content.Intent#ACTION_SEARCH} Intent with the suggestion as the search query, which your
-searchable Activity already handles (as described in <a href="search-dialog.html">Using the Android
-Search Dialog</a>).</p>
+the suggestions, your searchable activity receives a {@link
+android.content.Intent#ACTION_SEARCH} intent with the suggestion as the search query, which your
+searchable activity already handles (as described in <a href="search-dialog.html">Creating a Search
+Interface</a>).</p>
 
 <p>To provide recent queries suggestions, you need to:</p>
 
 <ul>
-  <li>Implement a searchable Activity, <a
-href="{@docRoot}guide/topics/search/search-dialog.html">using the Android Search Dialog</a>.</li>
+  <li>Implement a searchable activity, as described in <a
+href="{@docRoot}guide/topics/search/search-dialog.html">Creating a Search Interface</a>.</li>
   <li>Create a content provider that extends {@link
 android.content.SearchRecentSuggestionsProvider} and declare it in your application manifest.</li>
   <li>Modify the searchable configuration with information about the content provider that
@@ -64,20 +66,19 @@
   <li>Save queries to your content provider each time a search is executed.</li>
 </ul>
 
-<p>Just as the Search Manager displays the search dialog, it also displays the
-search suggestions. All you need to do is provide a source from which the suggestions can be
-retrieved.</p>
+<p>Just as the Android system displays the search dialog, it also displays the
+search suggestions below the dialog or search widget. All you need to do is provide a source from
+which the system can retrieve suggestions.</p>
 
-<p>When the Search Manager identifies that your Activity is searchable and provides search
-suggestions, the following procedure takes place as soon as the user types into the search
-dialog:</p>
+<p>When the system identifies that your activity is searchable and provides search
+suggestions, the following procedure takes place as soon as the user begins typing a query:</p>
 
 <ol>
-  <li>Search Manager takes the search query text (whatever has been typed so far) and performs a
+  <li>The system takes the search query text (whatever has been typed so far) and performs a
 query to the content provider that contains your suggestions.</li>
   <li>Your content provider returns a {@link android.database.Cursor} that points to all
 suggestions that match the search query text.</li>
-  <li>Search Manager displays the list of suggestions provided by the Cursor.</li>
+  <li>The system displays the list of suggestions provided by the Cursor.</li>
 </ol>
 
 <p>Once the recent query suggestions are displayed, the following might happen:</p>
@@ -86,10 +87,10 @@
   <li>If the user types another key, or changes the query in any way, the aforementioned steps are
 repeated and the suggestion list is updated.</li>
   <li>If the user executes the search, the suggestions are ignored and the search is delivered
-to your searchable Activity using the normal {@link android.content.Intent#ACTION_SEARCH}
-Intent.</li>
+to your searchable activity using the normal {@link android.content.Intent#ACTION_SEARCH}
+intent.</li>
   <li>If the user selects a suggestion, an
-{@link android.content.Intent#ACTION_SEARCH} Intent is delivered to your searchable Activity using
+{@link android.content.Intent#ACTION_SEARCH} intent is delivered to your searchable activity using
 the suggested text as the query.</li>
 </ul>
 
@@ -151,7 +152,7 @@
 
 <h2 id="RecentQuerySearchableConfiguration">Modifying the Searchable Configuration</h2>
 
-<p>To configure your search dialog to use your suggestions provider, you need to add
+<p>To configure the system to use your suggestions provider, you need to add
 the {@code android:searchSuggestAuthority} and {@code android:searchSuggestSelection} attributes to
 the {@code &lt;searchable&gt;} element in your searchable configuration file. For example:</p>
 
@@ -179,12 +180,12 @@
 <h2 id="SavingQueries">Saving Queries</h2>
 
 <p>To populate your collection of recent queries, add each query
-received by your searchable Activity to your {@link
+received by your searchable activity to your {@link
 android.content.SearchRecentSuggestionsProvider}. To do this, create an instance of {@link
 android.provider.SearchRecentSuggestions} and call {@link
 android.provider.SearchRecentSuggestions#saveRecentQuery(String,String) saveRecentQuery()} each time
-your searchable Activity receives a query. For example, here's how you can save the query during
-your Activity's {@link android.app.Activity#onCreate(Bundle) onCreate()} method:</p>
+your searchable activity receives a query. For example, here's how you can save the query during
+your activity's {@link android.app.Activity#onCreate(Bundle) onCreate()} method:</p>
 
 <pre>
 &#64;Override
@@ -192,10 +193,10 @@
     super.onCreate(savedInstanceState);
     setContentView(R.layout.main);
 
-    Intent Intent  = getIntent();
+    Intent intent  = getIntent();
 
-    if (Intent.ACTION_SEARCH.equals(Intent .getAction())) {
-        String query = Intent .getStringExtra(SearchManager.QUERY);
+    if (Intent.ACTION_SEARCH.equals(intent.getAction())) {
+        String query = intent.getStringExtra(SearchManager.QUERY);
         SearchRecentSuggestions suggestions = new SearchRecentSuggestions(this,
                 MySuggestionProvider.AUTHORITY, MySuggestionProvider.MODE);
         suggestions.saveRecentQuery(query, null);
@@ -212,7 +213,7 @@
 second line of the suggestion (or null). The second parameter is only used if you've enabled
 two-line mode for the search suggestions with {@link
 android.content.SearchRecentSuggestionsProvider#DATABASE_MODE_2LINES}. If you have enabled
-two-line mode, then the query text is also matched against this second line when the Search Manager
+two-line mode, then the query text is also matched against this second line when the system
 looks for matching suggestions.</p>
 
 
diff --git a/docs/html/guide/topics/search/index.jd b/docs/html/guide/topics/search/index.jd
index f563715..7ac5ff1 100644
--- a/docs/html/guide/topics/search/index.jd
+++ b/docs/html/guide/topics/search/index.jd
@@ -5,7 +5,7 @@
 <div id="qv">
 <h2>Topics</h2>
 <ol>
-<li><a href="search-dialog.html">Using the Android Search Dialog</a></li>
+<li><a href="search-dialog.html">Creating a Search Interface</a></li>
 <li><a href="adding-recent-query-suggestions.html">Adding Recent Query Suggestions</a></li>
 <li><a href="adding-custom-suggestions.html">Adding Custom Suggestions</a></li>
 </ol>
@@ -24,9 +24,8 @@
 
 <p>Search is a core user feature on Android. Users should be able
 to search any data that is available to them, whether the content is located on the device or
-the Internet. The search experience should be seamless and consistent across the entire
-system, which is why Android provides a search framework to help you provide users with
-a familiar search dialog and a great search experience.</p>
+the Internet. To help create a consistent search experience for users, Android provides a
+search framework that helps you implement search for your application.</p>
 
 <div class="figure" style="width:250px">
 <img src="{@docRoot}images/search/search-suggest-custom.png" alt="" height="417" />
@@ -34,16 +33,14 @@
 search suggestions.</p>
 </div>
 
-<p>Android's search framework provides a user interface in which users can perform a search and
-an interaction layer that communicates with your application, so you don't have to build
-your own search Activity. Instead, a search dialog appears at the top of the screen at the user's
-command without interrupting the current Activity.</p>
+<p>The search framework offers two modes of search input: a search dialog at the top of the
+screen or a search widget ({@link android.widget.SearchView}) that you can embed in your activity
+layout. In either case, the Android system will assist your search implementation by
+delivering search queries to a specific activity that performs searchs. You can also enable either
+the search dialog or widget to provide search suggestions as the user types. Figure 1 shows an
+example of the search dialog with optional search suggestions.</p>
 
-<p>The search framework manages the life of the search dialog. When users execute a search, the
-search framework passes the query text to your application so your application can perform a
-search. Figure 1 shows an example of the search dialog with optional search suggestions.</p>
-
-<p>Once your application is set up to use the search dialog, you can:</p>
+<p>Once you've set up either the search dialog or the search widget, you can:</p>
 
 <ul>
 <li>Enable voice search</li>
@@ -57,19 +54,19 @@
 if your data is stored in an SQLite database, you should use the {@link android.database.sqlite}
 APIs to perform searches.</p>
 
-<p>The following documents show you how to use the search dialog in your application:</p>
+<p>The following documents show you how to use Android's framework to implement search:</p>
 
 <dl>
-  <dt><strong><a href="search-dialog.html">Using the Android Search Dialog</a></strong></dt>
-  <dd>How to set up your application to use the search dialog. </dd>
+  <dt><strong><a href="search-dialog.html">Creating a Search Interface</a></strong></dt>
+  <dd>How to set up your application to use the search dialog or search widget. </dd>
   <dt><strong><a href="adding-recent-query-suggestions.html">Adding Recent Query
 Suggestions</a></strong></dt>
-  <dd>How to show suggestions based on queries previously used in the search dialog.</dd>
+  <dd>How to provide suggestions based on queries previously used.</dd>
   <dt><strong><a href="adding-custom-suggestions.html">Adding Custom Suggestions</a></strong></dt>
-  <dd>How to show suggestions based on custom data from your application and offer your suggestions
+  <dd>How to provide suggestions based on custom data from your application and also offer them
 in the system-wide Quick Search Box.</dd>
   <dt><strong><a href="searchable-config.html">Searchable Configuration</a></strong></dt>
-  <dd>A reference for the searchable configuration file (though the other
+  <dd>A reference document for the searchable configuration file (though the other
 documents also discuss the configuration file in terms of specific behaviors).</dd>
 </dl>
 
@@ -92,17 +89,17 @@
 send the personal information, you should not log it. If you must log it, protect that data
 very carefully and erase it as soon as possible.</p>
 </li>
-<li><strong>Provide the user with a way to clear their search history.</strong>
+<li><strong>Provide users with a way to clear their search history.</strong>
 <p>The search framework helps your application provide context-specific suggestions while the user
 types. Sometimes these
 suggestions are based on previous searches or other actions taken by the user in an earlier
 session. A user might not wish for previous searches to be revealed to other device users, for
-instance, if they share their phone with a friend. If your application provides suggestions that can
-reveal previous activities, you should implement the ability for the user to clear the search
-history. If you are using {@link android.provider.SearchRecentSuggestions}, you can simply call the
-{@link android.provider.SearchRecentSuggestions#clearHistory()} method. If you are implementing
-custom suggestions, you'll need to provide a similar "clear history" method in your provider that
-the user can execute.</p>
+instance, if the user shares the device with a friend. If your application provides suggestions that
+can reveal previous search activities, you should implement the ability for the user to clear the
+search history. If you are using {@link android.provider.SearchRecentSuggestions}, you can simply
+call the {@link android.provider.SearchRecentSuggestions#clearHistory()} method. If you are
+implementing custom suggestions, you'll need to provide a similar "clear history" method in your
+content provider that the user can execute.</p>
 </li>
 </ul>
 
diff --git a/docs/html/guide/topics/search/search-dialog.jd b/docs/html/guide/topics/search/search-dialog.jd
index 6699fe1..af6c8f2 100644
--- a/docs/html/guide/topics/search/search-dialog.jd
+++ b/docs/html/guide/topics/search/search-dialog.jd
@@ -1,38 +1,61 @@
-page.title=Using the Android Search Dialog
+page.title=Creating a Search Interface
 parent.title=Search
 parent.link=index.html
 @jd:body
 
 <div id="qv-wrapper">
 <div id="qv">
+
+  <h2>Quickview</h2>
+  <ul>
+    <li>The Android system sends search queries from the search dialog or widget to an activity you
+specify to perform searches and present results</li>
+    <li>You can put the search widget in the Action Bar, as an "action view," for quick
+access</li>
+  </ul>
+
+
 <h2>In this document</h2>
 <ol>
 <li><a href="#TheBasics">The Basics</a></li>
 <li><a href="#SearchableConfiguration">Creating a Searchable Configuration</a></li>
 <li><a href="#SearchableActivity">Creating a Searchable Activity</a>
   <ol>
-    <li><a href="#DeclaringSearchableActivity">Declaring a searchable Activity</a></li>
+    <li><a href="#DeclaringSearchableActivity">Declaring a searchable activity</a></li>
+    <li><a href="#EnableSearch">Enabling the search dialog and search widget</a></li>
     <li><a href="#PerformingSearch">Performing a search</a></li>
   </ol>
 </li>
-<li><a href="#InvokingTheSearchDialog">Invoking the Search Dialog</a>
+<li><a href="#UsingTheSearchDialog">Using the Search Dialog</a>
   <ol>
-    <li><a href="#LifeCycle">The impact of the search dialog on your Activity life-cycle</a></li>
+    <li><a href="#LifeCycle">The impact of the search dialog on your activity lifecycle</a></li>
+    <li><a href="#SearchContextData">Passing search context data</a></li>
   </ol>
 </li>
-<li><a href="#SearchContextData">Passing Search Context Data</a></li>
+<li><a href="#UsingSearchWidget">Using the Search Widget</a>
+  <ol>
+    <li><a href="#ConfiguringWidget">Configuring the search widget</a></li>
+    <li><a href="#WidgetFeatures">Other search widget features</a></li>
+  </ol>
+</li>
 <li><a href="#VoiceSearch">Adding Voice Search</a></li>
+<li><a href="#SearchSuggestions">Adding Search Suggestions</a></li>
 </ol>
 
 <h2>Key classes</h2>
 <ol>
 <li>{@link android.app.SearchManager}</li>
+<li>{@link android.widget.SearchView}</li>
 </ol>
 
 <h2>Related samples</h2>
 <ol>
 <li><a href="{@docRoot}resources/samples/SearchableDictionary/index.html">Searchable
 Dictionary</a></li>
+<li><a href="{@docRoot}resources/samples/ApiDemos/src/com/example/android/apis/view/SearchViewActionBar.html">SearchView
+    in the Action Bar</a></li>
+<li><a href="{@docRoot}resources/samples/ApiDemos/src/com/example/android/apis/view/SearchViewFilterMode.html">SearchView
+    filter mode</a></li>
 </ol>
 
 <h2>Downloads</h2>
@@ -50,16 +73,24 @@
 </div>
 </div>
 
-<p>When you want to implement search in your application, the last thing you should have to worry
-about is where to put the search box. When you implement search with the Android search framework,
-you don't have to. When the user invokes search, a search dialog appears at the top of the screen
-with your application icon to the left of the search box. When the user executes the search, your
-application receives the query so it can search your application's data. An example of the search
-dialog is shown in figure 1.</p>
+<p>When you're ready to add search functionality to your application, Android helps you implement
+the user interface with either a search dialog that appears at the top of the activity window or a
+search widget that you can insert in your layout. Both the search dialog and the widget can deliver
+the user's search query to a specific activity in your application. This way, the user can initiate
+a search from any activity where the search dialog or widget is available, and the system starts the
+appropriate activity to perform the search and present results.</p>
 
-<p>This guide shows you how to set up your application to provide search in the search
-dialog. When you use the search dialog, you provide a standardized search
-experience and can add features such as voice search and search suggestions.</p>
+<p>Other features available for the search dialog and widget include:</p>
+
+<ul>
+  <li>Voice search</li>
+  <li>Search suggestions based on recent queries</li>
+  <li>Search suggestions that match actual results in your application data</li>
+</ul>
+
+<p>This guide shows you how to set up your application to provide a search interface
+that's assisted by the Android system to deliver search queries, using either the
+search dialog or the search widget.</p>
 
 
 <h2 id="TheBasics">The Basics</h2>
@@ -69,40 +100,78 @@
 <p class="img-caption"><strong>Figure 1.</strong> Screenshot of an application's search dialog.</p>
 </div>
 
-<p>The Android search framework manages the search dialog for your application. You never need
-to draw it or worry about where it is, and your Activity is not interrupted when the search dialog
-appears. The Search Manager ({@link android.app.SearchManager}) is the component that does this work
-for you. It manages the life of the search dialog and sends your application the user's search
-query.</p>
+<p>Before you begin, you should decide whether you'll implement your search interface using the
+search dialog or the search widget. Both provide the same search features, but in slightly different
+ways:</p>
 
-<p>When the user executes a search, the Search Manager creates an {@link android.content.Intent} to
-pass the search query to the Activity that you've declared to handle searches. Basically, all you
-need is an Activity that receives the search Intent, performs the search, and presents the results.
-Specifically, you need the following:</p>
+<ul>
+  <li>The <strong>search dialog</strong> is a UI component that's controlled by the Android system.
+When activated by the user, the search dialog appears at the top of the activity, as shown in figure
+1.
+    <p>The Android system controls all events in the search dialog. When the user
+submits a query, the system delivers the query to the activity that you specify to
+handle searches. The dialog can also provide search suggestions while the user types.</p></li>
 
-<dl>
-  <dt>A searchable configuration</dt>
-  <dd>An XML file that configures the search dialog and includes settings for features such as voice
-search, search suggestion, and the hint text.</dd>
-  <dt>A searchable Activity</dt>
-  <dd>The {@link android.app.Activity} that receives the search query, then searches your data and
-displays the search results.</dd>
-  <dt>A mechanism by which the user can invoke search</dt>
-  <dd>The device search key invokes the search dialog, by default. However, a dedicated search key
-is not guaranteed on all devices, so provide another means by which the user can invoke a search,
-such as a search button in the Options Menu or elsewhere in the Activity UI.</dd>
-</dl>
+  <li>The <strong>search widget</strong> is an instance of {@link android.widget.SearchView} that
+you can place anywhere in your layout. By default, the search widget behaves like a standard {@link
+android.widget.EditText} widget and doesn't do anything, but you can configure it so that the
+Android system handles all input events, delivers queries to the appropriate activity, and provides
+search suggestions (just like the search dialog). However, the search widget is available only in
+Android 3.0 (API Level 11) and higher.
 
+<p class="note"><strong>Note:</strong> If you want, you can handle all user input into the
+search widget yourself, using various callback methods and listeners. This document, however,
+focuses on how to integrate the search widget with the system for an assisted search
+implementation. If you want to handle all user input yourself, read the reference documentation for
+{@link android.widget.SearchView} and its nested interfaces. </p></li>
+</ul>
+
+<p>When the user executes a search from the search dialog or a search widget, the system creates an
+{@link android.content.Intent} and stores the user query in it. The system then starts the activity
+that you've declared to handle searches (the "searchable activity") and delivers it the intent. To
+set up your application for this kind of assisted search, you need the following:</p>
+
+<ul>
+  <li>A searchable configuration
+  <p>An XML file that configures some settings for the search dialog or widget. It includes settings
+for features such as voice search, search suggestion, and hint text for the search box.</p></li>
+  <li>A searchable activity
+  <p>The {@link android.app.Activity} that receives the search query, searches your
+data, and displays the search results.</p></li>
+  <li>A search interface, provided by either:
+    <ul>
+      <li>The search dialog
+        <p>By default, the search dialog is hidden, but appears at the top of the screen when the 
+user presses the device SEARCH button (when available) or another button in your user interface.</p>
+      </li>
+      <li>Or, a {@link android.widget.SearchView} widget
+        <p>Using the search widget allows you to put the search box anywhere in your activity.
+Instead of putting it in your activity layout, however, it's usually more convenient for users as an
+<a href="{@docRoot}guide/topics/ui/actionbar.html#ActionView">action view in the Action Bar</a>.</p>
+      </li>
+    </ul>
+  </li>
+</ul>
+
+<p>The rest of this document shows you how to create the searchable configuration, searchable
+activity, and implement a search interface with either the search dialog or search widget.</p>
 
 
 <h2 id="SearchableConfiguration">Creating a Searchable Configuration</h2>
 
-<p>The searchable configuration is an XML file that defines several settings for the search
-dialog in your application. This file is traditionally named {@code searchable.xml} and must be
-saved in the {@code res/xml/} project directory.</p>
+<p>The first thing you need is an XML file called the searchable configuration. It configures
+certain UI aspects of the search dialog or widget and defines how features such as suggestions and
+voice search behave. This file is traditionally named {@code searchable.xml} and must be saved in
+the {@code res/xml/} project directory.</p>
 
-<p>The file must consist of the {@code &lt;searchable&gt;} element as the root node and specify one
-or more attributes that configure your search dialog. For example:</p>
+<p class="note"><strong>Note:</strong> The system uses this file to instantiate a {@link
+android.app.SearchableInfo} object, but you cannot create this object yourself at
+runtime&mdash;you must declare the searchable configuration in XML.</p>
+
+<p>The searchable configuration file must include the <a
+href="{@docRoot}guide/topics/search/searchable-config.html#searchable-element">{@code
+&lt;searchable&gt;}</a> element as the root node and specify one
+or more attributes. For example:</p>
 
 <pre>
 &lt;?xml version="1.0" encoding="utf-8"?>
@@ -112,51 +181,61 @@
 &lt;/searchable>
 </pre>
 
-<p>The {@code android:label} attribute is the only required attribute and points to a string
-resource, which should be the same as the application name. This label isn't actually visible to the
-user until you enable suggestions for Quick Search Box, at which point, this label is visible in the
-list of Searchable items in the system Settings.</p>
+<p>The {@code android:label} attribute is the only required attribute. It points to a string
+resource, which should be the application name. This label isn't actually visible to the
+user until you enable search suggestions for Quick Search Box. At that point, this label is visible
+in the list of Searchable items in the system Settings.</p>
 
 <p>Though it's not required, we recommend that you always include the {@code android:hint}
-attribute, which provides a hint string in the search dialog's text box before the user
-enters their query. The hint is important because it provides important clues to users about what
+attribute, which provides a hint string in the search box before users
+enters a query. The hint is important because it provides important clues to users about what
 they can search.</p>
 
 <p class="note"><strong>Tip:</strong> For consistency among other
 Android applications, you should format the string for {@code android:hint} as "Search
-<em>&lt;content-or-product&gt;</em>". For example, "Search songs and artists" or "Search
+&lt;content-or-product&gt;". For example, "Search songs and artists" or "Search
 YouTube".</p>
 
-<p>The {@code &lt;searchable&gt;} element accepts several other attributes. Most attributes apply
-only when configuring features such as search suggestions and voice search.</p>
-
-<p>For more details about the searchable configuration file, see the <a
-href="{@docRoot}guide/topics/search/searchable-config.html">Searchable Configuration</a>
-reference.</p>
+<p>The <a
+href="{@docRoot}guide/topics/search/searchable-config.html#searchable-element">{@code
+&lt;searchable&gt;}</a> element accepts several other attributes. However, you don't need
+most attributes until you add features such as <a href="#SearchSuggestions">search suggestions</a>
+and <a href="#VoiceSearch">voice search</a>. For detailed information about the searchable
+configuration file, see the <a
+href="{@docRoot}guide/topics/search/searchable-config.html">Searchable Configuration</a> reference
+document.</p>
 
 
 
 <h2 id="SearchableActivity">Creating a Searchable Activity</h2>
 
-<p>When the user executes a search from the search dialog, the Search Manager takes the query
-and sends it to your searchable {@link android.app.Activity} in the {@link
-android.content.Intent#ACTION_SEARCH} {@link android.content.Intent}. Your searchable Activity
-then searches your data using the query and presents the results to the user.</p>
+<p>A searchable activity is the {@link android.app.Activity} in your application that performs
+searches based on a query string and presents the search results.</p>
 
-<p>In order for the Search Manager to know where to deliver the search query, you must declare your
-searchable Activity in the Android manifest file.</p>
+<p>When the user executes a search in the search dialog or widget, the system starts your
+searchable activity and delivers it the search query in an {@link
+android.content.Intent} with the  {@link android.content.Intent#ACTION_SEARCH} action. Your
+searchable activity retrieves the query from the intent's {@link android.app.SearchManager#QUERY
+QUERY} extra, then searches your data and presents the results.</p>
+
+<p>Because you may include the search dialog or widget in any other activity in your application,
+the system must know which activity is your searchable activity, so it can properly deliver the
+search query. So, you must first declare your searchable activity in the Android manifest file.</p>
 
 
-<h3 id="DeclaringSearchableActivity">Declaring a searchable Activity</h3>
+<h3 id="DeclaringSearchableActivity">Declaring a searchable activity</h3>
 
-<p>If you don't have one already, create an {@link android.app.Activity} that performs
-searches and present search results. To set up this Activity as your searchable Activity:</p>
+<p>If you don't have one already, create an {@link android.app.Activity} that will perform
+searches and present results. You don't need to implement the search functionality yet&mdash;just
+create an activity that you can declare in the manifest. Inside the manifest's <a
+href="{@docRoot}guide/topics/manifest/activity-element.html">{@code &lt;activity&gt;}</a>
+element:</p>
 <ol>
-  <li>Declare the Activity to accept the {@link android.content.Intent#ACTION_SEARCH} {@link
-android.content.Intent}, in an <a
-href="{@docRoot}guide/topics/manifest/intent-filter-element.html">{@code &lt;intent-filter&gt;}</a>
+  <li>Declare the activity to accept the {@link android.content.Intent#ACTION_SEARCH} intent, in an
+<a href="{@docRoot}guide/topics/manifest/intent-filter-element.html">{@code
+&lt;intent-filter&gt;}</a>
 element.</li>
-  <li>Apply the searchable configuration, in a <a
+  <li>Specify the searchable configuration to use, in a <a
 href="{@docRoot}guide/topics/manifest/meta-data-element.html">{@code &lt;meta-data&gt;}</a>
 element.</li>
 </ol>
@@ -165,7 +244,7 @@
 
 <pre>
 &lt;application ... >
-    &lt;activity android:name=".MySearchableActivity" >
+    &lt;activity android:name=".SearchableActivity" >
         &lt;intent-filter>
             &lt;action android:name="android.intent.action.SEARCH" />
         &lt;/intent-filter>
@@ -181,71 +260,22 @@
 reference to the searchable configuration file (in this example, it
 refers to the {@code res/xml/searchable.xml} file).</p>
 
-<p class="note"><strong>Note:</strong> The {@code &lt;intent-filter&gt;} does not need a <a
+<p class="note"><strong>Note:</strong> The <a
+href="{@docRoot}guide/topics/manifest/intent-filter-element.html">{@code
+&lt;intent-filter&gt;}</a> does not need a <a
 href="{@docRoot}guide/topics/manifest/category-element.html">{@code &lt;category&gt;}</a> with the
-{@code DEFAULT} value, because the Search Manager delivers the {@link
-android.content.Intent#ACTION_SEARCH} Intent explicitly to your searchable Activity by name.</p>
+{@code DEFAULT} value (which you usually see in <a
+href="{@docRoot}guide/topics/manifest/activity-element.html">{@code &lt;activity&gt;}</a> elements),
+because the system delivers the {@link android.content.Intent#ACTION_SEARCH} intent explicitly to
+your searchable activity, using its component name.</p>
 
-<p>The search dialog is not, by default, available from every Activity of your
-application. Rather, the search dialog is presented to users only when they
-invoke search from a searchable context of your application. A searchable context is any Activity
-for which you have
-declared searchable meta-data in the manifest file. For example, the searchable Activity itself
-(declared in the manifest snippet above) is
-a searchable context because it includes meta-data that defines the
-searchable configuration. Any other Activity in your application is not a searchable context, by
-default, and thus, does not reveal the search dialog. However, you probably do want the search
-dialog available from your other activities (and to launch the searchable Activity when the user
-executes a search). You can do exactly that.</p>
-
-<p>If you want all of your activities to provide the search dialog, add another {@code
-&lt;meta-data&gt;} element inside the {@code
-&lt;application&gt;} element. Use this element to declare the existing searchable Activity as the
-default searchable Activity. For example:</p>
-
-<pre>
-&lt;application ... >
-    &lt;activity android:name=".MySearchableActivity" >
-        &lt;intent-filter>
-            &lt;action android:name="android.intent.action.SEARCH" />
-        &lt;/intent-filter>
-        &lt;meta-data android:name="android.app.searchable"
-                   android:resource="@xml/searchable"/>
-    &lt;/activity>
-    &lt;activity android:name=".AnotherActivity" ... >
-    &lt;/activity>
-    &lt;!-- declare the default searchable Activity for the whole app --&gt;
-    <b>&lt;meta-data android:name="android.app.default_searchable"
-               android:value=".MySearchableActivity" /&gt;</b>
-    ...
-&lt;/application>
-</pre>
-
-<p>The {@code &lt;meta-data&gt;} element with the {@code android:name} attribute value of
-{@code "android.app.default_searchable"} specifies a default searchable Activity for the context in
-which it is placed (which, in this case, is the entire application). The searchable Activity to
-use is specified with the {@code android:value} attribute. All other activities in the
-application, such as {@code AnotherActivity}, are now considered a searchable context and can invoke
-the search dialog. When a search is executed, {@code MySearchableActivity} is launched to handle
-the search query.</p>
-
-<p>You can also control which activities provide search at a more granular level.
-To specify only an individual Activity as a searchable context, place the {@code
-&lt;meta-data&gt;} with the {@code
-"android.app.default_searchable"} name inside the respective {@code &lt;activity&gt;}
-element (rather than inside the {@code &lt;application&gt;} element). While uncommon, you
-can also create more than one searchable Activity and provide each one in different contexts of your
-application, either by declaring a different searchable Activity in each {@code &lt;activity&gt;}
-element, or by declaring a default searchable Activity for the entire application and then
-overriding it with a {@code &lt;meta-data&gt;} element inside certain activities. (You might do
-this if you want to search different sets of data that cannot be handled by the same
-searchable Activity, depending on the currently open Activity.)</p>
 
 
 <h3 id="PerformingSearch">Performing a search</h3>
 
-<p>Once you have declared your searchable Activity, performing a search for the user involves
-three steps:</p>
+<p>Once you have declared your searchable activity in the manifest, performing a search in your
+searchable activity involves three steps:</p>
+
 <ol>
   <li><a href="#ReceivingTheQuery">Receiving the query</a></li>
   <li><a href="#SearchingYourData">Searching your data</a></li>
@@ -253,20 +283,19 @@
 </ol>
 
 <p>Traditionally, your search results should be presented in a {@link android.widget.ListView}, so
-you might want your searchable Activity to extend {@link android.app.ListActivity}, which
-provides easy access to {@link android.widget.ListView} APIs. (See the <a
-href="{@docRoot}resources/tutorials/views/hello-listview.html">List View Tutorial</a> for a simple
-{@link android.app.ListActivity} sample.)</p>
+you might want your searchable activity to extend {@link android.app.ListActivity}. It includes
+a default layout with a single {@link android.widget.ListView} and provides several
+convenience methods for working with the {@link android.widget.ListView}.</p>
 
 
 <h4 id="ReceivingTheQuery">Receiving the query</h4>
 
-<p>When a user executes a search from the search dialog, the Search Manager sends the {@link
-android.content.Intent#ACTION_SEARCH} {@link android.content.Intent} to your searchable Activity.
-This Intent carries the search query in the
+<p>When a user executes a search from the search dialog or widget, the system starts your
+searchable activity and sends it a {@link android.content.Intent#ACTION_SEARCH} intent. This intent
+carries the search query in the
 {@link android.app.SearchManager#QUERY QUERY} string extra. You must check for
-this Intent when the Activity starts and extract the string. For example, here's how you can get the
-query when your Activity starts:</p>
+this intent when the activity starts and extract the string. For example, here's how you can get the
+search query when your searchable activity starts:</p>
 
 <pre>
 &#64;Override
@@ -274,8 +303,8 @@
     super.onCreate(savedInstanceState);
     setContentView(R.layout.search);
 
+    // Get the intent, verify the action and get the query
     Intent intent = getIntent();
-
     if (Intent.ACTION_SEARCH.equals(intent.getAction())) {
       String query = intent.getStringExtra(SearchManager.QUERY);
       doMySearch(query);
@@ -284,7 +313,7 @@
 </pre>
 
 <p>The {@link android.app.SearchManager#QUERY QUERY} string is always included with
-the {@link android.content.Intent#ACTION_SEARCH} Intent. In this example, the query is
+the {@link android.content.Intent#ACTION_SEARCH} intent. In this example, the query is
 retrieved and passed to a local {@code doMySearch()} method where the actual search operation
 is done.</p>
 
@@ -294,12 +323,13 @@
 <p>The process of storing and searching your data is unique to your application.
 You can store and search your data in many ways, but this guide does not show you how to store your
 data and search it. Storing and searching your data is something you should carefully consider in
-terms of your needs and your data. However, here are some tips you might be able to apply:</p>
+terms of your needs and your data format. However, here are some tips you might be able to
+apply:</p>
 
   <ul>
     <li>If your data is stored in a SQLite database on the device, performing a full-text search
-(using FTS3, rather than a LIKE query) can provide a more robust search across text data and can
-produce results significantly faster. See <a href="http://sqlite.org/fts3.html">sqlite.org</a>
+(using FTS3, rather than a {@code LIKE} query) can provide a more robust search across text data and
+can produce results significantly faster. See <a href="http://sqlite.org/fts3.html">sqlite.org</a>
 for information about FTS3 and the {@link android.database.sqlite.SQLiteDatabase} class for
 information about SQLite on Android. Also look at the <a
 href="{@docRoot}resources/samples/SearchableDictionary/index.html">Searchable Dictionary</a> sample
@@ -307,43 +337,45 @@
     <li>If your data is stored online, then the perceived search performance might be
 inhibited by the user's data connection. You might want to display a spinning progress wheel until
 your search returns. See {@link android.net} for a reference of network APIs and <a
-href="{@docRoot}guide/topics/ui/dialogs.html#ProgressDialog">Creating a Progress Dialog</a> to see
-how you can display a progress wheel.</li>
+href="{@docRoot}guide/topics/ui/dialogs.html#ProgressDialog">Creating a Progress Dialog</a>
+for information about how to display a progress wheel.</li>
   </ul>
 
 
 <div class="sidebox-wrapper">
 <div class="sidebox">
 <h2>About Adapters</h2>
-<p>An Adapter binds individual items from a set of data into individual {@link
-android.view.View} objects. When the Adapter
-is applied to a {@link android.widget.ListView}, the Views are injected as individual items of the
-list. {@link
-android.widget.Adapter} is simply an interface, so implementations such as {@link
+<p>An {@link android.widget.Adapter} binds each item from a set of data into a
+{@link android.view.View} object. When the {@link android.widget.Adapter}
+is applied to a {@link android.widget.ListView}, each piece of data is inserted as an individual
+view into the list. {@link
+android.widget.Adapter} is just an interface, so implementations such as {@link
 android.widget.CursorAdapter} (for binding data from a {@link android.database.Cursor}) are needed.
-If none of the existing implementations work for your data, then you should implement your own from
+If none of the existing implementations work for your data, then you can implement your own from
 {@link android.widget.BaseAdapter}. Install the SDK Samples package for API Level 4 to see the
-original version of the Searchable Dictionary, which creates a custom BaseAdapter.</p>
+original version of the Searchable Dictionary, which creates a custom adapter to read data from
+a file.</p>
 </div>
 </div>
 
 <p>Regardless of where your data lives and how you search it, we recommend that you return search
-results to your searchable Activity with an {@link android.widget.Adapter}. This way, you can easily
+results to your searchable activity with an {@link android.widget.Adapter}. This way, you can easily
 present all the search results in a {@link android.widget.ListView}. If your data comes from a
-SQLite database query, then you can apply your results to a {@link android.widget.ListView}
+SQLite database query, you can apply your results to a {@link android.widget.ListView}
 using a {@link android.widget.CursorAdapter}. If your data comes in some other type of format, then
-you can create an extension of the {@link android.widget.BaseAdapter}.</p>
+you can create an extension of {@link android.widget.BaseAdapter}.</p>
+
 
 <h4 id="PresentingTheResults">Presenting the results</h4>
 
-<p>Presenting your search results is mostly a UI detail that is not handled by the search APIs.
-However, one option is to create your searchable Activity to extend {@link
-android.app.ListActivity} and call {@link
-android.app.ListActivity#setListAdapter(ListAdapter)}, passing it an {@link
+<p>As discussed above, the recommended UI for your search results is a {@link
+android.widget.ListView}, so you might want your searchable activity to extend {@link
+android.app.ListActivity}. You can then call {@link
+android.app.ListActivity#setListAdapter(ListAdapter) setListAdapter()}, passing it an {@link
 android.widget.Adapter} that is bound to your data. This injects all the
-results into the Activity {@link android.widget.ListView}.</p>
+search results into the activity {@link android.widget.ListView}.</p>
 
-<p>For more help presenting your results, see the {@link android.app.ListActivity}
+<p>For more help presenting your results in a list, see the {@link android.app.ListActivity}
 documentation.</p>
 
 <p>Also see the <a
@@ -353,22 +385,130 @@
 
 
 
-<h2 id="InvokingTheSearchDialog">Invoking the Search Dialog</h2>
 
-<p>Once you have a searchable Activity, invoking the search dialog is easy. Many Android
-devices provide a dedicated SEARCH key, which reveals the search dialog when the user presses it
-from a searchable context of your application. However, you should not assume that a SEARCH
-key is available on the user's device and should always provide a search button in your UI that
-invokes search.</p>
 
-<p>To invoke search from your Activity, call {@link android.app.Activity#onSearchRequested()}.</p>
+<h2 id="SearchDialog">Using the Search Dialog</h2>
 
-<p>For instance, you should provide a menu item in your <a
-href="{@docRoot}guide/topics/ui/menus.html#options-menu">Options Menu</a> or a button in your UI to
-invoke search with this method. The <a
+<div class="sidebox-wrapper">
+<div class="sidebox">
+  <h2>Should I use the search dialog or the widget?</h2>
+  <p>The answer depends mostly on whether you are developing for Android 3.0 (API Level 11 or
+higher), because the {@link android.widget.SearchView} widget was introduced in Android 3.0. So,
+if you are developing your application for a version of Android lower than 3.0, the search widget is
+not an option and you should use the search dialog to implement your search interface.</p>
+  <p>If you <em>are</em> developing for Android 3.0 or higher, then the decision depends more on
+your needs. In most cases, we recommend that you use the search widget as an "action view" in the
+Action Bar. However, it might not be an option for you to put the search
+widget in the Action Bar for some reason (perhaps there's not enough space or you don't use the
+Action Bar). So, you might instead want to put the search widget somewhere in your activity layout.
+And if all else fails, you can still use the search dialog if you prefer to keep the search box
+hidden. In fact, you might want to offer both the dialog and the widget in some cases. For more
+information about the widget, skip to <a href="#UsingSearchWidget">Using the Search Widget</a>.</p>
+</div>
+</div>
+
+<p>The search dialog provides a floating search box at the top of the screen, with the application
+icon on the left. The search dialog can provide search suggestions as the user types and, when
+the user executes a search, the system sends the search query to a
+searchable activity that performs the search. However, if you are developing
+your application for devices running Android 3.0, you should consider using the search widget
+instead (see the side box).</p>
+
+<p>The search dialog is always hidden by default, until the user activates it. If the user's device
+includes a SEARCH button, pressing it will activate the search dialog by default. Your application
+can also activate the search dialog on demand by calling {@link
+android.app.Activity#onSearchRequested onSearchRequested()}. However, neither of these work
+until you enable the search dialog for the activity.</p>
+
+<p>To enable the search dialog, you must indicate to the system which searchable activity should
+receive search queries from the search dialog, in order to perform searches. For example, in the
+previous section about <a href="#SearchableActivity">Creating a Searchable Activity</a>, a
+searchable activity named {@code SearchableActivity} was created. If you want a separate activity,
+named {@code OtherActivity}, to show the search dialog and deliver searches to {@code
+SearchableActivity}, you must declare in the manifest that {@code SearchableActivity} is the
+searchable activity to use for the search dialog in {@code OtherActivity}.</p>
+
+<p>To declare the searchable activity for an activity's search dialog,
+add a <a href="{@docRoot}guide/topics/manifest/meta-data-element.html">{@code &lt;meta-data&gt;}</a>
+element inside the respective activity's <a
+href="{@docRoot}guide/topics/manifest/activity-element.html">{@code &lt;activity&gt;}</a> element.
+The <a href="{@docRoot}guide/topics/manifest/meta-data-element.html">{@code &lt;meta-data&gt;}</a>
+element must include the {@code android:value} attribute that specifies the searchable activity's
+class name and the {@code android:name} attribute with a value of {@code
+"android.app.default_searchable"}.</p>
+
+<p>For example, here is the declaration for
+both a searchable activity, {@code SearchableActivity}, and another activity, {@code
+OtherActivity}, which uses {@code SearchableActivity} to perform searches executed from its
+search dialog:</p>
+
+<pre>
+&lt;application ... >
+    &lt;!-- this is the searchable activity; it performs searches --&gt;
+    &lt;activity android:name=".SearchableActivity" >
+        &lt;intent-filter>
+            &lt;action android:name="android.intent.action.SEARCH" />
+        &lt;/intent-filter>
+        &lt;meta-data android:name="android.app.searchable"
+                   android:resource="@xml/searchable"/>
+    &lt;/activity>
+
+    &lt;!-- this activity enables the search dialog to initiate searches
+         in the SearchableActivity --&gt;
+    &lt;activity android:name=".OtherActivity" ... >
+        &lt;!-- enable the search dialog to send searches to SearchableActivity -->
+        <b>&lt;meta-data android:name="android.app.default_searchable"
+                   android:value=".SearchableActivity" /&gt;</b>
+    &lt;/activity>
+    ...
+&lt;/application>
+</pre>
+
+<p>Because the {@code OtherActivity} now includes a <a
+href="{@docRoot}guide/topics/manifest/meta-data-element.html">{@code &lt;meta-data&gt;}</a>
+element to declare which searchable activity to use for searches, the activity has enabled the
+search dialog.
+While the user is in this activity, the device SEARCH button (if available) and the {@link
+android.app.Activity#onSearchRequested onSearchRequested()} method will activate the search dialog.
+When the user executes the search, the system starts {@code SearchableActivity} and delivers it
+the {@link android.content.Intent#ACTION_SEARCH} intent.</p>
+
+<p class="note"><strong>Note:</strong> The searchable activity itself provides the search dialog
+by default, so you don't need to add this declaration to {@code SearchableActivity}.</p>
+
+<p>If you want every activity in your application to provide the search dialog, insert the above <a
+href="{@docRoot}guide/topics/manifest/meta-data-element.html">{@code &lt;meta-data&gt;}</a>
+element as a child of the <a
+href="{@docRoot}guide/topics/manifest/application-element.html">{@code &lt;application&gt;}</a>
+element, instead of each <a
+href="{@docRoot}guide/topics/manifest/activity-element.html">{@code &lt;activity&gt;}</a>. This
+way, every activity inherits the value, provides the search dialog, and delivers searches to
+the same searchable activity. (If you have multiple searchable activities, you can override the
+default searchable activity by placing a different <a
+href="{@docRoot}guide/topics/manifest/meta-data-element.html">{@code &lt;meta-data&gt;}</a>
+declaration inside individual activities.)</p>
+
+<p>With the search dialog now enabled for your activities, your application is ready to perform
+searches.</p>
+
+
+<h3 id="InvokingTheSearchDialog">Invoking the search dialog</h3>
+
+<p>As mentioned above, the device SEARCH button and {@link android.app.Activity#onSearchRequested
+onSearchRequested()} method will open the search dialog, as long as the current activity
+has declared the searchable activity to use, as shown in the previous section.</p>
+
+<p>However, you should not assume that a SEARCH button is available on the user's device. You
+should always provide another search button in your UI that activates the search dialog by calling
+{@link android.app.Activity#onSearchRequested()}.</p>
+
+<p>For instance, you should either provide a menu item in your <a
+href="{@docRoot}guide/topics/ui/menus.html#options-menu">Options Menu</a> or a button in your
+activity layout that
+activates search by calling {@link android.app.Activity#onSearchRequested()}. The <a
 href="{@docRoot}shareables/search_icons.zip">search_icons.zip</a> file includes icons for
-medium and high density screens, which you can use for your search menu item or button (low density
-screens automatically scale-down the hdpi image by one half). </p>
+medium and high density screens, which you can use for your search menu item or button (low-density
+screens scale-down the hdpi image by one half). </p>
 
 <!-- ... maybe this should go into the Creating Menus document ....
 <p>If you chose to provide a shortcut key for the menu item,  using {@link
@@ -376,27 +516,28 @@
 key character, representing the default search key.</p>
 -->
 
-<p>You can also enable "type-to-search" functionality, which reveals the search dialog when the
-user starts typing on the keyboard and the keystrokes are inserted into the search dialog. You can
-enable type-to-search in your Activity by calling
+<p>You can also enable "type-to-search" functionality, which activates the search dialog when the
+user starts typing on the keyboard&mdash;the keystrokes are inserted into the search dialog. You can
+enable type-to-search in your activity by calling
 {@link android.app.Activity#setDefaultKeyMode(int) setDefaultKeyMode}({@link
-android.app.Activity#DEFAULT_KEYS_SEARCH_LOCAL}) during your Activity's
+android.app.Activity#DEFAULT_KEYS_SEARCH_LOCAL}) during your activity's
 {@link android.app.Activity#onCreate(Bundle) onCreate()} method.</p>
 
 
-<h3 id="LifeCycle">The impact of the search dialog on your Activity lifecycle</h3>
+<h3 id="LifeCycle">The impact of the search dialog on your activity lifecycle</h3>
 
 <p>The search dialog is a {@link android.app.Dialog} that floats at the top of the
-screen. It does not cause any change in the Activity stack, so when the search dialog appears, no
-lifecycle methods for the currently open Activity (such as {@link
-android.app.Activity#onPause()}) are called. Your Activity just loses input focus as it is given to
-the search dialog.
+screen. It does not cause any change in the activity stack, so when the search dialog appears, no
+lifecycle methods (such as {@link android.app.Activity#onPause()}) are called. Your activity just
+loses input focus, as input focus is given to the search dialog.
 </p>
 
-<p>If you want to be notified when search is invoked, override the {@link
-android.app.Activity#onSearchRequested()} method. When the system calls this method, you can do any
-work you want to when your Activity looses input focus to the search dialog (such as pause
-animations). Unless you are <a href="#SearchContextData">passing search context data</a>
+<p>If you want to be notified when the search dialog is activated, override the {@link
+android.app.Activity#onSearchRequested()} method. When the system calls this method, it is an
+indication that your activity has lost input focus to the search dialog, so you can do any
+work appropriate for the event (such as pause
+a game). Unless you are <a
+href="#SearchContextData">passing search context data</a>
 (discussed below), you should end the method by calling the super class implementation. For
 example:</p>
 
@@ -408,8 +549,8 @@
 }
 </pre>
 
-<p>If the user cancels search by pressing the BACK key, the Activity in which search was
-invoked re-gains input focus. You can register to be notified when the search dialog is
+<p>If the user cancels search by pressing the BACK button, the search dialog closes and the activity
+regains input focus. You can register to be notified when the search dialog is
 closed with {@link android.app.SearchManager#setOnDismissListener(SearchManager.OnDismissListener)
 setOnDismissListener()}
 and/or {@link android.app.SearchManager#setOnCancelListener(SearchManager.OnCancelListener)
@@ -420,25 +561,26 @@
 user explicitly exited the search dialog, so it is not called when a search is executed (in which
 case, the search dialog naturally disappears).</p>
 
-<p>If the current Activity is not the searchable Activity, then the normal Activity lifecycle
-events are triggered once the user executes a search (the current Activity receives {@link
+<p>If the current activity is not the searchable activity, then the normal activity lifecycle
+events are triggered once the user executes a search (the current activity receives {@link
 android.app.Activity#onPause()} and so forth, as
-described in <a href="{@docRoot}guide/topics/fundamentals/activities.html#Lifecycle">Activities</a>
-document). If, however, the current Activity is the searchable Activity, then one of two
+described in the <a
+href="{@docRoot}guide/topics/fundamentals/activities.html#Lifecycle">Activities</a>
+document). If, however, the current activity is the searchable activity, then one of two
 things happens:</p>
 
 <ol type="a">
-  <li>By default, the searchable Activity receives the {@link
-android.content.Intent#ACTION_SEARCH} Intent with a call to {@link
+  <li>By default, the searchable activity receives the {@link
+android.content.Intent#ACTION_SEARCH} intent with a call to {@link
 android.app.Activity#onCreate(Bundle) onCreate()} and a new instance of the
-Activity is brought to the top of the Activity stack. There are now two instances of your
-searchable Activity in the Activity stack (so pressing the BACK key goes back to the previous
-instance of the searchable Activity, rather than exiting the searchable Activity).</li>
-  <li>If you set {@code android:launchMode} to "singleTop", then the
-searchable Activity receives the {@link android.content.Intent#ACTION_SEARCH} Intent with a call
+activity is brought to the top of the activity stack. There are now two instances of your
+searchable activity in the activity stack (so pressing the BACK button goes back to the previous
+instance of the searchable activity, rather than exiting the searchable activity).</li>
+  <li>If you set {@code android:launchMode} to <code>"singleTop"</code>, then the
+searchable activity receives the {@link android.content.Intent#ACTION_SEARCH} intent with a call
 to {@link android.app.Activity#onNewIntent(Intent)}, passing the new {@link
-android.content.Intent#ACTION_SEARCH} Intent here. For example, here's how you might handle
-this case, in which the searchable Activity's launch mode is "singleTop":
+android.content.Intent#ACTION_SEARCH} intent here. For example, here's how you might handle
+this case, in which the searchable activity's launch mode is <code>"singleTop"</code>:
 <pre>
 &#64;Override
 public void onCreate(Bundle savedInstanceState) {
@@ -463,29 +605,29 @@
 
 <p>Compared to the example code in the section about <a href="#PerformingSearch">Performing a
 Search</a>, all the code to handle the
-search Intent is now in the {@code handleIntent()} method, so that both {@link
+search intent is now in the {@code handleIntent()} method, so that both {@link
 android.app.Activity#onCreate(Bundle)
 onCreate()} and {@link android.app.Activity#onNewIntent(Intent) onNewIntent()} can execute it.</p>
 
-<p>When the system calls {@link android.app.Activity#onNewIntent(Intent)}, the Activity has
+<p>When the system calls {@link android.app.Activity#onNewIntent(Intent)}, the activity has
 not been restarted, so the {@link android.app.Activity#getIntent()} method
-returns the same Intent that was received with {@link
+returns the same intent that was received with {@link
 android.app.Activity#onCreate(Bundle) onCreate()}. This is why you should call {@link
 android.app.Activity#setIntent(Intent)} inside {@link
-android.app.Activity#onNewIntent(Intent)} (so that the Intent saved by the Activity is updated in
+android.app.Activity#onNewIntent(Intent)} (so that the intent saved by the activity is updated in
 case you call {@link android.app.Activity#getIntent()} in the future).</p>
 
 </li>
 </ol>
 
-<p>The second scenario using "singleTop" launch mode is usually ideal, because chances are good that
-once a search is done, the user will perform additional searches and it's a bad experience if your
-application creates multiple instances of the searchable Activity. So, we recommend that you set
-your searchable Activity to "singleTop" launch mode in the application
-manifest. For example:</p>
+<p>The second scenario using <code>"singleTop"</code> launch mode is usually ideal, because chances
+are good that once a search is done, the user will perform additional searches and it's a bad
+experience if your application creates multiple instances of the searchable activity. So, we
+recommend that you set your searchable activity to <code>"singleTop"</code> launch mode in the
+application manifest. For example:</p>
 
 <pre>
-&lt;activity android:name=".MySearchableActivity"
+&lt;activity android:name=".SearchableActivity"
           <b>android:launchMode="singleTop"</b> >
     &lt;intent-filter>
         &lt;action android:name="android.intent.action.SEARCH" />
@@ -497,57 +639,192 @@
 
 
 
-<h2 id="SearchContextData">Passing Search Context Data</h2>
+<h3 id="SearchContextData">Passing search context data</h3>
 
-<p>To refine your search criteria from the current Activity instead of depending only on the user's
-search query, you can provide additional data in the Intent that the Search Manager sends to your
-searchable Activity. In a simple case, you can make your refinements inside the searchable
-Activity, for every search made, but if your
-search criteria varies from one searchable context to another, then you can pass whatever data
-is necessary to refine your search in the {@link android.app.SearchManager#APP_DATA} {@link
-android.os.Bundle}, which is included in the {@link android.content.Intent#ACTION_SEARCH}
-Intent.</p>
+<p>In some cases, you can make necessary refinements to the search query inside the searchable
+activity, for every search made. However, if you want to refine your search criteria based on the
+activity from which the user is performing a search, you can provide additional data in the intent
+that the system sends to your searchable activity. You can pass the additional data in the {@link
+android.app.SearchManager#APP_DATA} {@link android.os.Bundle}, which is included in the {@link
+android.content.Intent#ACTION_SEARCH} intent.</p>
 
-<p>To pass this kind of data to your searchable Activity, override  {@link
-android.app.Activity#onSearchRequested()} method for the Activity in which search can be invoked.
+<p>To pass this kind of data to your searchable activity, override the {@link
+android.app.Activity#onSearchRequested()} method for the activity from which the user can perform a
+search, create a {@link android.os.Bundle} with the additional data, and call {@link
+android.app.Activity#startSearch startSearch()} to activate the search dialog.
 For example:</p>
 
 <pre>
 &#64;Override
 public boolean onSearchRequested() {
      Bundle appData = new Bundle();
-     appData.putBoolean(MySearchableActivity.JARGON, true);
+     appData.putBoolean(SearchableActivity.JARGON, true);
      startSearch(null, false, appData, false);
      return true;
  }
 </pre>
 
-<p>Returning "true" indicates that you have successfully handled this callback event. Then in your
-searchable Activity, you can extract the data placed inside {@code appdata} from the {@link
+<p>Returning "true" indicates that you have successfully handled this callback event and
+called {@link android.app.Activity#startSearch startSearch()} to activate
+the search dialog. Once the user submits a query, it's delivered to your
+searchable activity along with the data you've added. You can extract the extra data from the {@link
 android.app.SearchManager#APP_DATA} {@link android.os.Bundle} to refine the search. For example:</p>
 
 <pre>
 Bundle appData = getIntent().getBundleExtra(SearchManager.APP_DATA);
 if (appData != null) {
-    boolean jargon = appData.getBoolean(MySearchableActivity.JARGON);
+    boolean jargon = appData.getBoolean(SearchableActivity.JARGON);
 }
 </pre>
 
 <p class="caution"><strong>Caution:</strong> Never call the {@link
 android.app.Activity#startSearch(String,boolean,Bundle,boolean) startSearch()} method from outside
-the {@link android.app.Activity#onSearchRequested()} callback method. To invoke the search dialog
-in your Activity, always call {@link android.app.Activity#onSearchRequested()}. Otherwise, {@link
+the {@link android.app.Activity#onSearchRequested()} callback method. To activate the search dialog
+in your activity, always call {@link android.app.Activity#onSearchRequested()}. Otherwise, {@link
 android.app.Activity#onSearchRequested()} is not called and customizations (such as the addition of
 {@code appData} in the above example) are missed.</p>
 
 
+
+<h2 id="UsingSearchWidget">Using the Search Widget</h2>
+
+<div class="figure" style="width:429px;margin:0">
+  <img src="{@docRoot}images/ui/actionbar-actionview.png" alt="" />
+  <p class="img-caption"><strong>Figure 2.</strong> The {@link
+android.widget.SearchView} widget as an "action view" in the Action Bar.</p>
+</div>
+
+<p>The {@link android.widget.SearchView} widget is available in Android 3.0 and higher. If
+you're developing your application for Android 3.0 and have decided to use the search widget, we
+recommend that you insert the search widget as an <a
+href="{@docRoot}guide/topics/ui/actionbar.html#ActionView">action view in the Action Bar</a>,
+instead of using the search dialog (and instead of placing the search widget in your activity
+layout). For example, figure 2 shows the search widget in the Action Bar.</p>
+
+<p>The search widget provides the same functionality as the search dialog. It starts the appropriate
+activity when the user executes a search, and it can provide search suggestions and perform voice
+search.</p>
+
+<p class="note"><strong>Note:</strong> When you use the search widget as an action view, you
+still might need to support using the search dialog, for cases in which the search widget does
+not fit in the Action Bar. See the following section about <a href="#UsingBoth">Using both
+the widget and the dialog</a>.</p>
+
+
+<h3 id="ConfiguringWidget">Configuring the search widget</h3>
+
+<p>After you've created a  <a href="#SearchableConfiguration">searchable configuration</a> and a <a
+href="#SearchableActivity">searchable activity</a>, as discussed above, you need to enable assisted
+search for each {@link android.widget.SearchView}. You can do so by calling {@link
+android.widget.SearchView#setSearchableInfo setSearchableInfo()} and passing it the {@link
+android.app.SearchableInfo} object that represents your searchable configuration.</p>
+
+<p>You can get a reference to the {@link android.app.SearchableInfo} by calling {@link
+android.app.SearchManager#getSearchableInfo getSearchableInfo()} on {@link
+android.app.SearchManager}.</p>
+
+<p>For example, if you're using a {@link android.widget.SearchView} as an action view in the <a
+href="{@docRoot}guide/topics/ui/actionbar.html">Action Bar</a>, you should enable the widget
+during the {@link android.app.Activity#onCreateOptionsMenu onCreateOptionsMenu()} callback:</p>
+
+<pre>
+&#64;Override
+public boolean onCreateOptionsMenu(Menu menu) {
+    // Inflate the options menu from XML
+    MenuInflater inflater = getMenuInflater();
+    inflater.inflate(R.menu.options_menu, menu);
+
+    // Get the SearchView and set the searchable configuration
+    SearchManager searchManager = (SearchManager) {@link android.app.Activity#getSystemService getSystemService}(Context.SEARCH_SERVICE);
+    SearchView searchView = (SearchView) menu.findItem(R.id.menu_search).getActionView();
+    searchView.setSearchableInfo(searchManager.getSearchableInfo({@link android.app.Activity#getComponentName()}));
+    searchView.setIconifiedByDefault(false); // Do not iconify the widget; expand it by default
+
+    return true;
+}
+</pre>
+
+<p>That's all you need. The search widget is now configured and the system will deliver search
+queries to your searchable activity. You can also enable <a href="#SearchSuggestions">search
+suggestions</a> for the search widget.</p>
+
+<p class="note"><strong>Note:</strong> If you want to handle all user input yourself, you can do so
+with some callback methods and event listeners. For more information, see the reference
+documentation for {@link android.widget.SearchView} and its nested interfaces for the
+appropriate event listeners.</p>
+
+<p>For more information about action views in the Action Bar, read <a
+href="{@docRoot}guide/topics/ui/actionbar.html#ActionView">Using the Action Bar</a> (which
+includes sample code for adding a search widget as an action view).</p>
+
+
+<h3 id="WidgetFeatures">Other search widget features</h3>
+
+<p>The {@link android.widget.SearchView} widget allows for a few additional features you might
+want:</p>
+
+<dl>
+  <dt>A submit button</dt>
+  <dd>By default, there's no button to submit a search query, so the user must press the
+"Return" key on the keyboard to initiate a search. You can add a "submit" button by calling
+{@link android.widget.SearchView#setSubmitButtonEnabled setSubmitButtonEnabled(true)}.</dd>
+  <dt>Query refinement for search suggestions</dt>
+  <dd>When you've enabled search suggestions, you usually expect users to simply select a
+suggestion, but they might also want to refine the suggested search query. You can add a button
+alongside each suggestion that inserts the suggestion in the search box for refinement by the
+user, by calling {@link android.widget.SearchView#setQueryRefinementEnabled
+setQueryRefinementEnabled(true)}.</dd>
+  <dt>The ability to toggle the search box visibility</dt>
+  <dd>By default, the search widget is "iconified," meaning that it is represented only by a
+search icon (a magnifying glass), and expands to show the search box when the user touches it.
+As shown above, you can show the search box by default, by calling {@link
+android.widget.SearchView#setIconifiedByDefault setIconifiedByDefault(false)}. You can also
+toggle the search widget appearance by calling {@link android.widget.SearchView#setIconified
+setIconified()}.</dd>
+</dl>
+
+<p>There are several other APIs in the {@link android.widget.SearchView} class that allow you to
+customize the search widget. However, most of them are used only when you handle all
+user input yourself, instead of using the Android system to deliver search queries and display
+search suggestions.</p>
+
+
+<h3 id="UsingBoth">Using both the widget and the dialog</h3>
+
+<p>If you insert the search widget in the Action Bar as an <a
+href="{@docRoot}guide/topics/ui/actionbar.html#ActionView">action view</a>, and you enable it to
+appear in the Action Bar "if there is room" (by setting {@code
+android:showAsAction="ifRoom"}), then there is a chance that the search widget will not appear
+as an action view, but the menu item will appear in the overflow menu. For example, when your
+application runs on a smaller screen, there might not be enough room in the Action Bar to display
+the search widget along with other action items or navigation elements, so the menu item will
+instead appear in the overflow menu. When placed in the overflow menu, the item works like an
+ordinary menu item and does not display the action view (the search widget).</p>
+
+<p>To handle this situation, the menu item to which you've attached the search widget should
+activate the search dialog when the user selects it from the overflow menu. In order for it to do
+so, you must implement {@link android.app.Activity#onOptionsItemSelected onOptionsItemSelected()} to
+handle the "Search" menu item and open the search dialog by calling {@link
+android.app.Activity#onSearchRequested onSearchRequested()}.</p>
+
+<p>For more information about how items in the Action Bar work and how to handle this situation, see
+the documentation for <a href="{@docRoot}guide/topics/ui/actionbar.html">Using the Action
+Bar</a>.</p>
+
+<p>Also see the <a
+href="{@docRoot}resources/samples/SearchableDictionary/src/com/example/android/searchabledict/
+SearchableDictionary.html">Searchable Dictionary</a> for an example implementation using
+both the dialog and the widget.</p>
+
+
+
 <h2 id="VoiceSearch">Adding Voice Search</h2>
 
-<p>You can add voice search functionality to your search dialog by adding the {@code
+<p>You can add voice search functionality to your search dialog or widget by adding the {@code
 android:voiceSearchMode} attribute to your searchable configuration. This adds a voice search
-button in the search dialog that launches a voice prompt. When the user
+button that launches a voice prompt. When the user
 has finished speaking, the transcribed search query is sent to your searchable
-Activity.</p>
+activity.</p>
 
 <p>For example:</p>
 
@@ -562,7 +839,7 @@
 
 <p>The value {@code showVoiceSearchButton} is required to enable voice
 search, while the second value, {@code launchRecognizer}, specifies that the voice search button
-should launch a recognizer that returns the transcribed text to the searchable Activity.</p>
+should launch a recognizer that returns the transcribed text to the searchable activity.</p>
 
 <p>You can provide additional attributes to specify the voice search behavior, such
 as the language to be expected and the maximum number of results to return. See the <a
@@ -571,6 +848,38 @@
 
 <p class="note"><strong>Note:</strong> Carefully consider whether voice search is appropriate for
 your application. All searches performed with the voice search button are immediately sent to
-your searchable Activity without a chance for the user to review the transcribed query. Sufficiently
+your searchable activity without a chance for the user to review the transcribed query. Sufficiently
 test the voice recognition and ensure that it understands the types of queries that
 the user might submit inside your application.</p>
+
+
+
+<h2 id="SearchSuggestions">Adding Search Suggestions</h2>
+
+<div class="figure" style="width:250px;margin:0">
+<img src="{@docRoot}images/search/search-suggest-custom.png" alt="" height="417" />
+<p class="img-caption"><strong>Figure 3.</strong> Screenshot of a search dialog with custom
+search suggestions.</p>
+</div>
+
+<p>Both the search dialog and the search widget can provide search suggestions as the user
+types, with assistance from the Android system. The system manages the list of suggestions and
+handles the event when the user selects a suggestion.</p>
+
+<p>You can provide two kinds of search suggestions:</p>
+
+<dl>
+  <dt>Recent query search suggestions</dt>
+  <dd>These suggestions are simply words that the user previously used as search queries in
+your application.
+  <p>See <a href="adding-recent-query-suggestions.html">Adding Recent Query
+Suggestions</a>.</p></dd>
+  <dt>Custom search suggestions</dt>
+  <dd>These are search suggestions that you provide from your own data source, to help users
+immediately select the correct spelling or item they are searching for. Figure 3 shows an
+example of custom suggestions for a dictionary application&mdash;the user can select a suggestion
+to instantly go to the definition.
+  <p>See <a href="adding-custom-suggestions.html">Adding Custom
+Suggestions</a></p></dd>
+</dl>
+
diff --git a/docs/html/guide/topics/search/searchable-config.jd b/docs/html/guide/topics/search/searchable-config.jd
index 2aa2db6..fb689f9 100644
--- a/docs/html/guide/topics/search/searchable-config.jd
+++ b/docs/html/guide/topics/search/searchable-config.jd
@@ -7,19 +7,20 @@
 <div id="qv">
 <h2>See also</h2>
 <ol>
-  <li><a href="search-dialog.html">Using the Android Search Dialog</a></li>
+  <li><a href="search-dialog.html">Creating a Search Interface</a></li>
   <li><a href="adding-recent-query-suggestions.html">Adding Recent Query Suggestions</a></li>
   <li><a href="adding-custom-suggestions.html">Adding Custom Suggestions</a></li>
 </ol>
 </div>
 </div>
 
-<p>To utilize the Android search framework and provide a custom search dialog, your
-application must provide a search
-configuration in the form of an XML resource. This document describes the search configuration XML
-in terms of its syntax and usage. For more information about how to implement search
-features for your application, see the developer guide about <a
-href="index.html">Search</a>.</p>
+<p>In order to implement search with assistance from the Android system (to deliver search queries
+to an activity and provide search suggestions), your application must provide a search configuration
+in the form of an XML file.</p>
+
+<p>This page describes the search configuration file in terms of its syntax and usage. For more
+information about how to implement search features for your application, begin with the developer
+guide about <a href="search-dialog.html">Creating a Search Interface</a>.</p>
 
 <dl class="xml">
 
@@ -66,7 +67,7 @@
 <dd>
 <dl class="tag-list">
   <dt id="searchable-element"><code>&lt;searchable&gt;</code></dt>
-  <dd>Defines all search configurations used with the search dialog.
+  <dd>Defines all search configurations used by the Android system to provide assisted search.
     <p class="caps">attributes:</p>
       <dl class="atn-list">
       <dt><code>android:label</code></dt>
@@ -86,21 +87,21 @@
 "Search songs and artists" or "Search YouTube".</dd>
 
       <dt><code>android:searchMode</code></dt>
-      <dd><em>Keyword</em>. Sets additional modes that control the search dialog presentation.
-Currently available modes define how the query text that appears in the search dialog
-should be rewritten when a custom suggestion receives focus. The following mode values are accepted:
+      <dd><em>Keyword</em>. Sets additional modes that control the search presentation.
+Currently available modes define how the query text should be rewritten when a custom suggestion
+receives focus. The following mode values are accepted:
         <table>
           <tr><th>Value</th><th>Description</th></tr>
           <tr>
             <td><code>"queryRewriteFromText"</code></td>
             <td>Use the value from the {@link android.app.SearchManager#SUGGEST_COLUMN_TEXT_1}
-colum to rewrite the query text in the search dialog.</td>
+column to rewrite the query text.</td>
           </tr>
           <tr>
             <td><code>"queryRewriteFromData"</code></td>
             <td>Use the value from the
             {@link android.app.SearchManager#SUGGEST_COLUMN_INTENT_DATA} column to rewrite the
-query text in the search dialog. This should only be used when the values in
+query text. This should only be used when the values in
             {@link android.app.SearchManager#SUGGEST_COLUMN_INTENT_DATA} are suitable for user
 inspection and editing, typically HTTP URI's.</td>
           </tr>
@@ -117,7 +118,7 @@
 
       <dt><code>android:inputType</code></dt>
       <dd><em>Keyword</em>. Defines the type of input method (such as the type of soft keyboard)
-to use with the search dialog. For most searches, in which free-form text is expected, you don't 
+to use. For most searches, in which free-form text is expected, you don't 
 need this attribute. See {@link android.R.attr#inputType} for a list of suitable values for this
 attribute.</dd>
 
@@ -161,14 +162,14 @@
 selectionArgs} parameter (and then ignore the {@code selection} parameter).</dd>
 
       <dt><code>android:searchSuggestIntentAction</code></dt>
-        <dd><em>String</em>. The default Intent action to be used when a user
+        <dd><em>String</em>. The default intent action to be used when a user
         clicks on a custom search suggestion (such as {@code "android.intent.action.VIEW"}).
         If this is not overridden by the selected suggestion (via the {@link
 android.app.SearchManager#SUGGEST_COLUMN_INTENT_ACTION} column), this value is placed in the action
 field of the {@link android.content.Intent} when the user clicks a suggestion.</dd>
 
       <dt><code>android:searchSuggestIntentData</code></dt>
-        <dd><em>String</em>. The default Intent data to be used when a user
+        <dd><em>String</em>. The default intent data to be used when a user
         clicks on a custom search suggestion.
         If not overridden by the selected suggestion (via the {@link
 android.app.SearchManager#SUGGEST_COLUMN_INTENT_DATA} column), this value is
@@ -177,7 +178,7 @@
 
       <dt><code>android:searchSuggestThreshold</code></dt>
         <dd><em>Integer</em>. The minimum number of characters needed to
-        trigger a suggestion look-up. Only guarantees that the Search Manager will not query your
+        trigger a suggestion look-up. Only guarantees that the system will not query your
         content provider for anything shorter than the threshold. The default value is 0.</dd>
       </dl>
 
@@ -210,20 +211,21 @@
         supersets of queries that have returned zero results in the past. For example, if
 your content provider returned zero results for "bo", it should be requiried for "bob". If set to
 "false", supersets are ignored for a single session ("bob" does not invoke a requery). This lasts
-only for the life of the search dialog (when the search dialog is reopened, "bo" queries your
+only for the life of the search dialog or the life of the activity when using the search widget
+(when the search dialog or activity is reopened, "bo" queries your
 content provider again). The default value is false.</dd>
       </dl>
 
 
     <h4>Voice search attributes</h4>
 
-    <p>To enable voice search for your search dialog, you'll need some of the
+    <p>To enable voice search, you'll need some of the
     following {@code &lt;searchable>} attributes:</p><br/>
 
       <dl class="atn-list">
         <dt><code>android:voiceSearchMode</code></dt>
         <dd><em>Keyword</em>. (Required to provide voice search capabilities.)
-          Enables voice search for the search dialog, with a specific mode for voice search.
+          Enables voice search, with a specific mode for voice search.
           (Voice search may not be provided by the device, in which case these flags
           have no effect.) The following mode values are accepted:
           <table>
@@ -238,14 +240,14 @@
               <td><code>"launchWebSearch"</code></td>
               <td>The voice search button takes the user directly
               to a built-in voice web search activity. Most applications don't need this flag, as
-              it takes the user away from the Activity in which search was invoked.</td>
+              it takes the user away from the activity in which search was invoked.</td>
             </tr>
             <tr>
               <td><code>"launchRecognizer"</code></td>
               <td>The voice search button takes
-              the user directly to a built-in voice recording activity. This Activity
+              the user directly to a built-in voice recording activity. This activity
               prompts the user to speak, transcribes the spoken text, and forwards the resulting
-              query text to the searchable Activity, just as if the user typed it into the
+              query text to the searchable activity, just as if the user typed it into the
               search UI and clicked the search button.</td>
             </tr>
           </table>
@@ -283,9 +285,9 @@
         <dt><code>android:voiceMaxResults</code></dt>
           <dd><em>Integer</em>. Forces the maximum number of results to return,
           including the "best" result which is always provided as the {@link
-android.content.Intent#ACTION_SEARCH} Intent's primary
+android.content.Intent#ACTION_SEARCH} intent's primary
           query. Must be 1 or greater. Use {@link android.speech.RecognizerIntent#EXTRA_RESULTS} to
-get the results from the Intent.
+get the results from the intent.
           If not provided, the recognizer chooses how many results to return.</dd>
       </dl>
   </dd> <!-- end searchable element -->
@@ -311,8 +313,8 @@
         <dd><em>String</em>. (Required.) A key code from {@link
 android.view.KeyEvent} that represents the action key
         you wish to respond to (for example {@code "KEYCODE_CALL"}). This is added to the
-        {@link android.content.Intent#ACTION_SEARCH ACTION_SEARCH} Intent that is passed to your
-        searchable Activity. To examine the key code, use
+        {@link android.content.Intent#ACTION_SEARCH ACTION_SEARCH} intent that is passed to your
+        searchable activity. To examine the key code, use
         {@link android.content.Intent#getIntExtra getIntExtra(SearchManager.ACTION_KEY)}. Not all
 keys are supported for a search action, as many of them are used for typing, navigation, or system
 functions.</dd>
@@ -320,15 +322,15 @@
       <dt><code>android:queryActionMsg</code></dt>
         <dd><em>String</em>. An action message to be sent if the action key is pressed while the
 user is entering query text. This is added to the
-        {@link android.content.Intent#ACTION_SEARCH ACTION_SEARCH} Intent that the Search Manager
-        passes to your searchable Activity. To examine the string, use
+        {@link android.content.Intent#ACTION_SEARCH ACTION_SEARCH} intent that the system
+        passes to your searchable activity. To examine the string, use
         {@link android.content.Intent#getStringExtra
         getStringExtra(SearchManager.ACTION_MSG)}.</dd>
 
       <dt><code>android:suggestActionMsg</code></dt>
         <dd><em>String</em>. An action message to be sent if the action key is pressed while a
         suggestion is in focus. This is added to the
-        Intent that that the Search Manager passes to your searchable Activity (using the action
+        intent that that the system passes to your searchable activity (using the action
 you've defined for the suggestion). To examine the string,
         use {@link android.content.Intent#getStringExtra 
         getStringExtra(SearchManager.ACTION_MSG)}. This should only be used if all your
@@ -344,10 +346,10 @@
 your content provider provides its own action message.
         <p>First, you must define a column in your
 content provider for each suggestion to provide an action message, then provide the name of that
-column in this attribute. The Search Manager looks at your suggestion cursor,
+column in this attribute. The system looks at your suggestion cursor,
         using the string provided here to select your action message column, and
         then select the action message string from the Cursor. That string is added to the
-        Intent that the Search Manager passes to your searchable Activity (using the action you've
+        intent that the system passes to your searchable activity (using the action you've
 defined for suggestions). To examine the string, use {@link
 android.content.Intent#getStringExtra getStringExtra(SearchManager.ACTION_MSG)}. If the data
 does not exist for the selected suggestion, the action key is ignored.</dd>
diff --git a/docs/html/guide/topics/ui/actionbar.jd b/docs/html/guide/topics/ui/actionbar.jd
index 065f95a..d8898ae3e 100644
--- a/docs/html/guide/topics/ui/actionbar.jd
+++ b/docs/html/guide/topics/ui/actionbar.jd
@@ -323,8 +323,7 @@
 
 <p>When adding an action view for a menu item, it's important that you still allow the item to
 behave as a normal menu item when it does not appear in the Action Bar. For example, a menu item to
-perform a search should, by default, bring up the <a
-href="{@docRoot}guide/topics/search/search-dialog.html">search dialog</a>, but if the item is
+perform a search should, by default, bring up the Android search dialog, but if the item is
 placed in the Action Bar, the action view appears with a {@link android.widget.SearchView}
 widget. Figure 4 shows an example of  the {@link android.widget.SearchView} widget in an action
 view.</p>
@@ -369,9 +368,7 @@
 <p>Now, when the menu item is displayed as an action item, it's action view appears instead of
 the icon and/or title text. However, if there's not enough room in the Action Bar, the item appears
 in the overflow menu as a normal menu item and you must respond to it from the {@link
-android.app.Activity#onOptionsItemSelected onOptionsItemSelected()} callback method. (For a
-guide to providing search functionality, see the <a
-href="{@docRoot}guide/topics/search/index.html">Search</a> documentation.)</p>
+android.app.Activity#onOptionsItemSelected onOptionsItemSelected()} callback method.</p>
 
 <p>When the activity first starts, the system populates the Action Bar and overflow menu by calling
 {@link android.app.Activity#onCreateOptionsMenu onCreateOptionsMenu()}.
@@ -392,8 +389,8 @@
 }
 </pre>
 
-<p>For more information about enabling search in the Action Bar, see the <a
-href="{@docRoot}guide/topics/search/index.html">Search</a> developer guide.</p>
+<p>For more information about using the search widget, see <a
+href="{@docRoot}guide/topics/search/search-dialog.html">Creating a Search Interface</a>.</p>
 
 
 
diff --git a/docs/html/guide/topics/wireless/bluetooth.jd b/docs/html/guide/topics/wireless/bluetooth.jd
index b3c76871..ae078b9 100644
--- a/docs/html/guide/topics/wireless/bluetooth.jd
+++ b/docs/html/guide/topics/wireless/bluetooth.jd
@@ -554,7 +554,7 @@
         BluetoothServerSocket tmp = null;
         try {
             // MY_UUID is the app's UUID string, also used by the client code
-            tmp = mAdapter.listenUsingRfcommWithServiceRecord(NAME, MY_UUID);
+            tmp = mBluetoothAdapter.listenUsingRfcommWithServiceRecord(NAME, MY_UUID);
         } catch (IOException e) { }
         mmServerSocket = tmp;
     }
@@ -690,7 +690,7 @@
 
     public void run() {
         // Cancel discovery because it will slow down the connection
-        mAdapter.cancelDiscovery();
+        mBluetoothAdapter.cancelDiscovery();
 
         try {
             // Connect the device through the socket. This will block
diff --git a/docs/html/images/avd-manager.png b/docs/html/images/avd-manager.png
index 69ce972..c33d8a8 100644
--- a/docs/html/images/avd-manager.png
+++ b/docs/html/images/avd-manager.png
Binary files differ
diff --git a/docs/html/images/billing_package.png b/docs/html/images/billing_package.png
old mode 100755
new mode 100644
index ec04c2d..951e117
--- a/docs/html/images/billing_package.png
+++ b/docs/html/images/billing_package.png
Binary files differ
diff --git a/docs/html/images/developing/adt-props-isLib.png b/docs/html/images/developing/adt-props-isLib.png
index 18bdb33..49c9111 100644
--- a/docs/html/images/developing/adt-props-isLib.png
+++ b/docs/html/images/developing/adt-props-isLib.png
Binary files differ
diff --git a/docs/html/images/developing/adt-props-libRef.png b/docs/html/images/developing/adt-props-libRef.png
index e61df51..73bccbd 100644
--- a/docs/html/images/developing/adt-props-libRef.png
+++ b/docs/html/images/developing/adt-props-libRef.png
Binary files differ
diff --git a/docs/html/images/developing/intellijidea_android_ide.png b/docs/html/images/developing/intellijidea_android_ide.png
new file mode 100644
index 0000000..b73a4e9
--- /dev/null
+++ b/docs/html/images/developing/intellijidea_android_ide.png
Binary files differ
diff --git a/docs/html/images/licensing_add_library.png b/docs/html/images/licensing_add_library.png
index 90b4435..3bbe6d5 100644
--- a/docs/html/images/licensing_add_library.png
+++ b/docs/html/images/licensing_add_library.png
Binary files differ
diff --git a/docs/html/images/licensing_gapis_8.png b/docs/html/images/licensing_gapis_8.png
index 43ad262..480d989 100644
--- a/docs/html/images/licensing_gapis_8.png
+++ b/docs/html/images/licensing_gapis_8.png
Binary files differ
diff --git a/docs/html/images/licensing_package.png b/docs/html/images/licensing_package.png
index 5da5632..eb2c5cf 100644
--- a/docs/html/images/licensing_package.png
+++ b/docs/html/images/licensing_package.png
Binary files differ
diff --git a/docs/html/index.jd b/docs/html/index.jd
index f1bb59f..7fcd7b6 100644
--- a/docs/html/index.jd
+++ b/docs/html/index.jd
@@ -13,7 +13,7 @@
                             <!-- total max width is 520px -->
                                   <img src="{@docRoot}assets/images/home/GDC2011.png" alt="Android at GDC 2011" width="203px" style="padding-left:22px;padding-bottom:28px;padding-top:22px;"/>
                                   <div id="announcement" style="width:275px">
-    <p>Android will be at the <a href="http://www.gdconf.com/">2011 Game Developers Conference</a> in San Francisco, from March 1st to 4th. We're looking forward to seeing you there!</p>
+    <p>Thanks to everyone who visited us at the <a href="http://www.gdconf.com/">Game Developers Conference</a> in San Francisco. We're looking forward to seeing your games running on Android!</p>
     <p><a href="http://android-developers.blogspot.com/2011/02/heading-for-gdc.html">Learn more &raquo;</a></p>
                                 </div> <!-- end annoucement -->
                             </div> <!-- end annoucement-block -->
diff --git a/docs/html/resources/dashboard/platform-versions.jd b/docs/html/resources/dashboard/platform-versions.jd
index d745cea..73d7fc1 100644
--- a/docs/html/resources/dashboard/platform-versions.jd
+++ b/docs/html/resources/dashboard/platform-versions.jd
@@ -52,7 +52,7 @@
 <div class="dashboard-panel">
 
 <img alt="" height="250" width="460"
-src="http://chart.apis.google.com/chart?&cht=p&chs=460x250&chd=t:3.9,6.3,31.4,57.6,0.8&chl=Android%201.5|Android%201.6|Android%202.1|Android%202.2|Android%202.3&chco=c4df9b,6fad0c" />
+src="http://chart.apis.google.com/chart?&cht=p&chs=460x250&chd=t:3.0,4.8,29.0,61.3,0.7,1.0,0.2&chl=Android%201.5|Android%201.6|Android%202.1|Android%202.2|Android%202.3|Android%202.3.3|Android%203.0&chco=c4df9b,6fad0c" />
 
 <table>
 <tr>
@@ -60,14 +60,16 @@
   <th>API Level</th>
   <th>Distribution</th>
 </tr>
-<tr><td>Android 1.5</td><td>3</td><td>3.9%</td></tr> 
-<tr><td>Android 1.6</td><td>4</td><td>6.3%</td></tr> 
-<tr><td>Android 2.1</td><td>7</td><td>31.4%</td></tr> 
-<tr><td>Android 2.2</td><td>8</td><td>57.6%</td></tr> 
-<tr><td>Android 2.3</td><td>9</td><td>0.8%</td></tr> 
+<tr><td>Android 1.5</td><td>3</td><td>3.0%</td></tr> 
+<tr><td>Android 1.6</td><td>4</td><td>4.8%</td></tr> 
+<tr><td>Android 2.1</td><td>7</td><td>29.0%</td></tr> 
+<tr><td>Android 2.2</td><td>8</td><td>61.3%</td></tr> 
+<tr><td>Android 2.3</td><td>9</td><td>0.7%</td></tr> 
+<tr><td>Android 2.3.3</td><td>10</td><td>1.0%</td></tr> 
+<tr><td>Android 3.0</td><td>11</td><td>0.2%</td></tr> 
 </table>
 
-<p><em>Data collected during two weeks ending on February 2, 2011</em></p>
+<p><em>Data collected during two weeks ending on March 15, 2011</em></p>
 <!--
 <p style="font-size:.9em">* <em>Other: 0.1% of devices running obsolete versions</em></p>
 -->
@@ -96,9 +98,9 @@
 <div class="dashboard-panel">
 
 <img alt="" height="250" width="660" style="padding:5px;background:#fff"
-src="http://chart.apis.google.com/chart?&cht=lc&chs=660x250&chxt=x,x,y,r&chxr=0,0,12|1,0,12|2,0,100|3,0,100&chxl=0%3A%7C08/01%7C08/15%7C09/01%7C09/15%7C10/01%7C10/15%7C11/01%7C11/15%7C12/01%7C12/15%7C01/01%7C01/15%7C02/01%7C1%3A%7C2010%7C%7C%7C%7C%7C%7C%7C%7C%7C%7C2011%7C%7C2011%7C2%3A%7C0%25%7C25%25%7C50%25%7C75%25%7C100%25%7C3%3A%7C0%25%7C25%25%7C50%25%7C75%25%7C100%25&chxp=0,0,1,2,3,4,5,6,7,8,9,10,11,12&chxtc=0,5&chd=t:99.8,99.7,99.8,99.9,99.9,99.9,100.0,99.9,99.8,99.7,99.6,99.4,99.1|84.3,86.5,87.9,89.2,90.2,91.1,92.0,92.7,93.4,94.1,94.8,95.1,95.2|64.0,68.1,70.3,72.1,73.8,75.3,77.4,79.6,82.2,84.4,86.8,87.8,88.9|4.3,11.3,27.8,32.1,33.4,34.5,37.1,40.5,44.3,47.7,51.4,53.8,57.5&chm=tAndroid 1.5,7caa36,0,0,15,,t::-5|b,c3df9b,0,1,0|tAndroid 1.6,5b831d,1,0,15,,t::-5|b,aadb5e,1,2,0|tAndroid 2.1,38540b,2,0,15,,t::-5|b,91da1e,2,3,0|tAndroid 2.2,131d02,3,1,15,,t::-5|B,6fad0c,3,4,0&chg=7,25&chdl=Android 1.5|Android 1.6|Android 2.1|Android 2.2&chco=add274,94d134,73ad18,507d08" />
+src="http://chart.apis.google.com/chart?&cht=lc&chs=660x250&chxt=x,x,y,r&chxr=0,0,12|1,0,12|2,0,100|3,0,100&chxl=0%3A%7C09/15%7C10/01%7C10/15%7C11/01%7C11/15%7C12/01%7C12/15%7C01/01%7C01/15%7C02/01%7C02/15%7C03/01%7C03/15%7C1%3A%7C2010%7C%7C%7C%7C%7C%7C%7C2011%7C%7C%7C%7C%7C2011%7C2%3A%7C0%25%7C25%25%7C50%25%7C75%25%7C100%25%7C3%3A%7C0%25%7C25%25%7C50%25%7C75%25%7C100%25&chxp=0,0,1,2,3,4,5,6,7,8,9,10,11,12&chxtc=0,5&chd=t:99.9,99.9,99.9,100.0,99.9,99.8,99.7,100.0,99.9,99.9,99.9,100.0,99.8|89.2,90.2,91.1,92.0,92.7,93.4,94.1,95.2,95.6,96.0,96.3,96.7,96.8|72.1,73.8,75.3,77.4,79.6,82.2,84.4,87.2,88.3,89.7,90.5,91.5,92.0|32.1,33.4,34.5,37.1,40.5,44.3,47.7,51.8,54.3,58.3,59.7,61.5,63.0|0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.4,0.6,0.7,0.8,1.1,1.7|0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.0&chm=tAndroid 1.5,7caa36,0,0,15,,t::-5|b,c3df9b,0,1,0|tAndroid 1.6,689326,1,0,15,,t::-5|b,b4db77,1,2,0|tAndroid 2.1,547a19,2,0,15,,t::-5|b,a5db51,2,3,0|tAndroid 2.2,3f5e0e,3,0,15,,t::-5|b,96dd28,3,4,0|b,83c916,4,5,0|B,6fad0c,5,6,0&chg=7,25&chdl=Android 1.5|Android 1.6|Android 2.1|Android 2.2|Android 2.3|Android 2.3.3&chco=add274,9dd14f,8ece2a,7ab61c,659b11,507d08" />
 
-<p><em>Last historical dataset collected during two weeks ending on February 2, 2011</em></p>
+<p><em>Last historical dataset collected during two weeks ending on March 15, 2011</em></p>
 
 
 </div><!-- end dashboard-panel -->
diff --git a/docs/html/resources/faq/commontasks.jd b/docs/html/resources/faq/commontasks.jd
index a5f5177..b211db0 100644
--- a/docs/html/resources/faq/commontasks.jd
+++ b/docs/html/resources/faq/commontasks.jd
@@ -223,7 +223,7 @@
 // Listen for results.
 protected void onActivityResult(int requestCode, int resultCode, Intent data){
     // See which child activity is calling us back.
-    switch (resultCode) {
+    switch (requestCode) {
         case CHOOSE_FIGHTER:
             // This is the standard resultCode that is sent back if the
             // activity crashed or didn't doesn't supply an explicit result.
@@ -257,7 +257,7 @@
             stats.putString("height","6\'2\""); 
             stats.putString("weight", "190 lbs");
             stats.putString("reach", "73\"");
-            setResult(RESULT_OK, "Washington", Bundle);
+            setResult(RESULT_OK, "Washington", stats);
             finish();
         }
     };
@@ -289,7 +289,12 @@
 will have a title bar visible to the user until <code>onCreate</code> runs.</p>
 <p>(Note that this can be applied to either the <code>&lt;application&gt;</code>
 tag or to individual <code>&lt;activity&gt;</code> tags.)</p>
-<a name="localhostalias" id="localhostalias"></a><h2>Referring to localhost from the emulated environment</h2>
+<p class="caution"><strong>Caution:</strong> This theme will also hide the Action Bar on Android
+3.0 and higher. If you want to keep the Action Bar, but hide the title bar, see how you can <a
+href="{@docRoot}guide/topics/ui/themes.html#SelectATheme">select a theme based on platform
+version</a>.</p>
+<a name="localhostalias" id="localhostalias"></a><h2>Referring to localhost from the emulated
+environment</h2>
 <p>
 If you need to refer to your host computer's <em>localhost</em>, such as when you 
 want the emulator client to contact a server running on the same host, use the alias 
diff --git a/docs/html/resources/tutorials/hello-world.jd b/docs/html/resources/tutorials/hello-world.jd
index 020c738..b11770f 100644
--- a/docs/html/resources/tutorials/hello-world.jd
+++ b/docs/html/resources/tutorials/hello-world.jd
@@ -433,7 +433,7 @@
 </pre>
 </li>
 
-<li>Now open and modify your <code>HelloAndroid</code> class use the
+<li>Now open and modify your <code>HelloAndroid</code> class and use the
 XML layout. Edit the file to look like this:
 <pre>
 package com.example.helloandroid;
diff --git a/docs/html/sdk/android-3.0.jd b/docs/html/sdk/android-3.0.jd
index 6c087bb..f88c3a6 100644
--- a/docs/html/sdk/android-3.0.jd
+++ b/docs/html/sdk/android-3.0.jd
@@ -556,11 +556,10 @@
 menu.</p></li>
     
     <li>{@link android.widget.SearchView}
-    <p>Provides a search box that works in conjunction with the Search Manager (in the same manner
-as the traditional <a href="{@docRoot}guide/topics/search/search-dialog.html">search dialog</a>). It
-can also display recent query suggestions or custom suggestions as configured by the search
-provider. This widget is particularly useful for offering search in the <a
-href="{@docRoot}guide/topics/ui/actionbar.html">Action Bar</a>.</p></li>
+    <p>Provides a search box that you can configure to deliver search queries to a specified
+activity and display search suggestions (in the same manner as the traditional search dialog). This
+widget is particularly useful for offering a search widget in the Action Bar. For more information,
+see <a href="{@docRoot}guide/topics/search/search-dialog.html">Creating a Search Interface</p>.</li>
     
     <li>{@link android.widget.StackView}
     <p>A view that displays its children in a 3D stack and allows users to swipe through
diff --git a/docs/html/sdk/eclipse-adt.jd b/docs/html/sdk/eclipse-adt.jd
index 3a7b39f..ece9d4a 100644
--- a/docs/html/sdk/eclipse-adt.jd
+++ b/docs/html/sdk/eclipse-adt.jd
@@ -1,8 +1,8 @@
 page.title=ADT Plugin for Eclipse
-adt.zip.version=10.0.0
-adt.zip.download=ADT-10.0.0.zip
-adt.zip.bytes=4243777
-adt.zip.checksum=bf88bff62bc45c3b6d062e2beed67765
+adt.zip.version=10.0.1
+adt.zip.download=ADT-10.0.1.zip
+adt.zip.bytes=5096182
+adt.zip.checksum=e26a77db08377bdd2e62edeb9a3e3701
 
 @jd:body
 
@@ -33,7 +33,7 @@
 <p>ADT extends the capabilities of Eclipse to let you quickly set up new Android
 projects, create an application UI, add components based on the Android
 Framework API, debug your applications using the Android SDK tools, and even
-export signed (or unsigned) APKs in order to distribute your application.</p>
+export signed (or unsigned) {@code .apk} files in order to distribute your application.</p>
 
 <p>Developing in Eclipse with ADT is highly recommended and is the fastest way
 to get started. With the guided project setup it provides, as well as tools
@@ -100,6 +100,36 @@
   <a href="#" onclick="return toggleDiv(this)">
         <img src="{@docRoot}assets/images/triangle-opened.png" class="toggle-img" height="9px"
 width="9px" />
+ADT 10.0.1</a> <em>(March 2011)</em>
+  <div class="toggleme">
+
+<dl>
+
+<dt>Dependencies:</dt>
+
+<dd>ADT 10.0.1 is designed for use with SDK Tools r10. If you haven't
+already installed SDK Tools r10 into your SDK, use the Android SDK and AVD Manager to do
+so.</dd>
+
+<dt>General notes:</dt>
+<dd>
+  <ul>
+    <li>Temporary work-around to resolve the rare cases in which the layout editor will
+not open.</li>
+    <li>Fix issue in which ADT 10.0.0 would install on Eclipse 3.4 and lower, even though ADT
+requires Eclipse 3.5 or higher (as of 10.0.0).</li>
+  </ul>
+</dd>
+</dl>
+</div>
+</div>
+
+
+
+<div class="toggleable closed">
+  <a href="#" onclick="return toggleDiv(this)">
+        <img src="{@docRoot}assets/images/triangle-closed.png" class="toggle-img" height="9px"
+width="9px" />
 ADT 10.0.0</a> <em>(February 2011)</em>
   <div class="toggleme">
 
@@ -594,13 +624,14 @@
 
 <p>ADT is a plugin for the Eclipse IDE. Before you can install or use ADT,
 you must have a compatible version of Eclipse installed on your development
-computer. </p>
+computer. Check the <a
+href="requirements.html">System Requirements</a> document for
+a list of Eclipse versions that are compatible with the Android SDK.</li></p>
 
 <ul>
 <li>If Eclipse is already installed on your computer, make sure that it is
-a version that is compatible with ADT and the Android SDK. Check the <a
-href="requirements.html">System Requirements</a> document for
-a list of Eclipse versions that are compatible with the Android SDK.</li>
+a version that is compatible with ADT and the Android SDK. 
+
 <li>If you need to install or update Eclipse, you can download it from this
 location:
 
@@ -608,7 +639,7 @@
 "http://www.eclipse.org/downloads/">http://www.eclipse.org/downloads/</a>
 </p>
 
-<p>For Eclipse 3.5 or newer, the "Eclipse Classic" version is recommended. Otherwise, a Java or RCP
+<p>The "Eclipse Classic" version is recommended. Otherwise, a Java or RCP
 version of Eclipse is recommended.</p></li>
 </ul>
 
@@ -624,19 +655,15 @@
 
 <h3 id="downloading">Downloading the ADT Plugin</h3>
 
-<p>Use Update Manager feature of your Eclipse installation to install the latest
+<p>Use the Update Manager feature of your Eclipse installation to install the latest
 revision of ADT on your development computer.<p>
 
 <p>Assuming that you have a compatible version of the Eclipse IDE installed, as
 described in <a href="#preparing">Preparing for Installation</a>, above, follow
 these steps to download the ADT plugin and install it in your Eclipse
-environment. </p>
+environment.</p>
 
-<table style="font-size:100%">
-<tr><th>Eclipse 3.5 (Galileo) and 3.6 (Helios)</th><th>Eclipse 3.4 (Ganymede)</th></tr>
-<tr>
-<td width="45%">
-<!-- 3.5+ steps -->
+
 <ol>
     <li>Start Eclipse, then select <strong>Help</strong> &gt; <strong>Install New
 Software...</strong>.</li>
@@ -655,35 +682,6 @@
     <li>When the installation completes, restart Eclipse. </li>
 </ol>
 
-</td>
-<td width="50%">
-
-<!-- 3.4 steps -->
-<ol>
-    <li>Start Eclipse, then select <strong>Help</strong> &gt; <strong>Software Updates...</strong>.
-In the dialog that appears, click the <strong>Available Software</strong> tab.</li>
-    <li>Click <strong>Add Site</strong>.</li>
-    <li>In the Add Site dialog that appears, enter this URL in the "Location" field:
-        <pre>https://dl-ssl.google.com/android/eclipse/</pre>
-        <p>Note: If you have trouble acquiring the plugin, you can try
-           using "http" in the URL, instead of "https" (https is preferred for
-           security reasons).</p>
-        <p>Click <strong>OK</strong>.</p>
-    </li>
-    <li>Back in the Available Software view, you should see the plugin listed by the URL,
-       with "Developer Tools" nested within it. Select the checkbox next to Developer Tools,
-        which will automatically select the nested tools. Then click
-        <strong>Install</strong></li>
-    <li>On the subsequent Install window, all of the included tools
-        should be checked. Click <strong>Next</strong>. </li>
-    <li>Read and accept the license agreements, then click <strong>Finish</strong>.</li>
-    <li>When the installation completes, restart Eclipse. </li>
-
-</ol>
-</td>
-</tr>
-</table>
-
 <h3 id="configuring">Configuring the ADT Plugin</h3>
 
 <p>Once you've successfully downloaded ADT as described above, the next step
@@ -807,11 +805,6 @@
 <p>Follow the steps below to check whether an update is available and, if so,
 to install it. </p>
 
-<table style="font-size:100%">
-<tr><th>Eclipse 3.5 (Galileo) and 3.6 (Helios)</th><th>Eclipse 3.4 (Ganymede)</th></tr>
-<tr>
-<td>
-<!-- 3.5+ steps -->
 <ol>
     <li>Select <strong>Help</strong> &gt; <strong>Check for Updates</strong>.
       <p>If there are no updates available, a dialog will say so and you're done.</p></li>
@@ -823,25 +816,6 @@
       Android Development Tools.</li>
     <li>Restart Eclipse.</li>
 </ol>
-</td>
-
-<td width="50%">
-<!-- 3.4 steps -->
-<ol>
-    <li>Select <strong>Help</strong> &gt; <strong>Software Updates</strong>.</li>
-    <li>Select the <strong>Available Software</strong> tab.</li>
-    <li>If there are updates available, select Android DDMS, Android Development Tools,
-      and Android Hierarchy Viewer, then click <strong>Update</strong>.</li>
-    <li>In the resulting Available Updates dialog, ensure that each of the listed tools
-      are selected, then click <strong>Next</strong>.</li>
-    <li>Read and accept the license agreement and then click <strong>Finish</strong>.
-      This will download and install the latest version of Android DDMS and
-      Android Development Tools.</li>
-    <li>Restart Eclipse.</li>
-</ol>
-</td>
-</tr>
-</table>
 
 
 <p>If you encounter problems during the update, remove the existing ADT plugin from Eclipse, then
diff --git a/docs/html/sdk/installing.jd b/docs/html/sdk/installing.jd
index b0fd761..a1080c2 100644
--- a/docs/html/sdk/installing.jd
+++ b/docs/html/sdk/installing.jd
@@ -96,13 +96,14 @@
 <p>If you will be developing in Eclipse with the Android Development
 Tools (ADT) Plugin&mdash;the recommended path if you are new to
 Android&mdash;make sure that you have a suitable version of Eclipse
-installed on your computer (3.4 or newer is recommended). If you need
-to install Eclipse, you can download it from this location: </p>
+installed on your computer as described in the
+<a href="requirements.html">System Requirements</a> document.
+If you need to install Eclipse, you can download it from this location: </p>
 
 <p style="margin-left:2em;"><a href=
 "http://www.eclipse.org/downloads/">http://www.eclipse.org/downloads/</a></p>
 
-<p>For Eclipse 3.5 or newer, the "Eclipse Classic" version is recommended. Otherwise, a Java or
+<p>The "Eclipse Classic" version is recommended. Otherwise, a Java or
 RCP version of Eclipse is recommended.</p>
 
 
diff --git a/docs/html/sdk/oem-usb.jd b/docs/html/sdk/oem-usb.jd
index e64c8d2..882a433 100644
--- a/docs/html/sdk/oem-usb.jd
+++ b/docs/html/sdk/oem-usb.jd
@@ -33,14 +33,17 @@
     <th>OEM</th>
     <th>Driver URL</th></tr>
 <tr><td>Acer</td>	<td><a
-href="http://www.acer.com/worldwide/support/mobile.html">http://www.acer.com/worldwide/support/
-mobile.html</a>
+href="http://www.acer.com/worldwide/support/mobile.html">http://www.acer.com/worldwide/support/mobile.html</a>
     </td></tr>
-
-<tr><td>Dell</td>	<td>
+  <tr>
+    <td>Asus</td>
+    <td><a href="http://support.asus.com/download/">http://support.asus.com/download/</a></td>
+  </tr>
+  <tr><td>
+       Dell
+    </td>	<td>
       <a
-href="http://support.dell.com/support/downloads/index.aspx?c=us&cs=19&l=en&s=dhs&~ck=anavml">http://
-support.dell.com/support/downloads/index.aspx?c=us&cs=19&l=en&s=dhs&~ck=anavml</a>  </td></tr>
+href="http://support.dell.com/support/downloads/index.aspx?c=us&cs=19&l=en&s=dhs&~ck=anavml">http://support.dell.com/support/downloads/index.aspx?c=us&cs=19&l=en&s=dhs&~ck=anavml</a>  </td></tr>
 
 <tr><td>Foxconn</td>	<td><a
 href="http://drivers.cmcs.com.tw/">http://drivers.cmcs.com.tw/</a></td>
@@ -56,17 +59,14 @@
   <tr><td>
        Garmin-Asus
     </td>	<td><a
-href="https://www.garminasus.com/en_US/support/pcsync/">https://www.garminasus.com/en_US/support/
-pcsync/</a></td>
+href="https://www.garminasus.com/en_US/support/pcsync/">https://www.garminasus.com/en_US/support/pcsync/</a></td>
 </tr><tr><td>HTC</td>	<td><a href="http://www.htc.com">http://www.htc.com </a> <br>Click on the
 support tab to select your products/device.  Different regions will have different links.</td>
 </tr>
 <tr><td>Huawei</td>	<td><a
-href="http://www.huaweidevice.com/worldwide/downloadCenter.do?method=list&flay=software&directoryId=20&treeId=0">http://www.huaweidevice.com/worldwide/downloadCenter.do?method=list&flay=software&
-directoryId=20&treeId=0</a></td>
+href="http://www.huaweidevice.com/worldwide/downloadCenter.do?method=list&flay=software&directoryId=20&treeId=0">http://www.huaweidevice.com/worldwide/downloadCenter.do?method=list&flay=software&directoryId=20&treeId=0</a></td>
 </tr><tr><td>KT Tech</td>	<td><a
-href="http://www.kttech.co.kr/cscenter/download05.asp">http://www.kttech.co.kr/cscenter/download05.
-asp</a> for EV-S100(Take)</td>
+href="http://www.kttech.co.kr/cscenter/download05.asp">http://www.kttech.co.kr/cscenter/download05.asp</a> for EV-S100(Take)</td>
 </tr>
   <tr>
     <td>
@@ -76,26 +76,19 @@
     </td>
   </tr>
   <tr><td>LGE</td>	<td><a
-href="http://www.lg.com/us/mobile-phones/mobile-support/mobile-lg-mobile-phone-support.jsp">http://
-www.lg.com/us/mobile-phones/mobile-support/mobile-lg-mobile-phone-support.jsp</a></td>
+href="http://www.lg.com/us/mobile-phones/mobile-support/mobile-lg-mobile-phone-support.jsp">http://www.lg.com/us/mobile-phones/mobile-support/mobile-lg-mobile-phone-support.jsp</a></td>
 </tr><tr><td>Motorola</td>	<td><a
-href="http://developer.motorola.com/docstools/USB_Drivers/">http://developer.motorola.com/docstools/
-USB_Drivers/</a></td>
+href="http://developer.motorola.com/docstools/USB_Drivers/">http://developer.motorola.com/docstools/USB_Drivers/</a></td>
 </tr><tr><td>Pantech</td>	<td><a
-href="http://www.isky.co.kr/cs/software/software.sky?fromUrl=index">http://www.isky.co.kr/cs/
-software/software.sky?fromUrl=index</a></td>
+href="http://www.isky.co.kr/cs/software/software.sky?fromUrl=index">http://www.isky.co.kr/cs/software/software.sky?fromUrl=index</a></td>
 </tr><tr><td>Samsung</td>	<td><a
-href="http://www.samsung.com/us/support/downloads">http://www.samsung.com/us/support/downloads</a></
-td>
+href="http://www.samsung.com/us/support/downloads">http://www.samsung.com/us/support/downloads</a></td>
 </tr><tr><td>Sharp</td>	<td><a
 href="http://k-tai.sharp.co.jp/support/">http://k-tai.sharp.co.jp/support/</a></td>
 </tr><tr><td>SK Telesys</td>	<td><a
-href="http://www.sk-w.com/service/wDownload/wDownload.jsp">http://www.sk-w.com/service/wDownload/
-wDownload.jsp</a></td></tr><tr>
+href="http://www.sk-w.com/service/wDownload/wDownload.jsp">http://www.sk-w.com/service/wDownload/wDownload.jsp</a></td></tr><tr>
 <td>Sony Ericsson</td>	<td><a
-href="http://developer.sonyericsson.com/wportal/devworld/search-downloads/android">http://developer.
-sonyericsson.com/wportal/devworld/search-downloads/android</a></td></tr><tr>
+href="http://developer.sonyericsson.com/wportal/devworld/search-downloads/android">http://developer.sonyericsson.com/wportal/devworld/search-downloads/android</a></td></tr><tr>
 <td>ZTE</td>	<td><a
-href="http://www.zte.com.cn/cn/products/mobile/services_support/index.jsp">http://www.zte.com.cn/cn/
-products/mobile/services_support/index.jsp</a></td></tr>
+href="http://www.zte.com.cn/cn/products/mobile/services_support/index.jsp">http://www.zte.com.cn/cn/products/mobile/services_support/index.jsp</a></td></tr>
 </table>
diff --git a/docs/html/sdk/preview/features.jd b/docs/html/sdk/preview/features.jd
index cd0dea1..d7ecc47 100644
--- a/docs/html/sdk/preview/features.jd
+++ b/docs/html/sdk/preview/features.jd
@@ -1,186 +1,8 @@
-page.title=Introduction to Honeycomb
 @jd:body
 
-<p>Welcome to the Honeycomb preview SDK. Honeycomb is the next major release of the Android
-platform and is optimized for tablet devices. This document provides an introduction to the new
-platform features and APIs available in Honeycomb.</p>
+<script type="text/javascript">
+  document.location=toRoot+"sdk/android-3.0.html"
+</script>
 
-
-<h2>Fragments</h2>
-
-<div class="figure" style="width:400px">
-  <img src="{@docRoot}images/preview_hc/fragments_layout.png" alt="" />
-  <p class="img-caption"><strong>Fragment Layout.</strong> An activity with two
-fragments: one with a list view, on the left, and one that displays selected content on the
-right. This demo is available in the samples package.</p>
-</div>
-
-
-<p>A new framework component that allows you to separate distinct elements of an activity into
-self-contained modules that define their own UI and lifecycle&mdash;defining what may be
-considered "sub-activities".</p>
-<ul>
-  <li>Multiple fragments can be combined in a single activity to build a multi-pane UI in which
-each pane manages its own lifecycle and user inputs</li>
-  <li>Fragments are self-contained and can be reused in multiple activities</li>
-  <li>Fragments can be added, removed, replaced and animated inside the activity</li>
-  <li>Fragment can be added to a back stack managed by the activity, preserving the state of
-fragments as they are changed and allowing the user to navigate backward through the different
-states</li>
-  <li>By <a
-href="{@docRoot}guide/topics/resources/providing-resources.html#AlternativeResources">providing
-alternative resources</a>, you can mix and match fragments, based
-on the screen size and orientation</li>
-  <li>Fragments have direct access to their container activity and can contribute items to the
-activity's Options Menu</li>
-</ul>
-
-<p>For more information, see the <a
-href="{@docRoot}guide/topics/fragments/index.html">Fragments</a> developer guide.</p>
-
-
-<h2>Action Bar</h2>
-
-<p>A replacement for the traditional title bar, which provides users quick access to global
-actions and different navigation modes.</p>
-<ul>
-  <li>Provides quick access to items from the Options Menu ("action items") and interactive
-widgets ("action views")</li>
-  <li>Includes the application logo in the left corner, which can perform actions when tapped
-and can be replaced with a custom logo</li>
-  <li>Provides breadcumbs for navigating backward through fragments</li>
-  <li>Offers built in navigation modes, including tabs and a drop-down list</li>
-  <li>Can be customized with themes and custom backgrounds</li>
-  <li>And more</li>
-</ul>
-
-<img src="{@docRoot}images/preview_hc/actionbar.png" alt="" />
-<p class="img-caption"><strong>Action Bar.</strong> An action bar with a custom logo,
-tabs, and Options Menu. This demo is available in the samples package.</p>
-
-<p>For more information, see the <a
-href="{@docRoot}guide/topics/ui/actionbar.html">Action Bar</a> developer guide.</p>
-
-
-<h2>System Clipboard</h2>
-
-<p>Applications can copy and paste data (beyond mere text) to and from the system-wide
-clipboard.</p>
-
-<ul>
-  <li>Clipped data can be plain text, a URI, or an intent</li>
-  <li>The new {@link android.content.ClipData} class represents a complex data type for the
-clipboard</li>
-  <li>The new {@link android.content.ClipboardManager} class allows apps to add {@link
-android.content.ClipData} to the clipboard (copy) and read {@link
-android.content.ClipData} from the clipboard (paste)</li>
-  <li>The {@link android.content.ContentProvider} class has been extended to generate byte
-streams based on data types added to the clipboard and point to data hosted in a
-content provider</li>
-</ul>
-
-<p>See {@link android.content.ClipData} and {@link android.content.ClipboardManager}
-for more information. You can also see an example implementation of copy/paste in an updated
-version of the NotePad application (available in the samples package).</p>
-
-
-<h2>Drag and Drop</h2>
-
-<p>New APIs to perform drag and drop operations, leveraging the system clipboard APIs to
-transport data.</p>
-
-<ul>
-  <li>Any {@link android.view.View} can be used for a drag and drop event and a thumbnail of that
-view is generated and used during the drag</li>
-  <li>{@link android.view.ViewGroup}s that can receive the object are notified during hover and drop
-events</li>
-  <li>The new {@link android.view.DragEvent} class describes a drag event relating to a view,
-including the item's current coordinates, the type of action (whether the drag has entered the
-view, exited the view, started, dropped, etc.), and provides access to the {@link
-android.content.ClipData} being carried</li>
-  <li>The new {@link android.view.View.OnDragListener} interface defines a callback that views
-can register in order to be notified of drag events being dispatched to the view; view's can
-register a drag listener with {@link android.view.View#setOnDragListener setOnDragListener()}</li>
-</ul>
-
-<p>See {@link android.view.DragEvent} and {@link android.view.View.OnDragListener} for more
-information.</p>
-
-
-<h2>New Animations</h2>
-
-<p>An all new animation framework.</p>
-
-<ul>
-  <li>A flexible animation system that allows you to animate the properties of any object (View,
-Drawable, Fragment, Object, anything)</li>
-</ul>
-
-<p>See the {@link android.animation} package.</p>
-
-
-<h2>Extended App Widgets</h2>
-
-<p>App widgets can now be more interactive and accept finger gestures.</p>
-
-<ul>
-  <li>The complete list of supported widgets for an app widget is now: {@link
-android.widget.AnalogClock}, {@link android.widget.Button}, {@link android.widget.Chronometer},
-{@link android.widget.ImageButton}, {@link android.widget.ImageView}, {@link
-android.widget.ProgressBar}, {@link android.widget.TextView}, {@link
-android.widget.ViewFlipper}, {@link android.widget.AdapterViewFlipper}, {@link
-android.widget.StackView}, {@link android.widget.ListView}, and {@link
-android.widget.GridView}.</li>
-</ul>
-
-
-<h2>Extended Status Bar Notifications</h2>
-
-<p>The {@link android.app.Notification} class has been extended to support more content-rich
-status bar notifications when on xlarge screens.</p>
-
-<ul>
-  <li>New {@link android.app.Notification.Builder} class helps you easily create new {@link
-android.app.Notification} objects</li>
-  <li>Support for a title in the status bar ticker (in addition to the normal ticker text)</li>
-  <li>Support for a large "sender" icon in the notification&mdash;a second icon intended for
-social applications to show the contact photo of the person who is the source of the
-notification</li>
-  <li>Support for custom layouts in the status bar ticker</li>
-  <li>Support for buttons in the expanded notification that deliver custom intents
-(such as to control ongoing music in the background)</li>
-</ul>
-
-
-<h2>Plus Android 2.3</h2>
-
-<p>Honeycomb includes all platform changes introduced for Android 2.3.</p>
-
-<p>To take full advantage of Honeycomb, you should also be aware of the new features
-and APIs introduced for Android 2.3. To learn more, read the <a
-href="{@docRoot}sdk/android-2.3.html">Android 2.3 release notes</a>.</p>
-
-<!--
-<div class="special">
-<p>To set up your preview SDK and start developing apps for Honeycomb, see the <a
-href="{@docRoot}sdk/preview/installing.html">Getting Started</a> guide.</p>
-</div>
--->
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+<p>You should have already been redirected by your browser. Please go to the
+<a href="{@docRoot}sdk/android-3.0.html">Android 3.0 Platform</a>.</p>
\ No newline at end of file
diff --git a/docs/html/sdk/preview/index.jd b/docs/html/sdk/preview/index.jd
index edfa02b..ed8f7e0 100644
--- a/docs/html/sdk/preview/index.jd
+++ b/docs/html/sdk/preview/index.jd
@@ -1,183 +1,2 @@
-page.title=Android 3.0 Preview SDK
+sdk.redirect=true
 @jd:body
-
-<p>Android 3.0 is the next major release of the Android platform and is optimized for tablet
-devices. We're offering a Preview SDK so you can get a head-start developing
-applications for it or simply optimize your existing application for upcoming
-tablets.</p>
-
-
-<h3>What is the Preview SDK?</h3>
-
-<p>The Android 3.0 Preview SDK is an early look at the upcoming version of Android 3.0, for
-developers only. </p>
-
-<p>The Preview SDK includes:</p>
-<ul>
-  <li>An early Android 3.0 system image for use in the Android emulator</li>
-  <li>An Android 3.0 library with non-final APIs</li>
-  <li>A new WXGA emulator skin for an extra large Android Virtual Device</li>
-  <li>New documentation for Android 3.0, including a complete API reference, new developer guides,
-and an API differences report between Android 3.0 and 2.3.</li>
-</ul>
-
-<div class="note">
-<p><strong>Be aware that:</strong></p>
-<ul>
-  <li>The APIs in the Preview SDK are <strong>not final</strong>. Some APIs may change in behavior
-or availability when the final SDK is made available.</li>
-  <li>You <strong>cannot</strong> publish an application that's built against the Preview
-SDK&mdash;you can only run an application built against the Preview SDK on the Android
-emulator.</li>
-  <li>The documentation on <a href="http://developer.android.com">developer.android.com</a>
-does <strong>not</strong> include the Android 3.0 documentation&mdash;to read the API reference and
-developer guides for Android 3.0, you must install the Android 3.0 Preview documentation from
-the AVD and SDK Manager.</li>
-</ul>
-</div>
-
-
-<p><b>About emulator performance</b></p>
-
-<p>Because the Android emulator must simulate the ARM instruction set architecture on your
-computer and the WXGA screen is significantly larger than what the emulator
-normally handles, emulator performance is much slower than usual. </p>
-
-<p>In particular, initializing the emulator can be slow and can take several
-minutes, depending on your hardware. When the emulator is booting there is
-limited user feedback, so please be patient and continue waiting until you see
-the home screen appear. </p>
-
-<p>We're working hard to resolve the performance issues in the emulator and it will improve in
-future releases. In the meantime, we wanted to give developers access to new APIs and an basic test
-environment as early as possible. </p>
-
-<p>Keeping in mind that performance on the emulator does not reflect the speed or performance of
-apps on actual devices running Android 3.0, developing and testing on the emulator is still an
-important tool in evaluating your application's appearance and functionality on the new platform. 
-</p>
-
-
-
-
-
-<h3>What can I do with the preview?</h3>
-
-<p>The Preview SDK is intended for testing existing applications on the new platform and
-developing new applications with new Android 3.0 APIs.</p>
-
-<p>If you have an existing Android application, you don't <em>have to</em> do anything. Android
-applications are always forward-compatible. If your application is a good citizen of the Android
-APIs, your app should work fine on devices running Android 3.0 without any additional work. However,
-in order to ensure proper performance and provide users a better experience when running your
-application on an Android 3.0 tablet, we recommend that you perform the following:</p>
-
-<ol>
-  <li><b>Test your application on Android 3.0</b>
-    <p>Simply install the Android 3.0 preview in your Android SDK, create an AVD using the
-Android 3.0 system image, install your application, and run some tests.</p>
-    <p>As mentioned above, your application should perform as expected. You might, however,
-discover that your activity layouts are less than ideal on a large screen or some other aspects
-of your application don't behave the way you expect.</p>
-  </li>
-  <li><b>Inherit the new "Holographic" theme</b>
-    <p>Android 3.0 offers an updated set of UI widgets that are redesigned for use on larger screens
-such as tablets and incorporate the new holographic theme. Your existing application can inherit
-the new design simply by setting the <a
-href="{@docRoot}guide/topics/manifest/uses-sdk-element.html">{@code &lt;uses-sdk&gt;}</a>
-element's {@code android:targetSdkVersion} attribute to {@code "Honeycomb"}.</p>
-    <p>If you do not update the {@code android:targetSdkVersion} attribute and the {@code
-android:minSdkVersion} is set to "9" or lower, then your application uses the widget designs
-from Android 2.3 and does <em>not</em> inherit the holographic theme.</p>
-    <p>In order for your application to match the rest of the system UI, we highly recommend you
-make this change to inherit the new widget styles and system theme. However, beware that doing so
-might conflict with color or text designs you applied to your application based on the previous
-system theme, so you should be sure to inspect your application UI when using the holographic
-theme.</p>
-  </li>
-  <li><b>Provide alternative layouts for extra large screens</b>
-    <p>As discussed in the guide to <a
-href="{@docRoot}guide/practices/screens_support.html">Supporting Multiple Screens</a>, Android
-2.3 and above support the <code>xlarge</code> resource qualifier, which you should use to supply
-alternative layouts for extra large screens.</p>
-    <p>By providing alternative layouts for some of your activities when running on extra large
-screens, you can improve the user experience of your application on a tablet without using any
-new APIs.</p>
-    <p>For example, here are some things to consider when creating a new layout for tables:</p>
-    <ul>
-      <li>Landscape layout: The "normal" orientation for tablets is usually landscape (wide), so
-you should be sure that your activities offer an appropriate layout for such a wide viewing
-area.</li>
-      <li>Button position: Consider whether the position of the most common buttons in your UI are
-easily accessible while holding a tablet with two hands.</li>
-    </ul>
-    <p class="note"><strong>Note:</strong> You can add alternative resources for <em>xlarge</em>
-screens without changing your {@code minSdkVersion}. For example, if you add alternative layouts in
-<code>res/layout-xlarge/</code> and your application is compatible with older versions, such
-as Android 1.5&mdash;which doesn't support <em>xlarge</em> screens&mdash;this layout directory is
-simply ignored by those devices.</p>
-  </li>
-</ol>
-
-
-<p>Otherwise, if you want to develop a new application or upgrade your existing application to
-use APIs added in Android 3.0, we encourage you to get started by developing against the Android
-3.0 preview platform. You can get started the same way as you would for any other version of
-Android.</p>
-
-
-<p>To get started&mdash;whether testing an existing application or creating a new one&mdash;follow
-the procedure in the following section to install the Preview SDK.</p>
-
-
-
-<h3 id="Setup">How do I get it?</h3>
-
-<p>To get the Preview SDK, you can download it using the Android SDK and AVD Manager.</p>
-
-<p>If you're new to Android development, start by <a href="{@docRoot}sdk/index.html">downloading the
-Android SDK starter package</a>.</p>
-
-<p><a href="{@docRoot}sdk/adding-components.html#launching">Launch the Android SDK and AVD
-Manager</a> and install the following:</p>
-<ul>
-  <li>SDK Platform Android Honeycomb Preview</li>
-  <li>Android SDK Tools, revision 9</li>
-  <li>Android SDK Platform-tools, revision 2</li>
-  <li>Documentation for Android 'Honeycomb' Preview</li>
-  <li>Samples for SDK API Honeycomb Preview</li>
-</ul>
-
-<p class="note"><strong>Note:</strong> Be sure to install the documentation component for the
-Honeycomb Preview SDK. The API reference for the Android 3.0 API is <strong>not</strong> available
-online.</p>
-
-<p>Once you have installed these components, open your SDK directory and navigate to {@code
-docs/sdk/} and open {@code index.html} in your browser. </p>
-
-
-
-<h3 id="Issues">Known issues</h3>
-
-<p>The following known issues occur for Android 3.0 AVDs that are loaded in the emulator:</p>
-
-<ul>
-  <li>The emulator displays a rotated portrait screen while in landscape
-orientation. To view the screen correctly in landscape orientation, turn off the auto-rotate setting
-in <strong>Settings > Screen > Auto-rotate screen</strong>. Then use Ctrl-F11 to rotate the
-emulator.</li>
-  <li>You cannot take screenshots of an emulator screen. The Device Screen Capture window displays
-<strong>Screen not available</strong>.</li>
-  <li>GPS emulation is currently not supported.</li>
-  <li>When rotating the emulator screen by pressing Ctrl-F11, the screen turns green momentarily,
-then displays the normal interface.</li>
-  <li>The Dev Tools application sometimes crashes when trying to use the Package Browser
-feature.</li>
-</ul>
-
-
-<div class="special">
- <p>For an overview of new features in Android 3.0, read the <a
-href="{@docRoot}sdk/android-3.0-highlights.html">Platform Highlights</a>.</p>
-</div>
-
diff --git a/docs/html/sdk/preview/installing.jd b/docs/html/sdk/preview/installing.jd
index c835c49..94c6f2f 100644
--- a/docs/html/sdk/preview/installing.jd
+++ b/docs/html/sdk/preview/installing.jd
@@ -1,62 +1,8 @@
-page.title=Getting Started with Honeycomb
 @jd:body
 
-<p>First, you need to set up your development environment with the new SDK Tools and preview
-platform:</p>
+<script type="text/javascript">
+  document.location=toRoot+"sdk/installing.html"
+</script>
 
-<ol>
-  <li>Unpack the SDK Tools r8 package you've received.
-    <p>If you have an existing Android SDK directory, simply replace your existing {@code
-tools/} directory with the one from the new package and add the {@code platform-tools/}
-directory along side it (at the root of the SDK directory).</p></li>
-  <li>Unpack the platform package ({@code android-Froyo}) and place it in your SDK's {@code
-platforms/} directory.</li>
-  <li>If you're using Eclipse, also update your Eclipse plugin using the provided archive file.
-    <ol>
-      <li>Select <strong>Help > Install new software</strong>.</li>
-      <li>Click <strong>Add</strong>.</li>
-      <li>Click <strong>Archive</strong>.</li>
-      <li>Locate and select the archive file. Click <strong>OK</strong>.
-        <p>Developer Tools now appear in the Available Software window and you can proceed
-to install the plugin.</p>
-      </li>
-    </ol>
-  </li>
-</ol>
-
-<p class="note"><strong>Note:</strong> Beginning with SDK Tools r8 (the version you've received),
-the {@code adb} tool is now located in the {@code &lt;sdk&gt;/platform-tools/} directory (instead
-of in {@code &lt;sdk&gt;/tools/}). Be sure to update your {@code PATH} environment variable and any
-build/debugging scripts you have.</p>
-
-
-
-<h2 id="Setup">Set Up Your AVD and Application</h2>
-
-<p>With your SDK now set up, follow these steps to start developing an application for
-Honeycomb.</p>
-
-<ol>
-
-  <li>Create a new AVD targeted to "Android Froyo (Preview)" and with a custom skin resolution of
-1280 x 800.</li>
-
-  <li>Set the build target of your application to "Android Froyo (Preview)".</li>
-  <li>Set your manifest file's {@code &lt;uses-sdk&gt;} element to use {@code
-android:minSdkVersion="Froyo"}. For example:
-<pre>
-&lt;manifest&gt;
-    &lt;uses-sdk android:minSdkVersion="Froyo" /&gt;
-    ...
-&lt;/manifest&gt;
-</pre>
-<p>"Froyo" is a provisional API Level for the Honeycomb release, used only during the preview
-period. When the APIs are
-finalized and the SDK is released publicly, you must update this with the appropriate API Level
-integer.</p>
-<p class="note"><strong>Note:</strong> By providing your {@code &lt;uses-sdk&gt;} element in the
-manifest file <em>before</em> the {@code &lt;application&gt;} element, your application will
-automatically apply the new Holographic theme.</p>
-</li>
-
-</ol>
+<p>You should have already been redirected by your browser. Please go to
+<a href="{@docRoot}sdk/installing.html">Installing the SDK</a>.</p>
\ No newline at end of file
diff --git a/docs/html/sdk/preview/requirements.jd b/docs/html/sdk/preview/requirements.jd
index 1e6b26b..b5aed80 100644
--- a/docs/html/sdk/preview/requirements.jd
+++ b/docs/html/sdk/preview/requirements.jd
@@ -1,5 +1,8 @@
-sdk.redirect=true
-
 @jd:body
 
+<script type="text/javascript">
+  document.location=toRoot+"sdk/requirements.html"
+</script>
 
+<p>You should have already been redirected by your browser. Please go to the
+<a href="{@docRoot}sdk/requirements.html">SDK System Requirements</a>.</p>
\ No newline at end of file
diff --git a/docs/html/sdk/preview/upgrading.jd b/docs/html/sdk/preview/upgrading.jd
index 1e6b26b..1c53bdb 100644
--- a/docs/html/sdk/preview/upgrading.jd
+++ b/docs/html/sdk/preview/upgrading.jd
@@ -1,5 +1,8 @@
-sdk.redirect=true
-
 @jd:body
 
+<script type="text/javascript">
+  document.location=toRoot+"sdk/index.html"
+</script>
 
+<p>You should have already been redirected by your browser. Please go to
+<a href="{@docRoot}sdk/index.html">the Android SDK</a>.</p>
\ No newline at end of file
diff --git a/docs/html/sdk/requirements.jd b/docs/html/sdk/requirements.jd
index 3d62dd9..f12d0aa 100644
--- a/docs/html/sdk/requirements.jd
+++ b/docs/html/sdk/requirements.jd
@@ -24,7 +24,9 @@
 
 <h4 style="margin-top:.25em"><em>Eclipse IDE</em></h4>
     <ul>
-      <li>Eclipse 3.4 (Ganymede) or greater</li>
+      <li>Eclipse 3.5 (Galileo) or greater 
+<p class="note"><strong>Note:</strong> Eclipse 3.4 (Ganymede) is no longer
+supported with the latest version of ADT.</p></li>
       <li>Eclipse <a href="http://www.eclipse.org/jdt">JDT</a> plugin (included
 in most Eclipse IDE packages) </li>
       <li>If you need to install or update Eclipse, you can download it from <a
diff --git a/docs/html/sdk/sdk_toc.cs b/docs/html/sdk/sdk_toc.cs
index a1c26db..6b9a5ce 100644
--- a/docs/html/sdk/sdk_toc.cs
+++ b/docs/html/sdk/sdk_toc.cs
@@ -129,7 +129,7 @@
       <span style="display:none" class="zh-TW"></span>
       </h2>
     <ul>
-      <li><a href="<?cs var:toroot ?>sdk/eclipse-adt.html">ADT 10.0.0
+      <li><a href="<?cs var:toroot ?>sdk/eclipse-adt.html">ADT 10.0.1
       <span style="display:none" class="de"></span>
       <span style="display:none" class="es"></span>
       <span style="display:none" class="fr"></span>
diff --git a/drm/common/DrmInfoEvent.cpp b/drm/common/DrmInfoEvent.cpp
index 8d115a8..27a5a2d 100644
--- a/drm/common/DrmInfoEvent.cpp
+++ b/drm/common/DrmInfoEvent.cpp
@@ -19,7 +19,7 @@
 
 using namespace android;
 
-DrmInfoEvent::DrmInfoEvent(int uniqueId, int infoType, const String8& message)
+DrmInfoEvent::DrmInfoEvent(int uniqueId, int infoType, const String8 message)
     : mUniqueId(uniqueId),
       mInfoType(infoType),
       mMessage(message) {
@@ -34,7 +34,7 @@
     return mInfoType;
 }
 
-const String8& DrmInfoEvent::getMessage() const {
+const String8 DrmInfoEvent::getMessage() const {
     return mMessage;
 }
 
diff --git a/drm/common/DrmSupportInfo.cpp b/drm/common/DrmSupportInfo.cpp
index 3e02093..3dee435 100644
--- a/drm/common/DrmSupportInfo.cpp
+++ b/drm/common/DrmSupportInfo.cpp
@@ -15,6 +15,7 @@
  */
 
 #include <drm/DrmSupportInfo.h>
+#include <strings.h>
 
 using namespace android;
 
@@ -45,7 +46,7 @@
     for (unsigned int i = 0; i < mMimeTypeVector.size(); i++) {
         const String8 item = mMimeTypeVector.itemAt(i);
 
-        if (String8("") != mimeType && item.find(mimeType) != -1) {
+        if (!strcasecmp(item.string(), mimeType.string())) {
             return true;
         }
     }
@@ -56,7 +57,7 @@
     for (unsigned int i = 0; i < mFileSuffixVector.size(); i++) {
         const String8 item = mFileSuffixVector.itemAt(i);
 
-        if (item.find(fileType) != -1) {
+        if (!strcasecmp(item.string(), fileType.string())) {
             return true;
         }
     }
@@ -152,4 +153,3 @@
     mIndex++;
     return value;
 }
-
diff --git a/drm/common/IDrmManagerService.cpp b/drm/common/IDrmManagerService.cpp
index ddbd220..c37b4f8 100644
--- a/drm/common/IDrmManagerService.cpp
+++ b/drm/common/IDrmManagerService.cpp
@@ -37,6 +37,78 @@
 
 using namespace android;
 
+static void writeDecrptHandleToParcelData(
+        const DecryptHandle* handle, Parcel* data) {
+    data->writeInt32(handle->decryptId);
+    data->writeString8(handle->mimeType);
+    data->writeInt32(handle->decryptApiType);
+    data->writeInt32(handle->status);
+
+    int size = handle->copyControlVector.size();
+    data->writeInt32(size);
+    for(int i = 0; i < size; i++) {
+        data->writeInt32(handle->copyControlVector.keyAt(i));
+        data->writeInt32(handle->copyControlVector.valueAt(i));
+    }
+
+    size = handle->extendedData.size();
+    data->writeInt32(size);
+    for(int i = 0; i < size; i++) {
+        data->writeString8(handle->extendedData.keyAt(i));
+        data->writeString8(handle->extendedData.valueAt(i));
+    }
+
+    if (NULL != handle->decryptInfo) {
+        data->writeInt32(handle->decryptInfo->decryptBufferLength);
+    } else {
+        data->writeInt32(INVALID_BUFFER_LENGTH);
+    }
+}
+
+static void readDecryptHandleFromParcelData(
+        DecryptHandle* handle, const Parcel& data) {
+    if (0 == data.dataAvail()) {
+        return;
+    }
+
+    handle->decryptId = data.readInt32();
+    handle->mimeType = data.readString8();
+    handle->decryptApiType = data.readInt32();
+    handle->status = data.readInt32();
+
+    int size = data.readInt32();
+    for (int i = 0; i < size; i ++) {
+        DrmCopyControl key = (DrmCopyControl)data.readInt32();
+        int value = data.readInt32();
+        handle->copyControlVector.add(key, value);
+    }
+
+    size = data.readInt32();
+    for (int i = 0; i < size; i ++) {
+        String8 key = data.readString8();
+        String8 value = data.readString8();
+        handle->extendedData.add(key, value);
+    }
+
+    handle->decryptInfo = NULL;
+    const int bufferLen = data.readInt32();
+    if (INVALID_BUFFER_LENGTH != bufferLen) {
+        handle->decryptInfo = new DecryptInfo();
+        handle->decryptInfo->decryptBufferLength = bufferLen;
+    }
+}
+
+static void clearDecryptHandle(DecryptHandle* handle) {
+    if (handle == NULL) {
+        return;
+    }
+    if (handle->decryptInfo) {
+        delete handle->decryptInfo;
+        handle->decryptInfo = NULL;
+    }
+    handle->copyControlVector.clear();
+}
+
 int BpDrmManagerService::addUniqueId(int uniqueId) {
     LOGV("add uniqueid");
     Parcel data, reply;
@@ -344,16 +416,7 @@
     data.writeInterfaceToken(IDrmManagerService::getInterfaceDescriptor());
     data.writeInt32(uniqueId);
 
-    data.writeInt32(decryptHandle->decryptId);
-    data.writeString8(decryptHandle->mimeType);
-    data.writeInt32(decryptHandle->decryptApiType);
-    data.writeInt32(decryptHandle->status);
-
-    if (NULL != decryptHandle->decryptInfo) {
-        data.writeInt32(decryptHandle->decryptInfo->decryptBufferLength);
-    } else {
-        data.writeInt32(INVALID_BUFFER_LENGTH);
-    }
+    writeDecrptHandleToParcelData(decryptHandle, &data);
 
     data.writeInt32(action);
     data.writeInt32(static_cast< int>(reserve));
@@ -370,16 +433,7 @@
     data.writeInterfaceToken(IDrmManagerService::getInterfaceDescriptor());
     data.writeInt32(uniqueId);
 
-    data.writeInt32(decryptHandle->decryptId);
-    data.writeString8(decryptHandle->mimeType);
-    data.writeInt32(decryptHandle->decryptApiType);
-    data.writeInt32(decryptHandle->status);
-
-    if (NULL != decryptHandle->decryptInfo) {
-        data.writeInt32(decryptHandle->decryptInfo->decryptBufferLength);
-    } else {
-        data.writeInt32(INVALID_BUFFER_LENGTH);
-    }
+    writeDecrptHandleToParcelData(decryptHandle, &data);
 
     data.writeInt32(playbackStatus);
     data.writeInt64(position);
@@ -560,15 +614,7 @@
     DecryptHandle* handle = NULL;
     if (0 != reply.dataAvail()) {
         handle = new DecryptHandle();
-        handle->decryptId = reply.readInt32();
-        handle->mimeType = reply.readString8();
-        handle->decryptApiType = reply.readInt32();
-        handle->status = reply.readInt32();
-        handle->decryptInfo = NULL;
-        if (0 != reply.dataAvail()) {
-            handle->decryptInfo = new DecryptInfo();
-            handle->decryptInfo->decryptBufferLength = reply.readInt32();
-        }
+        readDecryptHandleFromParcelData(handle, reply);
     }
     return handle;
 }
@@ -586,17 +632,9 @@
     DecryptHandle* handle = NULL;
     if (0 != reply.dataAvail()) {
         handle = new DecryptHandle();
-        handle->decryptId = reply.readInt32();
-        handle->mimeType = reply.readString8();
-        handle->decryptApiType = reply.readInt32();
-        handle->status = reply.readInt32();
-        handle->decryptInfo = NULL;
-        if (0 != reply.dataAvail()) {
-            handle->decryptInfo = new DecryptInfo();
-            handle->decryptInfo->decryptBufferLength = reply.readInt32();
-        }
+        readDecryptHandleFromParcelData(handle, reply);
     } else {
-        LOGE("no decryptHandle is generated in service side");
+        LOGV("no decryptHandle is generated in service side");
     }
     return handle;
 }
@@ -608,24 +646,10 @@
     data.writeInterfaceToken(IDrmManagerService::getInterfaceDescriptor());
     data.writeInt32(uniqueId);
 
-    data.writeInt32(decryptHandle->decryptId);
-    data.writeString8(decryptHandle->mimeType);
-    data.writeInt32(decryptHandle->decryptApiType);
-    data.writeInt32(decryptHandle->status);
-
-    if (NULL != decryptHandle->decryptInfo) {
-        data.writeInt32(decryptHandle->decryptInfo->decryptBufferLength);
-    } else {
-        data.writeInt32(INVALID_BUFFER_LENGTH);
-    }
+    writeDecrptHandleToParcelData(decryptHandle, &data);
 
     remote()->transact(CLOSE_DECRYPT_SESSION, data, &reply);
 
-    if (NULL != decryptHandle->decryptInfo) {
-        LOGV("deleting decryptInfo");
-        delete decryptHandle->decryptInfo; decryptHandle->decryptInfo = NULL;
-    }
-    delete decryptHandle; decryptHandle = NULL;
     return reply.readInt32();
 }
 
@@ -638,16 +662,8 @@
     data.writeInterfaceToken(IDrmManagerService::getInterfaceDescriptor());
     data.writeInt32(uniqueId);
 
-    data.writeInt32(decryptHandle->decryptId);
-    data.writeString8(decryptHandle->mimeType);
-    data.writeInt32(decryptHandle->decryptApiType);
-    data.writeInt32(decryptHandle->status);
+    writeDecrptHandleToParcelData(decryptHandle, &data);
 
-    if (NULL != decryptHandle->decryptInfo) {
-        data.writeInt32(decryptHandle->decryptInfo->decryptBufferLength);
-    } else {
-        data.writeInt32(INVALID_BUFFER_LENGTH);
-    }
     data.writeInt32(decryptUnitId);
 
     data.writeInt32(headerInfo->length);
@@ -666,16 +682,7 @@
     data.writeInterfaceToken(IDrmManagerService::getInterfaceDescriptor());
     data.writeInt32(uniqueId);
 
-    data.writeInt32(decryptHandle->decryptId);
-    data.writeString8(decryptHandle->mimeType);
-    data.writeInt32(decryptHandle->decryptApiType);
-    data.writeInt32(decryptHandle->status);
-
-    if (NULL != decryptHandle->decryptInfo) {
-        data.writeInt32(decryptHandle->decryptInfo->decryptBufferLength);
-    } else {
-        data.writeInt32(INVALID_BUFFER_LENGTH);
-    }
+    writeDecrptHandleToParcelData(decryptHandle, &data);
 
     data.writeInt32(decryptUnitId);
     data.writeInt32((*decBuffer)->length);
@@ -708,16 +715,7 @@
     data.writeInterfaceToken(IDrmManagerService::getInterfaceDescriptor());
     data.writeInt32(uniqueId);
 
-    data.writeInt32(decryptHandle->decryptId);
-    data.writeString8(decryptHandle->mimeType);
-    data.writeInt32(decryptHandle->decryptApiType);
-    data.writeInt32(decryptHandle->status);
-
-    if (NULL != decryptHandle->decryptInfo) {
-        data.writeInt32(decryptHandle->decryptInfo->decryptBufferLength);
-    } else {
-        data.writeInt32(INVALID_BUFFER_LENGTH);
-    }
+    writeDecrptHandleToParcelData(decryptHandle, &data);
 
     data.writeInt32(decryptUnitId);
 
@@ -735,16 +733,7 @@
     data.writeInterfaceToken(IDrmManagerService::getInterfaceDescriptor());
     data.writeInt32(uniqueId);
 
-    data.writeInt32(decryptHandle->decryptId);
-    data.writeString8(decryptHandle->mimeType);
-    data.writeInt32(decryptHandle->decryptApiType);
-    data.writeInt32(decryptHandle->status);
-
-    if (NULL != decryptHandle->decryptInfo) {
-        data.writeInt32(decryptHandle->decryptInfo->decryptBufferLength);
-    } else {
-        data.writeInt32(INVALID_BUFFER_LENGTH);
-    }
+    writeDecrptHandleToParcelData(decryptHandle, &data);
 
     data.writeInt32(numBytes);
     data.writeInt64(offset);
@@ -1069,24 +1058,14 @@
         const int uniqueId = data.readInt32();
 
         DecryptHandle handle;
-        handle.decryptId = data.readInt32();
-        handle.mimeType = data.readString8();
-        handle.decryptApiType = data.readInt32();
-        handle.status = data.readInt32();
-        handle.decryptInfo = NULL;
-
-        const int bufferLength = data.readInt32();
-        if (INVALID_BUFFER_LENGTH != bufferLength) {
-            handle.decryptInfo = new DecryptInfo();
-            handle.decryptInfo->decryptBufferLength = bufferLength;
-        }
+        readDecryptHandleFromParcelData(&handle, data);
 
         const status_t status
             = consumeRights(uniqueId, &handle, data.readInt32(),
                 static_cast<bool>(data.readInt32()));
         reply->writeInt32(status);
 
-        delete handle.decryptInfo; handle.decryptInfo = NULL;
+        clearDecryptHandle(&handle);
         return DRM_NO_ERROR;
     }
 
@@ -1098,23 +1077,13 @@
         const int uniqueId = data.readInt32();
 
         DecryptHandle handle;
-        handle.decryptId = data.readInt32();
-        handle.mimeType = data.readString8();
-        handle.decryptApiType = data.readInt32();
-        handle.status = data.readInt32();
-        handle.decryptInfo = NULL;
-
-        const int bufferLength = data.readInt32();
-        if (INVALID_BUFFER_LENGTH != bufferLength) {
-            handle.decryptInfo = new DecryptInfo();
-            handle.decryptInfo->decryptBufferLength = bufferLength;
-        }
+        readDecryptHandleFromParcelData(&handle, data);
 
         const status_t status
             = setPlaybackStatus(uniqueId, &handle, data.readInt32(), data.readInt64());
         reply->writeInt32(status);
 
-        delete handle.decryptInfo; handle.decryptInfo = NULL;
+        clearDecryptHandle(&handle);
         return DRM_NO_ERROR;
     }
 
@@ -1275,16 +1244,10 @@
             = openDecryptSession(uniqueId, fd, data.readInt64(), data.readInt64());
 
         if (NULL != handle) {
-            reply->writeInt32(handle->decryptId);
-            reply->writeString8(handle->mimeType);
-            reply->writeInt32(handle->decryptApiType);
-            reply->writeInt32(handle->status);
-            if (NULL != handle->decryptInfo) {
-                reply->writeInt32(handle->decryptInfo->decryptBufferLength);
-                delete handle->decryptInfo; handle->decryptInfo = NULL;
-            }
+            writeDecrptHandleToParcelData(handle, reply);
+            clearDecryptHandle(handle);
+            delete handle; handle = NULL;
         }
-        delete handle; handle = NULL;
         return DRM_NO_ERROR;
     }
 
@@ -1299,18 +1262,13 @@
         DecryptHandle* handle = openDecryptSession(uniqueId, uri.string());
 
         if (NULL != handle) {
-            reply->writeInt32(handle->decryptId);
-            reply->writeString8(handle->mimeType);
-            reply->writeInt32(handle->decryptApiType);
-            reply->writeInt32(handle->status);
-            if (NULL != handle->decryptInfo) {
-                reply->writeInt32(handle->decryptInfo->decryptBufferLength);
-                delete handle->decryptInfo; handle->decryptInfo = NULL;
-            }
+            writeDecrptHandleToParcelData(handle, reply);
+
+            clearDecryptHandle(handle);
+            delete handle; handle = NULL;
         } else {
-            LOGE("NULL decryptHandle is returned");
+            LOGV("NULL decryptHandle is returned");
         }
-        delete handle; handle = NULL;
         return DRM_NO_ERROR;
     }
 
@@ -1322,17 +1280,7 @@
         const int uniqueId = data.readInt32();
 
         DecryptHandle* handle = new DecryptHandle();
-        handle->decryptId = data.readInt32();
-        handle->mimeType = data.readString8();
-        handle->decryptApiType = data.readInt32();
-        handle->status = data.readInt32();
-        handle->decryptInfo = NULL;
-
-        const int bufferLength = data.readInt32();
-        if (INVALID_BUFFER_LENGTH != bufferLength) {
-            handle->decryptInfo = new DecryptInfo();
-            handle->decryptInfo->decryptBufferLength = bufferLength;
-        }
+        readDecryptHandleFromParcelData(handle, data);
 
         const status_t status = closeDecryptSession(uniqueId, handle);
         reply->writeInt32(status);
@@ -1347,17 +1295,8 @@
         const int uniqueId = data.readInt32();
 
         DecryptHandle handle;
-        handle.decryptId = data.readInt32();
-        handle.mimeType = data.readString8();
-        handle.decryptApiType = data.readInt32();
-        handle.status = data.readInt32();
-        handle.decryptInfo = NULL;
+        readDecryptHandleFromParcelData(&handle, data);
 
-        const int bufferLength = data.readInt32();
-        if (INVALID_BUFFER_LENGTH != bufferLength) {
-            handle.decryptInfo = new DecryptInfo();
-            handle.decryptInfo->decryptBufferLength = bufferLength;
-        }
         const int decryptUnitId = data.readInt32();
 
         //Filling Header info
@@ -1369,7 +1308,7 @@
             = initializeDecryptUnit(uniqueId, &handle, decryptUnitId, headerInfo);
         reply->writeInt32(status);
 
-        delete handle.decryptInfo; handle.decryptInfo = NULL;
+        clearDecryptHandle(&handle);
         delete headerInfo; headerInfo = NULL;
         return DRM_NO_ERROR;
     }
@@ -1382,17 +1321,8 @@
         const int uniqueId = data.readInt32();
 
         DecryptHandle handle;
-        handle.decryptId = data.readInt32();
-        handle.mimeType = data.readString8();
-        handle.decryptApiType = data.readInt32();
-        handle.status = data.readInt32();
-        handle.decryptInfo = NULL;
+        readDecryptHandleFromParcelData(&handle, data);
 
-        const int bufferLength = data.readInt32();
-        if (INVALID_BUFFER_LENGTH != bufferLength) {
-            handle.decryptInfo = new DecryptInfo();
-            handle.decryptInfo->decryptBufferLength = bufferLength;
-        }
         const int decryptUnitId = data.readInt32();
         const int decBufferSize = data.readInt32();
 
@@ -1419,7 +1349,7 @@
         reply->writeInt32(size);
         reply->write(decBuffer->data, size);
 
-        delete handle.decryptInfo; handle.decryptInfo = NULL;
+        clearDecryptHandle(&handle);
         delete encBuffer; encBuffer = NULL;
         delete decBuffer; decBuffer = NULL;
         delete [] buffer; buffer = NULL;
@@ -1435,22 +1365,12 @@
         const int uniqueId = data.readInt32();
 
         DecryptHandle handle;
-        handle.decryptId = data.readInt32();
-        handle.mimeType = data.readString8();
-        handle.decryptApiType = data.readInt32();
-        handle.status = data.readInt32();
-        handle.decryptInfo = NULL;
-
-        const int bufferLength = data.readInt32();
-        if (INVALID_BUFFER_LENGTH != bufferLength) {
-            handle.decryptInfo = new DecryptInfo();
-            handle.decryptInfo->decryptBufferLength = bufferLength;
-        }
+        readDecryptHandleFromParcelData(&handle, data);
 
         const status_t status = finalizeDecryptUnit(uniqueId, &handle, data.readInt32());
         reply->writeInt32(status);
 
-        delete handle.decryptInfo; handle.decryptInfo = NULL;
+        clearDecryptHandle(&handle);
         return DRM_NO_ERROR;
     }
 
@@ -1462,17 +1382,7 @@
         const int uniqueId = data.readInt32();
 
         DecryptHandle handle;
-        handle.decryptId = data.readInt32();
-        handle.mimeType = data.readString8();
-        handle.decryptApiType = data.readInt32();
-        handle.status = data.readInt32();
-        handle.decryptInfo = NULL;
-
-        const int bufferLength = data.readInt32();
-        if (INVALID_BUFFER_LENGTH != bufferLength) {
-            handle.decryptInfo = new DecryptInfo();
-            handle.decryptInfo->decryptBufferLength = bufferLength;
-        }
+        readDecryptHandleFromParcelData(&handle, data);
 
         const int numBytes = data.readInt32();
         char* buffer = new char[numBytes];
@@ -1485,7 +1395,7 @@
             reply->write(buffer, result);
         }
 
-        delete handle.decryptInfo; handle.decryptInfo = NULL;
+        clearDecryptHandle(&handle);
         delete [] buffer, buffer = NULL;
         return DRM_NO_ERROR;
     }
diff --git a/drm/drmserver/Android.mk b/drm/drmserver/Android.mk
index 5df2ff8..e3cd44f 100644
--- a/drm/drmserver/Android.mk
+++ b/drm/drmserver/Android.mk
@@ -19,10 +19,10 @@
 LOCAL_SRC_FILES:= \
     main_drmserver.cpp \
     DrmManager.cpp \
-    DrmManagerService.cpp \
-    StringTokenizer.cpp
+    DrmManagerService.cpp
 
 LOCAL_SHARED_LIBRARIES := \
+    libmedia \
     libutils \
     libbinder
 
diff --git a/drm/drmserver/DrmManager.cpp b/drm/drmserver/DrmManager.cpp
index ec400b7..2fee59c 100644
--- a/drm/drmserver/DrmManager.cpp
+++ b/drm/drmserver/DrmManager.cpp
@@ -37,7 +37,6 @@
 
 using namespace android;
 
-Vector<int> DrmManager::mUniqueIdVector;
 const String8 DrmManager::EMPTY_STRING("");
 
 DrmManager::DrmManager() :
@@ -51,6 +50,7 @@
 }
 
 int DrmManager::addUniqueId(int uniqueId) {
+    Mutex::Autolock _l(mLock);
     if (0 == uniqueId) {
         int temp = 0;
         bool foundUniqueId = false;
@@ -78,6 +78,7 @@
 }
 
 void DrmManager::removeUniqueId(int uniqueId) {
+    Mutex::Autolock _l(mLock);
     for (unsigned int i = 0; i < mUniqueIdVector.size(); i++) {
         if (uniqueId == mUniqueIdVector.itemAt(i)) {
             mUniqueIdVector.removeAt(i);
@@ -107,6 +108,7 @@
 }
 
 status_t DrmManager::unloadPlugIns() {
+    Mutex::Autolock _l(mLock);
     mConvertSessionMap.clear();
     mDecryptSessionMap.clear();
     mPlugInManager.unloadPlugIns();
@@ -116,7 +118,7 @@
 
 status_t DrmManager::setDrmServiceListener(
             int uniqueId, const sp<IDrmServiceListener>& drmServiceListener) {
-    Mutex::Autolock _l(mLock);
+    Mutex::Autolock _l(mListenerLock);
     if (NULL != drmServiceListener.get()) {
         mServiceListeners.add(uniqueId, drmServiceListener);
     } else {
@@ -126,6 +128,7 @@
 }
 
 void DrmManager::addClient(int uniqueId) {
+    Mutex::Autolock _l(mLock);
     if (!mSupportInfoToPlugInIdMap.isEmpty()) {
         Vector<String8> plugInIdList = mPlugInManager.getPlugInIdList();
         for (unsigned int index = 0; index < plugInIdList.size(); index++) {
@@ -137,6 +140,7 @@
 }
 
 void DrmManager::removeClient(int uniqueId) {
+    Mutex::Autolock _l(mLock);
     Vector<String8> plugInIdList = mPlugInManager.getPlugInIdList();
     for (unsigned int index = 0; index < plugInIdList.size(); index++) {
         IDrmEngine& rDrmEngine = mPlugInManager.getPlugIn(plugInIdList.itemAt(index));
@@ -145,6 +149,7 @@
 }
 
 DrmConstraints* DrmManager::getConstraints(int uniqueId, const String8* path, const int action) {
+    Mutex::Autolock _l(mLock);
     const String8 plugInId = getSupportedPlugInIdFromPath(uniqueId, *path);
     if (EMPTY_STRING != plugInId) {
         IDrmEngine& rDrmEngine = mPlugInManager.getPlugIn(plugInId);
@@ -154,6 +159,7 @@
 }
 
 DrmMetadata* DrmManager::getMetadata(int uniqueId, const String8* path) {
+    Mutex::Autolock _l(mLock);
     const String8 plugInId = getSupportedPlugInIdFromPath(uniqueId, *path);
     if (EMPTY_STRING != plugInId) {
         IDrmEngine& rDrmEngine = mPlugInManager.getPlugIn(plugInId);
@@ -163,6 +169,7 @@
 }
 
 status_t DrmManager::installDrmEngine(int uniqueId, const String8& absolutePath) {
+    Mutex::Autolock _l(mLock);
     mPlugInManager.loadPlugIn(absolutePath);
 
     IDrmEngine& rDrmEngine = mPlugInManager.getPlugIn(absolutePath);
@@ -176,6 +183,7 @@
 }
 
 bool DrmManager::canHandle(int uniqueId, const String8& path, const String8& mimeType) {
+    Mutex::Autolock _l(mLock);
     const String8 plugInId = getSupportedPlugInId(mimeType);
     bool result = (EMPTY_STRING != plugInId) ? true : false;
 
@@ -194,6 +202,7 @@
 }
 
 DrmInfoStatus* DrmManager::processDrmInfo(int uniqueId, const DrmInfo* drmInfo) {
+    Mutex::Autolock _l(mLock);
     const String8 plugInId = getSupportedPlugInId(drmInfo->getMimeType());
     if (EMPTY_STRING != plugInId) {
         IDrmEngine& rDrmEngine = mPlugInManager.getPlugIn(plugInId);
@@ -218,6 +227,7 @@
 }
 
 DrmInfo* DrmManager::acquireDrmInfo(int uniqueId, const DrmInfoRequest* drmInfoRequest) {
+    Mutex::Autolock _l(mLock);
     const String8 plugInId = getSupportedPlugInId(drmInfoRequest->getMimeType());
     if (EMPTY_STRING != plugInId) {
         IDrmEngine& rDrmEngine = mPlugInManager.getPlugIn(plugInId);
@@ -228,6 +238,7 @@
 
 status_t DrmManager::saveRights(int uniqueId, const DrmRights& drmRights,
             const String8& rightsPath, const String8& contentPath) {
+    Mutex::Autolock _l(mLock);
     const String8 plugInId = getSupportedPlugInId(drmRights.getMimeType());
     status_t result = DRM_ERROR_UNKNOWN;
     if (EMPTY_STRING != plugInId) {
@@ -238,6 +249,7 @@
 }
 
 String8 DrmManager::getOriginalMimeType(int uniqueId, const String8& path) {
+    Mutex::Autolock _l(mLock);
     const String8 plugInId = getSupportedPlugInIdFromPath(uniqueId, path);
     if (EMPTY_STRING != plugInId) {
         IDrmEngine& rDrmEngine = mPlugInManager.getPlugIn(plugInId);
@@ -247,6 +259,7 @@
 }
 
 int DrmManager::getDrmObjectType(int uniqueId, const String8& path, const String8& mimeType) {
+    Mutex::Autolock _l(mLock);
     const String8 plugInId = getSupportedPlugInId(uniqueId, path, mimeType);
     if (EMPTY_STRING != plugInId) {
         IDrmEngine& rDrmEngine = mPlugInManager.getPlugIn(plugInId);
@@ -256,6 +269,7 @@
 }
 
 int DrmManager::checkRightsStatus(int uniqueId, const String8& path, int action) {
+    Mutex::Autolock _l(mLock);
     const String8 plugInId = getSupportedPlugInIdFromPath(uniqueId, path);
     if (EMPTY_STRING != plugInId) {
         IDrmEngine& rDrmEngine = mPlugInManager.getPlugIn(plugInId);
@@ -267,6 +281,7 @@
 status_t DrmManager::consumeRights(
     int uniqueId, DecryptHandle* decryptHandle, int action, bool reserve) {
     status_t result = DRM_ERROR_UNKNOWN;
+    Mutex::Autolock _l(mDecryptLock);
     if (mDecryptSessionMap.indexOfKey(decryptHandle->decryptId) != NAME_NOT_FOUND) {
         IDrmEngine* drmEngine = mDecryptSessionMap.valueFor(decryptHandle->decryptId);
         result = drmEngine->consumeRights(uniqueId, decryptHandle, action, reserve);
@@ -277,6 +292,7 @@
 status_t DrmManager::setPlaybackStatus(
     int uniqueId, DecryptHandle* decryptHandle, int playbackStatus, int64_t position) {
     status_t result = DRM_ERROR_UNKNOWN;
+    Mutex::Autolock _l(mDecryptLock);
     if (mDecryptSessionMap.indexOfKey(decryptHandle->decryptId) != NAME_NOT_FOUND) {
         IDrmEngine* drmEngine = mDecryptSessionMap.valueFor(decryptHandle->decryptId);
         result = drmEngine->setPlaybackStatus(uniqueId, decryptHandle, playbackStatus, position);
@@ -286,6 +302,7 @@
 
 bool DrmManager::validateAction(
     int uniqueId, const String8& path, int action, const ActionDescription& description) {
+    Mutex::Autolock _l(mLock);
     const String8 plugInId = getSupportedPlugInIdFromPath(uniqueId, path);
     if (EMPTY_STRING != plugInId) {
         IDrmEngine& rDrmEngine = mPlugInManager.getPlugIn(plugInId);
@@ -295,6 +312,7 @@
 }
 
 status_t DrmManager::removeRights(int uniqueId, const String8& path) {
+    Mutex::Autolock _l(mLock);
     const String8 plugInId = getSupportedPlugInIdFromPath(uniqueId, path);
     status_t result = DRM_ERROR_UNKNOWN;
     if (EMPTY_STRING != plugInId) {
@@ -318,6 +336,7 @@
 }
 
 int DrmManager::openConvertSession(int uniqueId, const String8& mimeType) {
+    Mutex::Autolock _l(mConvertLock);
     int convertId = -1;
 
     const String8 plugInId = getSupportedPlugInId(mimeType);
@@ -325,7 +344,6 @@
         IDrmEngine& rDrmEngine = mPlugInManager.getPlugIn(plugInId);
 
         if (DRM_NO_ERROR == rDrmEngine.openConvertSession(uniqueId, mConvertId + 1)) {
-            Mutex::Autolock _l(mConvertLock);
             ++mConvertId;
             convertId = mConvertId;
             mConvertSessionMap.add(convertId, &rDrmEngine);
@@ -338,6 +356,7 @@
             int uniqueId, int convertId, const DrmBuffer* inputData) {
     DrmConvertedStatus *drmConvertedStatus = NULL;
 
+    Mutex::Autolock _l(mConvertLock);
     if (mConvertSessionMap.indexOfKey(convertId) != NAME_NOT_FOUND) {
         IDrmEngine* drmEngine = mConvertSessionMap.valueFor(convertId);
         drmConvertedStatus = drmEngine->convertData(uniqueId, convertId, inputData);
@@ -346,6 +365,7 @@
 }
 
 DrmConvertedStatus* DrmManager::closeConvertSession(int uniqueId, int convertId) {
+    Mutex::Autolock _l(mConvertLock);
     DrmConvertedStatus *drmConvertedStatus = NULL;
 
     if (mConvertSessionMap.indexOfKey(convertId) != NAME_NOT_FOUND) {
@@ -358,6 +378,7 @@
 
 status_t DrmManager::getAllSupportInfo(
                     int uniqueId, int* length, DrmSupportInfo** drmSupportInfoArray) {
+    Mutex::Autolock _l(mLock);
     Vector<String8> plugInPathList = mPlugInManager.getPlugInIdList();
     int size = plugInPathList.size();
     int validPlugins = 0;
@@ -437,7 +458,7 @@
     }
     if (DRM_NO_ERROR != result) {
         delete handle; handle = NULL;
-        LOGE("DrmManager::openDecryptSession: no capable plug-in found");
+        LOGV("DrmManager::openDecryptSession: no capable plug-in found");
     }
     return handle;
 }
@@ -458,6 +479,7 @@
 status_t DrmManager::initializeDecryptUnit(
     int uniqueId, DecryptHandle* decryptHandle, int decryptUnitId, const DrmBuffer* headerInfo) {
     status_t result = DRM_ERROR_UNKNOWN;
+    Mutex::Autolock _l(mDecryptLock);
     if (mDecryptSessionMap.indexOfKey(decryptHandle->decryptId) != NAME_NOT_FOUND) {
         IDrmEngine* drmEngine = mDecryptSessionMap.valueFor(decryptHandle->decryptId);
         result = drmEngine->initializeDecryptUnit(uniqueId, decryptHandle, decryptUnitId, headerInfo);
@@ -468,6 +490,8 @@
 status_t DrmManager::decrypt(int uniqueId, DecryptHandle* decryptHandle, int decryptUnitId,
             const DrmBuffer* encBuffer, DrmBuffer** decBuffer, DrmBuffer* IV) {
     status_t result = DRM_ERROR_UNKNOWN;
+
+    Mutex::Autolock _l(mDecryptLock);
     if (mDecryptSessionMap.indexOfKey(decryptHandle->decryptId) != NAME_NOT_FOUND) {
         IDrmEngine* drmEngine = mDecryptSessionMap.valueFor(decryptHandle->decryptId);
         result = drmEngine->decrypt(
@@ -479,6 +503,7 @@
 status_t DrmManager::finalizeDecryptUnit(
             int uniqueId, DecryptHandle* decryptHandle, int decryptUnitId) {
     status_t result = DRM_ERROR_UNKNOWN;
+    Mutex::Autolock _l(mDecryptLock);
     if (mDecryptSessionMap.indexOfKey(decryptHandle->decryptId) != NAME_NOT_FOUND) {
         IDrmEngine* drmEngine = mDecryptSessionMap.valueFor(decryptHandle->decryptId);
         result = drmEngine->finalizeDecryptUnit(uniqueId, decryptHandle, decryptUnitId);
@@ -490,6 +515,7 @@
             void* buffer, ssize_t numBytes, off64_t offset) {
     ssize_t result = DECRYPT_FILE_ERROR;
 
+    Mutex::Autolock _l(mDecryptLock);
     if (mDecryptSessionMap.indexOfKey(decryptHandle->decryptId) != NAME_NOT_FOUND) {
         IDrmEngine* drmEngine = mDecryptSessionMap.valueFor(decryptHandle->decryptId);
         result = drmEngine->pread(uniqueId, decryptHandle, buffer, numBytes, offset);
@@ -546,7 +572,7 @@
 }
 
 void DrmManager::onInfo(const DrmInfoEvent& event) {
-    Mutex::Autolock _l(mLock);
+    Mutex::Autolock _l(mListenerLock);
     for (unsigned int index = 0; index < mServiceListeners.size(); index++) {
         int uniqueId = mServiceListeners.keyAt(index);
 
diff --git a/drm/drmserver/DrmManagerService.cpp b/drm/drmserver/DrmManagerService.cpp
index 0901a44..583669e 100644
--- a/drm/drmserver/DrmManagerService.cpp
+++ b/drm/drmserver/DrmManagerService.cpp
@@ -19,6 +19,7 @@
 #include <utils/Log.h>
 
 #include <private/android_filesystem_config.h>
+#include <media/MemoryLeakTrackUtil.h>
 
 #include <errno.h>
 #include <utils/threads.h>
@@ -256,3 +257,31 @@
     return mDrmManager->pread(uniqueId, decryptHandle, buffer, numBytes, offset);
 }
 
+status_t DrmManagerService::dump(int fd, const Vector<String16>& args)
+{
+    const size_t SIZE = 256;
+    char buffer[SIZE];
+    String8 result;
+    if (checkCallingPermission(String16("android.permission.DUMP")) == false) {
+        snprintf(buffer, SIZE, "Permission Denial: "
+                "can't dump DrmManagerService from pid=%d, uid=%d\n",
+                IPCThreadState::self()->getCallingPid(),
+                IPCThreadState::self()->getCallingUid());
+        result.append(buffer);
+    } else {
+#if DRM_MEMORY_LEAK_TRACK
+        bool dumpMem = false;
+        for (size_t i = 0; i < args.size(); i++) {
+            if (args[i] == String16("-m")) {
+                dumpMem = true;
+            }
+        }
+        if (dumpMem) {
+            dumpMemoryAddresses(fd);
+        }
+#endif
+    }
+    write(fd, result.string(), result.size());
+    return NO_ERROR;
+}
+
diff --git a/drm/drmserver/StringTokenizer.cpp b/drm/drmserver/StringTokenizer.cpp
deleted file mode 100644
index 2130a00..0000000
--- a/drm/drmserver/StringTokenizer.cpp
+++ /dev/null
@@ -1,66 +0,0 @@
-/*
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "StringTokenizer.h"
-
-using namespace android;
-
-StringTokenizer::StringTokenizer(const String8& string, const String8& delimiter) {
-    splitString(string, delimiter);
-}
-
-void StringTokenizer::splitString(const String8& string, const String8& delimiter) {
-    for (unsigned int i = 0; i < string.length(); i++) {
-        unsigned int position = string.find(delimiter.string(), i);
-        if (string.length() != position) {
-            String8 token(string.string()+i, position-i);
-            if (token.length()) {
-                mStringTokenizerVector.push(token);
-                i = position + delimiter.length() - 1;
-            }
-        } else {
-            mStringTokenizerVector.push(String8(string.string()+i, string.length()-i));
-            break;
-        }
-    }
-}
-
-StringTokenizer::Iterator StringTokenizer::iterator() {
-    return Iterator(this);
-}
-
-StringTokenizer::Iterator::Iterator(const StringTokenizer::Iterator& iterator) :
-    mStringTokenizer(iterator.mStringTokenizer),
-    mIndex(iterator.mIndex) {
-}
-
-StringTokenizer::Iterator& StringTokenizer::Iterator::operator=(
-            const StringTokenizer::Iterator& iterator) {
-    mStringTokenizer = iterator.mStringTokenizer;
-    mIndex = iterator.mIndex;
-    return *this;
-}
-
-bool StringTokenizer::Iterator::hasNext() {
-    return mIndex < mStringTokenizer->mStringTokenizerVector.size();
-}
-
-String8& StringTokenizer::Iterator::next() {
-    String8& value = mStringTokenizer->mStringTokenizerVector.editItemAt(mIndex);
-    mIndex++;
-    return value;
-}
-
diff --git a/drm/java/android/drm/DrmErrorEvent.java b/drm/java/android/drm/DrmErrorEvent.java
index 20fd8aa..7cc9a87 100644
--- a/drm/java/android/drm/DrmErrorEvent.java
+++ b/drm/java/android/drm/DrmErrorEvent.java
@@ -16,6 +16,8 @@
 
 package android.drm;
 
+import java.util.HashMap;
+
 /**
  * This is an entity class which would be passed to caller in
  * {@link DrmManagerClient.OnErrorListener#onError(DrmManagerClient, DrmErrorEvent)}
@@ -53,16 +55,34 @@
      * associated with all DRM schemes.
      */
     public static final int TYPE_REMOVE_ALL_RIGHTS_FAILED = 2007;
+    /**
+     * TYPE_ACQUIRE_DRM_INFO_FAILED, when failed to acquire DrmInfo.
+     */
+    public static final int TYPE_ACQUIRE_DRM_INFO_FAILED = 2008;
 
     /**
      * constructor to create DrmErrorEvent object with given parameters
      *
      * @param uniqueId Unique session identifier
-     * @param type Type of information
+     * @param type Type of the event. It could be one of the types defined above
      * @param message Message description
      */
     public DrmErrorEvent(int uniqueId, int type, String message) {
         super(uniqueId, type, message);
     }
+
+    /**
+     * constructor to create DrmErrorEvent object with given parameters
+     *
+     * @param uniqueId Unique session identifier
+     * @param type Type of the event. It could be one of the types defined above
+     * @param message Message description
+     * @param attributes Attributes for extensible information. Could be any
+     * information provided by the plugin
+     */
+    public DrmErrorEvent(int uniqueId, int type, String message,
+                            HashMap<String, Object> attributes) {
+        super(uniqueId, type, message, attributes);
+    }
 }
 
diff --git a/drm/java/android/drm/DrmEvent.java b/drm/java/android/drm/DrmEvent.java
index f7bc5cd..eba458b 100644
--- a/drm/java/android/drm/DrmEvent.java
+++ b/drm/java/android/drm/DrmEvent.java
@@ -16,6 +16,8 @@
 
 package android.drm;
 
+import java.util.HashMap;
+
 /**
  * This is the base class which would be used to notify the caller
  * about any event occurred in DRM framework.
@@ -33,11 +35,36 @@
     public static final int TYPE_DRM_INFO_PROCESSED = 1002;
 
     public static final String DRM_INFO_STATUS_OBJECT = "drm_info_status_object";
+    public static final String DRM_INFO_OBJECT = "drm_info_object";
 
     private final int mUniqueId;
     private final int mType;
     private String mMessage = "";
 
+    private HashMap<String, Object> mAttributes = new HashMap<String, Object>();
+
+    /**
+     * constructor for DrmEvent class
+     *
+     * @param uniqueId Unique session identifier
+     * @param type Type of information
+     * @param message Message description
+     * @param attributes Attributes for extensible information
+     */
+    protected DrmEvent(int uniqueId, int type, String message,
+                            HashMap<String, Object> attributes) {
+        mUniqueId = uniqueId;
+        mType = type;
+
+        if (null != message) {
+            mMessage = message;
+        }
+
+        if (null != attributes) {
+            mAttributes = attributes;
+        }
+    }
+
     /**
      * constructor for DrmEvent class
      *
@@ -80,5 +107,15 @@
     public String getMessage() {
         return mMessage;
     }
+
+    /**
+     * Returns the attribute corresponding to the specified key
+     *
+     * @return one of the attributes or null if no mapping for
+     * the key is found
+     */
+    public Object getAttribute(String key) {
+        return mAttributes.get(key);
+    }
 }
 
diff --git a/drm/java/android/drm/DrmInfoEvent.java b/drm/java/android/drm/DrmInfoEvent.java
index a778e06..190199a 100644
--- a/drm/java/android/drm/DrmInfoEvent.java
+++ b/drm/java/android/drm/DrmInfoEvent.java
@@ -16,6 +16,8 @@
 
 package android.drm;
 
+import java.util.HashMap;
+
 /**
  * This is an entity class which would be passed to caller in
  * {@link DrmManagerClient.OnInfoListener#onInfo(DrmManagerClient, DrmInfoEvent)}
@@ -45,16 +47,34 @@
      * already done for the given account.
      */
     public static final int TYPE_ACCOUNT_ALREADY_REGISTERED = 5;
+    /**
+     * TYPE_RIGHTS_REMOVED, when the rights has been removed.
+     */
+    public static final int TYPE_RIGHTS_REMOVED = 6;
 
     /**
      * constructor to create DrmInfoEvent object with given parameters
      *
      * @param uniqueId Unique session identifier
-     * @param type Type of information
+     * @param type Type of the event. It could be one of the types defined above
      * @param message Message description
      */
     public DrmInfoEvent(int uniqueId, int type, String message) {
         super(uniqueId, type, message);
     }
+
+    /**
+     * constructor to create DrmInfoEvent object with given parameters
+     *
+     * @param uniqueId Unique session identifier
+     * @param type Type of the event. It could be one of the types defined above
+     * @param message Message description
+     * @param attributes Attributes for extensible information. Could be any
+     * information provided by the plugin
+     */
+    public DrmInfoEvent(int uniqueId, int type, String message,
+                            HashMap<String, Object> attributes) {
+        super(uniqueId, type, message, attributes);
+    }
 }
 
diff --git a/drm/java/android/drm/DrmInfoRequest.java b/drm/java/android/drm/DrmInfoRequest.java
index a5a799c..366a342 100644
--- a/drm/java/android/drm/DrmInfoRequest.java
+++ b/drm/java/android/drm/DrmInfoRequest.java
@@ -28,7 +28,7 @@
  *
  */
 public class DrmInfoRequest {
-    // Changes in following constants should be in sync with DrmInfoRequest.cpp
+    // Changes in following constants should be in sync with DrmInfoRequest.h
     /**
      * Constants defines the type of {@link DrmInfoRequest}
      */
diff --git a/drm/java/android/drm/DrmManagerClient.java b/drm/java/android/drm/DrmManagerClient.java
index c541456..f7479b5 100644
--- a/drm/java/android/drm/DrmManagerClient.java
+++ b/drm/java/android/drm/DrmManagerClient.java
@@ -81,10 +81,8 @@
          *
          * @param client DrmManagerClient instance
          * @param event instance which wraps type and message
-         * @param attributes resultant values in key and value pair.
          */
-        public void onEvent(DrmManagerClient client, DrmEvent event,
-                HashMap<String, Object> attributes);
+        public void onEvent(DrmManagerClient client, DrmEvent event);
     }
 
     /**
@@ -128,12 +126,17 @@
             case ACTION_PROCESS_DRM_INFO: {
                 final DrmInfo drmInfo = (DrmInfo) msg.obj;
                 DrmInfoStatus status = _processDrmInfo(mUniqueId, drmInfo);
+
+                attributes.put(DrmEvent.DRM_INFO_STATUS_OBJECT, status);
+                attributes.put(DrmEvent.DRM_INFO_OBJECT, drmInfo);
+
                 if (null != status && DrmInfoStatus.STATUS_OK == status.statusCode) {
-                    attributes.put(DrmEvent.DRM_INFO_STATUS_OBJECT, status);
-                    event = new DrmEvent(mUniqueId, getEventType(status.infoType), null);
+                    event = new DrmEvent(mUniqueId,
+                            getEventType(status.infoType), null, attributes);
                 } else {
                     int infoType = (null != status) ? status.infoType : drmInfo.getInfoType();
-                    error = new DrmErrorEvent(mUniqueId, getErrorType(infoType), null);
+                    error = new DrmErrorEvent(mUniqueId,
+                            getErrorType(infoType), null, attributes);
                 }
                 break;
             }
@@ -151,7 +154,7 @@
                 return;
             }
             if (null != mOnEventListener && null != event) {
-                mOnEventListener.onEvent(DrmManagerClient.this, event, attributes);
+                mOnEventListener.onEvent(DrmManagerClient.this, event);
             }
             if (null != mOnErrorListener && null != error) {
                 mOnErrorListener.onError(DrmManagerClient.this, error);
@@ -181,7 +184,7 @@
         }
 
         public void handleMessage(Message msg) {
-            DrmInfoEvent event = null;
+            DrmInfoEvent info = null;
             DrmErrorEvent error = null;
 
             switch (msg.what) {
@@ -197,11 +200,15 @@
                     } catch (IOException e) {
                         e.printStackTrace();
                     }
-                    event = new DrmInfoEvent(uniqueId, infoType, message);
+                    info = new DrmInfoEvent(uniqueId, infoType, message);
                     break;
                 }
-                case DrmInfoEvent.TYPE_ALREADY_REGISTERED_BY_ANOTHER_ACCOUNT: {
-                    event = new DrmInfoEvent(uniqueId, infoType, message);
+                case DrmInfoEvent.TYPE_ALREADY_REGISTERED_BY_ANOTHER_ACCOUNT:
+                case DrmInfoEvent.TYPE_RIGHTS_INSTALLED:
+                case DrmInfoEvent.TYPE_WAIT_FOR_RIGHTS:
+                case DrmInfoEvent.TYPE_ACCOUNT_ALREADY_REGISTERED:
+                case DrmInfoEvent.TYPE_RIGHTS_REMOVED: {
+                    info = new DrmInfoEvent(uniqueId, infoType, message);
                     break;
                 }
                 default:
@@ -209,8 +216,8 @@
                     break;
                 }
 
-                if (null != mOnInfoListener && null != event) {
-                    mOnInfoListener.onInfo(DrmManagerClient.this, event);
+                if (null != mOnInfoListener && null != info) {
+                    mOnInfoListener.onInfo(DrmManagerClient.this, info);
                 }
                 if (null != mOnErrorListener && null != error) {
                     mOnErrorListener.onError(DrmManagerClient.this, error);
@@ -735,6 +742,7 @@
      * This method expects uri in the following format
      *     content://media/<table_name>/<row_index> (or)
      *     file://sdcard/test.mp4
+     *     http://test.com/test.mp4
      *
      * Here <table_name> shall be "video" or "audio" or "images"
      * <row_index> the index of the content in given table
@@ -746,6 +754,10 @@
             if (null == scheme || scheme.equals("") ||
                     scheme.equals(ContentResolver.SCHEME_FILE)) {
                 path = uri.getPath();
+
+            } else if (scheme.equals("http")) {
+                path = uri.toString();
+
             } else if (scheme.equals(ContentResolver.SCHEME_CONTENT)) {
                 String[] projection = new String[] {MediaStore.MediaColumns.DATA};
                 Cursor cursor = null;
diff --git a/drm/jni/Android.mk b/drm/jni/Android.mk
index b65e4da..69bb48d 100644
--- a/drm/jni/Android.mk
+++ b/drm/jni/Android.mk
@@ -42,7 +42,7 @@
     $(TOP)/frameworks/base/drm/libdrmframework/plugins/common/include \
     $(TOP)/frameworks/base/include
 
-LOCAL_PRELINK_MODULE := false
+
 
 LOCAL_MODULE_TAGS := optional
 
diff --git a/drm/libdrmframework/Android.mk b/drm/libdrmframework/Android.mk
index 99133ba..f1526a4 100644
--- a/drm/libdrmframework/Android.mk
+++ b/drm/libdrmframework/Android.mk
@@ -40,7 +40,7 @@
     $(TOP)/frameworks/base/drm/libdrmframework/include \
     $(TOP)/frameworks/base/include
 
-LOCAL_PRELINK_MODULE := false
+
 
 LOCAL_MODULE_TAGS := optional
 
diff --git a/drm/libdrmframework/DrmManagerClient.cpp b/drm/libdrmframework/DrmManagerClient.cpp
index 7b51822..8b781326 100644
--- a/drm/libdrmframework/DrmManagerClient.cpp
+++ b/drm/libdrmframework/DrmManagerClient.cpp
@@ -77,13 +77,13 @@
     return mDrmManagerClientImpl->checkRightsStatus(mUniqueId, path, action);
 }
 
-status_t DrmManagerClient::consumeRights(DecryptHandle* decryptHandle, int action, bool reserve) {
-    Mutex::Autolock _l(mDecryptLock);
+status_t DrmManagerClient::consumeRights(
+            sp<DecryptHandle> &decryptHandle, int action, bool reserve) {
     return mDrmManagerClientImpl->consumeRights(mUniqueId, decryptHandle, action, reserve);
 }
 
 status_t DrmManagerClient::setPlaybackStatus(
-            DecryptHandle* decryptHandle, int playbackStatus, int64_t position) {
+            sp<DecryptHandle> &decryptHandle, int playbackStatus, int64_t position) {
     return mDrmManagerClientImpl
             ->setPlaybackStatus(mUniqueId, decryptHandle, playbackStatus, position);
 }
@@ -117,41 +117,39 @@
     return mDrmManagerClientImpl->getAllSupportInfo(mUniqueId, length, drmSupportInfoArray);
 }
 
-DecryptHandle* DrmManagerClient::openDecryptSession(int fd, off64_t offset, off64_t length) {
+sp<DecryptHandle> DrmManagerClient::openDecryptSession(int fd, off64_t offset, off64_t length) {
     return mDrmManagerClientImpl->openDecryptSession(mUniqueId, fd, offset, length);
 }
 
-DecryptHandle* DrmManagerClient::openDecryptSession(const char* uri) {
+sp<DecryptHandle> DrmManagerClient::openDecryptSession(const char* uri) {
     return mDrmManagerClientImpl->openDecryptSession(mUniqueId, uri);
 }
 
-status_t DrmManagerClient::closeDecryptSession(DecryptHandle* decryptHandle) {
+status_t DrmManagerClient::closeDecryptSession(sp<DecryptHandle> &decryptHandle) {
     return mDrmManagerClientImpl->closeDecryptSession(mUniqueId, decryptHandle);
 }
 
 status_t DrmManagerClient::initializeDecryptUnit(
-            DecryptHandle* decryptHandle, int decryptUnitId, const DrmBuffer* headerInfo) {
-    Mutex::Autolock _l(mDecryptLock);
+            sp<DecryptHandle> &decryptHandle, int decryptUnitId, const DrmBuffer* headerInfo) {
     return mDrmManagerClientImpl->initializeDecryptUnit(
             mUniqueId, decryptHandle, decryptUnitId, headerInfo);
 }
 
 status_t DrmManagerClient::decrypt(
-    DecryptHandle* decryptHandle, int decryptUnitId,
-    const DrmBuffer* encBuffer, DrmBuffer** decBuffer, DrmBuffer* IV) {
-    Mutex::Autolock _l(mDecryptLock);
+            sp<DecryptHandle> &decryptHandle, int decryptUnitId,
+            const DrmBuffer* encBuffer, DrmBuffer** decBuffer, DrmBuffer* IV) {
     return mDrmManagerClientImpl->decrypt(
             mUniqueId, decryptHandle, decryptUnitId, encBuffer, decBuffer, IV);
 }
 
-status_t DrmManagerClient::finalizeDecryptUnit(DecryptHandle* decryptHandle, int decryptUnitId) {
-    Mutex::Autolock _l(mDecryptLock);
-    return mDrmManagerClientImpl->finalizeDecryptUnit(mUniqueId, decryptHandle, decryptUnitId);
+status_t DrmManagerClient::finalizeDecryptUnit(
+            sp<DecryptHandle> &decryptHandle, int decryptUnitId) {
+    return mDrmManagerClientImpl->finalizeDecryptUnit(mUniqueId,
+            decryptHandle, decryptUnitId);
 }
 
 ssize_t DrmManagerClient::pread(
-            DecryptHandle* decryptHandle, void* buffer, ssize_t numBytes, off64_t offset) {
-    Mutex::Autolock _l(mDecryptLock);
+            sp<DecryptHandle> &decryptHandle, void* buffer, ssize_t numBytes, off64_t offset) {
     return mDrmManagerClientImpl->pread(mUniqueId, decryptHandle, buffer, numBytes, offset);
 }
 
diff --git a/drm/libdrmframework/DrmManagerClientImpl.cpp b/drm/libdrmframework/DrmManagerClientImpl.cpp
index d20de92..a57dd98 100644
--- a/drm/libdrmframework/DrmManagerClientImpl.cpp
+++ b/drm/libdrmframework/DrmManagerClientImpl.cpp
@@ -28,8 +28,9 @@
 
 #define INVALID_VALUE -1
 
-Mutex DrmManagerClientImpl::mMutex;
-sp<IDrmManagerService> DrmManagerClientImpl::mDrmManagerService;
+Mutex DrmManagerClientImpl::sMutex;
+sp<IDrmManagerService> DrmManagerClientImpl::sDrmManagerService;
+sp<DrmManagerClientImpl::DeathNotifier> DrmManagerClientImpl::sDeathNotifier;
 const String8 DrmManagerClientImpl::EMPTY_STRING("");
 
 DrmManagerClientImpl* DrmManagerClientImpl::create(int* pUniqueId) {
@@ -47,8 +48,8 @@
 }
 
 const sp<IDrmManagerService>& DrmManagerClientImpl::getDrmManagerService() {
-    mMutex.lock();
-    if (NULL == mDrmManagerService.get()) {
+    Mutex::Autolock lock(sMutex);
+    if (NULL == sDrmManagerService.get()) {
         sp<IServiceManager> sm = defaultServiceManager();
         sp<IBinder> binder;
         do {
@@ -62,11 +63,13 @@
             reqt.tv_nsec = 500000000; //0.5 sec
             nanosleep(&reqt, NULL);
         } while (true);
-
-        mDrmManagerService = interface_cast<IDrmManagerService>(binder);
+        if (NULL == sDeathNotifier.get()) {
+            sDeathNotifier = new DeathNotifier();
+        }
+        binder->linkToDeath(sDeathNotifier);
+        sDrmManagerService = interface_cast<IDrmManagerService>(binder);
     }
-    mMutex.unlock();
-    return mDrmManagerService;
+    return sDrmManagerService;
 }
 
 void DrmManagerClientImpl::addClient(int uniqueId) {
@@ -78,14 +81,16 @@
 }
 
 status_t DrmManagerClientImpl::setOnInfoListener(
-            int uniqueId, const sp<DrmManagerClient::OnInfoListener>& infoListener) {
+            int uniqueId,
+            const sp<DrmManagerClient::OnInfoListener>& infoListener) {
     Mutex::Autolock _l(mLock);
     mOnInfoListener = infoListener;
     return getDrmManagerService()->setDrmServiceListener(uniqueId,
             (NULL != infoListener.get()) ? this : NULL);
 }
 
-status_t DrmManagerClientImpl::installDrmEngine(int uniqueId, const String8& drmEngineFile) {
+status_t DrmManagerClientImpl::installDrmEngine(
+        int uniqueId, const String8& drmEngineFile) {
     status_t status = DRM_ERROR_UNKNOWN;
     if (EMPTY_STRING != drmEngineFile) {
         status = getDrmManagerService()->installDrmEngine(uniqueId, drmEngineFile);
@@ -97,7 +102,8 @@
         int uniqueId, const String8* path, const int action) {
     DrmConstraints *drmConstraints = NULL;
     if ((NULL != path) && (EMPTY_STRING != *path)) {
-        drmConstraints = getDrmManagerService()->getConstraints(uniqueId, path, action);
+        drmConstraints =
+            getDrmManagerService()->getConstraints(uniqueId, path, action);
     }
     return drmConstraints;
 }
@@ -110,7 +116,8 @@
     return drmMetadata;
 }
 
-bool DrmManagerClientImpl::canHandle(int uniqueId, const String8& path, const String8& mimeType) {
+bool DrmManagerClientImpl::canHandle(
+        int uniqueId, const String8& path, const String8& mimeType) {
     bool retCode = false;
     if ((EMPTY_STRING != path) || (EMPTY_STRING != mimeType)) {
         retCode = getDrmManagerService()->canHandle(uniqueId, path, mimeType);
@@ -118,7 +125,8 @@
     return retCode;
 }
 
-DrmInfoStatus* DrmManagerClientImpl::processDrmInfo(int uniqueId, const DrmInfo* drmInfo) {
+DrmInfoStatus* DrmManagerClientImpl::processDrmInfo(
+        int uniqueId, const DrmInfo* drmInfo) {
     DrmInfoStatus *drmInfoStatus = NULL;
     if (NULL != drmInfo) {
         drmInfoStatus = getDrmManagerService()->processDrmInfo(uniqueId, drmInfo);
@@ -126,7 +134,8 @@
     return drmInfoStatus;
 }
 
-DrmInfo* DrmManagerClientImpl::acquireDrmInfo(int uniqueId, const DrmInfoRequest* drmInfoRequest) {
+DrmInfo* DrmManagerClientImpl::acquireDrmInfo(
+        int uniqueId, const DrmInfoRequest* drmInfoRequest) {
     DrmInfo* drmInfo = NULL;
     if (NULL != drmInfoRequest) {
         drmInfo = getDrmManagerService()->acquireDrmInfo(uniqueId, drmInfoRequest);
@@ -137,13 +146,12 @@
 status_t DrmManagerClientImpl::saveRights(int uniqueId, const DrmRights& drmRights,
             const String8& rightsPath, const String8& contentPath) {
     status_t status = DRM_ERROR_UNKNOWN;
-    if (EMPTY_STRING != contentPath) {
-        status = getDrmManagerService()->saveRights(uniqueId, drmRights, rightsPath, contentPath);
-    }
-    return status;
+    return getDrmManagerService()->saveRights(
+                uniqueId, drmRights, rightsPath, contentPath);
 }
 
-String8 DrmManagerClientImpl::getOriginalMimeType(int uniqueId, const String8& path) {
+String8 DrmManagerClientImpl::getOriginalMimeType(
+        int uniqueId, const String8& path) {
     String8 mimeType = EMPTY_STRING;
     if (EMPTY_STRING != path) {
         mimeType = getDrmManagerService()->getOriginalMimeType(uniqueId, path);
@@ -155,7 +163,8 @@
             int uniqueId, const String8& path, const String8& mimeType) {
     int drmOjectType = DrmObjectType::UNKNOWN;
     if ((EMPTY_STRING != path) || (EMPTY_STRING != mimeType)) {
-         drmOjectType = getDrmManagerService()->getDrmObjectType(uniqueId, path, mimeType);
+         drmOjectType =
+             getDrmManagerService()->getDrmObjectType(uniqueId, path, mimeType);
     }
     return drmOjectType;
 }
@@ -164,35 +173,41 @@
             int uniqueId, const String8& path, int action) {
     int rightsStatus = RightsStatus::RIGHTS_INVALID;
     if (EMPTY_STRING != path) {
-        rightsStatus = getDrmManagerService()->checkRightsStatus(uniqueId, path, action);
+        rightsStatus =
+            getDrmManagerService()->checkRightsStatus(uniqueId, path, action);
     }
     return rightsStatus;
 }
 
 status_t DrmManagerClientImpl::consumeRights(
-            int uniqueId, DecryptHandle* decryptHandle, int action, bool reserve) {
+            int uniqueId, sp<DecryptHandle> &decryptHandle,
+            int action, bool reserve) {
     status_t status = DRM_ERROR_UNKNOWN;
-    if (NULL != decryptHandle) {
-        status = getDrmManagerService()->consumeRights(uniqueId, decryptHandle, action, reserve);
+    if (NULL != decryptHandle.get()) {
+        status = getDrmManagerService()->consumeRights(
+                uniqueId, decryptHandle.get(), action, reserve);
     }
     return status;
 }
 
 status_t DrmManagerClientImpl::setPlaybackStatus(
-            int uniqueId, DecryptHandle* decryptHandle, int playbackStatus, int64_t position) {
+            int uniqueId, sp<DecryptHandle> &decryptHandle,
+            int playbackStatus, int64_t position) {
     status_t status = DRM_ERROR_UNKNOWN;
-    if (NULL != decryptHandle) {
+    if (NULL != decryptHandle.get()) {
         status = getDrmManagerService()->setPlaybackStatus(
-                uniqueId, decryptHandle, playbackStatus, position);
+                uniqueId, decryptHandle.get(), playbackStatus, position);
     }
     return status;
 }
 
 bool DrmManagerClientImpl::validateAction(
-            int uniqueId, const String8& path, int action, const ActionDescription& description) {
+            int uniqueId, const String8& path,
+            int action, const ActionDescription& description) {
     bool retCode = false;
     if (EMPTY_STRING != path) {
-        retCode = getDrmManagerService()->validateAction(uniqueId, path, action, description);
+        retCode = getDrmManagerService()->validateAction(
+                uniqueId, path, action, description);
     }
     return retCode;
 }
@@ -209,7 +224,8 @@
     return getDrmManagerService()->removeAllRights(uniqueId);
 }
 
-int DrmManagerClientImpl::openConvertSession(int uniqueId, const String8& mimeType) {
+int DrmManagerClientImpl::openConvertSession(
+        int uniqueId, const String8& mimeType) {
     int retCode = INVALID_VALUE;
     if (EMPTY_STRING != mimeType) {
         retCode = getDrmManagerService()->openConvertSession(uniqueId, mimeType);
@@ -221,12 +237,14 @@
             int uniqueId, int convertId, const DrmBuffer* inputData) {
     DrmConvertedStatus* drmConvertedStatus = NULL;
     if (NULL != inputData) {
-         drmConvertedStatus = getDrmManagerService()->convertData(uniqueId, convertId, inputData);
+         drmConvertedStatus =
+             getDrmManagerService()->convertData(uniqueId, convertId, inputData);
     }
     return drmConvertedStatus;
 }
 
-DrmConvertedStatus* DrmManagerClientImpl::closeConvertSession(int uniqueId, int convertId) {
+DrmConvertedStatus* DrmManagerClientImpl::closeConvertSession(
+        int uniqueId, int convertId) {
     return getDrmManagerService()->closeConvertSession(uniqueId, convertId);
 }
 
@@ -234,17 +252,19 @@
             int uniqueId, int* length, DrmSupportInfo** drmSupportInfoArray) {
     status_t status = DRM_ERROR_UNKNOWN;
     if ((NULL != drmSupportInfoArray) && (NULL != length)) {
-        status = getDrmManagerService()->getAllSupportInfo(uniqueId, length, drmSupportInfoArray);
+        status = getDrmManagerService()->getAllSupportInfo(
+                uniqueId, length, drmSupportInfoArray);
     }
     return status;
 }
 
-DecryptHandle* DrmManagerClientImpl::openDecryptSession(
+sp<DecryptHandle> DrmManagerClientImpl::openDecryptSession(
             int uniqueId, int fd, off64_t offset, off64_t length) {
     return getDrmManagerService()->openDecryptSession(uniqueId, fd, offset, length);
 }
 
-DecryptHandle* DrmManagerClientImpl::openDecryptSession(int uniqueId, const char* uri) {
+sp<DecryptHandle> DrmManagerClientImpl::openDecryptSession(
+        int uniqueId, const char* uri) {
     DecryptHandle* handle = NULL;
     if (NULL != uri) {
         handle = getDrmManagerService()->openDecryptSession(uniqueId, uri);
@@ -252,50 +272,57 @@
     return handle;
 }
 
-status_t DrmManagerClientImpl::closeDecryptSession(int uniqueId, DecryptHandle* decryptHandle) {
+status_t DrmManagerClientImpl::closeDecryptSession(
+        int uniqueId, sp<DecryptHandle> &decryptHandle) {
     status_t status = DRM_ERROR_UNKNOWN;
-    if (NULL != decryptHandle) {
-        status = getDrmManagerService()->closeDecryptSession( uniqueId, decryptHandle);
+    if (NULL != decryptHandle.get()) {
+        status = getDrmManagerService()->closeDecryptSession(
+                uniqueId, decryptHandle.get());
     }
     return status;
 }
 
-status_t DrmManagerClientImpl::initializeDecryptUnit(int uniqueId, DecryptHandle* decryptHandle,
-            int decryptUnitId, const DrmBuffer* headerInfo) {
+status_t DrmManagerClientImpl::initializeDecryptUnit(
+        int uniqueId, sp<DecryptHandle> &decryptHandle,
+        int decryptUnitId, const DrmBuffer* headerInfo) {
     status_t status = DRM_ERROR_UNKNOWN;
-    if ((NULL != decryptHandle) && (NULL != headerInfo)) {
+    if ((NULL != decryptHandle.get()) && (NULL != headerInfo)) {
         status = getDrmManagerService()->initializeDecryptUnit(
-                uniqueId, decryptHandle, decryptUnitId, headerInfo);
+                uniqueId, decryptHandle.get(), decryptUnitId, headerInfo);
     }
     return status;
 }
 
-status_t DrmManagerClientImpl::decrypt(int uniqueId, DecryptHandle* decryptHandle,
-            int decryptUnitId, const DrmBuffer* encBuffer, DrmBuffer** decBuffer, DrmBuffer* IV) {
+status_t DrmManagerClientImpl::decrypt(
+        int uniqueId, sp<DecryptHandle> &decryptHandle,
+        int decryptUnitId, const DrmBuffer* encBuffer,
+        DrmBuffer** decBuffer, DrmBuffer* IV) {
     status_t status = DRM_ERROR_UNKNOWN;
-    if ((NULL != decryptHandle) && (NULL != encBuffer)
+    if ((NULL != decryptHandle.get()) && (NULL != encBuffer)
         && (NULL != decBuffer) && (NULL != *decBuffer)) {
         status = getDrmManagerService()->decrypt(
-                uniqueId, decryptHandle, decryptUnitId, encBuffer, decBuffer, IV);
+                uniqueId, decryptHandle.get(), decryptUnitId,
+                encBuffer, decBuffer, IV);
     }
     return status;
 }
 
 status_t DrmManagerClientImpl::finalizeDecryptUnit(
-            int uniqueId, DecryptHandle* decryptHandle, int decryptUnitId) {
+            int uniqueId, sp<DecryptHandle> &decryptHandle, int decryptUnitId) {
     status_t status = DRM_ERROR_UNKNOWN;
-    if (NULL != decryptHandle) {
-        status
-            = getDrmManagerService()->finalizeDecryptUnit(uniqueId, decryptHandle, decryptUnitId);
+    if (NULL != decryptHandle.get()) {
+        status = getDrmManagerService()->finalizeDecryptUnit(
+                    uniqueId, decryptHandle.get(), decryptUnitId);
     }
     return status;
 }
 
-ssize_t DrmManagerClientImpl::pread(int uniqueId, DecryptHandle* decryptHandle,
+ssize_t DrmManagerClientImpl::pread(int uniqueId, sp<DecryptHandle> &decryptHandle,
             void* buffer, ssize_t numBytes, off64_t offset) {
     ssize_t retCode = INVALID_VALUE;
-    if ((NULL != decryptHandle) && (NULL != buffer) && (0 < numBytes)) {
-        retCode = getDrmManagerService()->pread(uniqueId, decryptHandle, buffer, numBytes, offset);
+    if ((NULL != decryptHandle.get()) && (NULL != buffer) && (0 < numBytes)) {
+        retCode = getDrmManagerService()->pread(
+                uniqueId, decryptHandle.get(), buffer, numBytes, offset);
     }
     return retCode;
 }
@@ -309,3 +336,16 @@
     return DRM_NO_ERROR;
 }
 
+DrmManagerClientImpl::DeathNotifier::~DeathNotifier() {
+    Mutex::Autolock lock(sMutex);
+    if (NULL != sDrmManagerService.get()) {
+        sDrmManagerService->asBinder()->unlinkToDeath(this);
+    }
+}
+
+void DrmManagerClientImpl::DeathNotifier::binderDied(const wp<IBinder>& who) {
+    Mutex::Autolock lock(sMutex);
+    DrmManagerClientImpl::sDrmManagerService.clear();
+    LOGW("DrmManager server died!");
+}
+
diff --git a/drm/libdrmframework/include/DrmManager.h b/drm/libdrmframework/include/DrmManager.h
index e05366d..af2c2a8 100644
--- a/drm/libdrmframework/include/DrmManager.h
+++ b/drm/libdrmframework/include/DrmManager.h
@@ -30,7 +30,6 @@
 class DrmRegistrationInfo;
 class DrmUnregistrationInfo;
 class DrmRightsAcquisitionInfo;
-class DrmContentIds;
 class DrmConstraints;
 class DrmMetadata;
 class DrmRights;
@@ -141,12 +140,13 @@
     bool canHandle(int uniqueId, const String8& path);
 
 private:
-    static Vector<int> mUniqueIdVector;
+    Vector<int> mUniqueIdVector;
     static const String8 EMPTY_STRING;
 
     int mDecryptSessionId;
     int mConvertId;
     Mutex mLock;
+    Mutex mListenerLock;
     Mutex mDecryptLock;
     Mutex mConvertLock;
     TPlugInManager<IDrmEngine> mPlugInManager;
diff --git a/drm/libdrmframework/include/DrmManagerClientImpl.h b/drm/libdrmframework/include/DrmManagerClientImpl.h
index 0a7fcd1..564896b 100644
--- a/drm/libdrmframework/include/DrmManagerClientImpl.h
+++ b/drm/libdrmframework/include/DrmManagerClientImpl.h
@@ -189,7 +189,7 @@
      * @return status_t
      *     Returns DRM_NO_ERROR for success, DRM_ERROR_UNKNOWN for failure
      */
-    status_t consumeRights(int uniqueId, DecryptHandle* decryptHandle, int action, bool reserve);
+    status_t consumeRights(int uniqueId, sp<DecryptHandle> &decryptHandle, int action, bool reserve);
 
     /**
      * Informs the DRM engine about the playback actions performed on the DRM files.
@@ -203,7 +203,7 @@
      *     Returns DRM_NO_ERROR for success, DRM_ERROR_UNKNOWN for failure
      */
     status_t setPlaybackStatus(
-            int uniqueId, DecryptHandle* decryptHandle, int playbackStatus, int64_t position);
+            int uniqueId, sp<DecryptHandle> &decryptHandle, int playbackStatus, int64_t position);
 
     /**
      * Validates whether an action on the DRM content is allowed or not.
@@ -303,7 +303,7 @@
      * @return
      *     Handle for the decryption session
      */
-    DecryptHandle* openDecryptSession(int uniqueId, int fd, off64_t offset, off64_t length);
+    sp<DecryptHandle> openDecryptSession(int uniqueId, int fd, off64_t offset, off64_t length);
 
     /**
      * Open the decrypt session to decrypt the given protected content
@@ -313,7 +313,7 @@
      * @return
      *     Handle for the decryption session
      */
-    DecryptHandle* openDecryptSession(int uniqueId, const char* uri);
+    sp<DecryptHandle> openDecryptSession(int uniqueId, const char* uri);
 
     /**
      * Close the decrypt session for the given handle
@@ -323,7 +323,7 @@
      * @return status_t
      *     Returns DRM_NO_ERROR for success, DRM_ERROR_UNKNOWN for failure
      */
-    status_t closeDecryptSession(int uniqueId, DecryptHandle* decryptHandle);
+    status_t closeDecryptSession(int uniqueId, sp<DecryptHandle> &decryptHandle);
 
     /**
      * Initialize decryption for the given unit of the protected content
@@ -335,7 +335,7 @@
      * @return status_t
      *     Returns DRM_NO_ERROR for success, DRM_ERROR_UNKNOWN for failure
      */
-    status_t initializeDecryptUnit(int uniqueId, DecryptHandle* decryptHandle,
+    status_t initializeDecryptUnit(int uniqueId, sp<DecryptHandle> &decryptHandle,
             int decryptUnitId, const DrmBuffer* headerInfo);
 
     /**
@@ -355,7 +355,7 @@
      *     DRM_ERROR_SESSION_NOT_OPENED, DRM_ERROR_DECRYPT_UNIT_NOT_INITIALIZED,
      *     DRM_ERROR_DECRYPT for failure.
      */
-    status_t decrypt(int uniqueId, DecryptHandle* decryptHandle, int decryptUnitId,
+    status_t decrypt(int uniqueId, sp<DecryptHandle> &decryptHandle, int decryptUnitId,
             const DrmBuffer* encBuffer, DrmBuffer** decBuffer, DrmBuffer* IV);
 
     /**
@@ -367,7 +367,7 @@
      * @return status_t
      *     Returns DRM_NO_ERROR for success, DRM_ERROR_UNKNOWN for failure
      */
-    status_t finalizeDecryptUnit(int uniqueId, DecryptHandle* decryptHandle, int decryptUnitId);
+    status_t finalizeDecryptUnit(int uniqueId, sp<DecryptHandle> &decryptHandle, int decryptUnitId);
 
     /**
      * Reads the specified number of bytes from an open DRM file.
@@ -380,7 +380,7 @@
      *
      * @return Number of bytes read. Returns -1 for Failure.
      */
-    ssize_t pread(int uniqueId, DecryptHandle* decryptHandle,
+    ssize_t pread(int uniqueId, sp<DecryptHandle> &decryptHandle,
             void* buffer, ssize_t numBytes, off64_t offset);
 
     /**
@@ -407,9 +407,17 @@
     Mutex mLock;
     sp<DrmManagerClient::OnInfoListener> mOnInfoListener;
 
+    class DeathNotifier: public IBinder::DeathRecipient {
+        public:
+            DeathNotifier() {}
+            virtual ~DeathNotifier();
+            virtual void binderDied(const wp<IBinder>& who);
+    };
+
 private:
-    static Mutex mMutex;
-    static sp<IDrmManagerService> mDrmManagerService;
+    static Mutex sMutex;
+    static sp<DeathNotifier> sDeathNotifier;
+    static sp<IDrmManagerService> sDrmManagerService;
     static const sp<IDrmManagerService>& getDrmManagerService();
     static const String8 EMPTY_STRING;
 };
diff --git a/drm/libdrmframework/include/DrmManagerService.h b/drm/libdrmframework/include/DrmManagerService.h
index d0a0db7..227496a 100644
--- a/drm/libdrmframework/include/DrmManagerService.h
+++ b/drm/libdrmframework/include/DrmManagerService.h
@@ -115,6 +115,8 @@
     ssize_t pread(int uniqueId, DecryptHandle* decryptHandle,
             void* buffer, ssize_t numBytes, off64_t offset);
 
+    virtual status_t dump(int fd, const Vector<String16>& args);
+
 private:
     DrmManager* mDrmManager;
 };
diff --git a/drm/libdrmframework/include/IDrmManagerService.h b/drm/libdrmframework/include/IDrmManagerService.h
index 2424ea5..7727e55 100644
--- a/drm/libdrmframework/include/IDrmManagerService.h
+++ b/drm/libdrmframework/include/IDrmManagerService.h
@@ -25,7 +25,6 @@
 
 namespace android {
 
-class DrmContentIds;
 class DrmConstraints;
 class DrmMetadata;
 class DrmRights;
diff --git a/drm/libdrmframework/include/PlugInManager.h b/drm/libdrmframework/include/PlugInManager.h
index 9ad195f..8029138 100644
--- a/drm/libdrmframework/include/PlugInManager.h
+++ b/drm/libdrmframework/include/PlugInManager.h
@@ -230,11 +230,9 @@
      */
     bool isPlugIn(const struct dirent* pEntry) const {
         String8 sName(pEntry->d_name);
-        int extentionPos = sName.size() - String8(PLUGIN_EXTENSION).size();
-        if (extentionPos < 0) {
-            return false;
-        }
-        return extentionPos == (int)sName.find(PLUGIN_EXTENSION);
+        String8 extension(sName.getPathExtension());
+        // Note that the plug-in extension must exactly match case
+        return extension == String8(PLUGIN_EXTENSION);
     }
 
     /**
diff --git a/drm/libdrmframework/include/StringTokenizer.h b/drm/libdrmframework/include/StringTokenizer.h
deleted file mode 100644
index 70e7558..0000000
--- a/drm/libdrmframework/include/StringTokenizer.h
+++ /dev/null
@@ -1,87 +0,0 @@
-/*
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef __STRING_TOKENIZER_H__
-#define __STRING_TOKENIZER_H__
-
-#include <drm/drm_framework_common.h>
-
-namespace android {
-
-/**
- * This is an utility class for String manipulation.
- *
- */
-class StringTokenizer {
-public:
-    /**
-     * Iterator for string tokens
-     */
-    class Iterator {
-        friend class StringTokenizer;
-    private:
-        Iterator(StringTokenizer* StringTokenizer)
-         : mStringTokenizer(StringTokenizer), mIndex(0) {}
-
-    public:
-        Iterator(const Iterator& iterator);
-        Iterator& operator=(const Iterator& iterator);
-        virtual ~Iterator() {}
-
-    public:
-        bool hasNext();
-        String8& next();
-
-    private:
-        StringTokenizer* mStringTokenizer;
-        unsigned int mIndex;
-    };
-
-public:
-    /**
-     * Constructor for StringTokenizer
-     *
-     * @param[in] string Complete string data
-     * @param[in] delimeter Delimeter used to split the string
-     */
-    StringTokenizer(const String8& string, const String8& delimeter);
-
-    /**
-     * Destructor for StringTokenizer
-     */
-    ~StringTokenizer() {}
-
-private:
-    /**
-     * Splits the string according to the delimeter
-     */
-    void splitString(const String8& string, const String8& delimeter);
-
-public:
-    /**
-     * Returns Iterator object to walk through the split string values
-     *
-     * @return Iterator object
-     */
-    Iterator iterator();
-
-private:
-    Vector<String8> mStringTokenizerVector;
-};
-
-};
-#endif /* __STRING_TOKENIZER_H__ */
-
diff --git a/drm/libdrmframework/plugins/common/include/IDrmEngine.h b/drm/libdrmframework/plugins/common/include/IDrmEngine.h
index d05c24f..77460f6 100644
--- a/drm/libdrmframework/plugins/common/include/IDrmEngine.h
+++ b/drm/libdrmframework/plugins/common/include/IDrmEngine.h
@@ -21,7 +21,6 @@
 
 namespace android {
 
-class DrmContentIds;
 class DrmConstraints;
 class DrmMetadata;
 class DrmRights;
diff --git a/drm/libdrmframework/plugins/forward-lock/FwdLockEngine/Android.mk b/drm/libdrmframework/plugins/forward-lock/FwdLockEngine/Android.mk
index af67aa3..9805a40 100644
--- a/drm/libdrmframework/plugins/forward-lock/FwdLockEngine/Android.mk
+++ b/drm/libdrmframework/plugins/forward-lock/FwdLockEngine/Android.mk
@@ -47,7 +47,7 @@
     libfwdlock-converter \
     libfwdlock-decoder
 
-LOCAL_PRELINK_MODULE := false
+
 
 LOCAL_C_INCLUDES += \
     $(JNI_H_INCLUDE) \
diff --git a/drm/libdrmframework/plugins/passthru/Android.mk b/drm/libdrmframework/plugins/passthru/Android.mk
index 7856d37..be18b64 100644
--- a/drm/libdrmframework/plugins/passthru/Android.mk
+++ b/drm/libdrmframework/plugins/passthru/Android.mk
@@ -32,7 +32,7 @@
  LOCAL_SHARED_LIBRARIES += libdl
 endif
 
-LOCAL_PRELINK_MODULE := false
+
 
 LOCAL_C_INCLUDES += \
     $(TOP)/frameworks/base/drm/libdrmframework/include \
diff --git a/graphics/java/android/graphics/SurfaceTexture.java b/graphics/java/android/graphics/SurfaceTexture.java
index 970b207..b8327a8 100644
--- a/graphics/java/android/graphics/SurfaceTexture.java
+++ b/graphics/java/android/graphics/SurfaceTexture.java
@@ -144,6 +144,21 @@
         nativeGetTransformMatrix(mtx);
     }
 
+    /**
+     * Retrieve the timestamp associated with the texture image set by the most recent call to
+     * updateTexImage.
+     *
+     * This timestamp is in nanoseconds, and is guaranteed to be monotonically increasing. The
+     * specific meaning and zero point of the timestamp depends on the source providing images to
+     * the SurfaceTexture. Unless otherwise specified by the image source, timestamps cannot
+     * generally be compared across SurfaceTexture instances, or across multiple program
+     * invocations. It is mostly useful for determining time offsets between subsequent frames.
+     * @hide
+     */
+    public long getTimestamp() {
+        return nativeGetTimestamp();
+    }
+
     protected void finalize() throws Throwable {
         try {
             nativeFinalize();
@@ -182,6 +197,7 @@
     private native void nativeInit(int texName, Object weakSelf);
     private native void nativeFinalize();
     private native void nativeGetTransformMatrix(float[] mtx);
+    private native long nativeGetTimestamp();
     private native void nativeUpdateTexImage();
 
     /*
diff --git a/graphics/java/android/renderscript/BaseObj.java b/graphics/java/android/renderscript/BaseObj.java
index 669beac..8ce1d9a 100644
--- a/graphics/java/android/renderscript/BaseObj.java
+++ b/graphics/java/android/renderscript/BaseObj.java
@@ -75,11 +75,17 @@
      * @param name The name to assign to the object.
      */
     public void setName(String name) {
+        if (name == null) {
+            throw new RSIllegalArgumentException(
+                "setName requires a string of non-zero length.");
+        }
         if(name.length() < 1) {
-            throw new RSIllegalArgumentException("setName does not accept a zero length string.");
+            throw new RSIllegalArgumentException(
+                "setName does not accept a zero length string.");
         }
         if(mName != null) {
-            throw new RSIllegalArgumentException("setName object already has a name.");
+            throw new RSIllegalArgumentException(
+                "setName object already has a name.");
         }
 
         try {
@@ -106,9 +112,9 @@
     }
 
     /**
-     * destroy disconnects the object from the native object effectivly
+     * destroy disconnects the object from the native object effectively
      * rendering this java object dead.  The primary use is to force immediate
-     * cleanup of resources when its believed the GC will not respond quickly
+     * cleanup of resources when it is believed the GC will not respond quickly
      * enough.
      */
     synchronized public void destroy() {
diff --git a/graphics/java/android/renderscript/Matrix2f.java b/graphics/java/android/renderscript/Matrix2f.java
index 78ff97b..acc5bd8 100644
--- a/graphics/java/android/renderscript/Matrix2f.java
+++ b/graphics/java/android/renderscript/Matrix2f.java
@@ -42,7 +42,7 @@
     *                  floats long
     */
     public Matrix2f(float[] dataArray) {
-        mMat = new float[2];
+        mMat = new float[4];
         System.arraycopy(dataArray, 0, mMat, 0, mMat.length);
     }
 
diff --git a/graphics/java/android/renderscript/RenderScript.java b/graphics/java/android/renderscript/RenderScript.java
index 1b10c5c..f577532 100644
--- a/graphics/java/android/renderscript/RenderScript.java
+++ b/graphics/java/android/renderscript/RenderScript.java
@@ -83,17 +83,17 @@
                  int alphaMin, int alphaPref,
                  int depthMin, int depthPref,
                  int stencilMin, int stencilPref,
-                 int samplesMin, int samplesPref, float samplesQ);
+                 int samplesMin, int samplesPref, float samplesQ, int dpi);
     synchronized int nContextCreateGL(int dev, int ver,
                  int colorMin, int colorPref,
                  int alphaMin, int alphaPref,
                  int depthMin, int depthPref,
                  int stencilMin, int stencilPref,
-                 int samplesMin, int samplesPref, float samplesQ) {
+                 int samplesMin, int samplesPref, float samplesQ, int dpi) {
         return rsnContextCreateGL(dev, ver, colorMin, colorPref,
                                   alphaMin, alphaPref, depthMin, depthPref,
                                   stencilMin, stencilPref,
-                                  samplesMin, samplesPref, samplesQ);
+                                  samplesMin, samplesPref, samplesQ, dpi);
     }
     native int  rsnContextCreate(int dev, int ver);
     synchronized int nContextCreate(int dev, int ver) {
@@ -457,20 +457,11 @@
         rsnScriptSetVarObj(mContext, id, slot, val);
     }
 
-    native void rsnScriptCBegin(int con);
-    synchronized void nScriptCBegin() {
+    native int  rsnScriptCCreate(int con, String resName, String cacheDir,
+                                 byte[] script, int length);
+    synchronized int nScriptCCreate(String resName, String cacheDir, byte[] script, int length) {
         validate();
-        rsnScriptCBegin(mContext);
-    }
-    native void rsnScriptCSetScript(int con, byte[] script, int offset, int length);
-    synchronized void nScriptCSetScript(byte[] script, int offset, int length) {
-        validate();
-        rsnScriptCSetScript(mContext, script, offset, length);
-    }
-    native int  rsnScriptCCreate(int con, String packageName, String resName, String cacheDir);
-    synchronized int nScriptCCreate(String packageName, String resName, String cacheDir) {
-        validate();
-        return rsnScriptCCreate(mContext, packageName, resName, cacheDir);
+        return rsnScriptCCreate(mContext, resName, cacheDir, script, length);
     }
 
     native void rsnSamplerBegin(int con);
diff --git a/graphics/java/android/renderscript/RenderScriptGL.java b/graphics/java/android/renderscript/RenderScriptGL.java
index 4359795..d4b5434 100644
--- a/graphics/java/android/renderscript/RenderScriptGL.java
+++ b/graphics/java/android/renderscript/RenderScriptGL.java
@@ -165,13 +165,14 @@
         mWidth = 0;
         mHeight = 0;
         mDev = nDeviceCreate();
+        int dpi = ctx.getResources().getDisplayMetrics().densityDpi;
         mContext = nContextCreateGL(mDev, 0,
                                     mSurfaceConfig.mColorMin, mSurfaceConfig.mColorPref,
                                     mSurfaceConfig.mAlphaMin, mSurfaceConfig.mAlphaPref,
                                     mSurfaceConfig.mDepthMin, mSurfaceConfig.mDepthPref,
                                     mSurfaceConfig.mStencilMin, mSurfaceConfig.mStencilPref,
                                     mSurfaceConfig.mSamplesMin, mSurfaceConfig.mSamplesPref,
-                                    mSurfaceConfig.mSamplesQ);
+                                    mSurfaceConfig.mSamplesQ, dpi);
         if (mContext == 0) {
             throw new RSDriverException("Failed to create RS context.");
         }
diff --git a/graphics/java/android/renderscript/ScriptC.java b/graphics/java/android/renderscript/ScriptC.java
index 9445283..f865753 100644
--- a/graphics/java/android/renderscript/ScriptC.java
+++ b/graphics/java/android/renderscript/ScriptC.java
@@ -92,16 +92,13 @@
             throw new Resources.NotFoundException();
         }
 
-        rs.nScriptCBegin();
-        rs.nScriptCSetScript(pgm, 0, pgmLength);
-
         // E.g, /system/apps/Fountain.apk
-        String packageName = rs.getApplicationContext().getPackageResourcePath();
+        //String packageName = rs.getApplicationContext().getPackageResourcePath();
         // For res/raw/fountain.bc, it wil be /com.android.fountain:raw/fountain
         String resName = resources.getResourceName(resourceID);
         String cacheDir = rs.getApplicationContext().getCacheDir().toString();
 
         Log.v(TAG, "Create script for resource = " + resName);
-        return rs.nScriptCCreate(packageName, resName, cacheDir);
+        return rs.nScriptCCreate(resName, cacheDir, pgm, pgmLength);
     }
 }
diff --git a/graphics/jni/android_renderscript_RenderScript.cpp b/graphics/jni/android_renderscript_RenderScript.cpp
index f86343a..c7f4809 100644
--- a/graphics/jni/android_renderscript_RenderScript.cpp
+++ b/graphics/jni/android_renderscript_RenderScript.cpp
@@ -164,7 +164,8 @@
                  int alphaMin, int alphaPref,
                  int depthMin, int depthPref,
                  int stencilMin, int stencilPref,
-                 int samplesMin, int samplesPref, float samplesQ)
+                 int samplesMin, int samplesPref, float samplesQ,
+                 int dpi)
 {
     RsSurfaceConfig sc;
     sc.alphaMin = alphaMin;
@@ -178,7 +179,7 @@
     sc.samplesQ = samplesQ;
 
     LOG_API("nContextCreateGL");
-    return (jint)rsContextCreateGL((RsDevice)dev, ver, sc);
+    return (jint)rsContextCreateGL((RsDevice)dev, ver, sc, dpi);
 }
 
 static void
@@ -847,65 +848,51 @@
 
 // -----------------------------------
 
-static void
-nScriptCBegin(JNIEnv *_env, jobject _this, RsContext con)
+static jint
+nScriptCCreate(JNIEnv *_env, jobject _this, RsContext con,
+               jstring resName, jstring cacheDir,
+               jbyteArray scriptRef, jint length)
 {
-    LOG_API("nScriptCBegin, con(%p)", con);
-    rsScriptCBegin(con);
-}
+    LOG_API("nScriptCCreate, con(%p)", con);
 
-static void
-nScriptCSetScript(JNIEnv *_env, jobject _this, RsContext con, jbyteArray scriptRef,
-                  jint offset, jint length)
-{
-    LOG_API("!!! nScriptCSetScript, con(%p)", con);
+    AutoJavaStringToUTF8 resNameUTF(_env, resName);
+    AutoJavaStringToUTF8 cacheDirUTF(_env, cacheDir);
+    jint ret = 0;
+
     jint _exception = 0;
     jint remaining;
-    jbyte* script_base = 0;
     jbyte* script_ptr;
     if (!scriptRef) {
         _exception = 1;
         //_env->ThrowNew(IAEClass, "script == null");
         goto exit;
     }
-    if (offset < 0) {
-        _exception = 1;
-        //_env->ThrowNew(IAEClass, "offset < 0");
-        goto exit;
-    }
     if (length < 0) {
         _exception = 1;
         //_env->ThrowNew(IAEClass, "length < 0");
         goto exit;
     }
-    remaining = _env->GetArrayLength(scriptRef) - offset;
+    remaining = _env->GetArrayLength(scriptRef);
     if (remaining < length) {
         _exception = 1;
         //_env->ThrowNew(IAEClass, "length > script.length - offset");
         goto exit;
     }
-    script_base = (jbyte *)
+    script_ptr = (jbyte *)
         _env->GetPrimitiveArrayCritical(scriptRef, (jboolean *)0);
-    script_ptr = script_base + offset;
 
-    rsScriptCSetText(con, (const char *)script_ptr, length);
+    //rsScriptCSetText(con, (const char *)script_ptr, length);
+
+    ret = (jint)rsScriptCCreate(con, resNameUTF.c_str(), cacheDirUTF.c_str(),
+                                (const char *)script_ptr, length);
 
 exit:
-    if (script_base) {
-        _env->ReleasePrimitiveArrayCritical(scriptRef, script_base,
+    if (script_ptr) {
+        _env->ReleasePrimitiveArrayCritical(scriptRef, script_ptr,
                 _exception ? JNI_ABORT: 0);
     }
-}
 
-static jint
-nScriptCCreate(JNIEnv *_env, jobject _this, RsContext con, jstring packageName, jstring resName, jstring cacheDir)
-{
-    LOG_API("nScriptCCreate, con(%p)", con);
-    AutoJavaStringToUTF8 packageNameUTF(_env, packageName);
-    AutoJavaStringToUTF8 resNameUTF(_env, resName);
-    AutoJavaStringToUTF8 cacheDirUTF(_env, cacheDir);
-    jint i = (jint)rsScriptCCreate(con, packageNameUTF.c_str(), resNameUTF.c_str(), cacheDirUTF.c_str());
-    return i;
+    return ret;
 }
 
 // ---------------------------------------------------------------------------
@@ -1213,7 +1200,7 @@
 
 // All methods below are thread protected in java.
 {"rsnContextCreate",                 "(II)I",                                 (void*)nContextCreate },
-{"rsnContextCreateGL",               "(IIIIIIIIIIIIF)I",                      (void*)nContextCreateGL },
+{"rsnContextCreateGL",               "(IIIIIIIIIIIIFI)I",                     (void*)nContextCreateGL },
 {"rsnContextFinish",                 "(I)V",                                  (void*)nContextFinish },
 {"rsnContextSetPriority",            "(II)V",                                 (void*)nContextSetPriority },
 {"rsnContextSetSurface",             "(IIILandroid/view/Surface;)V",          (void*)nContextSetSurface },
@@ -1281,9 +1268,7 @@
 {"rsnScriptSetVarV",                 "(III[B)V",                              (void*)nScriptSetVarV },
 {"rsnScriptSetVarObj",               "(IIII)V",                               (void*)nScriptSetVarObj },
 
-{"rsnScriptCBegin",                  "(I)V",                                  (void*)nScriptCBegin },
-{"rsnScriptCSetScript",              "(I[BII)V",                              (void*)nScriptCSetScript },
-{"rsnScriptCCreate",                 "(ILjava/lang/String;Ljava/lang/String;Ljava/lang/String;)I",  (void*)nScriptCCreate },
+{"rsnScriptCCreate",                 "(ILjava/lang/String;Ljava/lang/String;[BI)I",  (void*)nScriptCCreate },
 
 {"rsnProgramStoreBegin",             "(III)V",                                (void*)nProgramStoreBegin },
 {"rsnProgramStoreDepthFunc",         "(II)V",                                 (void*)nProgramStoreDepthFunc },
diff --git a/include/android_runtime/android_graphics_SurfaceTexture.h b/include/android_runtime/android_graphics_SurfaceTexture.h
new file mode 100644
index 0000000..8e6fc6e
--- /dev/null
+++ b/include/android_runtime/android_graphics_SurfaceTexture.h
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef _ANDROID_GRAPHICS_SURFACETEXTURE_H
+#define _ANDROID_GRAPHICS_SURFACETEXTURE_H
+
+#include <android/native_window.h>
+
+#include "jni.h"
+
+namespace android {
+
+extern sp<ANativeWindow> android_SurfaceTexture_getNativeWindow(
+        JNIEnv* env, jobject thiz);
+
+} // namespace android
+
+#endif // _ANDROID_GRAPHICS_SURFACETEXTURE_H
diff --git a/include/drm/DrmInfoEvent.h b/include/drm/DrmInfoEvent.h
index 7b409ff..dfca228 100644
--- a/include/drm/DrmInfoEvent.h
+++ b/include/drm/DrmInfoEvent.h
@@ -43,6 +43,8 @@
     //! TYPE_ACCOUNT_ALREADY_REGISTERED, when registration has been
     //! already done for the given account.
     static const int TYPE_ACCOUNT_ALREADY_REGISTERED = 5;
+    //! TYPE_RIGHTS_REMOVED, when the rights has been removed.
+    static const int TYPE_RIGHTS_REMOVED = 6;
 
     /**
      * The following constant values should be in sync with DrmErrorEvent.java
@@ -61,6 +63,11 @@
     static const int TYPE_NO_INTERNET_CONNECTION = 2005;
     //! TYPE_PROCESS_DRM_INFO_FAILED, when failed to process DrmInfo.
     static const int TYPE_PROCESS_DRM_INFO_FAILED = 2006;
+    //! TYPE_REMOVE_ALL_RIGHTS_FAILED, when failed to remove all the rights objects
+    //! associated with all DRM schemes.
+    static const int TYPE_REMOVE_ALL_RIGHTS_FAILED = 2007;
+    //! TYPE_ACQUIRE_DRM_INFO_FAILED, when failed to acquire DrmInfo.
+    static const int TYPE_ACQUIRE_DRM_INFO_FAILED = 2008;
 
 public:
     /**
@@ -70,7 +77,7 @@
      * @param[in] infoType Type of information
      * @param[in] message Message description
      */
-    DrmInfoEvent(int uniqueId, int infoType, const String8& message);
+    DrmInfoEvent(int uniqueId, int infoType, const String8 message);
 
     /**
      * Destructor for DrmInfoEvent
@@ -97,12 +104,12 @@
      *
      * @return Message description
      */
-    const String8& getMessage() const;
+    const String8 getMessage() const;
 
 private:
     int mUniqueId;
     int mInfoType;
-    const String8& mMessage;
+    const String8 mMessage;
 };
 
 };
diff --git a/include/drm/DrmManagerClient.h b/include/drm/DrmManagerClient.h
index 085ebf1..5011137 100644
--- a/include/drm/DrmManagerClient.h
+++ b/include/drm/DrmManagerClient.h
@@ -69,7 +69,7 @@
      * @return
      *     Handle for the decryption session
      */
-    DecryptHandle* openDecryptSession(int fd, off64_t offset, off64_t length);
+    sp<DecryptHandle> openDecryptSession(int fd, off64_t offset, off64_t length);
 
     /**
      * Open the decrypt session to decrypt the given protected content
@@ -78,7 +78,7 @@
      * @return
      *     Handle for the decryption session
      */
-    DecryptHandle* openDecryptSession(const char* uri);
+    sp<DecryptHandle> openDecryptSession(const char* uri);
 
     /**
      * Close the decrypt session for the given handle
@@ -87,7 +87,7 @@
      * @return status_t
      *     Returns DRM_NO_ERROR for success, DRM_ERROR_UNKNOWN for failure
      */
-    status_t closeDecryptSession(DecryptHandle* decryptHandle);
+    status_t closeDecryptSession(sp<DecryptHandle> &decryptHandle);
 
     /**
      * Consumes the rights for a content.
@@ -101,7 +101,7 @@
      *     Returns DRM_NO_ERROR for success, DRM_ERROR_UNKNOWN for failure.
      *     In case license has been expired, DRM_ERROR_LICENSE_EXPIRED will be returned.
      */
-    status_t consumeRights(DecryptHandle* decryptHandle, int action, bool reserve);
+    status_t consumeRights(sp<DecryptHandle> &decryptHandle, int action, bool reserve);
 
     /**
      * Informs the DRM engine about the playback actions performed on the DRM files.
@@ -113,7 +113,8 @@
      * @return status_t
      *     Returns DRM_NO_ERROR for success, DRM_ERROR_UNKNOWN for failure
      */
-    status_t setPlaybackStatus(DecryptHandle* decryptHandle, int playbackStatus, int64_t position);
+    status_t setPlaybackStatus(
+            sp<DecryptHandle> &decryptHandle, int playbackStatus, int64_t position);
 
     /**
      * Initialize decryption for the given unit of the protected content
@@ -125,7 +126,7 @@
      *     Returns DRM_NO_ERROR for success, DRM_ERROR_UNKNOWN for failure
      */
     status_t initializeDecryptUnit(
-            DecryptHandle* decryptHandle, int decryptUnitId, const DrmBuffer* headerInfo);
+            sp<DecryptHandle> &decryptHandle, int decryptUnitId, const DrmBuffer* headerInfo);
 
     /**
      * Decrypt the protected content buffers for the given unit
@@ -144,7 +145,7 @@
      *     DRM_ERROR_DECRYPT for failure.
      */
     status_t decrypt(
-            DecryptHandle* decryptHandle, int decryptUnitId,
+            sp<DecryptHandle> &decryptHandle, int decryptUnitId,
             const DrmBuffer* encBuffer, DrmBuffer** decBuffer, DrmBuffer* IV = NULL);
 
     /**
@@ -155,7 +156,8 @@
      * @return status_t
      *     Returns DRM_NO_ERROR for success, DRM_ERROR_UNKNOWN for failure
      */
-    status_t finalizeDecryptUnit(DecryptHandle* decryptHandle, int decryptUnitId);
+    status_t finalizeDecryptUnit(
+            sp<DecryptHandle> &decryptHandle, int decryptUnitId);
 
     /**
      * Reads the specified number of bytes from an open DRM file.
@@ -167,7 +169,8 @@
      *
      * @return Number of bytes read. Returns -1 for Failure.
      */
-    ssize_t pread(DecryptHandle* decryptHandle, void* buffer, ssize_t numBytes, off64_t offset);
+    ssize_t pread(sp<DecryptHandle> &decryptHandle,
+            void* buffer, ssize_t numBytes, off64_t offset);
 
     /**
      * Validates whether an action on the DRM content is allowed or not.
@@ -365,7 +368,6 @@
 
 private:
     int mUniqueId;
-    Mutex mDecryptLock;
     DrmManagerClientImpl* mDrmManagerClientImpl;
 };
 
diff --git a/include/drm/drm_framework_common.h b/include/drm/drm_framework_common.h
index 1758cdd..d2d1d7e 100644
--- a/include/drm/drm_framework_common.h
+++ b/include/drm/drm_framework_common.h
@@ -19,6 +19,7 @@
 
 #include <utils/Vector.h>
 #include <utils/KeyedVector.h>
+#include <utils/RefBase.h>
 #include <utils/String8.h>
 #include <utils/Errors.h>
 
@@ -43,6 +44,17 @@
 };
 
 /**
+ * copy control settings used in DecryptHandle::copyControlVector
+ */
+enum DrmCopyControl {
+    DRM_COPY_CONTROL_BASE = 1000,
+    // the key used to set the value for HDCP
+    // if the associated value is 1, then HDCP is required
+    // otherwise, HDCP is not required
+    DRM_COPY_CONTROL_HDCP = DRM_COPY_CONTROL_BASE
+};
+
+/**
  * Defines DRM Buffer
  */
 class DrmBuffer {
@@ -240,7 +252,7 @@
 /**
  * Defines decryption handle
  */
-class DecryptHandle {
+class DecryptHandle : public RefBase {
 public:
     /**
      * Decryption session Handle
@@ -279,16 +291,32 @@
      * e.g. size of memory to be allocated to get the decrypted content.
      */
     DecryptInfo* decryptInfo;
+    /**
+     * Defines a vector for the copy control settings sent from the DRM plugin
+     * to the player
+     */
+    KeyedVector<DrmCopyControl, int> copyControlVector;
+
+    /**
+     * Defines a vector for any extra data the DRM plugin wants to send
+     * to the native code
+     */
+    KeyedVector<String8, String8> extendedData;
 
 public:
     DecryptHandle():
             decryptId(INVALID_VALUE),
             mimeType(""),
             decryptApiType(INVALID_VALUE),
-            status(INVALID_VALUE) {
+            status(INVALID_VALUE),
+            decryptInfo(NULL) {
 
     }
 
+    ~DecryptHandle() {
+        delete decryptInfo; decryptInfo = NULL;
+    }
+
     bool operator<(const DecryptHandle& handle) const {
         return (decryptId < handle.decryptId);
     }
diff --git a/include/gui/ISurfaceTexture.h b/include/gui/ISurfaceTexture.h
index 168310c..6ed3c6f 100644
--- a/include/gui/ISurfaceTexture.h
+++ b/include/gui/ISurfaceTexture.h
@@ -62,8 +62,11 @@
     // contents of the buffer associated with slot and transfers ownership of
     // that slot back to the server. It is not valid to call queueBuffer on a
     // slot that is not owned by the client or one for which a buffer associated
-    // via requestBuffer.
-    virtual status_t queueBuffer(int slot) = 0;
+    // via requestBuffer. In addition, a timestamp must be provided by the
+    // client for this buffer. The timestamp is measured in nanoseconds, and
+    // must be monotonically increasing. Its other properties (zero point, etc)
+    // are client-dependent, and should be documented by the client.
+    virtual status_t queueBuffer(int slot, int64_t timestamp) = 0;
 
     // cancelBuffer indicates that the client does not wish to fill in the
     // buffer associated with slot and transfers ownership of the slot back to
diff --git a/include/gui/SurfaceTexture.h b/include/gui/SurfaceTexture.h
index 9bf38f7..afa64d3 100644
--- a/include/gui/SurfaceTexture.h
+++ b/include/gui/SurfaceTexture.h
@@ -66,7 +66,12 @@
     // unmodified.
     virtual status_t dequeueBuffer(int *buf);
 
-    virtual status_t queueBuffer(int buf);
+    // queueBuffer returns a filled buffer to the SurfaceTexture. In addition, a
+    // timestamp must be provided for the buffer. The timestamp is in
+    // nanoseconds, and must be monotonically increasing. Its other semantics
+    // (zero point, etc) are client-dependent and should be documented by the
+    // client.
+    virtual status_t queueBuffer(int buf, int64_t timestamp);
     virtual void cancelBuffer(int buf);
     virtual status_t setCrop(const Rect& reg);
     virtual status_t setTransform(uint32_t transform);
@@ -98,6 +103,14 @@
     // functions.
     void getTransformMatrix(float mtx[16]);
 
+    // getTimestamp retrieves the timestamp associated with the texture image
+    // set by the most recent call to updateTexImage.
+    //
+    // The timestamp is in nanoseconds, and is monotonically increasing. Its
+    // other semantics (zero point, etc) are source-dependent and should be
+    // documented by the source.
+    int64_t getTimestamp();
+
     // setFrameAvailableListener sets the listener object that will be notified
     // when a new frame becomes available.
     void setFrameAvailableListener(const sp<FrameAvailableListener>& l);
@@ -172,6 +185,10 @@
     // gets set to mLastQueuedTransform each time updateTexImage is called.
     uint32_t mCurrentTransform;
 
+    // mCurrentTimestamp is the timestamp for the current texture. It
+    // gets set to mLastQueuedTimestamp each time updateTexImage is called.
+    int64_t mCurrentTimestamp;
+
     // mLastQueued is the buffer slot index of the most recently enqueued buffer.
     // At construction time it is initialized to INVALID_BUFFER_SLOT, and is
     // updated each time queueBuffer is called.
@@ -187,6 +204,10 @@
     // queueBuffer gets called.
     uint32_t mLastQueuedTransform;
 
+    // mLastQueuedTimestamp is the timestamp for the buffer that was most
+    // recently queued. This gets set by queueBuffer.
+    int64_t mLastQueuedTimestamp;
+
     // mNextCrop is the crop rectangle that will be used for the next buffer
     // that gets queued. It is set by calling setCrop.
     Rect mNextCrop;
diff --git a/include/gui/SurfaceTextureClient.h b/include/gui/SurfaceTextureClient.h
index 4cdece9..df82bf2 100644
--- a/include/gui/SurfaceTextureClient.h
+++ b/include/gui/SurfaceTextureClient.h
@@ -33,6 +33,8 @@
 public:
     SurfaceTextureClient(const sp<ISurfaceTexture>& surfaceTexture);
 
+    sp<ISurfaceTexture> getISurfaceTexture() const;
+
 private:
 
     // can't be copied
@@ -61,6 +63,7 @@
     int dispatchSetBufferCount(va_list args);
     int dispatchSetBuffersGeometry(va_list args);
     int dispatchSetBuffersTransform(va_list args);
+    int dispatchSetBuffersTimestamp(va_list args);
     int dispatchSetCrop(va_list args);
     int dispatchSetUsage(va_list args);
 
@@ -69,6 +72,7 @@
     int setBufferCount(int bufferCount);
     int setBuffersGeometry(int w, int h, int format);
     int setBuffersTransform(int transform);
+    int setBuffersTimestamp(int64_t timestamp);
     int setCrop(Rect const* rect);
     int setUsage(uint32_t reqUsage);
 
@@ -112,6 +116,11 @@
     // at the next deuque operation. It is initialized to 0.
     uint32_t mReqUsage;
 
+    // mTimestamp is the timestamp that will be used for the next buffer queue
+    // operation. It defaults to NATIVE_WINDOW_TIMESTAMP_AUTO, which means that
+    // a timestamp is auto-generated when queueBuffer is called.
+    int64_t mTimestamp;
+
     // mMutex is the mutex used to prevent concurrent access to the member
     // variables of SurfaceTexture objects. It must be locked whenever the
     // member variables are accessed.
diff --git a/include/media/AudioRecord.h b/include/media/AudioRecord.h
index 5f7cd90..293764d 100644
--- a/include/media/AudioRecord.h
+++ b/include/media/AudioRecord.h
@@ -346,12 +346,14 @@
     };
 
             bool processAudioBuffer(const sp<ClientRecordThread>& thread);
-            status_t openRecord(uint32_t sampleRate,
+            status_t openRecord_l(uint32_t sampleRate,
                                 int format,
                                 int channelCount,
                                 int frameCount,
                                 uint32_t flags,
                                 audio_io_handle_t input);
+            audio_io_handle_t getInput_l();
+            status_t restoreRecord_l(audio_track_cblk_t*& cblk);
 
     sp<IAudioRecord>        mAudioRecord;
     sp<IMemory>             mCblkMemory;
diff --git a/include/media/AudioTrack.h b/include/media/AudioTrack.h
index 813a905..3e346db 100644
--- a/include/media/AudioTrack.h
+++ b/include/media/AudioTrack.h
@@ -437,7 +437,7 @@
     };
 
             bool processAudioBuffer(const sp<AudioTrackThread>& thread);
-            status_t createTrack(int streamType,
+            status_t createTrack_l(int streamType,
                                  uint32_t sampleRate,
                                  int format,
                                  int channelCount,
@@ -446,6 +446,10 @@
                                  const sp<IMemory>& sharedBuffer,
                                  audio_io_handle_t output,
                                  bool enforceFrameCount);
+            void flush_l();
+            status_t setLoop_l(uint32_t loopStart, uint32_t loopEnd, int loopCount);
+            audio_io_handle_t getOutput_l();
+            status_t restoreTrack_l(audio_track_cblk_t*& cblk, bool fromStart);
 
     sp<IAudioTrack>         mAudioTrack;
     sp<IMemory>             mCblkMemory;
diff --git a/include/media/IMediaMetadataRetriever.h b/include/media/IMediaMetadataRetriever.h
index 8e3cdbb..1c1c268 100644
--- a/include/media/IMediaMetadataRetriever.h
+++ b/include/media/IMediaMetadataRetriever.h
@@ -18,10 +18,11 @@
 #ifndef ANDROID_IMEDIAMETADATARETRIEVER_H
 #define ANDROID_IMEDIAMETADATARETRIEVER_H
 
-#include <utils/RefBase.h>
 #include <binder/IInterface.h>
 #include <binder/Parcel.h>
 #include <binder/IMemory.h>
+#include <utils/KeyedVector.h>
+#include <utils/RefBase.h>
 
 namespace android {
 
@@ -30,7 +31,11 @@
 public:
     DECLARE_META_INTERFACE(MediaMetadataRetriever);
     virtual void            disconnect() = 0;
-    virtual status_t        setDataSource(const char* srcUrl) = 0;
+
+    virtual status_t        setDataSource(
+            const char *srcUrl,
+            const KeyedVector<String8, String8> *headers = NULL) = 0;
+
     virtual status_t        setDataSource(int fd, int64_t offset, int64_t length) = 0;
     virtual sp<IMemory>     getFrameAtTime(int64_t timeUs, int option) = 0;
     virtual sp<IMemory>     extractAlbumArt() = 0;
diff --git a/include/media/MediaMetadataRetrieverInterface.h b/include/media/MediaMetadataRetrieverInterface.h
index 0449122..27b7e4d 100644
--- a/include/media/MediaMetadataRetrieverInterface.h
+++ b/include/media/MediaMetadataRetrieverInterface.h
@@ -30,7 +30,11 @@
 public:
                         MediaMetadataRetrieverBase() {}
     virtual             ~MediaMetadataRetrieverBase() {}
-    virtual status_t    setDataSource(const char *url) = 0;
+
+    virtual status_t    setDataSource(
+            const char *url,
+            const KeyedVector<String8, String8> *headers = NULL) = 0;
+
     virtual status_t    setDataSource(int fd, int64_t offset, int64_t length) = 0;
     virtual VideoFrame* getFrameAtTime(int64_t timeUs, int option) = 0;
     virtual MediaAlbumArt* extractAlbumArt() = 0;
diff --git a/include/media/MemoryLeakTrackUtil.h b/include/media/MemoryLeakTrackUtil.h
new file mode 100644
index 0000000..290b748
--- /dev/null
+++ b/include/media/MemoryLeakTrackUtil.h
@@ -0,0 +1,28 @@
+
+/*
+ * Copyright 2011, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#ifndef MEMORY_LEAK_TRACK_UTIL_H
+#define MEMORY_LEAK_TRACK_UTIL_H
+
+namespace android {
+/*
+ * Dump the memory adddress of the calling process to the given fd.
+ */
+extern void dumpMemoryAddresses(int fd);
+
+};
+
+#endif  // MEMORY_LEAK_TRACK_UTIL_H
diff --git a/include/media/mediametadataretriever.h b/include/media/mediametadataretriever.h
index e905006..3e343e0 100644
--- a/include/media/mediametadataretriever.h
+++ b/include/media/mediametadataretriever.h
@@ -47,6 +47,12 @@
     METADATA_KEY_ALBUMARTIST     = 13,
     METADATA_KEY_DISC_NUMBER     = 14,
     METADATA_KEY_COMPILATION     = 15,
+    METADATA_KEY_HAS_AUDIO       = 16,
+    METADATA_KEY_HAS_VIDEO       = 17,
+    METADATA_KEY_VIDEO_WIDTH     = 18,
+    METADATA_KEY_VIDEO_HEIGHT    = 19,
+    METADATA_KEY_BITRATE         = 20,
+
     // Add more here...
 };
 
@@ -56,7 +62,11 @@
     MediaMetadataRetriever();
     ~MediaMetadataRetriever();
     void disconnect();
-    status_t setDataSource(const char* dataSourceUrl);
+
+    status_t setDataSource(
+            const char *dataSourceUrl,
+            const KeyedVector<String8, String8> *headers = NULL);
+
     status_t setDataSource(int fd, int64_t offset, int64_t length);
     sp<IMemory> getFrameAtTime(int64_t timeUs, int option);
     sp<IMemory> extractAlbumArt();
diff --git a/include/media/mediarecorder.h b/include/media/mediarecorder.h
index a710546..67d940b 100644
--- a/include/media/mediarecorder.h
+++ b/include/media/mediarecorder.h
@@ -104,35 +104,62 @@
 };
 
 /*
- * The state machine of the media_recorder uses a set of different state names.
- * The mapping between the media_recorder and the pvauthorengine is shown below:
- *
- *    mediarecorder                        pvauthorengine
- * ----------------------------------------------------------------
- *    MEDIA_RECORDER_ERROR                 ERROR
- *    MEDIA_RECORDER_IDLE                  IDLE
- *    MEDIA_RECORDER_INITIALIZED           OPENED
- *    MEDIA_RECORDER_DATASOURCE_CONFIGURED
- *    MEDIA_RECORDER_PREPARED              INITIALIZED
- *    MEDIA_RECORDER_RECORDING             RECORDING
+ * The state machine of the media_recorder.
  */
 enum media_recorder_states {
+    // Error state.
     MEDIA_RECORDER_ERROR                 =      0,
+
+    // Recorder was just created.
     MEDIA_RECORDER_IDLE                  = 1 << 0,
+
+    // Recorder has been initialized.
     MEDIA_RECORDER_INITIALIZED           = 1 << 1,
+
+    // Configuration of the recorder has been completed.
     MEDIA_RECORDER_DATASOURCE_CONFIGURED = 1 << 2,
+
+    // Recorder is ready to start.
     MEDIA_RECORDER_PREPARED              = 1 << 3,
+
+    // Recording is in progress.
     MEDIA_RECORDER_RECORDING             = 1 << 4,
 };
 
 // The "msg" code passed to the listener in notify.
 enum media_recorder_event_type {
+    MEDIA_RECORDER_EVENT_LIST_START               = 1,
     MEDIA_RECORDER_EVENT_ERROR                    = 1,
-    MEDIA_RECORDER_EVENT_INFO                     = 2
+    MEDIA_RECORDER_EVENT_INFO                     = 2,
+    MEDIA_RECORDER_EVENT_LIST_END                 = 99,
+
+    // Track related event types
+    MEDIA_RECORDER_TRACK_EVENT_LIST_START         = 100,
+    MEDIA_RECORDER_TRACK_EVENT_ERROR              = 100,
+    MEDIA_RECORDER_TRACK_EVENT_INFO               = 101,
+    MEDIA_RECORDER_TRACK_EVENT_LIST_END           = 1000,
 };
 
+/*
+ * The (part of) "what" code passed to the listener in notify.
+ * When the error or info type is track specific, the what has
+ * the following layout:
+ * the left-most 16-bit is meant for error or info type.
+ * the right-most 4-bit is meant for track id.
+ * the rest is reserved.
+ *
+ * | track id | reserved |     error or info type     |
+ * 31         28         16                           0
+ *
+ */
 enum media_recorder_error_type {
-    MEDIA_RECORDER_ERROR_UNKNOWN                  = 1
+    MEDIA_RECORDER_ERROR_UNKNOWN                   = 1,
+
+    // Track related error type
+    MEDIA_RECORDER_TRACK_ERROR_LIST_START          = 100,
+    MEDIA_RECORDER_TRACK_ERROR_GENERAL             = 100,
+    MEDIA_RECORDER_ERROR_VIDEO_NO_SYNC_FRAME       = 200,
+    MEDIA_RECORDER_TRACK_ERROR_LIST_END            = 1000,
 };
 
 // The codes are distributed as follow:
@@ -141,11 +168,15 @@
 //
 enum media_recorder_info_type {
     MEDIA_RECORDER_INFO_UNKNOWN                   = 1,
+
     MEDIA_RECORDER_INFO_MAX_DURATION_REACHED      = 800,
     MEDIA_RECORDER_INFO_MAX_FILESIZE_REACHED      = 801,
-    MEDIA_RECORDER_INFO_COMPLETION_STATUS         = 802,
-    MEDIA_RECORDER_INFO_PROGRESS_FRAME_STATUS     = 803,
-    MEDIA_RECORDER_INFO_PROGRESS_TIME_STATUS      = 804,
+
+    // All track related informtional events start here
+    MEDIA_RECORDER_TRACK_INFO_LIST_START           = 1000,
+    MEDIA_RECORDER_TRACK_INFO_COMPLETION_STATUS    = 1000,
+    MEDIA_RECORDER_TRACK_INFO_PROGRESS_IN_TIME     = 1001,
+    MEDIA_RECORDER_TRACK_INFO_LIST_END             = 2000,
 };
 
 // ----------------------------------------------------------------------------
diff --git a/include/media/stagefright/ACodec.h b/include/media/stagefright/ACodec.h
index a969796..f13e9bb 100644
--- a/include/media/stagefright/ACodec.h
+++ b/include/media/stagefright/ACodec.h
@@ -1,3 +1,19 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
 #ifndef A_CODEC_H_
 
 #define A_CODEC_H_
diff --git a/include/media/stagefright/AudioPlayer.h b/include/media/stagefright/AudioPlayer.h
index d12ee9c..0b79324 100644
--- a/include/media/stagefright/AudioPlayer.h
+++ b/include/media/stagefright/AudioPlayer.h
@@ -108,6 +108,8 @@
 
     void reset();
 
+    uint32_t getNumFramesPendingPlayout() const;
+
     AudioPlayer(const AudioPlayer &);
     AudioPlayer &operator=(const AudioPlayer &);
 };
diff --git a/include/media/stagefright/DataSource.h b/include/media/stagefright/DataSource.h
index f95e56a..d30e908 100644
--- a/include/media/stagefright/DataSource.h
+++ b/include/media/stagefright/DataSource.h
@@ -75,10 +75,10 @@
     static void RegisterDefaultSniffers();
 
     // for DRM
-    virtual DecryptHandle* DrmInitialization() {
+    virtual sp<DecryptHandle> DrmInitialization() {
         return NULL;
     }
-    virtual void getDrmInfo(DecryptHandle **handle, DrmManagerClient **client) {};
+    virtual void getDrmInfo(sp<DecryptHandle> &handle, DrmManagerClient **client) {};
 
     virtual String8 getUri() {
         return String8();
diff --git a/include/media/stagefright/FileSource.h b/include/media/stagefright/FileSource.h
index 51a4343..6cf86dc 100644
--- a/include/media/stagefright/FileSource.h
+++ b/include/media/stagefright/FileSource.h
@@ -38,9 +38,9 @@
 
     virtual status_t getSize(off64_t *size);
 
-    virtual DecryptHandle* DrmInitialization();
+    virtual sp<DecryptHandle> DrmInitialization();
 
-    virtual void getDrmInfo(DecryptHandle **handle, DrmManagerClient **client);
+    virtual void getDrmInfo(sp<DecryptHandle> &handle, DrmManagerClient **client);
 
 protected:
     virtual ~FileSource();
@@ -52,7 +52,7 @@
     Mutex mLock;
 
     /*for DRM*/
-    DecryptHandle *mDecryptHandle;
+    sp<DecryptHandle> mDecryptHandle;
     DrmManagerClient *mDrmManagerClient;
     int64_t mDrmBufOffset;
     int64_t mDrmBufSize;
diff --git a/include/media/stagefright/MPEG4Writer.h b/include/media/stagefright/MPEG4Writer.h
index 5c5229d..15f86ea 100644
--- a/include/media/stagefright/MPEG4Writer.h
+++ b/include/media/stagefright/MPEG4Writer.h
@@ -157,7 +157,7 @@
     bool use32BitFileOffset() const;
     bool exceedsFileDurationLimit();
     bool isFileStreamable() const;
-    void trackProgressStatus(const Track* track, int64_t timeUs, status_t err = OK);
+    void trackProgressStatus(size_t trackId, int64_t timeUs, status_t err = OK);
     void writeCompositionMatrix(int32_t degrees);
 
     MPEG4Writer(const MPEG4Writer &);
diff --git a/include/media/stagefright/MediaDebug.h b/include/media/stagefright/MediaDebug.h
index c8a8f00e7..2ca9667 100644
--- a/include/media/stagefright/MediaDebug.h
+++ b/include/media/stagefright/MediaDebug.h
@@ -1,3 +1,19 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
 #ifndef MEDIA_DEBUG_H_
 
 #define MEDIA_DEBUG_H_
diff --git a/include/media/stagefright/OMXCodec.h b/include/media/stagefright/OMXCodec.h
index f7d837a..93b5d24 100644
--- a/include/media/stagefright/OMXCodec.h
+++ b/include/media/stagefright/OMXCodec.h
@@ -50,6 +50,9 @@
 
         // Only submit one input buffer at one time.
         kOnlySubmitOneInputBufferAtOneTime = 64,
+
+        // Enable GRALLOC_USAGE_PROTECTED for output buffers from native window
+        kEnableGrallocUsageProtected = 128,
     };
     static sp<MediaSource> Create(
             const sp<IOMX> &omx,
@@ -197,6 +200,7 @@
 
     bool mIsMetaDataStoredInVideoBuffers;
     bool mOnlySubmitOneBufferAtOneTime;
+    bool mEnableGrallocUsageProtected;
 
     OMXCodec(const sp<IOMX> &omx, IOMX::node_id node, uint32_t quirks,
              bool isEncoder, const char *mime, const char *componentName,
diff --git a/include/media/stagefright/foundation/AHandlerReflector.h b/include/media/stagefright/foundation/AHandlerReflector.h
index 857866a..9d201b5 100644
--- a/include/media/stagefright/foundation/AHandlerReflector.h
+++ b/include/media/stagefright/foundation/AHandlerReflector.h
@@ -1,3 +1,19 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
 #ifndef A_HANDLER_REFLECTOR_H_
 
 #define A_HANDLER_REFLECTOR_H_
diff --git a/include/media/stagefright/foundation/AHierarchicalStateMachine.h b/include/media/stagefright/foundation/AHierarchicalStateMachine.h
index b5786fb..d2e6b28 100644
--- a/include/media/stagefright/foundation/AHierarchicalStateMachine.h
+++ b/include/media/stagefright/foundation/AHierarchicalStateMachine.h
@@ -1,3 +1,19 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
 #ifndef A_HIERARCHICAL_STATE_MACHINE_H_
 
 #define A_HIERARCHICAL_STATE_MACHINE_H_
diff --git a/include/private/hwui/DrawGlInfo.h b/include/private/hwui/DrawGlInfo.h
new file mode 100644
index 0000000..1e9912b
--- /dev/null
+++ b/include/private/hwui/DrawGlInfo.h
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_HWUI_DRAW_GL_INFO_H
+#define ANDROID_HWUI_DRAW_GL_INFO_H
+
+namespace android {
+namespace uirenderer {
+
+/**
+ * Structure used by OpenGLRenderer::callDrawGLFunction() to pass and
+ * receive data from OpenGL functors.
+ */
+struct DrawGlInfo {
+    // Input: current clip rect
+    int clipLeft;
+    int clipTop;
+    int clipRight;
+    int clipBottom;
+
+    // Input: is the render target an FBO
+    bool isLayer;
+
+    // Input: current transform matrix, in OpenGL format
+    float transform[16];
+
+    // Output: dirty region to redraw
+    float dirtyLeft;
+    float dirtyTop;
+    float dirtyRight;
+    float dirtyBottom;
+}; // struct DrawGlInfo
+
+}; // namespace uirenderer
+}; // namespace android
+
+#endif // ANDROID_HWUI_DRAW_GL_INFO_H
diff --git a/include/private/media/AudioTrackShared.h b/include/private/media/AudioTrackShared.h
index c6990bf..4610135 100644
--- a/include/private/media/AudioTrackShared.h
+++ b/include/private/media/AudioTrackShared.h
@@ -31,6 +31,7 @@
 #define MAX_STARTUP_TIMEOUT_MS  3000    // Longer timeout period at startup to cope with A2DP init time
 #define MAX_RUN_TIMEOUT_MS      1000
 #define WAIT_PERIOD_MS          10
+#define RESTORE_TIMEOUT_MS      5000    // Maximum waiting time for a track to be restored
 
 #define CBLK_UNDERRUN_MSK       0x0001
 #define CBLK_UNDERRUN_ON        0x0001  // underrun (out) or overrrun (in) indication
@@ -47,6 +48,12 @@
 #define CBLK_DISABLED_MSK       0x0010
 #define CBLK_DISABLED_ON        0x0010  // track disabled by AudioFlinger due to underrun:
 #define CBLK_DISABLED_OFF       0x0000  // must be re-started
+#define CBLK_RESTORING_MSK      0x0020
+#define CBLK_RESTORING_ON       0x0020  // track is being restored after invalidation
+#define CBLK_RESTORING_OFF      0x0000  // by AudioFlinger
+#define CBLK_RESTORED_MSK       0x0040
+#define CBLK_RESTORED_ON        0x0040  // track has been restored after invalidation
+#define CBLK_RESTORED_OFF       0x0040  // by AudioFlinger
 
 struct audio_track_cblk_t
 {
diff --git a/include/surfaceflinger/ISurfaceComposer.h b/include/surfaceflinger/ISurfaceComposer.h
index 361e7dc..dea1b10 100644
--- a/include/surfaceflinger/ISurfaceComposer.h
+++ b/include/surfaceflinger/ISurfaceComposer.h
@@ -138,6 +138,10 @@
      * This is an ASYNCHRONOUS call.
      */
     virtual void signal() const = 0;
+
+    /* verify that an ISurface was created by SurfaceFlinger.
+     */
+    virtual bool authenticateSurface(const sp<ISurface>& surface) const = 0;
 };
 
 // ----------------------------------------------------------------------------
@@ -161,7 +165,8 @@
         SIGNAL,
         CAPTURE_SCREEN,
         TURN_ELECTRON_BEAM_OFF,
-        TURN_ELECTRON_BEAM_ON
+        TURN_ELECTRON_BEAM_ON,
+        AUTHENTICATE_SURFACE,
     };
 
     virtual status_t    onTransact( uint32_t code,
diff --git a/include/surfaceflinger/Surface.h b/include/surfaceflinger/Surface.h
index 9e0b5bb..a59d9e5 100644
--- a/include/surfaceflinger/Surface.h
+++ b/include/surfaceflinger/Surface.h
@@ -226,7 +226,8 @@
     int  dispatch_set_buffer_count(va_list args);
     int  dispatch_set_buffers_geometry(va_list args);
     int  dispatch_set_buffers_transform(va_list args);
-    
+    int  dispatch_set_buffers_timestamp(va_list args);
+
     void setUsage(uint32_t reqUsage);
     int  connect(int api);
     int  disconnect(int api);
@@ -234,6 +235,7 @@
     int  setBufferCount(int bufferCount);
     int  setBuffersGeometry(int w, int h, int format);
     int  setBuffersTransform(int transform);
+    int  setBuffersTimestamp(int64_t timestamp);
 
     /*
      *  private stuff...
diff --git a/include/ui/Input.h b/include/ui/Input.h
index e92d7f5..8e8b61b 100644
--- a/include/ui/Input.h
+++ b/include/ui/Input.h
@@ -27,6 +27,7 @@
 #include <utils/Timers.h>
 #include <utils/RefBase.h>
 #include <utils/String8.h>
+#include <utils/BitSet.h>
 
 #ifdef HAVE_ANDROID_OS
 class SkMatrix;
@@ -144,6 +145,14 @@
 };
 
 /*
+ * Button state.
+ */
+enum {
+    // Primary button pressed (left mouse button).
+    BUTTON_STATE_PRIMARY = 1 << 0,
+};
+
+/*
  * Describes the basic configuration of input devices that are present.
  */
 struct InputConfiguration {
@@ -200,6 +209,13 @@
     status_t writeToParcel(Parcel* parcel) const;
 #endif
 
+    bool operator==(const PointerCoords& other) const;
+    inline bool operator!=(const PointerCoords& other) const {
+        return !(*this == other);
+    }
+
+    void copyFrom(const PointerCoords& other);
+
 private:
     void tooManyAxes(int axis);
 };
@@ -295,6 +311,13 @@
 
     inline int32_t getAction() const { return mAction; }
 
+    inline int32_t getActionMasked() const { return mAction & AMOTION_EVENT_ACTION_MASK; }
+
+    inline int32_t getActionIndex() const {
+        return (mAction & AMOTION_EVENT_ACTION_POINTER_INDEX_MASK)
+                >> AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT;
+    }
+
     inline void setAction(int32_t action) { mAction = action; }
 
     inline int32_t getFlags() const { return mFlags; }
@@ -442,6 +465,8 @@
                 AMOTION_EVENT_AXIS_ORIENTATION, pointerIndex, historicalIndex);
     }
 
+    ssize_t findPointerIndex(int32_t pointerId) const;
+
     void initialize(
             int32_t deviceId,
             int32_t source,
@@ -535,6 +560,67 @@
 };
 
 /*
+ * Calculates the velocity of pointer movements over time.
+ */
+class VelocityTracker {
+public:
+    struct Position {
+        float x, y;
+    };
+
+    VelocityTracker();
+
+    // Resets the velocity tracker state.
+    void clear();
+
+    // Resets the velocity tracker state for specific pointers.
+    // Call this method when some pointers have changed and may be reusing
+    // an id that was assigned to a different pointer earlier.
+    void clearPointers(BitSet32 idBits);
+
+    // Adds movement information for a set of pointers.
+    // The idBits bitfield specifies the pointer ids of the pointers whose positions
+    // are included in the movement.
+    // The positions array contains position information for each pointer in order by
+    // increasing id.  Its size should be equal to the number of one bits in idBits.
+    void addMovement(nsecs_t eventTime, BitSet32 idBits, const Position* positions);
+
+    // Adds movement information for all pointers in a MotionEvent, including historical samples.
+    void addMovement(const MotionEvent* event);
+
+    // Gets the velocity of the specified pointer id in position units per second.
+    // Returns false and sets the velocity components to zero if there is no movement
+    // information for the pointer.
+    bool getVelocity(uint32_t id, float* outVx, float* outVy) const;
+
+    // Gets the active pointer id, or -1 if none.
+    inline int32_t getActivePointerId() const { return mActivePointerId; }
+
+    // Gets a bitset containing all pointer ids from the most recent movement.
+    inline BitSet32 getCurrentPointerIdBits() const { return mMovements[mIndex].idBits; }
+
+private:
+    // Number of samples to keep.
+    static const uint32_t HISTORY_SIZE = 10;
+
+    // Oldest sample to consider when calculating the velocity.
+    static const nsecs_t MAX_AGE = 200 * 1000000; // 200 ms
+
+    // The minimum duration between samples when estimating velocity.
+    static const nsecs_t MIN_DURATION = 10 * 1000000; // 10 ms
+
+    struct Movement {
+        nsecs_t eventTime;
+        BitSet32 idBits;
+        Position positions[MAX_POINTERS];
+    };
+
+    uint32_t mIndex;
+    Movement mMovements[HISTORY_SIZE];
+    int32_t mActivePointerId;
+};
+
+/*
  * Describes the characteristics and capabilities of an input device.
  */
 class InputDeviceInfo {
@@ -544,6 +630,8 @@
     ~InputDeviceInfo();
 
     struct MotionRange {
+        int32_t axis;
+        uint32_t source;
         float min;
         float max;
         float flat;
@@ -556,16 +644,17 @@
     inline const String8 getName() const { return mName; }
     inline uint32_t getSources() const { return mSources; }
 
-    const MotionRange* getMotionRange(int32_t axis) const;
+    const MotionRange* getMotionRange(int32_t axis, uint32_t source) const;
 
     void addSource(uint32_t source);
-    void addMotionRange(int32_t axis, float min, float max, float flat, float fuzz);
-    void addMotionRange(int32_t axis, const MotionRange& range);
+    void addMotionRange(int32_t axis, uint32_t source,
+            float min, float max, float flat, float fuzz);
+    void addMotionRange(const MotionRange& range);
 
     inline void setKeyboardType(int32_t keyboardType) { mKeyboardType = keyboardType; }
     inline int32_t getKeyboardType() const { return mKeyboardType; }
 
-    inline const KeyedVector<int32_t, MotionRange> getMotionRanges() const {
+    inline const Vector<MotionRange>& getMotionRanges() const {
         return mMotionRanges;
     }
 
@@ -575,7 +664,7 @@
     uint32_t mSources;
     int32_t mKeyboardType;
 
-    KeyedVector<int32_t, MotionRange> mMotionRanges;
+    Vector<MotionRange> mMotionRanges;
 };
 
 /*
diff --git a/include/ui/KeyLayoutMap.h b/include/ui/KeyLayoutMap.h
index 904c8f3..d82d0c8 100644
--- a/include/ui/KeyLayoutMap.h
+++ b/include/ui/KeyLayoutMap.h
@@ -24,6 +24,36 @@
 
 namespace android {
 
+struct AxisInfo {
+    enum Mode {
+        // Axis value is reported directly.
+        MODE_NORMAL = 0,
+        // Axis value should be inverted before reporting.
+        MODE_INVERT = 1,
+        // Axis value should be split into two axes
+        MODE_SPLIT = 2,
+    };
+
+    // Axis mode.
+    Mode mode;
+
+    // Axis id.
+    // When split, this is the axis used for values smaller than the split position.
+    int32_t axis;
+
+    // When split, this is the axis used for values after higher than the split position.
+    int32_t highAxis;
+
+    // The split value, or 0 if not split.
+    int32_t splitValue;
+
+    // The flat value, or -1 if none.
+    int32_t flatOverride;
+
+    AxisInfo() : mode(MODE_NORMAL), axis(-1), highAxis(-1), splitValue(0), flatOverride(-1) {
+    }
+};
+
 /**
  * Describes a mapping from keyboard scan codes and joystick axes to Android key codes and axes.
  */
@@ -36,7 +66,7 @@
     status_t mapKey(int32_t scanCode, int32_t* keyCode, uint32_t* flags) const;
     status_t findScanCodesForKey(int32_t keyCode, Vector<int32_t>* outScanCodes) const;
 
-    status_t mapAxis(int32_t scanCode, int32_t* axis) const;
+    status_t mapAxis(int32_t scanCode, AxisInfo* outAxisInfo) const;
 
 private:
     struct Key {
@@ -45,7 +75,7 @@
     };
 
     KeyedVector<int32_t, Key> mKeys;
-    KeyedVector<int32_t, int32_t> mAxes;
+    KeyedVector<int32_t, AxisInfo> mAxes;
 
     KeyLayoutMap();
 
diff --git a/include/ui/KeycodeLabels.h b/include/ui/KeycodeLabels.h
index bdfbf7c..8383957 100755
--- a/include/ui/KeycodeLabels.h
+++ b/include/ui/KeycodeLabels.h
@@ -228,6 +228,9 @@
     { "BUTTON_14", 201 },
     { "BUTTON_15", 202 },
     { "BUTTON_16", 203 },
+    { "LANGUAGE_SWITCH", 204 },
+    { "MANNER_MODE", 205 },
+    { "3D_MODE", 206 },
 
     // NOTE: If you add a new keycode here you must also add it to several other files.
     //       Refer to frameworks/base/core/java/android/view/KeyEvent.java for the full list.
@@ -270,6 +273,11 @@
     { "HAT_Y", 16 },
     { "LTRIGGER", 17 },
     { "RTRIGGER", 18 },
+    { "THROTTLE", 19 },
+    { "RUDDER", 20 },
+    { "WHEEL", 21 },
+    { "GAS", 22 },
+    { "BRAKE", 23 },
     { "GENERIC_1", 32 },
     { "GENERIC_2", 33 },
     { "GENERIC_3", 34 },
diff --git a/include/ui/egl/android_natives.h b/include/ui/egl/android_natives.h
index fd83f46..0a6e4fb 100644
--- a/include/ui/egl/android_natives.h
+++ b/include/ui/egl/android_natives.h
@@ -57,7 +57,7 @@
 {
     /* a magic value defined by the actual EGL native type */
     int magic;
-    
+
     /* the sizeof() of the actual EGL native type */
     int version;
 
@@ -95,6 +95,29 @@
      * 5. Queue, dequeue, queue, dequeue, ad infinitum
      */
     NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS,
+
+    /* Check whether queueBuffer operations on the ANativeWindow send the buffer
+     * to the window compositor.  The query sets the returned 'value' argument
+     * to 1 if the ANativeWindow DOES send queued buffers directly to the window
+     * compositor and 0 if the buffers do not go directly to the window
+     * compositor.
+     *
+     * This can be used to determine whether protected buffer content should be
+     * sent to the ANativeWindow.  Note, however, that a result of 1 does NOT
+     * indicate that queued buffers will be protected from applications or users
+     * capturing their contents.  If that behavior is desired then some other
+     * mechanism (e.g. the GRALLOC_USAGE_PROTECTED flag) should be used in
+     * conjunction with this query.
+     */
+    NATIVE_WINDOW_QUEUES_TO_WINDOW_COMPOSER,
+
+    /* Get the concrete type of a ANativeWindow.  See below for the list of
+     * possible return values.
+     *
+     * This query should not be used outside the Android framework and will
+     * likely be removed in the near future.
+     */
+    NATIVE_WINDOW_CONCRETE_TYPE,
 };
 
 /* valid operations for the (*perform)() hook */
@@ -106,6 +129,7 @@
     NATIVE_WINDOW_SET_BUFFER_COUNT,
     NATIVE_WINDOW_SET_BUFFERS_GEOMETRY,
     NATIVE_WINDOW_SET_BUFFERS_TRANSFORM,
+    NATIVE_WINDOW_SET_BUFFERS_TIMESTAMP,
 };
 
 /* parameter for NATIVE_WINDOW_[DIS]CONNECT */
@@ -127,7 +151,22 @@
     NATIVE_WINDOW_TRANSFORM_ROT_270 = HAL_TRANSFORM_ROT_270,
 };
 
-struct ANativeWindow 
+/* values returned by the NATIVE_WINDOW_CONCRETE_TYPE query */
+enum {
+    NATIVE_WINDOW_FRAMEBUFFER,                  // FramebufferNativeWindow
+    NATIVE_WINDOW_SURFACE,                      // Surface
+    NATIVE_WINDOW_SURFACE_TEXTURE_CLIENT,       // SurfaceTextureClient
+};
+
+/* parameter for NATIVE_WINDOW_SET_BUFFERS_TIMESTAMP
+ *
+ * Special timestamp value to indicate that timestamps should be auto-generated
+ * by the native window when queueBuffer is called.  This is equal to INT64_MIN,
+ * defined directly to avoid problems with C99/C++ inclusion of stdint.h.
+ */
+const int64_t NATIVE_WINDOW_TIMESTAMP_AUTO = (-9223372036854775807LL-1);
+
+struct ANativeWindow
 {
 #ifdef __cplusplus
     ANativeWindow()
@@ -232,7 +271,8 @@
      *     NATIVE_WINDOW_SET_BUFFER_COUNT
      *     NATIVE_WINDOW_SET_BUFFERS_GEOMETRY
      *     NATIVE_WINDOW_SET_BUFFERS_TRANSFORM
-     *  
+     *     NATIVE_WINDOW_SET_BUFFERS_TIMESTAMP
+     *
      */
     
     int     (*perform)(struct ANativeWindow* window,
@@ -359,6 +399,22 @@
             transform);
 }
 
+/*
+ * native_window_set_buffers_timestamp(..., int64_t timestamp)
+ * All buffers queued after this call will be associated with the timestamp
+ * parameter specified. If the timestamp is set to NATIVE_WINDOW_TIMESTAMP_AUTO
+ * (the default), timestamps will be generated automatically when queueBuffer is
+ * called. The timestamp is measured in nanoseconds, and must be monotonically
+ * increasing.
+ */
+static inline int native_window_set_buffers_timestamp(
+        ANativeWindow* window,
+        int64_t timestamp)
+{
+    return window->perform(window, NATIVE_WINDOW_SET_BUFFERS_TIMESTAMP,
+            timestamp);
+}
+
 // ---------------------------------------------------------------------------
 
 /* FIXME: this is legacy for pixmaps */
diff --git a/include/utils/BitSet.h b/include/utils/BitSet.h
index f5dbcd94..de748b5 100644
--- a/include/utils/BitSet.h
+++ b/include/utils/BitSet.h
@@ -61,6 +61,16 @@
     // Result is undefined if all bits are marked.
     inline uint32_t firstUnmarkedBit() const { return __builtin_clz(~ value); }
 
+    // Finds the last marked bit in the set.
+    // Result is undefined if all bits are unmarked.
+    inline uint32_t lastMarkedBit() const { return 31 - __builtin_ctz(value); }
+
+    // Gets the index of the specified bit in the set, which is the number of
+    // marked bits that appear before the specified bit.
+    inline uint32_t getIndexOfBit(uint32_t n) const {
+        return __builtin_popcount(value & ~(0xffffffffUL >> n));
+    }
+
     inline bool operator== (const BitSet32& other) const { return value == other.value; }
     inline bool operator!= (const BitSet32& other) const { return value != other.value; }
 };
diff --git a/include/utils/Functor.h b/include/utils/Functor.h
index 3955bc3..e24ded4 100644
--- a/include/utils/Functor.h
+++ b/include/utils/Functor.h
@@ -25,7 +25,7 @@
 public:
     Functor() {}
     virtual ~Functor() {}
-    virtual status_t operator ()() { return true; }
+    virtual status_t operator ()(int what, void* data) { return NO_ERROR; }
 };
 
 }; // namespace android
diff --git a/include/utils/String8.h b/include/utils/String8.h
index 6b49ff5..4163697 100644
--- a/include/utils/String8.h
+++ b/include/utils/String8.h
@@ -165,8 +165,8 @@
     String8 walkPath(String8* outRemains = NULL) const;
 
     /*
-     * Return the filename extension.  This is the last '.' and up to
-     * four characters that follow it.  The '.' is included in case we
+     * Return the filename extension.  This is the last '.' and any number
+     * of characters that follow it.  The '.' is included in case we
      * decide to expand our definition of what constitutes an extension.
      *
      * "/tmp/foo/bar.c" --> ".c"
diff --git a/include/utils/Timers.h b/include/utils/Timers.h
index 9a9e07c..8b4d322 100644
--- a/include/utils/Timers.h
+++ b/include/utils/Timers.h
@@ -88,6 +88,16 @@
 nsecs_t systemTime(int clock);
 #endif // def __cplusplus
 
+/**
+ * Returns the number of milliseconds to wait between the reference time and the timeout time.
+ * If the timeout is in the past relative to the reference time, returns 0.
+ * If the timeout is more than INT_MAX milliseconds in the future relative to the reference time,
+ * such as when timeoutTime == LLONG_MAX, returns -1 to indicate an infinite timeout delay.
+ * Otherwise, returns the difference between the reference time and timeout time
+ * rounded up to the next millisecond.
+ */
+int toMillisecondTimeoutDelay(nsecs_t referenceTime, nsecs_t timeoutTime);
+
 #ifdef __cplusplus
 } // extern "C"
 #endif
diff --git a/include/utils/Vector.h b/include/utils/Vector.h
index ec851bd..6fd307f 100644
--- a/include/utils/Vector.h
+++ b/include/utils/Vector.h
@@ -162,6 +162,9 @@
      inline status_t        sort(compar_t cmp);
      inline status_t        sort(compar_r_t cmp, void* state);
 
+     // for debugging only
+     inline size_t getItemSize() const { return itemSize(); }
+
 protected:
     virtual void    do_construct(void* storage, size_t num) const;
     virtual void    do_destroy(void* storage, size_t num) const;
diff --git a/libs/gui/ISurfaceTexture.cpp b/libs/gui/ISurfaceTexture.cpp
index d661fd5..bc14ad5 100644
--- a/libs/gui/ISurfaceTexture.cpp
+++ b/libs/gui/ISurfaceTexture.cpp
@@ -88,10 +88,11 @@
         return result;
     }
 
-    virtual status_t queueBuffer(int buf) {
+    virtual status_t queueBuffer(int buf, int64_t timestamp) {
         Parcel data, reply;
         data.writeInterfaceToken(ISurfaceTexture::getInterfaceDescriptor());
         data.writeInt32(buf);
+        data.writeInt64(timestamp);
         remote()->transact(QUEUE_BUFFER, data, &reply);
         status_t result = reply.readInt32();
         return result;
@@ -174,7 +175,8 @@
         case QUEUE_BUFFER: {
             CHECK_INTERFACE(ISurfaceTexture, data, reply);
             int buf = data.readInt32();
-            status_t result = queueBuffer(buf);
+            int64_t timestamp = data.readInt64();
+            status_t result = queueBuffer(buf, timestamp);
             reply->writeInt32(result);
             return NO_ERROR;
         } break;
@@ -196,7 +198,6 @@
             return NO_ERROR;
         } break;
         case SET_TRANSFORM: {
-            Rect reg;
             CHECK_INTERFACE(ISurfaceTexture, data, reply);
             uint32_t transform = data.readInt32();
             status_t result = setTransform(transform);
diff --git a/libs/gui/SurfaceTexture.cpp b/libs/gui/SurfaceTexture.cpp
index 3bed959..cdaca47 100644
--- a/libs/gui/SurfaceTexture.cpp
+++ b/libs/gui/SurfaceTexture.cpp
@@ -76,9 +76,15 @@
 static void mtxMul(float out[16], const float a[16], const float b[16]);
 
 SurfaceTexture::SurfaceTexture(GLuint tex) :
-    mBufferCount(MIN_BUFFER_SLOTS), mCurrentTexture(INVALID_BUFFER_SLOT),
-    mCurrentTransform(0), mLastQueued(INVALID_BUFFER_SLOT),
-    mLastQueuedTransform(0), mNextTransform(0), mTexName(tex) {
+    mBufferCount(MIN_BUFFER_SLOTS),
+    mCurrentTexture(INVALID_BUFFER_SLOT),
+    mCurrentTransform(0),
+    mCurrentTimestamp(0),
+    mLastQueued(INVALID_BUFFER_SLOT),
+    mLastQueuedTransform(0),
+    mLastQueuedTimestamp(0),
+    mNextTransform(0),
+    mTexName(tex) {
     LOGV("SurfaceTexture::SurfaceTexture");
     for (int i = 0; i < NUM_BUFFER_SLOTS; i++) {
         mSlots[i].mEglImage = EGL_NO_IMAGE_KHR;
@@ -153,7 +159,7 @@
     return OK;
 }
 
-status_t SurfaceTexture::queueBuffer(int buf) {
+status_t SurfaceTexture::queueBuffer(int buf, int64_t timestamp) {
     LOGV("SurfaceTexture::queueBuffer");
     Mutex::Autolock lock(mMutex);
     if (buf < 0 || mBufferCount <= buf) {
@@ -172,6 +178,7 @@
     mLastQueued = buf;
     mLastQueuedCrop = mNextCrop;
     mLastQueuedTransform = mNextTransform;
+    mLastQueuedTimestamp = timestamp;
     if (mFrameAvailableListener != 0) {
         mFrameAvailableListener->onFrameAvailable();
     }
@@ -246,12 +253,13 @@
         mCurrentTextureBuf = mSlots[mCurrentTexture].mGraphicBuffer;
         mCurrentCrop = mLastQueuedCrop;
         mCurrentTransform = mLastQueuedTransform;
+        mCurrentTimestamp = mLastQueuedTimestamp;
     }
     return OK;
 }
 
 void SurfaceTexture::getTransformMatrix(float mtx[16]) {
-    LOGV("SurfaceTexture::updateTexImage");
+    LOGV("SurfaceTexture::getTransformMatrix");
     Mutex::Autolock lock(mMutex);
 
     float xform[16];
@@ -283,11 +291,42 @@
     sp<GraphicBuffer>& buf(mSlots[mCurrentTexture].mGraphicBuffer);
     float tx, ty, sx, sy;
     if (!mCurrentCrop.isEmpty()) {
-        tx = float(mCurrentCrop.left) / float(buf->getWidth());
-        ty = float(buf->getHeight() - mCurrentCrop.bottom) /
-                float(buf->getHeight());
-        sx = float(mCurrentCrop.width()) / float(buf->getWidth());
-        sy = float(mCurrentCrop.height()) / float(buf->getHeight());
+        // In order to prevent bilinear sampling at the of the crop rectangle we
+        // may need to shrink it by 2 texels in each direction.  Normally this
+        // would just need to take 1/2 a texel off each end, but because the
+        // chroma channels will likely be subsampled we need to chop off a whole
+        // texel.  This will cause artifacts if someone does nearest sampling
+        // with 1:1 pixel:texel ratio, but it's impossible to simultaneously
+        // accomodate the bilinear and nearest sampling uses.
+        //
+        // If nearest sampling turns out to be a desirable usage of these
+        // textures then we could add the ability to switch a SurfaceTexture to
+        // nearest-mode.  Preferably, however, the image producers (video
+        // decoder, camera, etc.) would simply not use a crop rectangle (or at
+        // least not tell the framework about it) so that the GPU can do the
+        // correct edge behavior.
+        int xshrink = 0, yshrink = 0;
+        if (mCurrentCrop.left > 0) {
+            tx = float(mCurrentCrop.left + 1) / float(buf->getWidth());
+            xshrink++;
+        } else {
+            tx = 0.0f;
+        }
+        if (mCurrentCrop.right < buf->getWidth()) {
+            xshrink++;
+        }
+        if (mCurrentCrop.bottom < buf->getHeight()) {
+            ty = (float(buf->getHeight() - mCurrentCrop.bottom) + 1.0f) /
+                    float(buf->getHeight());
+            yshrink++;
+        } else {
+            ty = 0.0f;
+        }
+        if (mCurrentCrop.top > 0) {
+            yshrink++;
+        }
+        sx = float(mCurrentCrop.width() - xshrink) / float(buf->getWidth());
+        sy = float(mCurrentCrop.height() - yshrink) / float(buf->getHeight());
     } else {
         tx = 0.0f;
         ty = 0.0f;
@@ -298,7 +337,7 @@
         sx, 0, 0, 0,
         0, sy, 0, 0,
         0, 0, 1, 0,
-        sx*tx, sy*ty, 0, 1,
+        tx, ty, 0, 1,
     };
 
     float mtxBeforeFlipV[16];
@@ -311,6 +350,12 @@
     mtxMul(mtx, mtxFlipV, mtxBeforeFlipV);
 }
 
+nsecs_t SurfaceTexture::getTimestamp() {
+    LOGV("SurfaceTexture::getTimestamp");
+    Mutex::Autolock lock(mMutex);
+    return mCurrentTimestamp;
+}
+
 void SurfaceTexture::setFrameAvailableListener(
         const sp<FrameAvailableListener>& l) {
     LOGV("SurfaceTexture::setFrameAvailableListener");
diff --git a/libs/gui/SurfaceTextureClient.cpp b/libs/gui/SurfaceTextureClient.cpp
index 43b330c..a4812d0 100644
--- a/libs/gui/SurfaceTextureClient.cpp
+++ b/libs/gui/SurfaceTextureClient.cpp
@@ -26,7 +26,8 @@
 SurfaceTextureClient::SurfaceTextureClient(
         const sp<ISurfaceTexture>& surfaceTexture):
         mSurfaceTexture(surfaceTexture), mAllocator(0), mReqWidth(1),
-        mReqHeight(1), mReqFormat(DEFAULT_FORMAT), mReqUsage(0), mMutex() {
+        mReqHeight(1), mReqFormat(DEFAULT_FORMAT), mReqUsage(0),
+        mTimestamp(NATIVE_WINDOW_TIMESTAMP_AUTO), mMutex() {
     // Initialize the ANativeWindow function pointers.
     ANativeWindow::setSwapInterval  = setSwapInterval;
     ANativeWindow::dequeueBuffer    = dequeueBuffer;
@@ -40,6 +41,10 @@
     mAllocator = mSurfaceTexture->getAllocator();
 }
 
+sp<ISurfaceTexture> SurfaceTextureClient::getISurfaceTexture() const {
+    return mSurfaceTexture;
+}
+
 int SurfaceTextureClient::setSwapInterval(ANativeWindow* window, int interval) {
     SurfaceTextureClient* c = getSelf(window);
     return c->setSwapInterval(interval);
@@ -131,9 +136,17 @@
 int SurfaceTextureClient::queueBuffer(android_native_buffer_t* buffer) {
     LOGV("SurfaceTextureClient::queueBuffer");
     Mutex::Autolock lock(mMutex);
+    int64_t timestamp;
+    if (mTimestamp == NATIVE_WINDOW_TIMESTAMP_AUTO) {
+        timestamp = systemTime(SYSTEM_TIME_MONOTONIC);
+        LOGV("SurfaceTextureClient::queueBuffer making up timestamp: %.2f ms",
+             timestamp / 1000000.f);
+    } else {
+        timestamp = mTimestamp;
+    }
     for (int i = 0; i < NUM_BUFFER_SLOTS; i++) {
         if (mSlots[i]->handle == buffer->handle) {
-            return mSurfaceTexture->queueBuffer(i);
+            return mSurfaceTexture->queueBuffer(i, timestamp);
         }
     }
     LOGE("queueBuffer: unknown buffer queued");
@@ -156,6 +169,13 @@
     case NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS:
         *value = MIN_UNDEQUEUED_BUFFERS;
         return NO_ERROR;
+    case NATIVE_WINDOW_QUEUES_TO_WINDOW_COMPOSER:
+        // SurfaceTextureClient currently never queues frames to SurfaceFlinger.
+        *value = 0;
+        return NO_ERROR;
+    case NATIVE_WINDOW_CONCRETE_TYPE:
+        *value = NATIVE_WINDOW_SURFACE_TEXTURE_CLIENT;
+        return NO_ERROR;
     }
     return BAD_VALUE;
 }
@@ -185,6 +205,9 @@
     case NATIVE_WINDOW_SET_BUFFERS_TRANSFORM:
         res = dispatchSetBuffersTransform(args);
         break;
+    case NATIVE_WINDOW_SET_BUFFERS_TIMESTAMP:
+        res = dispatchSetBuffersTimestamp(args);
+        break;
     default:
         res = NAME_NOT_FOUND;
         break;
@@ -229,6 +252,11 @@
     return setBuffersTransform(transform);
 }
 
+int SurfaceTextureClient::dispatchSetBuffersTimestamp(va_list args) {
+    int64_t timestamp = va_arg(args, int64_t);
+    return setBuffersTimestamp(timestamp);
+}
+
 int SurfaceTextureClient::connect(int api) {
     LOGV("SurfaceTextureClient::connect");
     // XXX: Implement this!
@@ -312,6 +340,14 @@
     return err;
 }
 
+int SurfaceTextureClient::setBuffersTimestamp(int64_t timestamp)
+{
+    LOGV("SurfaceTextureClient::setBuffersTimestamp");
+    Mutex::Autolock lock(mMutex);
+    mTimestamp = timestamp;
+    return NO_ERROR;
+}
+
 void SurfaceTextureClient::freeAllBuffers() {
     for (int i = 0; i < NUM_BUFFER_SLOTS; i++) {
         mSlots[i] = 0;
diff --git a/libs/gui/tests/Android.mk b/libs/gui/tests/Android.mk
new file mode 100644
index 0000000..7516299
--- /dev/null
+++ b/libs/gui/tests/Android.mk
@@ -0,0 +1,51 @@
+# Build the unit tests.
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+ifneq ($(TARGET_SIMULATOR),true)
+
+LOCAL_MODULE := SurfaceTexture_test
+
+LOCAL_MODULE_TAGS := tests
+
+LOCAL_SRC_FILES := \
+    SurfaceTextureClient_test.cpp \
+    SurfaceTexture_test.cpp \
+
+LOCAL_SHARED_LIBRARIES := \
+	libEGL \
+	libGLESv2 \
+	libandroid \
+	libbinder \
+	libcutils \
+	libgui \
+	libstlport \
+	libsurfaceflinger_client \
+	libui \
+	libutils \
+
+LOCAL_STATIC_LIBRARIES := \
+	libgtest \
+	libgtest_main \
+
+LOCAL_C_INCLUDES := \
+    bionic \
+    bionic/libstdc++/include \
+    external/gtest/include \
+    external/stlport/stlport \
+
+include $(BUILD_EXECUTABLE)
+
+# Build the manual test programs.
+include $(call all-subdir-makefiles)
+
+endif
+
+# Include subdirectory makefiles
+# ============================================================
+
+# If we're building with ONE_SHOT_MAKEFILE (mm, mmm), then what the framework
+# team really wants is to build the stuff defined by this makefile.
+ifeq (,$(ONE_SHOT_MAKEFILE))
+include $(call first-makefiles-under,$(LOCAL_PATH))
+endif
diff --git a/libs/gui/tests/SurfaceTextureClient_test.cpp b/libs/gui/tests/SurfaceTextureClient_test.cpp
new file mode 100644
index 0000000..94b05bc
--- /dev/null
+++ b/libs/gui/tests/SurfaceTextureClient_test.cpp
@@ -0,0 +1,103 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <EGL/egl.h>
+#include <gtest/gtest.h>
+#include <gui/SurfaceTextureClient.h>
+
+namespace android {
+
+class SurfaceTextureClientTest : public ::testing::Test {
+protected:
+    virtual void SetUp() {
+        mST = new SurfaceTexture(123);
+        mSTC = new SurfaceTextureClient(mST);
+    }
+
+    virtual void TearDown() {
+        mST.clear();
+        mSTC.clear();
+    }
+
+    sp<SurfaceTexture> mST;
+    sp<SurfaceTextureClient> mSTC;
+};
+
+TEST_F(SurfaceTextureClientTest, GetISurfaceTextureIsNotNull) {
+    sp<ISurfaceTexture> ist(mSTC->getISurfaceTexture());
+    ASSERT_TRUE(ist != NULL);
+}
+
+TEST_F(SurfaceTextureClientTest, QueuesToWindowCompositorIsFalse) {
+    sp<ANativeWindow> anw(mSTC);
+    int result = -123;
+    int err = anw->query(anw.get(), NATIVE_WINDOW_QUEUES_TO_WINDOW_COMPOSER,
+            &result);
+    EXPECT_EQ(NO_ERROR, err);
+    EXPECT_EQ(0, result);
+}
+
+TEST_F(SurfaceTextureClientTest, ConcreteTypeIsSurfaceTextureClient) {
+    sp<ANativeWindow> anw(mSTC);
+    int result = -123;
+    int err = anw->query(anw.get(), NATIVE_WINDOW_CONCRETE_TYPE, &result);
+    EXPECT_EQ(NO_ERROR, err);
+    EXPECT_EQ(NATIVE_WINDOW_SURFACE_TEXTURE_CLIENT, result);
+}
+
+TEST_F(SurfaceTextureClientTest, ANativeWindowLockFails) {
+    sp<ANativeWindow> anw(mSTC);
+    ANativeWindow_Buffer buf;
+    ASSERT_EQ(BAD_VALUE, ANativeWindow_lock(anw.get(), &buf, NULL));
+}
+
+TEST_F(SurfaceTextureClientTest, EglCreateWindowSurfaceFails) {
+    sp<ANativeWindow> anw(mSTC);
+
+    EGLDisplay dpy = eglGetDisplay(EGL_DEFAULT_DISPLAY);
+    ASSERT_EQ(EGL_SUCCESS, eglGetError());
+    ASSERT_NE(EGL_NO_DISPLAY, dpy);
+
+    EGLint majorVersion;
+    EGLint minorVersion;
+    EXPECT_TRUE(eglInitialize(dpy, &majorVersion, &minorVersion));
+    ASSERT_EQ(EGL_SUCCESS, eglGetError());
+
+    EGLConfig myConfig = {0};
+    EGLint numConfigs = 0;
+    EGLint configAttribs[] = {
+        EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
+        EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
+        EGL_RED_SIZE, 8,
+        EGL_GREEN_SIZE, 8,
+        EGL_BLUE_SIZE, 8,
+        EGL_ALPHA_SIZE, 8,
+        EGL_DEPTH_SIZE, 16,
+        EGL_STENCIL_SIZE, 8,
+        EGL_NONE };
+    EXPECT_TRUE(eglChooseConfig(dpy, configAttribs, &myConfig, 1,
+            &numConfigs));
+    ASSERT_EQ(EGL_SUCCESS, eglGetError());
+
+    EGLSurface eglSurface = eglCreateWindowSurface(dpy, myConfig, anw.get(),
+            NULL);
+    ASSERT_EQ(EGL_NO_SURFACE, eglSurface);
+    ASSERT_EQ(EGL_BAD_NATIVE_WINDOW, eglGetError());
+
+    eglTerminate(dpy);
+}
+
+}
diff --git a/libs/gui/tests/SurfaceTexture_test.cpp b/libs/gui/tests/SurfaceTexture_test.cpp
new file mode 100644
index 0000000..4184463
--- /dev/null
+++ b/libs/gui/tests/SurfaceTexture_test.cpp
@@ -0,0 +1,621 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <gtest/gtest.h>
+#include <gui/SurfaceTexture.h>
+#include <gui/SurfaceTextureClient.h>
+#include <ui/GraphicBuffer.h>
+#include <utils/String8.h>
+
+#include <surfaceflinger/ISurfaceComposer.h>
+#include <surfaceflinger/Surface.h>
+#include <surfaceflinger/SurfaceComposerClient.h>
+
+#include <EGL/egl.h>
+#include <EGL/eglext.h>
+#include <GLES2/gl2.h>
+#include <GLES2/gl2ext.h>
+
+#include <ui/FramebufferNativeWindow.h>
+
+namespace android {
+
+class GLTest : public ::testing::Test {
+protected:
+
+    GLTest():
+            mEglDisplay(EGL_NO_DISPLAY),
+            mEglSurface(EGL_NO_SURFACE),
+            mEglContext(EGL_NO_CONTEXT) {
+    }
+
+    virtual void SetUp() {
+        EGLBoolean returnValue;
+
+        mEglDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY);
+        ASSERT_EQ(EGL_SUCCESS, eglGetError());
+        ASSERT_NE(EGL_NO_DISPLAY, mEglDisplay);
+
+        EGLint majorVersion;
+        EGLint minorVersion;
+        EXPECT_TRUE(eglInitialize(mEglDisplay, &majorVersion, &minorVersion));
+        ASSERT_EQ(EGL_SUCCESS, eglGetError());
+        RecordProperty("EglVersionMajor", majorVersion);
+        RecordProperty("EglVersionMajor", minorVersion);
+
+        EGLConfig myConfig = {0};
+        EGLint numConfigs = 0;
+        EXPECT_TRUE(eglChooseConfig(mEglDisplay, getConfigAttribs(), &myConfig,
+                1, &numConfigs));
+        ASSERT_EQ(EGL_SUCCESS, eglGetError());
+
+        char* displaySecsEnv = getenv("GLTEST_DISPLAY_SECS");
+        if (displaySecsEnv != NULL) {
+            mDisplaySecs = atoi(displaySecsEnv);
+            if (mDisplaySecs < 0) {
+                mDisplaySecs = 0;
+            }
+        } else {
+            mDisplaySecs = 0;
+        }
+
+        if (mDisplaySecs > 0) {
+            mComposerClient = new SurfaceComposerClient;
+            ASSERT_EQ(NO_ERROR, mComposerClient->initCheck());
+
+            mSurfaceControl = mComposerClient->createSurface(getpid(),
+                    String8("Test Surface"), 0,
+                    getSurfaceWidth(), getSurfaceHeight(),
+                    PIXEL_FORMAT_RGB_888, 0);
+
+            ASSERT_TRUE(mSurfaceControl != NULL);
+            ASSERT_TRUE(mSurfaceControl->isValid());
+
+            ASSERT_EQ(NO_ERROR, mComposerClient->openTransaction());
+            ASSERT_EQ(NO_ERROR, mSurfaceControl->setLayer(30000));
+            ASSERT_EQ(NO_ERROR, mSurfaceControl->show());
+            ASSERT_EQ(NO_ERROR, mComposerClient->closeTransaction());
+
+            sp<ANativeWindow> window = mSurfaceControl->getSurface();
+            mEglSurface = eglCreateWindowSurface(mEglDisplay, myConfig,
+                    window.get(), NULL);
+        } else {
+            EGLint pbufferAttribs[] = {
+                EGL_WIDTH, getSurfaceWidth(),
+                EGL_HEIGHT, getSurfaceHeight(),
+                EGL_NONE };
+
+            mEglSurface = eglCreatePbufferSurface(mEglDisplay, myConfig,
+                    pbufferAttribs);
+        }
+        ASSERT_EQ(EGL_SUCCESS, eglGetError());
+        ASSERT_NE(EGL_NO_SURFACE, mEglSurface);
+
+        mEglContext = eglCreateContext(mEglDisplay, myConfig, EGL_NO_CONTEXT,
+                getContextAttribs());
+        ASSERT_EQ(EGL_SUCCESS, eglGetError());
+        ASSERT_NE(EGL_NO_CONTEXT, mEglContext);
+
+        EXPECT_TRUE(eglMakeCurrent(mEglDisplay, mEglSurface, mEglSurface,
+                mEglContext));
+        ASSERT_EQ(EGL_SUCCESS, eglGetError());
+
+        EGLint w, h;
+        EXPECT_TRUE(eglQuerySurface(mEglDisplay, mEglSurface, EGL_WIDTH, &w));
+        ASSERT_EQ(EGL_SUCCESS, eglGetError());
+        EXPECT_TRUE(eglQuerySurface(mEglDisplay, mEglSurface, EGL_HEIGHT, &h));
+        ASSERT_EQ(EGL_SUCCESS, eglGetError());
+        RecordProperty("EglSurfaceWidth", w);
+        RecordProperty("EglSurfaceHeight", h);
+
+        glViewport(0, 0, w, h);
+        ASSERT_EQ(GLenum(GL_NO_ERROR), glGetError());
+    }
+
+    virtual void TearDown() {
+        // Display the result 
+        if (mDisplaySecs > 0 && mEglSurface != EGL_NO_SURFACE) {
+            eglSwapBuffers(mEglDisplay, mEglSurface);
+            sleep(mDisplaySecs);
+        }
+
+        if (mComposerClient != NULL) {
+            mComposerClient->dispose();
+        }
+        if (mEglContext != EGL_NO_CONTEXT) {
+            eglDestroyContext(mEglDisplay, mEglContext);
+        }
+        if (mEglSurface != EGL_NO_SURFACE) {
+            eglDestroySurface(mEglDisplay, mEglSurface);
+        }
+        if (mEglDisplay != EGL_NO_DISPLAY) {
+            eglMakeCurrent(mEglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE,
+                    EGL_NO_CONTEXT);
+            eglTerminate(mEglDisplay);
+        }
+        ASSERT_EQ(EGL_SUCCESS, eglGetError());
+    }
+
+    virtual EGLint const* getConfigAttribs() {
+        static EGLint sDefaultConfigAttribs[] = {
+            EGL_SURFACE_TYPE, EGL_PBUFFER_BIT,
+            EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
+            EGL_RED_SIZE, 8,
+            EGL_GREEN_SIZE, 8,
+            EGL_BLUE_SIZE, 8,
+            EGL_ALPHA_SIZE, 8,
+            EGL_DEPTH_SIZE, 16,
+            EGL_STENCIL_SIZE, 8,
+            EGL_NONE };
+
+        return sDefaultConfigAttribs;
+    }
+
+    virtual EGLint const* getContextAttribs() {
+        static EGLint sDefaultContextAttribs[] = {
+            EGL_CONTEXT_CLIENT_VERSION, 2,
+            EGL_NONE };
+
+        return sDefaultContextAttribs;
+    }
+
+    virtual EGLint getSurfaceWidth() {
+        return 64;
+    }
+
+    virtual EGLint getSurfaceHeight() {
+        return 64;
+    }
+
+    void loadShader(GLenum shaderType, const char* pSource, GLuint* outShader) {
+        GLuint shader = glCreateShader(shaderType);
+        ASSERT_EQ(GLenum(GL_NO_ERROR), glGetError());
+        if (shader) {
+            glShaderSource(shader, 1, &pSource, NULL);
+            ASSERT_EQ(GLenum(GL_NO_ERROR), glGetError());
+            glCompileShader(shader);
+            ASSERT_EQ(GLenum(GL_NO_ERROR), glGetError());
+            GLint compiled = 0;
+            glGetShaderiv(shader, GL_COMPILE_STATUS, &compiled);
+            ASSERT_EQ(GLenum(GL_NO_ERROR), glGetError());
+            if (!compiled) {
+                GLint infoLen = 0;
+                glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &infoLen);
+                ASSERT_EQ(GLenum(GL_NO_ERROR), glGetError());
+                if (infoLen) {
+                    char* buf = (char*) malloc(infoLen);
+                    if (buf) {
+                        glGetShaderInfoLog(shader, infoLen, NULL, buf);
+                        printf("Shader compile log:\n%s\n", buf);
+                        free(buf);
+                        FAIL();
+                    }
+                } else {
+                    char* buf = (char*) malloc(0x1000);
+                    if (buf) {
+                        glGetShaderInfoLog(shader, 0x1000, NULL, buf);
+                        printf("Shader compile log:\n%s\n", buf);
+                        free(buf);
+                        FAIL();
+                    }
+                }
+                glDeleteShader(shader);
+                shader = 0;
+            }
+        }
+        ASSERT_TRUE(shader != 0);
+        *outShader = shader;
+    }
+
+    void createProgram(const char* pVertexSource, const char* pFragmentSource,
+            GLuint* outPgm) {
+        GLuint vertexShader, fragmentShader;
+        {
+            SCOPED_TRACE("compiling vertex shader");
+            loadShader(GL_VERTEX_SHADER, pVertexSource, &vertexShader);
+            if (HasFatalFailure()) {
+                return;
+            }
+        }
+        {
+            SCOPED_TRACE("compiling fragment shader");
+            loadShader(GL_FRAGMENT_SHADER, pFragmentSource, &fragmentShader);
+            if (HasFatalFailure()) {
+                return;
+            }
+        }
+
+        GLuint program = glCreateProgram();
+        ASSERT_EQ(GLenum(GL_NO_ERROR), glGetError());
+        if (program) {
+            glAttachShader(program, vertexShader);
+            ASSERT_EQ(GLenum(GL_NO_ERROR), glGetError());
+            glAttachShader(program, fragmentShader);
+            ASSERT_EQ(GLenum(GL_NO_ERROR), glGetError());
+            glLinkProgram(program);
+            GLint linkStatus = GL_FALSE;
+            glGetProgramiv(program, GL_LINK_STATUS, &linkStatus);
+            if (linkStatus != GL_TRUE) {
+                GLint bufLength = 0;
+                glGetProgramiv(program, GL_INFO_LOG_LENGTH, &bufLength);
+                if (bufLength) {
+                    char* buf = (char*) malloc(bufLength);
+                    if (buf) {
+                        glGetProgramInfoLog(program, bufLength, NULL, buf);
+                        printf("Program link log:\n%s\n", buf);
+                        free(buf);
+                        FAIL();
+                    }
+                }
+                glDeleteProgram(program);
+                program = 0;
+            }
+        }
+        glDeleteShader(vertexShader);
+        glDeleteShader(fragmentShader);
+        ASSERT_TRUE(program != 0);
+        *outPgm = program;
+    }
+
+    ::testing::AssertionResult checkPixel(int x, int y, int r,
+            int g, int b, int a) {
+        GLubyte pixel[4];
+        String8 msg;
+        glReadPixels(x, y, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, pixel);
+        GLenum err = glGetError();
+        if (err != GL_NO_ERROR) {
+            msg += String8::format("error reading pixel: %#x", err);
+            while ((err = glGetError()) != GL_NO_ERROR) {
+                msg += String8::format(", %#x", err);
+            }
+            fprintf(stderr, "pixel check failure: %s\n", msg.string());
+            return ::testing::AssertionFailure(
+                    ::testing::Message(msg.string()));
+        }
+        if (r >= 0 && GLubyte(r) != pixel[0]) {
+            msg += String8::format("r(%d isn't %d)", pixel[0], r);
+        }
+        if (g >= 0 && GLubyte(g) != pixel[1]) {
+            if (!msg.isEmpty()) {
+                msg += " ";
+            }
+            msg += String8::format("g(%d isn't %d)", pixel[1], g);
+        }
+        if (b >= 0 && GLubyte(b) != pixel[2]) {
+            if (!msg.isEmpty()) {
+                msg += " ";
+            }
+            msg += String8::format("b(%d isn't %d)", pixel[2], b);
+        }
+        if (a >= 0 && GLubyte(a) != pixel[3]) {
+            if (!msg.isEmpty()) {
+                msg += " ";
+            }
+            msg += String8::format("a(%d isn't %d)", pixel[3], a);
+        }
+        if (!msg.isEmpty()) {
+            fprintf(stderr, "pixel check failure: %s\n", msg.string());
+            return ::testing::AssertionFailure(
+                    ::testing::Message(msg.string()));
+        } else {
+            return ::testing::AssertionSuccess();
+        }
+    }
+
+    int mDisplaySecs;
+    sp<SurfaceComposerClient> mComposerClient;
+    sp<SurfaceControl> mSurfaceControl;
+
+    EGLDisplay mEglDisplay;
+    EGLSurface mEglSurface;
+    EGLContext mEglContext;
+};
+
+// XXX: Code above this point should live elsewhere
+
+class SurfaceTextureGLTest : public GLTest {
+protected:
+    static const GLint TEX_ID = 123;
+
+    virtual void SetUp() {
+        GLTest::SetUp();
+        mST = new SurfaceTexture(TEX_ID);
+        mSTC = new SurfaceTextureClient(mST);
+        mANW = mSTC;
+
+        const char vsrc[] =
+            "attribute vec4 vPosition;\n"
+            "varying vec2 texCoords;\n"
+            "uniform mat4 texMatrix;\n"
+            "void main() {\n"
+            "  vec2 vTexCoords = 0.5 * (vPosition.xy + vec2(1.0, 1.0));\n"
+            "  texCoords = (texMatrix * vec4(vTexCoords, 0.0, 1.0)).xy;\n"
+            "  gl_Position = vPosition;\n"
+            "}\n";
+
+        const char fsrc[] =
+            "#extension GL_OES_EGL_image_external : require\n"
+            "precision mediump float;\n"
+            "uniform samplerExternalOES texSampler;\n"
+            "varying vec2 texCoords;\n"
+            "void main() {\n"
+            "  gl_FragColor = texture2D(texSampler, texCoords);\n"
+            "}\n";
+
+        {
+            SCOPED_TRACE("creating shader program");
+            createProgram(vsrc, fsrc, &mPgm);
+            if (HasFatalFailure()) {
+                return;
+            }
+        }
+
+        mPositionHandle = glGetAttribLocation(mPgm, "vPosition");
+        ASSERT_EQ(GLenum(GL_NO_ERROR), glGetError());
+        ASSERT_NE(-1, mPositionHandle);
+        mTexSamplerHandle = glGetUniformLocation(mPgm, "texSampler");
+        ASSERT_EQ(GLenum(GL_NO_ERROR), glGetError());
+        ASSERT_NE(-1, mTexSamplerHandle);
+        mTexMatrixHandle = glGetUniformLocation(mPgm, "texMatrix");
+        ASSERT_EQ(GLenum(GL_NO_ERROR), glGetError());
+        ASSERT_NE(-1, mTexMatrixHandle);
+    }
+
+    // drawTexture draws the SurfaceTexture over the entire GL viewport.
+    void drawTexture() {
+        const GLfloat triangleVertices[] = {
+            -1.0f, 1.0f,
+            -1.0f, -1.0f,
+            1.0f, -1.0f,
+            1.0f, 1.0f,
+        };
+
+        glVertexAttribPointer(mPositionHandle, 2, GL_FLOAT, GL_FALSE, 0, triangleVertices);
+        ASSERT_EQ(GLenum(GL_NO_ERROR), glGetError());
+        glEnableVertexAttribArray(mPositionHandle);
+        ASSERT_EQ(GLenum(GL_NO_ERROR), glGetError());
+
+        glUseProgram(mPgm);
+        glUniform1i(mTexSamplerHandle, 0);
+        ASSERT_EQ(GLenum(GL_NO_ERROR), glGetError());
+        glBindTexture(GL_TEXTURE_EXTERNAL_OES, TEX_ID);
+        ASSERT_EQ(GLenum(GL_NO_ERROR), glGetError());
+
+        GLfloat texMatrix[16];
+        mST->getTransformMatrix(texMatrix);
+        glUniformMatrix4fv(mTexMatrixHandle, 1, GL_FALSE, texMatrix);
+
+        glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
+        ASSERT_EQ(GLenum(GL_NO_ERROR), glGetError());
+    }
+
+    sp<SurfaceTexture> mST;
+    sp<SurfaceTextureClient> mSTC;
+    sp<ANativeWindow> mANW;
+
+    GLuint mPgm;
+    GLint mPositionHandle;
+    GLint mTexSamplerHandle;
+    GLint mTexMatrixHandle;
+};
+
+// Fill a YV12 buffer with a multi-colored checkerboard pattern
+void fillYV12Buffer(uint8_t* buf, int w, int h, int stride) {
+    const int blockWidth = w > 16 ? w / 16 : 1;
+    const int blockHeight = h > 16 ? h / 16 : 1;
+    const int yuvTexOffsetY = 0;
+    int yuvTexStrideY = stride;
+    int yuvTexOffsetV = yuvTexStrideY * h;
+    int yuvTexStrideV = (yuvTexStrideY/2 + 0xf) & ~0xf;
+    int yuvTexOffsetU = yuvTexOffsetV + yuvTexStrideV * h/2;
+    int yuvTexStrideU = yuvTexStrideV;
+    for (int x = 0; x < w; x++) {
+        for (int y = 0; y < h; y++) {
+            int parityX = (x / blockWidth) & 1;
+            int parityY = (y / blockHeight) & 1;
+            unsigned char intensity = (parityX ^ parityY) ? 63 : 191;
+            buf[yuvTexOffsetY + (y * yuvTexStrideY) + x] = intensity;
+            if (x < w / 2 && y < h / 2) {
+                buf[yuvTexOffsetU + (y * yuvTexStrideU) + x] = intensity;
+                if (x * 2 < w / 2 && y * 2 < h / 2) {
+                    buf[yuvTexOffsetV + (y*2 * yuvTexStrideV) + x*2 + 0] =
+                    buf[yuvTexOffsetV + (y*2 * yuvTexStrideV) + x*2 + 1] =
+                    buf[yuvTexOffsetV + ((y*2+1) * yuvTexStrideV) + x*2 + 0] =
+                    buf[yuvTexOffsetV + ((y*2+1) * yuvTexStrideV) + x*2 + 1] =
+                        intensity;
+                }
+            }
+        }
+    }
+}
+
+// Fill a YV12 buffer with red outside a given rectangle and green inside it.
+void fillYV12BufferRect(uint8_t* buf, int w, int h, int stride,
+        const android_native_rect_t& rect) {
+    const int yuvTexOffsetY = 0;
+    int yuvTexStrideY = stride;
+    int yuvTexOffsetV = yuvTexStrideY * h;
+    int yuvTexStrideV = (yuvTexStrideY/2 + 0xf) & ~0xf;
+    int yuvTexOffsetU = yuvTexOffsetV + yuvTexStrideV * h/2;
+    int yuvTexStrideU = yuvTexStrideV;
+    for (int x = 0; x < w; x++) {
+        for (int y = 0; y < h; y++) {
+            bool inside = rect.left <= x && x < rect.right &&
+                    rect.top <= y && y < rect.bottom;
+            buf[yuvTexOffsetY + (y * yuvTexStrideY) + x] = inside ? 240 : 64;
+            if (x < w / 2 && y < h / 2) {
+                bool inside = rect.left <= 2*x && 2*x < rect.right &&
+                        rect.top <= 2*y && 2*y < rect.bottom;
+                buf[yuvTexOffsetU + (y * yuvTexStrideU) + x] = 16;
+                buf[yuvTexOffsetV + (y * yuvTexStrideV) + x] =
+                        inside ? 16 : 255;
+            }
+        }
+    }
+}
+
+TEST_F(SurfaceTextureGLTest, TexturingFromCpuFilledYV12BufferNpot) {
+    const int yuvTexWidth = 64;
+    const int yuvTexHeight = 66;
+
+    ASSERT_EQ(NO_ERROR, native_window_set_buffers_geometry(mANW.get(),
+            yuvTexWidth, yuvTexHeight, HAL_PIXEL_FORMAT_YV12));
+    ASSERT_EQ(NO_ERROR, native_window_set_usage(mANW.get(),
+            GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN));
+
+    android_native_buffer_t* anb;
+    ASSERT_EQ(NO_ERROR, mANW->dequeueBuffer(mANW.get(), &anb));
+    ASSERT_TRUE(anb != NULL);
+
+    sp<GraphicBuffer> buf(new GraphicBuffer(anb, false));
+    ASSERT_EQ(NO_ERROR, mANW->lockBuffer(mANW.get(), buf->getNativeBuffer()));
+
+    // Fill the buffer with the a checkerboard pattern
+    uint8_t* img = NULL;
+    buf->lock(GRALLOC_USAGE_SW_WRITE_OFTEN, (void**)(&img));
+    fillYV12Buffer(img, yuvTexWidth, yuvTexHeight, buf->getStride());
+    buf->unlock();
+    ASSERT_EQ(NO_ERROR, mANW->queueBuffer(mANW.get(), buf->getNativeBuffer()));
+
+    mST->updateTexImage();
+
+    glClearColor(0.2, 0.2, 0.2, 0.2);
+    glClear(GL_COLOR_BUFFER_BIT);
+
+    drawTexture();
+
+    EXPECT_TRUE(checkPixel( 0,  0, 255, 127, 255, 255));
+    EXPECT_TRUE(checkPixel(63,  0,   0, 133,   0, 255));
+    EXPECT_TRUE(checkPixel(63, 63,   0, 133,   0, 255));
+    EXPECT_TRUE(checkPixel( 0, 63, 255, 127, 255, 255));
+
+    EXPECT_TRUE(checkPixel(22, 44, 247,  70, 255, 255));
+    EXPECT_TRUE(checkPixel(45, 52, 209,  32, 235, 255));
+    EXPECT_TRUE(checkPixel(52, 51, 100, 255,  73, 255));
+    EXPECT_TRUE(checkPixel( 7, 31, 155,   0, 118, 255));
+    EXPECT_TRUE(checkPixel(31,  9, 148,  71, 110, 255));
+    EXPECT_TRUE(checkPixel(29, 35, 255, 127, 255, 255));
+    EXPECT_TRUE(checkPixel(36, 22, 155,  29,   0, 255));
+}
+
+// XXX: This test is disabled because it it currently broken on all devices to
+// which I have access.  Some of the checkPixel calls are not correct because
+// I just copied them from the npot test above and haven't bothered to figure
+// out the correct values.
+TEST_F(SurfaceTextureGLTest, DISABLED_TexturingFromCpuFilledYV12BufferPow2) {
+    const int yuvTexWidth = 64;
+    const int yuvTexHeight = 64;
+
+    ASSERT_EQ(NO_ERROR, native_window_set_buffers_geometry(mANW.get(),
+            yuvTexWidth, yuvTexHeight, HAL_PIXEL_FORMAT_YV12));
+    ASSERT_EQ(NO_ERROR, native_window_set_usage(mANW.get(),
+            GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN));
+
+    android_native_buffer_t* anb;
+    ASSERT_EQ(NO_ERROR, mANW->dequeueBuffer(mANW.get(), &anb));
+    ASSERT_TRUE(anb != NULL);
+
+    sp<GraphicBuffer> buf(new GraphicBuffer(anb, false));
+    ASSERT_EQ(NO_ERROR, mANW->lockBuffer(mANW.get(), buf->getNativeBuffer()));
+
+    // Fill the buffer with the a checkerboard pattern
+    uint8_t* img = NULL;
+    buf->lock(GRALLOC_USAGE_SW_WRITE_OFTEN, (void**)(&img));
+    fillYV12Buffer(img, yuvTexWidth, yuvTexHeight, buf->getStride());
+    buf->unlock();
+    ASSERT_EQ(NO_ERROR, mANW->queueBuffer(mANW.get(), buf->getNativeBuffer()));
+
+    mST->updateTexImage();
+
+    glClearColor(0.2, 0.2, 0.2, 0.2);
+    glClear(GL_COLOR_BUFFER_BIT);
+
+    drawTexture();
+
+    EXPECT_TRUE(checkPixel( 0,  0, 255, 127, 255, 255));
+    EXPECT_TRUE(checkPixel(63,  0,   0, 133,   0, 255));
+    EXPECT_TRUE(checkPixel(63, 63,   0, 133,   0, 255));
+    EXPECT_TRUE(checkPixel( 0, 63, 255, 127, 255, 255));
+
+    EXPECT_TRUE(checkPixel(22, 19, 247,  70, 255, 255));
+    EXPECT_TRUE(checkPixel(45, 11, 209,  32, 235, 255));
+    EXPECT_TRUE(checkPixel(52, 12, 100, 255,  73, 255));
+    EXPECT_TRUE(checkPixel( 7, 32, 155,   0, 118, 255));
+    EXPECT_TRUE(checkPixel(31, 54, 148,  71, 110, 255));
+    EXPECT_TRUE(checkPixel(29, 28, 255, 127, 255, 255));
+    EXPECT_TRUE(checkPixel(36, 41, 155,  29,   0, 255));
+}
+
+TEST_F(SurfaceTextureGLTest, TexturingFromCpuFilledYV12BufferWithCrop) {
+    const int yuvTexWidth = 64;
+    const int yuvTexHeight = 66;
+
+    ASSERT_EQ(NO_ERROR, native_window_set_buffers_geometry(mANW.get(),
+            yuvTexWidth, yuvTexHeight, HAL_PIXEL_FORMAT_YV12));
+    ASSERT_EQ(NO_ERROR, native_window_set_usage(mANW.get(),
+            GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN));
+
+    android_native_rect_t crops[] = {
+        {4, 6, 22, 36},
+        {0, 6, 22, 36},
+        {4, 0, 22, 36},
+        {4, 6, yuvTexWidth, 36},
+        {4, 6, 22, yuvTexHeight},
+    };
+
+    for (int i = 0; i < 5; i++) {
+        const android_native_rect_t& crop(crops[i]);
+        SCOPED_TRACE(String8::format("rect{ l: %d t: %d r: %d b: %d }", crop.left,
+                crop.top, crop.right, crop.bottom).string());
+
+        ASSERT_EQ(NO_ERROR, native_window_set_crop(mANW.get(), &crop));
+
+        android_native_buffer_t* anb;
+        ASSERT_EQ(NO_ERROR, mANW->dequeueBuffer(mANW.get(), &anb));
+        ASSERT_TRUE(anb != NULL);
+
+        sp<GraphicBuffer> buf(new GraphicBuffer(anb, false));
+        ASSERT_EQ(NO_ERROR, mANW->lockBuffer(mANW.get(), buf->getNativeBuffer()));
+
+        uint8_t* img = NULL;
+        buf->lock(GRALLOC_USAGE_SW_WRITE_OFTEN, (void**)(&img));
+        fillYV12BufferRect(img, yuvTexWidth, yuvTexHeight, buf->getStride(), crop);
+        buf->unlock();
+        ASSERT_EQ(NO_ERROR, mANW->queueBuffer(mANW.get(), buf->getNativeBuffer()));
+
+        mST->updateTexImage();
+
+        glClearColor(0.2, 0.2, 0.2, 0.2);
+        glClear(GL_COLOR_BUFFER_BIT);
+
+        drawTexture();
+
+        EXPECT_TRUE(checkPixel( 0,  0,  82, 255,  35, 255));
+        EXPECT_TRUE(checkPixel(63,  0,  82, 255,  35, 255));
+        EXPECT_TRUE(checkPixel(63, 63,  82, 255,  35, 255));
+        EXPECT_TRUE(checkPixel( 0, 63,  82, 255,  35, 255));
+
+        EXPECT_TRUE(checkPixel(25, 14,  82, 255,  35, 255));
+        EXPECT_TRUE(checkPixel(35, 31,  82, 255,  35, 255));
+        EXPECT_TRUE(checkPixel(57,  6,  82, 255,  35, 255));
+        EXPECT_TRUE(checkPixel( 5, 42,  82, 255,  35, 255));
+        EXPECT_TRUE(checkPixel(32, 33,  82, 255,  35, 255));
+        EXPECT_TRUE(checkPixel(16, 26,  82, 255,  35, 255));
+        EXPECT_TRUE(checkPixel(46, 51,  82, 255,  35, 255));
+    }
+}
+
+}
diff --git a/libs/hwui/Android.mk b/libs/hwui/Android.mk
index 38e0848..b465fee 100644
--- a/libs/hwui/Android.mk
+++ b/libs/hwui/Android.mk
@@ -15,7 +15,6 @@
 		LayerCache.cpp \
 		LayerRenderer.cpp \
 		Matrix.cpp \
-		OpenGLDebugRenderer.cpp \
 		OpenGLRenderer.cpp \
 		Patch.cpp \
 		PatchCache.cpp \
@@ -43,7 +42,6 @@
 	LOCAL_SHARED_LIBRARIES := libcutils libutils libGLESv2 libskia libui
 	LOCAL_MODULE := libhwui
 	LOCAL_MODULE_TAGS := optional
-	LOCAL_PRELINK_MODULE := false
 	
 	include $(BUILD_SHARED_LIBRARY)
 
diff --git a/libs/hwui/DisplayListRenderer.cpp b/libs/hwui/DisplayListRenderer.cpp
index d5d2ba0..bf1182c 100644
--- a/libs/hwui/DisplayListRenderer.cpp
+++ b/libs/hwui/DisplayListRenderer.cpp
@@ -53,6 +53,7 @@
     "DrawArc",
     "DrawPath",
     "DrawLines",
+    "DrawPoints",
     "DrawText",
     "ResetShader",
     "SetupShader",
@@ -95,10 +96,6 @@
         delete mPaths.itemAt(i);
     }
     mPaths.clear();
-    for (size_t i = 0; i < mOriginalPaths.size(); i++) {
-        caches.resourceCache.decrementRefcount(mOriginalPaths.itemAt(i));
-    }
-    mOriginalPaths.clear();
 
     for (size_t i = 0; i < mMatrices.size(); i++) {
         delete mMatrices.itemAt(i);
@@ -150,13 +147,6 @@
         mPaths.add(paths.itemAt(i));
     }
 
-    const Vector<SkPath*> &originalPaths = recorder.getOriginalPaths();
-    for (size_t i = 0; i < originalPaths.size(); i++) {
-        SkPath* path = originalPaths.itemAt(i);
-        mOriginalPaths.add(path);
-        caches.resourceCache.incrementRefcount(path);
-    }
-
     const Vector<SkMatrix*> &matrices = recorder.getMatrices();
     for (size_t i = 0; i < matrices.size(); i++) {
         mMatrices.add(matrices.itemAt(i));
@@ -166,7 +156,7 @@
 void DisplayList::init() {
 }
 
-bool DisplayList::replay(OpenGLRenderer& renderer, uint32_t level) {
+bool DisplayList::replay(OpenGLRenderer& renderer, Rect& dirty, uint32_t level) {
     bool needsInvalidate = false;
     TextContainer text;
     mReader.rewind();
@@ -189,7 +179,7 @@
             case DrawGLFunction: {
                 Functor *functor = (Functor *) getInt();
                 DISPLAY_LIST_LOGD("%s%s %p", (char*) indent, OP_NAMES[op], functor);
-                needsInvalidate |= renderer.callDrawGLFunction(functor);
+                needsInvalidate |= renderer.callDrawGLFunction(functor, dirty);
             }
             break;
             case Save: {
@@ -285,9 +275,12 @@
             break;
             case DrawDisplayList: {
                 DisplayList* displayList = getDisplayList();
-                DISPLAY_LIST_LOGD("%s%s %p, %d", (char*) indent, OP_NAMES[op],
-                    displayList, level + 1);
-                needsInvalidate |= renderer.drawDisplayList(displayList, level + 1);
+                uint32_t width = getUInt();
+                uint32_t height = getUInt();
+                DISPLAY_LIST_LOGD("%s%s %p, %dx%d, %d", (char*) indent, OP_NAMES[op],
+                    displayList, width, height, level + 1);
+                needsInvalidate |= renderer.drawDisplayList(displayList, width, height,
+                        dirty, level + 1);
             }
             break;
             case DrawLayer: {
@@ -449,6 +442,13 @@
                 renderer.drawLines(points, count, getPaint());
             }
             break;
+            case DrawPoints: {
+                int count = 0;
+                float* points = getFloats(count);
+                DISPLAY_LIST_LOGD("%s%s", (char*) indent, OP_NAMES[op]);
+                renderer.drawPoints(points, count, getPaint());
+            }
+            break;
             case DrawText: {
                 getText(&text);
                 int count = getInt();
@@ -530,12 +530,6 @@
     }
     mBitmapResources.clear();
 
-    for (size_t i = 0; i < mOriginalPaths.size(); i++) {
-        SkPath* resource = mOriginalPaths.itemAt(i);
-        caches.resourceCache.decrementRefcount(resource);
-    }
-    mOriginalPaths.clear();
-
     for (size_t i = 0; i < mShaders.size(); i++) {
        caches.resourceCache.decrementRefcount(mShaders.itemAt(i));
     }
@@ -589,7 +583,8 @@
 void DisplayListRenderer::resume() {
 }
 
-bool DisplayListRenderer::callDrawGLFunction(Functor *functor) {
+bool DisplayListRenderer::callDrawGLFunction(Functor *functor, Rect& dirty) {
+    // Ignore dirty during recording, it matters only when we replay
     addOp(DisplayList::DrawGLFunction);
     addInt((int) functor);
     return false; // No invalidate needed at record-time
@@ -673,9 +668,13 @@
     return OpenGLRenderer::clipRect(left, top, right, bottom, op);
 }
 
-bool DisplayListRenderer::drawDisplayList(DisplayList* displayList, uint32_t level) {
+bool DisplayListRenderer::drawDisplayList(DisplayList* displayList,
+        uint32_t width, uint32_t height, Rect& dirty, uint32_t level) {
+    // dirty is an out parameter and should not be recorded,
+    // it matters only when replaying the display list
     addOp(DisplayList::DrawDisplayList);
     addDisplayList(displayList);
+    addSize(width, height);
     return false;
 }
 
@@ -796,6 +795,12 @@
     addPaint(paint);
 }
 
+void DisplayListRenderer::drawPoints(float* points, int count, SkPaint* paint) {
+    addOp(DisplayList::DrawPoints);
+    addFloats(points, count);
+    addPaint(paint);
+}
+
 void DisplayListRenderer::drawText(const char* text, int bytesCount, int count,
         float x, float y, SkPaint* paint) {
     addOp(DisplayList::DrawText);
diff --git a/libs/hwui/DisplayListRenderer.h b/libs/hwui/DisplayListRenderer.h
index e8f189d..da57e4a 100644
--- a/libs/hwui/DisplayListRenderer.h
+++ b/libs/hwui/DisplayListRenderer.h
@@ -89,6 +89,7 @@
         DrawArc,
         DrawPath,
         DrawLines,
+        DrawPoints,
         DrawText,
         ResetShader,
         SetupShader,
@@ -103,7 +104,7 @@
 
     void initFromDisplayListRenderer(const DisplayListRenderer& recorder, bool reusing = false);
 
-    bool replay(OpenGLRenderer& renderer, uint32_t level = 0);
+    bool replay(OpenGLRenderer& renderer, Rect& dirty, uint32_t level = 0);
 
 private:
     void init();
@@ -144,6 +145,10 @@
         return mReader.readInt();
     }
 
+    inline uint32_t getUInt() {
+        return mReader.readU32();
+    }
+
     SkMatrix* getMatrix() {
         return (SkMatrix*) getInt();
     }
@@ -189,7 +194,6 @@
 
     Vector<SkPaint*> mPaints;
     Vector<SkPath*> mPaths;
-    Vector<SkPath*> mOriginalPaths;
     Vector<SkMatrix*> mMatrices;
     Vector<SkiaShader*> mShaders;
 
@@ -214,7 +218,7 @@
     void prepareDirty(float left, float top, float right, float bottom, bool opaque);
     void finish();
 
-    bool callDrawGLFunction(Functor *functor);
+    bool callDrawGLFunction(Functor *functor, Rect& dirty);
 
     void interrupt();
     void resume();
@@ -238,7 +242,8 @@
 
     bool clipRect(float left, float top, float right, float bottom, SkRegion::Op op);
 
-    bool drawDisplayList(DisplayList* displayList, uint32_t level = 0);
+    bool drawDisplayList(DisplayList* displayList, uint32_t width, uint32_t height,
+            Rect& dirty, uint32_t level = 0);
     void drawLayer(Layer* layer, float x, float y, SkPaint* paint);
     void drawBitmap(SkBitmap* bitmap, float left, float top, SkPaint* paint);
     void drawBitmap(SkBitmap* bitmap, SkMatrix* matrix, SkPaint* paint);
@@ -260,6 +265,7 @@
             float startAngle, float sweepAngle, bool useCenter, SkPaint* paint);
     void drawPath(SkPath* path, SkPaint* paint);
     void drawLines(float* points, int count, SkPaint* paint);
+    void drawPoints(float* points, int count, SkPaint* paint);
     void drawText(const char* text, int bytesCount, int count, float x, float y, SkPaint* paint);
 
     void resetShader();
@@ -293,10 +299,6 @@
         return mPaths;
     }
 
-    const Vector<SkPath*>& getOriginalPaths() const {
-        return mOriginalPaths;
-    }
-
     const Vector<SkMatrix*>& getMatrices() const {
         return mMatrices;
     }
@@ -323,6 +325,11 @@
         mWriter.writeInt(value);
     }
 
+    inline void addSize(uint32_t w, uint32_t h) {
+        mWriter.writeInt(w);
+        mWriter.writeInt(h);
+    }
+
     void addInts(const int32_t* values, uint32_t count) {
         mWriter.writeInt(count);
         for (uint32_t i = 0; i < count; i++) {
@@ -373,16 +380,9 @@
 
         SkPath* pathCopy = mPathMap.valueFor(path);
         if (pathCopy == NULL || pathCopy->getGenerationID() != path->getGenerationID()) {
-            if (pathCopy == NULL) {
-                pathCopy = path;
-                mOriginalPaths.add(path);
-                Caches& caches = Caches::getInstance();
-                caches.resourceCache.incrementRefcount(path);
-            } else {
-                pathCopy = new SkPath(*path);
-                mPaths.add(pathCopy);
-            }
+            pathCopy = new SkPath(*path);
             mPathMap.add(path, pathCopy);
+            mPaths.add(pathCopy);
         }
 
         addInt((int) pathCopy);
@@ -459,7 +459,6 @@
     Vector<SkPaint*> mPaints;
     DefaultKeyedVector<SkPaint*, SkPaint*> mPaintMap;
 
-    Vector<SkPath*> mOriginalPaths;
     Vector<SkPath*> mPaths;
     DefaultKeyedVector<SkPath*, SkPath*> mPathMap;
 
diff --git a/libs/hwui/Layer.h b/libs/hwui/Layer.h
index bb284379..26e240f 100644
--- a/libs/hwui/Layer.h
+++ b/libs/hwui/Layer.h
@@ -103,6 +103,11 @@
      * have been drawn.
      */
     Region region;
+    /**
+     * If the region is a rectangle, coordinates of the
+     * region are stored here.
+     */
+    Rect regionRect;
 
     /**
      * Color filter used to draw this layer. Optional.
diff --git a/libs/hwui/LayerRenderer.cpp b/libs/hwui/LayerRenderer.cpp
index b1eb164..ba110ec 100644
--- a/libs/hwui/LayerRenderer.cpp
+++ b/libs/hwui/LayerRenderer.cpp
@@ -101,6 +101,20 @@
             mLayer->meshIndices = NULL;
             mLayer->meshElementCount = 0;
         }
+
+        const android::Rect& bounds = mLayer->region.getBounds();
+        mLayer->regionRect.set(bounds.leftTop().x, bounds.leftTop().y,
+                bounds.rightBottom().x, bounds.rightBottom().y);
+
+        const float texX = 1.0f / float(mLayer->width);
+        const float texY = 1.0f / float(mLayer->height);
+        const float height = mLayer->layer.getHeight();
+        mLayer->texCoords.set(
+                mLayer->regionRect.left * texX,
+                (height - mLayer->regionRect.top) * texY,
+                mLayer->regionRect.right * texX,
+                (height - mLayer->regionRect.bottom) * texY);
+
         return;
     }
 
diff --git a/libs/hwui/OpenGLDebugRenderer.cpp b/libs/hwui/OpenGLDebugRenderer.cpp
deleted file mode 100644
index 05870bb..0000000
--- a/libs/hwui/OpenGLDebugRenderer.cpp
+++ /dev/null
@@ -1,156 +0,0 @@
-/*
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#define LOG_TAG "OpenGLRenderer"
-
-#include <utils/StopWatch.h>
-
-#include "OpenGLDebugRenderer.h"
-
-namespace android {
-namespace uirenderer {
-
-void OpenGLDebugRenderer::prepareDirty(float left, float top,
-        float right, float bottom, bool opaque) {
-    mPrimitivesCount = 0;
-    LOGD("========= Frame start =========");
-    OpenGLRenderer::prepareDirty(left, top, right, bottom, opaque);
-}
-
-void OpenGLDebugRenderer::finish() {
-    LOGD("========= Frame end =========");
-    LOGD("Primitives draw count = %d", mPrimitivesCount);
-    OpenGLRenderer::finish();
-}
-
-void OpenGLDebugRenderer::composeLayer(sp<Snapshot> current, sp<Snapshot> previous) {
-    mPrimitivesCount++;
-    StopWatch w("composeLayer");
-    return OpenGLRenderer::composeLayer(current, previous);
-}
-
-int OpenGLDebugRenderer::saveLayer(float left, float top, float right, float bottom,
-        SkPaint* p, int flags) {
-    mPrimitivesCount++;
-    StopWatch w("saveLayer");
-    return OpenGLRenderer::saveLayer(left, top, right, bottom, p, flags);
-}
-
-bool OpenGLDebugRenderer::drawDisplayList(DisplayList* displayList, uint32_t level) {
-    mPrimitivesCount++;
-    StopWatch w("drawDisplayList");
-    return OpenGLRenderer::drawDisplayList(displayList);
-}
-
-void OpenGLDebugRenderer::drawLayer(Layer* layer, float x, float y, SkPaint* paint) {
-    mPrimitivesCount++;
-    StopWatch w("drawLayer");
-    OpenGLRenderer::drawLayer(layer, x, y, paint);
-}
-
-void OpenGLDebugRenderer::drawBitmap(SkBitmap* bitmap, float left, float top,
-        SkPaint* paint) {
-    mPrimitivesCount++;
-    StopWatch w("drawBitmap");
-    OpenGLRenderer::drawBitmap(bitmap, left, top, paint);
-}
-
-void OpenGLDebugRenderer::drawBitmap(SkBitmap* bitmap, SkMatrix* matrix,
-        SkPaint* paint) {
-    mPrimitivesCount++;
-    StopWatch w("drawBitmapMatrix");
-    OpenGLRenderer::drawBitmap(bitmap, matrix, paint);
-}
-
-void OpenGLDebugRenderer::drawBitmap(SkBitmap* bitmap, float srcLeft, float srcTop,
-        float srcRight, float srcBottom, float dstLeft, float dstTop,
-        float dstRight, float dstBottom, SkPaint* paint) {
-    mPrimitivesCount++;
-    StopWatch w("drawBitmapRect");
-    OpenGLRenderer::drawBitmap(bitmap, srcLeft, srcTop, srcRight, srcBottom,
-            dstLeft, dstTop, dstRight, dstBottom, paint);
-}
-
-void OpenGLDebugRenderer::drawPatch(SkBitmap* bitmap, const int32_t* xDivs, const int32_t* yDivs,
-        const uint32_t* colors, uint32_t width, uint32_t height, int8_t numColors,
-        float left, float top, float right, float bottom, SkPaint* paint) {
-    mPrimitivesCount++;
-    StopWatch w("drawPatch");
-    OpenGLRenderer::drawPatch(bitmap, xDivs, yDivs, colors, width, height, numColors,
-            left, top, right, bottom, paint);
-}
-
-void OpenGLDebugRenderer::drawColor(int color, SkXfermode::Mode mode) {
-    mPrimitivesCount++;
-    StopWatch w("drawColor");
-    OpenGLRenderer::drawColor(color, mode);
-}
-
-void OpenGLDebugRenderer::drawRect(float left, float top, float right, float bottom,
-        SkPaint* paint) {
-    mPrimitivesCount++;
-    StopWatch w("drawRect");
-    OpenGLRenderer::drawRect(left, top, right, bottom, paint);
-}
-
-void OpenGLDebugRenderer::drawRoundRect(float left, float top, float right, float bottom,
-        float rx, float ry, SkPaint* paint) {
-    mPrimitivesCount++;
-    StopWatch w("drawRoundRect");
-    OpenGLRenderer::drawRoundRect(left, top, right, bottom, rx, ry, paint);
-}
-
-void OpenGLDebugRenderer::drawCircle(float x, float y, float radius, SkPaint* paint) {
-    mPrimitivesCount++;
-    StopWatch w("drawCircle");
-    OpenGLRenderer::drawCircle(x, y, radius, paint);
-}
-
-void OpenGLDebugRenderer::drawOval(float left, float top, float right, float bottom,
-        SkPaint* paint) {
-    mPrimitivesCount++;
-    StopWatch w("drawOval");
-    OpenGLRenderer::drawOval(left, top, right, bottom, paint);
-}
-
-void OpenGLDebugRenderer::drawArc(float left, float top, float right, float bottom,
-        float startAngle, float sweepAngle, bool useCenter, SkPaint* paint) {
-    mPrimitivesCount++;
-    StopWatch w("drawArc");
-    OpenGLRenderer::drawArc(left, top, right, bottom, startAngle, sweepAngle, useCenter, paint);
-}
-
-void OpenGLDebugRenderer::drawPath(SkPath* path, SkPaint* paint) {
-    mPrimitivesCount++;
-    StopWatch w("drawPath");
-    OpenGLRenderer::drawPath(path, paint);
-}
-
-void OpenGLDebugRenderer::drawLines(float* points, int count, SkPaint* paint) {
-    mPrimitivesCount++;
-    StopWatch w("drawLines");
-    OpenGLRenderer::drawLines(points, count, paint);
-}
-
-void OpenGLDebugRenderer::drawText(const char* text, int bytesCount, int count, float x, float y,
-        SkPaint* paint) {
-    mPrimitivesCount++;
-    StopWatch w("drawText");
-    OpenGLRenderer::drawText(text, bytesCount, count, x, y, paint);
-}
-
-}; // namespace uirenderer
-}; // namespace android
diff --git a/libs/hwui/OpenGLDebugRenderer.h b/libs/hwui/OpenGLDebugRenderer.h
deleted file mode 100644
index 1a18a67..0000000
--- a/libs/hwui/OpenGLDebugRenderer.h
+++ /dev/null
@@ -1,77 +0,0 @@
-/*
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef ANDROID_HWUI_OPENGL_DEBUG_RENDERER_H
-#define ANDROID_HWUI_OPENGL_DEBUG_RENDERER_H
-
-#include "OpenGLRenderer.h"
-
-namespace android {
-namespace uirenderer {
-
-///////////////////////////////////////////////////////////////////////////////
-// Renderer
-///////////////////////////////////////////////////////////////////////////////
-
-class OpenGLDebugRenderer: public OpenGLRenderer {
-public:
-    OpenGLDebugRenderer(): mPrimitivesCount(0) {
-    }
-
-    ~OpenGLDebugRenderer() {
-    }
-
-    void prepareDirty(float left, float top, float right, float bottom, bool opaque);
-    void finish();
-
-    int saveLayer(float left, float top, float right, float bottom,
-            SkPaint* p, int flags);
-
-    bool drawDisplayList(DisplayList* displayList, uint32_t level = 0);
-    void drawLayer(Layer* layer, float x, float y, SkPaint* paint);
-    void drawBitmap(SkBitmap* bitmap, float left, float top, SkPaint* paint);
-    void drawBitmap(SkBitmap* bitmap, SkMatrix* matrix, SkPaint* paint);
-    void drawBitmap(SkBitmap* bitmap, float srcLeft, float srcTop,
-            float srcRight, float srcBottom, float dstLeft, float dstTop,
-            float dstRight, float dstBottom, SkPaint* paint);
-    void drawPatch(SkBitmap* bitmap, const int32_t* xDivs, const int32_t* yDivs,
-            const uint32_t* colors, uint32_t width, uint32_t height, int8_t numColors,
-            float left, float top, float right, float bottom, SkPaint* paint);
-    void drawColor(int color, SkXfermode::Mode mode);
-    void drawRect(float left, float top, float right, float bottom, SkPaint* paint);
-    void drawRoundRect(float left, float top, float right, float bottom,
-            float rx, float ry, SkPaint* paint);
-    void drawCircle(float x, float y, float radius, SkPaint* paint);
-    void drawOval(float left, float top, float right, float bottom, SkPaint* paint);
-    void drawArc(float left, float top, float right, float bottom,
-            float startAngle, float sweepAngle, bool useCenter, SkPaint* paint);
-    void drawPath(SkPath* path, SkPaint* paint);
-    void drawLines(float* points, int count, SkPaint* paint);
-    void drawText(const char* text, int bytesCount, int count, float x, float y,
-            SkPaint* paint);
-
-protected:
-    void composeLayer(sp<Snapshot> current, sp<Snapshot> previous);
-
-private:
-    uint32_t mPrimitivesCount;
-
-}; // class OpenGLDebugRenderer
-
-}; // namespace uirenderer
-}; // namespace android
-
-#endif // ANDROID_HWUI_OPENGL_DEBUG_RENDERER_H
diff --git a/libs/hwui/OpenGLRenderer.cpp b/libs/hwui/OpenGLRenderer.cpp
index dfca7eb..6c454a4 100644
--- a/libs/hwui/OpenGLRenderer.cpp
+++ b/libs/hwui/OpenGLRenderer.cpp
@@ -26,6 +26,8 @@
 #include <utils/Log.h>
 #include <utils/StopWatch.h>
 
+#include <private/hwui/DrawGlInfo.h>
+
 #include <ui/Rect.h>
 
 #include "OpenGLRenderer.h"
@@ -210,25 +212,40 @@
     glBlendEquation(GL_FUNC_ADD);
 }
 
-bool OpenGLRenderer::callDrawGLFunction(Functor *functor) {
+bool OpenGLRenderer::callDrawGLFunction(Functor *functor, Rect& dirty) {
     interrupt();
     if (mDirtyClip) {
         setScissorFromClip();
     }
 
+    Rect clip(*mSnapshot->clipRect);
+    clip.snapToPixelBoundaries();
+
 #if RENDER_LAYERS_AS_REGIONS
     // Since we don't know what the functor will draw, let's dirty
     // tne entire clip region
     if (hasLayer()) {
-        Rect clip(*mSnapshot->clipRect);
-        clip.snapToPixelBoundaries();
         dirtyLayerUnchecked(clip, getRegion());
     }
 #endif
 
-    status_t result = (*functor)();
+    DrawGlInfo info;
+    info.clipLeft = clip.left;
+    info.clipTop = clip.top;
+    info.clipRight = clip.right;
+    info.clipBottom = clip.bottom;
+    info.isLayer = hasLayer();
+    getSnapshot()->transform->copyTo(&info.transform[0]);
+
+    status_t result = (*functor)(0, &info);
+
+    if (result != 0) {
+        Rect localDirty(info.dirtyLeft, info.dirtyTop, info.dirtyRight, info.dirtyBottom);
+        dirty.unionWith(localDirty);
+    }
+
     resume();
-    return (result == 0) ? false : true;
+    return result != 0;
 }
 
 ///////////////////////////////////////////////////////////////////////////////
@@ -396,22 +413,23 @@
 
     // Window coordinates of the layer
     Rect bounds(left, top, right, bottom);
-    if (fboLayer) {
-        // Clear the previous layer regions before we change the viewport
-        clearLayerRegions();
-    } else {
+    if (!fboLayer) {
         mSnapshot->transform->mapRect(bounds);
 
         // Layers only make sense if they are in the framebuffer's bounds
-        bounds.intersect(*snapshot->clipRect);
+        if (bounds.intersect(*snapshot->clipRect)) {
+            // We cannot work with sub-pixels in this case
+            bounds.snapToPixelBoundaries();
 
-        // We cannot work with sub-pixels in this case
-        bounds.snapToPixelBoundaries();
-
-        // When the layer is not an FBO, we may use glCopyTexImage so we
-        // need to make sure the layer does not extend outside the bounds
-        // of the framebuffer
-        bounds.intersect(snapshot->previous->viewport);
+            // When the layer is not an FBO, we may use glCopyTexImage so we
+            // need to make sure the layer does not extend outside the bounds
+            // of the framebuffer
+            if (!bounds.intersect(snapshot->previous->viewport)) {
+                bounds.setEmpty();
+            }
+        } else {
+            bounds.setEmpty();
+        }
     }
 
     if (bounds.isEmpty() || bounds.getWidth() > mCaches.maxTextureSize ||
@@ -457,8 +475,14 @@
                 glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, bounds.left,
                         snapshot->height - bounds.bottom, bounds.getWidth(), bounds.getHeight());
             }
-            // Enqueue the buffer coordinates to clear the corresponding region later
-            mLayers.push(new Rect(bounds));
+
+            // Clear the framebuffer where the layer will draw
+            glScissor(bounds.left, mSnapshot->height - bounds.bottom,
+                    bounds.getWidth(), bounds.getHeight());
+            glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
+            glClear(GL_COLOR_BUFFER_BIT);
+
+            dirtyClip();
         }
     }
 
@@ -623,7 +647,7 @@
 void OpenGLRenderer::composeLayerRegion(Layer* layer, const Rect& rect) {
 #if RENDER_LAYERS_AS_REGIONS
     if (layer->region.isRect()) {
-        composeLayerRect(layer, rect);
+        composeLayerRect(layer, layer->regionRect);
         layer->region.clear();
         return;
     }
@@ -753,31 +777,6 @@
 #endif
 }
 
-void OpenGLRenderer::clearLayerRegions() {
-    if (mLayers.size() == 0 || mSnapshot->isIgnored()) return;
-
-    Rect clipRect(*mSnapshot->clipRect);
-    clipRect.snapToPixelBoundaries();
-
-    for (uint32_t i = 0; i < mLayers.size(); i++) {
-        Rect* bounds = mLayers.itemAt(i);
-        if (clipRect.intersects(*bounds)) {
-            // Clear the framebuffer where the layer will draw
-            glScissor(bounds->left, mSnapshot->height - bounds->bottom,
-                    bounds->getWidth(), bounds->getHeight());
-            glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
-            glClear(GL_COLOR_BUFFER_BIT);
-
-            // Restore the clip
-            dirtyClip();
-        }
-
-        delete bounds;
-    }
-
-    mLayers.clear();
-}
-
 ///////////////////////////////////////////////////////////////////////////////
 // Transforms
 ///////////////////////////////////////////////////////////////////////////////
@@ -863,7 +862,6 @@
 ///////////////////////////////////////////////////////////////////////////////
 
 void OpenGLRenderer::setupDraw() {
-    clearLayerRegions();
     if (mDirtyClip) {
         setScissorFromClip();
     }
@@ -881,6 +879,11 @@
     mDescription.hasAlpha8Texture = isAlpha8;
 }
 
+void OpenGLRenderer::setupDrawPoint(float pointSize) {
+    mDescription.isPoint = true;
+    mDescription.pointSize = pointSize;
+}
+
 void OpenGLRenderer::setupDrawColor(int color) {
     setupDrawColor(color, (color >> 24) & 0xFF);
 }
@@ -989,6 +992,11 @@
     }
 }
 
+void OpenGLRenderer::setupDrawPointUniforms() {
+    int slot = mCaches.currentProgram->getUniform("pointSize");
+    glUniform1f(slot, mDescription.pointSize);
+}
+
 void OpenGLRenderer::setupDrawColorUniforms() {
     if (mColorSet || (mShader && mSetShaderColor)) {
         mCaches.currentProgram->setColor(mColorR, mColorG, mColorB, mColorA);
@@ -1057,15 +1065,57 @@
 // Drawing
 ///////////////////////////////////////////////////////////////////////////////
 
-bool OpenGLRenderer::drawDisplayList(DisplayList* displayList, uint32_t level) {
+bool OpenGLRenderer::drawDisplayList(DisplayList* displayList, uint32_t width, uint32_t height,
+        Rect& dirty, uint32_t level) {
+    if (quickReject(0.0f, 0.0f, width, height)) {
+        return false;
+    }
+
     // All the usual checks and setup operations (quickReject, setupDraw, etc.)
     // will be performed by the display list itself
     if (displayList) {
-        return displayList->replay(*this, level);
+        return displayList->replay(*this, dirty, level);
     }
+
     return false;
 }
 
+void OpenGLRenderer::drawAlphaBitmap(Texture* texture, float left, float top, SkPaint* paint) {
+    int alpha;
+    SkXfermode::Mode mode;
+    getAlphaAndMode(paint, &alpha, &mode);
+
+    setTextureWrapModes(texture, GL_CLAMP_TO_EDGE, GL_CLAMP_TO_EDGE);
+
+    float x = left;
+    float y = top;
+
+    bool ignoreTransform = false;
+    if (mSnapshot->transform->isPureTranslate()) {
+        x = (int) floorf(left + mSnapshot->transform->getTranslateX() + 0.5f);
+        y = (int) floorf(top + mSnapshot->transform->getTranslateY() + 0.5f);
+        ignoreTransform = true;
+    }
+
+    setupDraw();
+    setupDrawWithTexture(true);
+    setupDrawAlpha8Color(paint->getColor(), alpha);
+    setupDrawColorFilter();
+    setupDrawShader();
+    setupDrawBlending(true, mode);
+    setupDrawProgram();
+    setupDrawModelView(x, y, x + texture->width, y + texture->height, ignoreTransform);
+    setupDrawTexture(texture->id);
+    setupDrawPureColorUniforms();
+    setupDrawColorFilterUniforms();
+    setupDrawShaderUniforms();
+    setupDrawMesh(NULL, (GLvoid*) gMeshTextureOffset);
+
+    glDrawArrays(GL_TRIANGLE_STRIP, 0, gMeshCount);
+
+    finishDrawTexture();
+}
+
 void OpenGLRenderer::drawBitmap(SkBitmap* bitmap, float left, float top, SkPaint* paint) {
     const float right = left + bitmap->width();
     const float bottom = top + bitmap->height();
@@ -1079,7 +1129,11 @@
     if (!texture) return;
     const AutoTexture autoCleanup(texture);
 
-    drawTextureRect(left, top, right, bottom, texture, paint);
+    if (bitmap->getConfig() == SkBitmap::kA8_Config) {
+        drawAlphaBitmap(texture, left, top, paint);
+    } else {
+        drawTextureRect(left, top, right, bottom, texture, paint);
+    }
 }
 
 void OpenGLRenderer::drawBitmap(SkBitmap* bitmap, SkMatrix* matrix, SkPaint* paint) {
@@ -1382,28 +1436,68 @@
     } else {
         // TODO: Handle the AA case
         for (int i = 0; i < count; i += 4) {
-            const float left = fmin(points[i], points[i + 1]);
-            const float right = fmax(points[i], points[i + 1]);
-            const float top = fmin(points[i + 2], points[i + 3]);
-            const float bottom = fmax(points[i + 2], points[i + 3]);
+            TextureVertex::set(vertex++, points[i], points[i + 1], 0.0f, 0.0f);
+            TextureVertex::set(vertex++, points[i + 2], points[i + 3], 0.0f, 0.0f);
 
-            if (!quickReject(left, top, right, bottom)) {
-                TextureVertex::set(vertex++, points[i], points[i + 1], 0.0f, 0.0f);
-                TextureVertex::set(vertex++, points[i + 2], points[i + 3], 0.0f, 0.0f);
+            generatedVerticesCount += 2;
 
-                generatedVerticesCount += 2;
+            const float left = fmin(points[i], points[i + 2]);
+            const float right = fmax(points[i], points[i + 2]);
+            const float top = fmin(points[i + 1], points[i + 3]);
+            const float bottom = fmax(points[i + 1], points[i + 3]);
 
-                dirtyLayer(left, top, right, bottom, *mSnapshot->transform);
-            }
+            dirtyLayer(left, top,
+                    right == left ? left + 1 : right, bottom == top ? top + 1 : bottom,
+                    *mSnapshot->transform);
         }
 
-        if (generatedVerticesCount > 0) {
-            glLineWidth(1.0f);
-            glDrawArrays(GL_LINES, 0, generatedVerticesCount);
-        }
+        glLineWidth(1.0f);
+        glDrawArrays(GL_LINES, 0, generatedVerticesCount);
     }
 }
 
+void OpenGLRenderer::drawPoints(float* points, int count, SkPaint* paint) {
+    if (mSnapshot->isIgnored()) return;
+
+    // TODO: The paint's cap style defines whether the points are square or circular
+    // TODO: Handle AA for round points
+
+    // A stroke width of 0 has a special meaningin Skia:
+    // it draws an unscaled 1px point
+    const bool isHairLine = paint->getStrokeWidth() == 0.0f;
+
+    int alpha;
+    SkXfermode::Mode mode;
+    getAlphaAndMode(paint, &alpha, &mode);
+
+    int verticesCount = count >> 1;
+    int generatedVerticesCount = 0;
+
+    TextureVertex pointsData[verticesCount];
+    TextureVertex* vertex = &pointsData[0];
+
+    setupDraw();
+    setupDrawPoint(isHairLine ? 1.0f : paint->getStrokeWidth());
+    setupDrawColor(paint->getColor(), alpha);
+    setupDrawColorFilter();
+    setupDrawShader();
+    setupDrawBlending(mode);
+    setupDrawProgram();
+    setupDrawModelViewIdentity();
+    setupDrawColorUniforms();
+    setupDrawColorFilterUniforms();
+    setupDrawPointUniforms();
+    setupDrawShaderIdentityUniforms();
+    setupDrawMesh(vertex);
+
+    for (int i = 0; i < count; i += 2) {
+        TextureVertex::set(vertex++, points[i], points[i + 1], 0.0f, 0.0f);
+        generatedVerticesCount++;
+    }
+
+    glDrawArrays(GL_POINTS, 0, generatedVerticesCount);
+}
+
 void OpenGLRenderer::drawColor(int color, SkXfermode::Mode mode) {
     // No need to check against the clip, we fill the clip region
     if (mSnapshot->isIgnored()) return;
@@ -1522,7 +1616,6 @@
             break;
     }
 
-    // TODO: Handle paint->getTextScaleX()
     const float oldX = x;
     const float oldY = y;
     const bool pureTranslate = mSnapshot->transform->isPureTranslate();
@@ -1654,8 +1747,7 @@
 #if RENDER_LAYERS_AS_REGIONS
     if (!layer->region.isEmpty()) {
         if (layer->region.isRect()) {
-            const Rect r(x, y, x + layer->layer.getWidth(), y + layer->layer.getHeight());
-            composeLayerRect(layer, r);
+            composeLayerRect(layer, layer->regionRect);
         } else if (layer->mesh) {
             const float a = alpha / 255.0f;
             const Rect& rect = layer->layer;
@@ -1666,13 +1758,11 @@
             setupDrawColorFilter();
             setupDrawBlending(layer->blend || layer->alpha < 255, layer->mode, false);
             setupDrawProgram();
+            setupDrawModelViewTranslate(x, y,
+                    x + layer->layer.getWidth(), y + layer->layer.getHeight());
             setupDrawPureColorUniforms();
             setupDrawColorFilterUniforms();
             setupDrawTexture(layer->texture);
-            // TODO: The current layer, if any, will be dirtied with the bounding box
-            //       of the layer we are drawing. Since the layer we are drawing has
-            //       a mesh, we know the dirty region, we should use it instead
-            setupDrawModelViewTranslate(rect.left, rect.top, rect.right, rect.bottom);
             setupDrawMesh(&layer->mesh[0].position[0], &layer->mesh[0].texture[0]);
 
             glDrawElements(GL_TRIANGLES, layer->meshElementCount,
diff --git a/libs/hwui/OpenGLRenderer.h b/libs/hwui/OpenGLRenderer.h
index 7bbf034..4b93b80 100644
--- a/libs/hwui/OpenGLRenderer.h
+++ b/libs/hwui/OpenGLRenderer.h
@@ -70,7 +70,7 @@
     virtual void interrupt();
     virtual void resume();
 
-    virtual bool callDrawGLFunction(Functor *functor);
+    virtual bool callDrawGLFunction(Functor *functor, Rect& dirty);
 
     int getSaveCount() const;
     virtual int save(int flags);
@@ -96,7 +96,8 @@
     bool quickReject(float left, float top, float right, float bottom);
     virtual bool clipRect(float left, float top, float right, float bottom, SkRegion::Op op);
 
-    virtual bool drawDisplayList(DisplayList* displayList, uint32_t level = 0);
+    virtual bool drawDisplayList(DisplayList* displayList, uint32_t width, uint32_t height,
+            Rect& dirty, uint32_t level = 0);
     virtual void drawLayer(Layer* layer, float x, float y, SkPaint* paint);
     virtual void drawBitmap(SkBitmap* bitmap, float left, float top, SkPaint* paint);
     virtual void drawBitmap(SkBitmap* bitmap, SkMatrix* matrix, SkPaint* paint);
@@ -118,6 +119,7 @@
             float startAngle, float sweepAngle, bool useCenter, SkPaint* paint);
     virtual void drawPath(SkPath* path, SkPaint* paint);
     virtual void drawLines(float* points, int count, SkPaint* paint);
+    virtual void drawPoints(float* points, int count, SkPaint* paint);
     virtual void drawText(const char* text, int bytesCount, int count, float x, float y,
             SkPaint* paint);
 
@@ -247,12 +249,6 @@
     void composeLayerRect(Layer* layer, const Rect& rect, bool swap = false);
 
     /**
-     * Clears all the regions corresponding to the current list of layers.
-     * This method MUST be invoked before any drawing operation.
-     */
-    void clearLayerRegions();
-
-    /**
      * Mark the layer as dirty at the specified coordinates. The coordinates
      * are transformed with the supplied matrix.
      */
@@ -284,6 +280,8 @@
     void drawShape(float left, float top, const PathTexture* texture, SkPaint* paint);
     void drawRectAsShape(float left, float top, float right, float bottom, SkPaint* p);
 
+    void drawAlphaBitmap(Texture* texture, float left, float top, SkPaint* paint);
+
     /**
      * Draws a textured rectangle with the specified texture. The specified coordinates
      * are transformed by the current snapshot's transform matrix.
@@ -427,6 +425,7 @@
      * Various methods to setup OpenGL rendering.
      */
     void setupDrawWithTexture(bool isAlpha8 = false);
+    void setupDrawPoint(float pointSize);
     void setupDrawColor(int color);
     void setupDrawColor(int color, int alpha);
     void setupDrawColor(float r, float g, float b, float a);
@@ -445,6 +444,7 @@
             bool ignoreTransform = false, bool ignoreModelView = false);
     void setupDrawModelViewTranslate(float left, float top, float right, float bottom,
             bool ignoreTransform = false);
+    void setupDrawPointUniforms();
     void setupDrawColorUniforms();
     void setupDrawPureColorUniforms();
     void setupDrawShaderIdentityUniforms();
@@ -499,9 +499,6 @@
     // Various caches
     Caches& mCaches;
 
-    // List of rectangles to clear due to calls to saveLayer()
-    Vector<Rect*> mLayers;
-
     // Indentity matrix
     const mat4 mIdentity;
 
diff --git a/libs/hwui/PathCache.h b/libs/hwui/PathCache.h
index dc67e16..7ff8b74 100644
--- a/libs/hwui/PathCache.h
+++ b/libs/hwui/PathCache.h
@@ -41,8 +41,7 @@
         path = NULL;
     }
 
-    PathCacheEntry(const PathCacheEntry& entry):
-            ShapeCacheEntry(entry) {
+    PathCacheEntry(const PathCacheEntry& entry): ShapeCacheEntry(entry) {
         path = entry.path;
     }
 
@@ -55,6 +54,7 @@
     }
 
     SkPath* path;
+
 }; // PathCacheEntry
 
 /**
diff --git a/libs/hwui/ProgramCache.cpp b/libs/hwui/ProgramCache.cpp
index 0b6c7b5..2562306 100644
--- a/libs/hwui/ProgramCache.cpp
+++ b/libs/hwui/ProgramCache.cpp
@@ -41,6 +41,8 @@
         "attribute vec2 texCoords;\n";
 const char* gVS_Header_Uniforms =
         "uniform mat4 transform;\n";
+const char* gVS_Header_Uniforms_IsPoint =
+        "uniform float pointSize;\n";
 const char* gVS_Header_Uniforms_HasGradient[3] = {
         // Linear
         "uniform mat4 screenSpace;\n",
@@ -56,6 +58,8 @@
         "varying vec2 outTexCoords;\n";
 const char* gVS_Header_Varyings_HasBitmap =
         "varying vec2 outBitmapTexCoords;\n";
+const char* gVS_Header_Varyings_PointHasBitmap =
+        "varying vec2 outPointBitmapTexCoords;\n";
 const char* gVS_Header_Varyings_HasGradient[3] = {
         // Linear
         "varying vec2 linear;\n",
@@ -78,8 +82,12 @@
 };
 const char* gVS_Main_OutBitmapTexCoords =
         "    outBitmapTexCoords = (textureTransform * position).xy * textureDimension;\n";
+const char* gVS_Main_OutPointBitmapTexCoords =
+        "    outPointBitmapTexCoords = (textureTransform * position).xy * textureDimension;\n";
 const char* gVS_Main_Position =
         "    gl_Position = transform * position;\n";
+const char* gVS_Main_PointSize =
+        "    gl_PointSize = pointSize;\n";
 const char* gVS_Footer =
         "}\n\n";
 
@@ -93,6 +101,9 @@
         "precision mediump float;\n\n";
 const char* gFS_Uniforms_Color =
         "uniform vec4 color;\n";
+const char* gFS_Header_Uniforms_PointHasBitmap =
+        "uniform vec2 textureDimension;\n"
+        "uniform float pointSize;\n";
 const char* gFS_Uniforms_TextureSampler =
         "uniform sampler2D sampler;\n";
 const char* gFS_Uniforms_GradientSampler[3] = {
@@ -121,6 +132,10 @@
         "\nvoid main(void) {\n"
         "    lowp vec4 fragColor;\n";
 
+const char* gFS_Main_PointBitmapTexCoords =
+        "    vec2 outBitmapTexCoords = outPointBitmapTexCoords + "
+        "((gl_PointCoord - vec2(0.5, 0.5)) * textureDimension * vec2(pointSize, pointSize));\n";
+
 // Fast cases
 const char* gFS_Fast_SingleColor =
         "\nvoid main(void) {\n"
@@ -347,6 +362,9 @@
     if (description.hasBitmap) {
         shader.append(gVS_Header_Uniforms_HasBitmap);
     }
+    if (description.isPoint) {
+        shader.append(gVS_Header_Uniforms_IsPoint);
+    }
     // Varyings
     if (description.hasTexture) {
         shader.append(gVS_Header_Varyings_HasTexture);
@@ -355,7 +373,9 @@
         shader.append(gVS_Header_Varyings_HasGradient[description.gradientType]);
     }
     if (description.hasBitmap) {
-        shader.append(gVS_Header_Varyings_HasBitmap);
+        shader.append(description.isPoint ?
+                gVS_Header_Varyings_PointHasBitmap :
+                gVS_Header_Varyings_HasBitmap);
     }
 
     // Begin the shader
@@ -367,7 +387,12 @@
             shader.append(gVS_Main_OutGradient[description.gradientType]);
         }
         if (description.hasBitmap) {
-            shader.append(gVS_Main_OutBitmapTexCoords);
+            shader.append(description.isPoint ?
+                    gVS_Main_OutPointBitmapTexCoords :
+                    gVS_Main_OutBitmapTexCoords);
+        }
+        if (description.isPoint) {
+            shader.append(gVS_Main_PointSize);
         }
         // Output transformed position
         shader.append(gVS_Main_Position);
@@ -399,7 +424,9 @@
         shader.append(gVS_Header_Varyings_HasGradient[description.gradientType]);
     }
     if (description.hasBitmap) {
-        shader.append(gVS_Header_Varyings_HasBitmap);
+        shader.append(description.isPoint ?
+                gVS_Header_Varyings_PointHasBitmap :
+                gVS_Header_Varyings_HasBitmap);
     }
 
     // Uniforms
@@ -417,9 +444,13 @@
     if (description.hasGradient) {
         shader.append(gFS_Uniforms_GradientSampler[description.gradientType]);
     }
+    if (description.hasBitmap && description.isPoint) {
+        shader.append(gFS_Header_Uniforms_PointHasBitmap);
+    }
 
     // Optimization for common cases
-    if (!blendFramebuffer && description.colorOp == ProgramDescription::kColorNone) {
+    if (!blendFramebuffer && description.colorOp == ProgramDescription::kColorNone &&
+            !description.isPoint) {
         bool fast = false;
 
         const bool noShader = !description.hasGradient && !description.hasBitmap;
@@ -507,6 +538,9 @@
             shader.append(gFS_Main_FetchGradient[description.gradientType]);
         }
         if (description.hasBitmap) {
+            if (description.isPoint) {
+                shader.append(gFS_Main_PointBitmapTexCoords);
+            }
             if (!description.isBitmapNpot) {
                 shader.append(gFS_Main_FetchBitmap);
             } else {
diff --git a/libs/hwui/ProgramCache.h b/libs/hwui/ProgramCache.h
index 3acd18a..737d91b 100644
--- a/libs/hwui/ProgramCache.h
+++ b/libs/hwui/ProgramCache.h
@@ -71,7 +71,9 @@
 #define PROGRAM_BITMAP_WRAPT_SHIFT 11
 
 #define PROGRAM_GRADIENT_TYPE_SHIFT 33
-#define PROGRAM_MODULATE 35
+#define PROGRAM_MODULATE_SHIFT 35
+
+#define PROGRAM_IS_POINT_SHIFT 36
 
 ///////////////////////////////////////////////////////////////////////////////
 // Types
@@ -135,6 +137,9 @@
     SkXfermode::Mode framebufferMode;
     bool swapSrcDst;
 
+    bool isPoint;
+    float pointSize;
+
     /**
      * Resets this description. All fields are reset back to the default
      * values they hold after building a new instance.
@@ -162,6 +167,9 @@
 
         framebufferMode = SkXfermode::kClear_Mode;
         swapSrcDst = false;
+
+        isPoint = false;
+        pointSize = 0.0f;
     }
 
     /**
@@ -223,7 +231,8 @@
         }
         key |= (framebufferMode & PROGRAM_MAX_XFERMODE) << PROGRAM_XFERMODE_FRAMEBUFFER_SHIFT;
         if (swapSrcDst) key |= PROGRAM_KEY_SWAP_SRC_DST;
-        if (modulate) key |= programid(0x1) << PROGRAM_MODULATE;
+        if (modulate) key |= programid(0x1) << PROGRAM_MODULATE_SHIFT;
+        if (isPoint) key |= programid(0x1) << PROGRAM_IS_POINT_SHIFT;
         return key;
     }
 
@@ -231,9 +240,11 @@
      * Logs the specified message followed by the key identifying this program.
      */
     void log(const char* message) const {
+#if DEBUG_PROGRAMS
         programid k = key();
         PROGRAM_LOGD("%s (key = 0x%.8x%.8x)", message, uint32_t(k >> 32),
                 uint32_t(k & 0xffffffff));
+#endif
     }
 
 private:
diff --git a/libs/hwui/ShapeCache.h b/libs/hwui/ShapeCache.h
index 4c626dd..859e503 100644
--- a/libs/hwui/ShapeCache.h
+++ b/libs/hwui/ShapeCache.h
@@ -96,7 +96,7 @@
     ShapeCacheEntry(const ShapeCacheEntry& entry):
         shapeType(entry.shapeType), join(entry.join), cap(entry.cap),
         style(entry.style), miter(entry.miter),
-        strokeWidth(entry.strokeWidth) {
+        strokeWidth(entry.strokeWidth), pathEffect(entry.pathEffect) {
     }
 
     ShapeCacheEntry(ShapeType type, SkPaint* paint) {
@@ -108,18 +108,19 @@
         v = paint->getStrokeWidth();
         strokeWidth = *(uint32_t*) &v;
         style = paint->getStyle();
+        pathEffect = paint->getPathEffect();
     }
 
     virtual ~ShapeCacheEntry() {
     }
 
-    // shapeType must be checked in subclasses operator<
     ShapeType shapeType;
     SkPaint::Join join;
     SkPaint::Cap cap;
     SkPaint::Style style;
     uint32_t miter;
     uint32_t strokeWidth;
+    SkPathEffect* pathEffect;
 
     bool operator<(const ShapeCacheEntry& rhs) const {
         LTE_INT(shapeType) {
@@ -128,7 +129,9 @@
                     LTE_INT(style) {
                         LTE_INT(miter) {
                             LTE_INT(strokeWidth) {
-                                return lessThan(rhs);
+                                LTE_INT(pathEffect) {
+                                    return lessThan(rhs);
+                                }
                             }
                         }
                     }
diff --git a/libs/hwui/TextDropShadowCache.h b/libs/hwui/TextDropShadowCache.h
index 62c4250..d46686d 100644
--- a/libs/hwui/TextDropShadowCache.h
+++ b/libs/hwui/TextDropShadowCache.h
@@ -42,6 +42,17 @@
 
         textSize = paint->getTextSize();
         typeface = paint->getTypeface();
+
+        flags = 0;
+        if (paint->isFakeBoldText()) {
+            flags |= Font::kFakeBold;
+        }
+
+        const float skewX = paint->getTextSkewX();
+        italicStyle = *(uint32_t*) &skewX;
+
+        const float scaleXFloat = paint->getTextScaleX();
+        scaleX = *(uint32_t*) &scaleXFloat;
     }
 
     ~ShadowText() {
@@ -51,6 +62,9 @@
     uint32_t len;
     float textSize;
     SkTypeface* typeface;
+    uint32_t flags;
+    uint32_t italicStyle;
+    uint32_t scaleX;
     const char16_t* text;
     String16 str;
 
@@ -65,7 +79,13 @@
             LTE_INT(radius) {
                 LTE_FLOAT(textSize) {
                     LTE_INT(typeface) {
-                        return strncmp16(text, rhs.text, len >> 1) < 0;
+                        LTE_INT(flags) {
+                            LTE_INT(italicStyle) {
+                                LTE_INT(scaleX) {
+                                    return strncmp16(text, rhs.text, len >> 1) < 0;
+                                }
+                            }
+                        }
                     }
                 }
             }
diff --git a/libs/rs/Android.mk b/libs/rs/Android.mk
index 0836887..14152d8 100644
--- a/libs/rs/Android.mk
+++ b/libs/rs/Android.mk
@@ -28,7 +28,6 @@
 # slangdata_output_var_name := rs_runtime_lib_bc
 # LOCAL_MODULE := librslib_rt
 
-# LOCAL_PRELINK_MODULE := false
 # LOCAL_MODULE_CLASS := STATIC_LIBRARIES
 
 # LOCAL_MODULE_TAGS := optional
@@ -114,7 +113,9 @@
 	rsStream.cpp \
 	rsThreadIO.cpp \
 	rsType.cpp \
-	rsVertexArray.cpp
+	rsVertexArray.cpp \
+	driver/rsdBcc.cpp \
+	driver/rsdCore.cpp
 
 
 LOCAL_SHARED_LIBRARIES += libz libcutils libutils libEGL libGLESv1_CM libGLESv2 libui libbcc
diff --git a/libs/rs/RenderScript.h b/libs/rs/RenderScript.h
index bb5e4aa..cb6d7e0 100644
--- a/libs/rs/RenderScript.h
+++ b/libs/rs/RenderScript.h
@@ -24,313 +24,23 @@
 extern "C" {
 #endif
 
-//////////////////////////////////////////////////////
-//
-
-typedef void * RsAsyncVoidPtr;
-
-typedef void * RsAdapter1D;
-typedef void * RsAdapter2D;
-typedef void * RsAllocation;
-typedef void * RsAnimation;
-typedef void * RsContext;
-typedef void * RsDevice;
-typedef void * RsElement;
-typedef void * RsFile;
-typedef void * RsFont;
-typedef void * RsSampler;
-typedef void * RsScript;
-typedef void * RsMesh;
-typedef void * RsType;
-typedef void * RsObjectBase;
-
-typedef void * RsProgram;
-typedef void * RsProgramVertex;
-typedef void * RsProgramFragment;
-typedef void * RsProgramStore;
-typedef void * RsProgramRaster;
-
-typedef void (* RsBitmapCallback_t)(void *);
-
-enum RsDeviceParam {
-    RS_DEVICE_PARAM_FORCE_SOFTWARE_GL,
-    RS_DEVICE_PARAM_COUNT
-};
-
-typedef struct {
-    uint32_t colorMin;
-    uint32_t colorPref;
-    uint32_t alphaMin;
-    uint32_t alphaPref;
-    uint32_t depthMin;
-    uint32_t depthPref;
-    uint32_t stencilMin;
-    uint32_t stencilPref;
-    uint32_t samplesMin;
-    uint32_t samplesPref;
-    float samplesQ;
-} RsSurfaceConfig;
+#include "RenderScriptDefines.h"
 
 RsDevice rsDeviceCreate();
 void rsDeviceDestroy(RsDevice);
 void rsDeviceSetConfig(RsDevice, RsDeviceParam, int32_t value);
 
 RsContext rsContextCreate(RsDevice, uint32_t version);
-RsContext rsContextCreateGL(RsDevice, uint32_t version, RsSurfaceConfig sc);
+RsContext rsContextCreateGL(RsDevice, uint32_t version,
+                            RsSurfaceConfig sc, uint32_t dpi);
 void rsContextDestroy(RsContext);
 
-enum RsMessageToClientType {
-    RS_MESSAGE_TO_CLIENT_NONE = 0,
-    RS_MESSAGE_TO_CLIENT_EXCEPTION = 1,
-    RS_MESSAGE_TO_CLIENT_RESIZE = 2,
-    RS_MESSAGE_TO_CLIENT_ERROR = 3,
-    RS_MESSAGE_TO_CLIENT_USER = 4
-};
-
 RsMessageToClientType rsContextGetMessage(RsContext vrsc, void *data, size_t *receiveLen, uint32_t *subID, size_t bufferLen, bool wait);
 RsMessageToClientType rsContextPeekMessage(RsContext vrsc, size_t *receiveLen, uint32_t *subID, bool wait);
 void rsContextInitToClient(RsContext);
 void rsContextDeinitToClient(RsContext);
 
-#define RS_MAX_TEXTURE 2
-#define RS_MAX_ATTRIBS 16
-
-
-enum RsAllocationUsageType {
-    RS_ALLOCATION_USAGE_SCRIPT = 0x0001,
-    RS_ALLOCATION_USAGE_GRAPHICS_TEXTURE = 0x0002,
-    RS_ALLOCATION_USAGE_GRAPHICS_VERTEX = 0x0004,
-    RS_ALLOCATION_USAGE_GRAPHICS_CONSTANTS = 0x0008,
-
-    RS_ALLOCATION_USAGE_ALL = 0x000F
-};
-
-enum RsAllocationMipmapControl {
-    RS_ALLOCATION_MIPMAP_NONE = 0,
-    RS_ALLOCATION_MIPMAP_FULL = 1,
-    RS_ALLOCATION_MIPMAP_ON_SYNC_TO_TEXTURE = 2
-};
-
-enum RsAllocationCubemapFace {
-    RS_ALLOCATION_CUBMAP_FACE_POSITVE_X = 0,
-    RS_ALLOCATION_CUBMAP_FACE_NEGATIVE_X = 1,
-    RS_ALLOCATION_CUBMAP_FACE_POSITVE_Y = 2,
-    RS_ALLOCATION_CUBMAP_FACE_NEGATIVE_Y = 3,
-    RS_ALLOCATION_CUBMAP_FACE_POSITVE_Z = 4,
-    RS_ALLOCATION_CUBMAP_FACE_NEGATIVE_Z = 5
-};
-
-enum RsDataType {
-    RS_TYPE_NONE,
-    RS_TYPE_FLOAT_16,
-    RS_TYPE_FLOAT_32,
-    RS_TYPE_FLOAT_64,
-    RS_TYPE_SIGNED_8,
-    RS_TYPE_SIGNED_16,
-    RS_TYPE_SIGNED_32,
-    RS_TYPE_SIGNED_64,
-    RS_TYPE_UNSIGNED_8,
-    RS_TYPE_UNSIGNED_16,
-    RS_TYPE_UNSIGNED_32,
-    RS_TYPE_UNSIGNED_64,
-
-    RS_TYPE_BOOLEAN,
-
-    RS_TYPE_UNSIGNED_5_6_5,
-    RS_TYPE_UNSIGNED_5_5_5_1,
-    RS_TYPE_UNSIGNED_4_4_4_4,
-
-    RS_TYPE_MATRIX_4X4,
-    RS_TYPE_MATRIX_3X3,
-    RS_TYPE_MATRIX_2X2,
-
-    RS_TYPE_ELEMENT = 1000,
-    RS_TYPE_TYPE,
-    RS_TYPE_ALLOCATION,
-    RS_TYPE_SAMPLER,
-    RS_TYPE_SCRIPT,
-    RS_TYPE_MESH,
-    RS_TYPE_PROGRAM_FRAGMENT,
-    RS_TYPE_PROGRAM_VERTEX,
-    RS_TYPE_PROGRAM_RASTER,
-    RS_TYPE_PROGRAM_STORE,
-};
-
-enum RsDataKind {
-    RS_KIND_USER,
-
-    RS_KIND_PIXEL_L = 7,
-    RS_KIND_PIXEL_A,
-    RS_KIND_PIXEL_LA,
-    RS_KIND_PIXEL_RGB,
-    RS_KIND_PIXEL_RGBA,
-};
-
-enum RsSamplerParam {
-    RS_SAMPLER_MIN_FILTER,
-    RS_SAMPLER_MAG_FILTER,
-    RS_SAMPLER_WRAP_S,
-    RS_SAMPLER_WRAP_T,
-    RS_SAMPLER_WRAP_R,
-    RS_SAMPLER_ANISO
-};
-
-enum RsSamplerValue {
-    RS_SAMPLER_NEAREST,
-    RS_SAMPLER_LINEAR,
-    RS_SAMPLER_LINEAR_MIP_LINEAR,
-    RS_SAMPLER_WRAP,
-    RS_SAMPLER_CLAMP,
-    RS_SAMPLER_LINEAR_MIP_NEAREST,
-};
-
-enum RsTextureTarget {
-    RS_TEXTURE_2D,
-    RS_TEXTURE_CUBE
-};
-
-enum RsDimension {
-    RS_DIMENSION_X,
-    RS_DIMENSION_Y,
-    RS_DIMENSION_Z,
-    RS_DIMENSION_LOD,
-    RS_DIMENSION_FACE,
-
-    RS_DIMENSION_ARRAY_0 = 100,
-    RS_DIMENSION_ARRAY_1,
-    RS_DIMENSION_ARRAY_2,
-    RS_DIMENSION_ARRAY_3,
-    RS_DIMENSION_MAX = RS_DIMENSION_ARRAY_3
-};
-
-enum RsDepthFunc {
-    RS_DEPTH_FUNC_ALWAYS,
-    RS_DEPTH_FUNC_LESS,
-    RS_DEPTH_FUNC_LEQUAL,
-    RS_DEPTH_FUNC_GREATER,
-    RS_DEPTH_FUNC_GEQUAL,
-    RS_DEPTH_FUNC_EQUAL,
-    RS_DEPTH_FUNC_NOTEQUAL
-};
-
-enum RsBlendSrcFunc {
-    RS_BLEND_SRC_ZERO,                  // 0
-    RS_BLEND_SRC_ONE,                   // 1
-    RS_BLEND_SRC_DST_COLOR,             // 2
-    RS_BLEND_SRC_ONE_MINUS_DST_COLOR,   // 3
-    RS_BLEND_SRC_SRC_ALPHA,             // 4
-    RS_BLEND_SRC_ONE_MINUS_SRC_ALPHA,   // 5
-    RS_BLEND_SRC_DST_ALPHA,             // 6
-    RS_BLEND_SRC_ONE_MINUS_DST_ALPHA,   // 7
-    RS_BLEND_SRC_SRC_ALPHA_SATURATE     // 8
-};
-
-enum RsBlendDstFunc {
-    RS_BLEND_DST_ZERO,                  // 0
-    RS_BLEND_DST_ONE,                   // 1
-    RS_BLEND_DST_SRC_COLOR,             // 2
-    RS_BLEND_DST_ONE_MINUS_SRC_COLOR,   // 3
-    RS_BLEND_DST_SRC_ALPHA,             // 4
-    RS_BLEND_DST_ONE_MINUS_SRC_ALPHA,   // 5
-    RS_BLEND_DST_DST_ALPHA,             // 6
-    RS_BLEND_DST_ONE_MINUS_DST_ALPHA    // 7
-};
-
-enum RsTexEnvMode {
-    RS_TEX_ENV_MODE_NONE,
-    RS_TEX_ENV_MODE_REPLACE,
-    RS_TEX_ENV_MODE_MODULATE,
-    RS_TEX_ENV_MODE_DECAL
-};
-
-enum RsProgramParam {
-    RS_PROGRAM_PARAM_INPUT,
-    RS_PROGRAM_PARAM_OUTPUT,
-    RS_PROGRAM_PARAM_CONSTANT,
-    RS_PROGRAM_PARAM_TEXTURE_TYPE,
-};
-
-enum RsPrimitive {
-    RS_PRIMITIVE_POINT,
-    RS_PRIMITIVE_LINE,
-    RS_PRIMITIVE_LINE_STRIP,
-    RS_PRIMITIVE_TRIANGLE,
-    RS_PRIMITIVE_TRIANGLE_STRIP,
-    RS_PRIMITIVE_TRIANGLE_FAN
-};
-
-enum RsError {
-    RS_ERROR_NONE = 0,
-    RS_ERROR_BAD_SHADER = 1,
-    RS_ERROR_BAD_SCRIPT = 2,
-    RS_ERROR_BAD_VALUE = 3,
-    RS_ERROR_OUT_OF_MEMORY = 4,
-    RS_ERROR_DRIVER = 5,
-
-    RS_ERROR_FATAL_UNKNOWN = 0x1000,
-    RS_ERROR_FATAL_DRIVER = 0x1001,
-    RS_ERROR_FATAL_PROGRAM_LINK = 0x1002
-};
-
-enum RsAnimationInterpolation {
-    RS_ANIMATION_INTERPOLATION_STEP,
-    RS_ANIMATION_INTERPOLATION_LINEAR,
-    RS_ANIMATION_INTERPOLATION_BEZIER,
-    RS_ANIMATION_INTERPOLATION_CARDINAL,
-    RS_ANIMATION_INTERPOLATION_HERMITE,
-    RS_ANIMATION_INTERPOLATION_BSPLINE
-};
-
-enum RsAnimationEdge {
-    RS_ANIMATION_EDGE_UNDEFINED,
-    RS_ANIMATION_EDGE_CONSTANT,
-    RS_ANIMATION_EDGE_GRADIENT,
-    RS_ANIMATION_EDGE_CYCLE,
-    RS_ANIMATION_EDGE_OSCILLATE,
-    RS_ANIMATION_EDGE_CYLE_RELATIVE
-};
-
-enum RsA3DClassID {
-    RS_A3D_CLASS_ID_UNKNOWN,
-    RS_A3D_CLASS_ID_MESH,
-    RS_A3D_CLASS_ID_TYPE,
-    RS_A3D_CLASS_ID_ELEMENT,
-    RS_A3D_CLASS_ID_ALLOCATION,
-    RS_A3D_CLASS_ID_PROGRAM_VERTEX,
-    RS_A3D_CLASS_ID_PROGRAM_RASTER,
-    RS_A3D_CLASS_ID_PROGRAM_FRAGMENT,
-    RS_A3D_CLASS_ID_PROGRAM_STORE,
-    RS_A3D_CLASS_ID_SAMPLER,
-    RS_A3D_CLASS_ID_ANIMATION,
-    RS_A3D_CLASS_ID_ADAPTER_1D,
-    RS_A3D_CLASS_ID_ADAPTER_2D,
-    RS_A3D_CLASS_ID_SCRIPT_C
-};
-
-enum RsCullMode {
-    RS_CULL_BACK,
-    RS_CULL_FRONT,
-    RS_CULL_NONE
-};
-
-typedef struct {
-    RsA3DClassID classID;
-    const char* objectName;
-} RsFileIndexEntry;
-
-// Script to Script
-typedef struct {
-    uint32_t xStart;
-    uint32_t xEnd;
-    uint32_t yStart;
-    uint32_t yEnd;
-    uint32_t zStart;
-    uint32_t zEnd;
-    uint32_t arrayStart;
-    uint32_t arrayEnd;
-
-} RsScriptCall;
-
+//
 // A3D loading and object update code.
 // Should only be called at object creation, not thread safe
 RsObjectBase rsaFileA3DGetEntryByIndex(RsContext, uint32_t idx, RsFile);
diff --git a/libs/rs/RenderScriptDefines.h b/libs/rs/RenderScriptDefines.h
new file mode 100644
index 0000000..4e1ac88
--- /dev/null
+++ b/libs/rs/RenderScriptDefines.h
@@ -0,0 +1,325 @@
+/*
+ * 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 RENDER_SCRIPT_DEFINES_H
+#define RENDER_SCRIPT_DEFINES_H
+
+#include <stdint.h>
+#include <sys/types.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+//////////////////////////////////////////////////////
+//
+
+typedef void * RsAsyncVoidPtr;
+
+typedef void * RsAdapter1D;
+typedef void * RsAdapter2D;
+typedef void * RsAllocation;
+typedef void * RsAnimation;
+typedef void * RsContext;
+typedef void * RsDevice;
+typedef void * RsElement;
+typedef void * RsFile;
+typedef void * RsFont;
+typedef void * RsSampler;
+typedef void * RsScript;
+typedef void * RsMesh;
+typedef void * RsType;
+typedef void * RsObjectBase;
+
+typedef void * RsProgram;
+typedef void * RsProgramVertex;
+typedef void * RsProgramFragment;
+typedef void * RsProgramStore;
+typedef void * RsProgramRaster;
+
+typedef void (* RsBitmapCallback_t)(void *);
+
+enum RsDeviceParam {
+    RS_DEVICE_PARAM_FORCE_SOFTWARE_GL,
+    RS_DEVICE_PARAM_COUNT
+};
+
+typedef struct {
+    uint32_t colorMin;
+    uint32_t colorPref;
+    uint32_t alphaMin;
+    uint32_t alphaPref;
+    uint32_t depthMin;
+    uint32_t depthPref;
+    uint32_t stencilMin;
+    uint32_t stencilPref;
+    uint32_t samplesMin;
+    uint32_t samplesPref;
+    float samplesQ;
+} RsSurfaceConfig;
+
+enum RsMessageToClientType {
+    RS_MESSAGE_TO_CLIENT_NONE = 0,
+    RS_MESSAGE_TO_CLIENT_EXCEPTION = 1,
+    RS_MESSAGE_TO_CLIENT_RESIZE = 2,
+    RS_MESSAGE_TO_CLIENT_ERROR = 3,
+    RS_MESSAGE_TO_CLIENT_USER = 4
+};
+
+enum RsAllocationUsageType {
+    RS_ALLOCATION_USAGE_SCRIPT = 0x0001,
+    RS_ALLOCATION_USAGE_GRAPHICS_TEXTURE = 0x0002,
+    RS_ALLOCATION_USAGE_GRAPHICS_VERTEX = 0x0004,
+    RS_ALLOCATION_USAGE_GRAPHICS_CONSTANTS = 0x0008,
+
+    RS_ALLOCATION_USAGE_ALL = 0x000F
+};
+
+enum RsAllocationMipmapControl {
+    RS_ALLOCATION_MIPMAP_NONE = 0,
+    RS_ALLOCATION_MIPMAP_FULL = 1,
+    RS_ALLOCATION_MIPMAP_ON_SYNC_TO_TEXTURE = 2
+};
+
+enum RsAllocationCubemapFace {
+    RS_ALLOCATION_CUBMAP_FACE_POSITVE_X = 0,
+    RS_ALLOCATION_CUBMAP_FACE_NEGATIVE_X = 1,
+    RS_ALLOCATION_CUBMAP_FACE_POSITVE_Y = 2,
+    RS_ALLOCATION_CUBMAP_FACE_NEGATIVE_Y = 3,
+    RS_ALLOCATION_CUBMAP_FACE_POSITVE_Z = 4,
+    RS_ALLOCATION_CUBMAP_FACE_NEGATIVE_Z = 5
+};
+
+enum RsDataType {
+    RS_TYPE_NONE,
+    RS_TYPE_FLOAT_16,
+    RS_TYPE_FLOAT_32,
+    RS_TYPE_FLOAT_64,
+    RS_TYPE_SIGNED_8,
+    RS_TYPE_SIGNED_16,
+    RS_TYPE_SIGNED_32,
+    RS_TYPE_SIGNED_64,
+    RS_TYPE_UNSIGNED_8,
+    RS_TYPE_UNSIGNED_16,
+    RS_TYPE_UNSIGNED_32,
+    RS_TYPE_UNSIGNED_64,
+
+    RS_TYPE_BOOLEAN,
+
+    RS_TYPE_UNSIGNED_5_6_5,
+    RS_TYPE_UNSIGNED_5_5_5_1,
+    RS_TYPE_UNSIGNED_4_4_4_4,
+
+    RS_TYPE_MATRIX_4X4,
+    RS_TYPE_MATRIX_3X3,
+    RS_TYPE_MATRIX_2X2,
+
+    RS_TYPE_ELEMENT = 1000,
+    RS_TYPE_TYPE,
+    RS_TYPE_ALLOCATION,
+    RS_TYPE_SAMPLER,
+    RS_TYPE_SCRIPT,
+    RS_TYPE_MESH,
+    RS_TYPE_PROGRAM_FRAGMENT,
+    RS_TYPE_PROGRAM_VERTEX,
+    RS_TYPE_PROGRAM_RASTER,
+    RS_TYPE_PROGRAM_STORE,
+};
+
+enum RsDataKind {
+    RS_KIND_USER,
+
+    RS_KIND_PIXEL_L = 7,
+    RS_KIND_PIXEL_A,
+    RS_KIND_PIXEL_LA,
+    RS_KIND_PIXEL_RGB,
+    RS_KIND_PIXEL_RGBA,
+};
+
+enum RsSamplerParam {
+    RS_SAMPLER_MIN_FILTER,
+    RS_SAMPLER_MAG_FILTER,
+    RS_SAMPLER_WRAP_S,
+    RS_SAMPLER_WRAP_T,
+    RS_SAMPLER_WRAP_R,
+    RS_SAMPLER_ANISO
+};
+
+enum RsSamplerValue {
+    RS_SAMPLER_NEAREST,
+    RS_SAMPLER_LINEAR,
+    RS_SAMPLER_LINEAR_MIP_LINEAR,
+    RS_SAMPLER_WRAP,
+    RS_SAMPLER_CLAMP,
+    RS_SAMPLER_LINEAR_MIP_NEAREST,
+};
+
+enum RsTextureTarget {
+    RS_TEXTURE_2D,
+    RS_TEXTURE_CUBE
+};
+
+enum RsDimension {
+    RS_DIMENSION_X,
+    RS_DIMENSION_Y,
+    RS_DIMENSION_Z,
+    RS_DIMENSION_LOD,
+    RS_DIMENSION_FACE,
+
+    RS_DIMENSION_ARRAY_0 = 100,
+    RS_DIMENSION_ARRAY_1,
+    RS_DIMENSION_ARRAY_2,
+    RS_DIMENSION_ARRAY_3,
+    RS_DIMENSION_MAX = RS_DIMENSION_ARRAY_3
+};
+
+enum RsDepthFunc {
+    RS_DEPTH_FUNC_ALWAYS,
+    RS_DEPTH_FUNC_LESS,
+    RS_DEPTH_FUNC_LEQUAL,
+    RS_DEPTH_FUNC_GREATER,
+    RS_DEPTH_FUNC_GEQUAL,
+    RS_DEPTH_FUNC_EQUAL,
+    RS_DEPTH_FUNC_NOTEQUAL
+};
+
+enum RsBlendSrcFunc {
+    RS_BLEND_SRC_ZERO,                  // 0
+    RS_BLEND_SRC_ONE,                   // 1
+    RS_BLEND_SRC_DST_COLOR,             // 2
+    RS_BLEND_SRC_ONE_MINUS_DST_COLOR,   // 3
+    RS_BLEND_SRC_SRC_ALPHA,             // 4
+    RS_BLEND_SRC_ONE_MINUS_SRC_ALPHA,   // 5
+    RS_BLEND_SRC_DST_ALPHA,             // 6
+    RS_BLEND_SRC_ONE_MINUS_DST_ALPHA,   // 7
+    RS_BLEND_SRC_SRC_ALPHA_SATURATE     // 8
+};
+
+enum RsBlendDstFunc {
+    RS_BLEND_DST_ZERO,                  // 0
+    RS_BLEND_DST_ONE,                   // 1
+    RS_BLEND_DST_SRC_COLOR,             // 2
+    RS_BLEND_DST_ONE_MINUS_SRC_COLOR,   // 3
+    RS_BLEND_DST_SRC_ALPHA,             // 4
+    RS_BLEND_DST_ONE_MINUS_SRC_ALPHA,   // 5
+    RS_BLEND_DST_DST_ALPHA,             // 6
+    RS_BLEND_DST_ONE_MINUS_DST_ALPHA    // 7
+};
+
+enum RsTexEnvMode {
+    RS_TEX_ENV_MODE_NONE,
+    RS_TEX_ENV_MODE_REPLACE,
+    RS_TEX_ENV_MODE_MODULATE,
+    RS_TEX_ENV_MODE_DECAL
+};
+
+enum RsProgramParam {
+    RS_PROGRAM_PARAM_INPUT,
+    RS_PROGRAM_PARAM_OUTPUT,
+    RS_PROGRAM_PARAM_CONSTANT,
+    RS_PROGRAM_PARAM_TEXTURE_TYPE,
+};
+
+enum RsPrimitive {
+    RS_PRIMITIVE_POINT,
+    RS_PRIMITIVE_LINE,
+    RS_PRIMITIVE_LINE_STRIP,
+    RS_PRIMITIVE_TRIANGLE,
+    RS_PRIMITIVE_TRIANGLE_STRIP,
+    RS_PRIMITIVE_TRIANGLE_FAN
+};
+
+enum RsError {
+    RS_ERROR_NONE = 0,
+    RS_ERROR_BAD_SHADER = 1,
+    RS_ERROR_BAD_SCRIPT = 2,
+    RS_ERROR_BAD_VALUE = 3,
+    RS_ERROR_OUT_OF_MEMORY = 4,
+    RS_ERROR_DRIVER = 5,
+
+    RS_ERROR_FATAL_UNKNOWN = 0x1000,
+    RS_ERROR_FATAL_DRIVER = 0x1001,
+    RS_ERROR_FATAL_PROGRAM_LINK = 0x1002
+};
+
+enum RsAnimationInterpolation {
+    RS_ANIMATION_INTERPOLATION_STEP,
+    RS_ANIMATION_INTERPOLATION_LINEAR,
+    RS_ANIMATION_INTERPOLATION_BEZIER,
+    RS_ANIMATION_INTERPOLATION_CARDINAL,
+    RS_ANIMATION_INTERPOLATION_HERMITE,
+    RS_ANIMATION_INTERPOLATION_BSPLINE
+};
+
+enum RsAnimationEdge {
+    RS_ANIMATION_EDGE_UNDEFINED,
+    RS_ANIMATION_EDGE_CONSTANT,
+    RS_ANIMATION_EDGE_GRADIENT,
+    RS_ANIMATION_EDGE_CYCLE,
+    RS_ANIMATION_EDGE_OSCILLATE,
+    RS_ANIMATION_EDGE_CYLE_RELATIVE
+};
+
+enum RsA3DClassID {
+    RS_A3D_CLASS_ID_UNKNOWN,
+    RS_A3D_CLASS_ID_MESH,
+    RS_A3D_CLASS_ID_TYPE,
+    RS_A3D_CLASS_ID_ELEMENT,
+    RS_A3D_CLASS_ID_ALLOCATION,
+    RS_A3D_CLASS_ID_PROGRAM_VERTEX,
+    RS_A3D_CLASS_ID_PROGRAM_RASTER,
+    RS_A3D_CLASS_ID_PROGRAM_FRAGMENT,
+    RS_A3D_CLASS_ID_PROGRAM_STORE,
+    RS_A3D_CLASS_ID_SAMPLER,
+    RS_A3D_CLASS_ID_ANIMATION,
+    RS_A3D_CLASS_ID_ADAPTER_1D,
+    RS_A3D_CLASS_ID_ADAPTER_2D,
+    RS_A3D_CLASS_ID_SCRIPT_C
+};
+
+enum RsCullMode {
+    RS_CULL_BACK,
+    RS_CULL_FRONT,
+    RS_CULL_NONE
+};
+
+typedef struct {
+    RsA3DClassID classID;
+    const char* objectName;
+} RsFileIndexEntry;
+
+// Script to Script
+typedef struct {
+    uint32_t xStart;
+    uint32_t xEnd;
+    uint32_t yStart;
+    uint32_t yEnd;
+    uint32_t zStart;
+    uint32_t zEnd;
+    uint32_t arrayStart;
+    uint32_t arrayEnd;
+
+} RsScriptCall;
+
+#ifdef __cplusplus
+};
+#endif
+
+#endif // RENDER_SCRIPT_DEFINES_H
+
+
+
+
diff --git a/libs/rs/driver/rsdBcc.cpp b/libs/rs/driver/rsdBcc.cpp
new file mode 100644
index 0000000..6e4edce
--- /dev/null
+++ b/libs/rs/driver/rsdBcc.cpp
@@ -0,0 +1,545 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+#include "rsdCore.h"
+#include "rsdBcc.h"
+
+#include "rsContext.h"
+#include "rsScriptC.h"
+
+#include "utils/Timers.h"
+#include "utils/StopWatch.h"
+extern "C" {
+#include "libdex/ZipArchive.h"
+}
+
+
+using namespace android;
+using namespace android::renderscript;
+
+struct DrvScript {
+    int (*mRoot)();
+    void (*mInit)();
+
+    BCCScriptRef mBccScript;
+
+    uint32_t mInvokeFunctionCount;
+    InvokeFunc_t *mInvokeFunctions;
+    uint32_t mFieldCount;
+    void ** mFieldAddress;
+    bool * mFieldIsObject;
+
+    const uint8_t * mScriptText;
+    uint32_t mScriptTextLength;
+
+    //uint32_t * mObjectSlots;
+    //uint32_t mObjectSlotCount;
+
+    uint32_t mPragmaCount;
+    const char ** mPragmaKeys;
+    const char ** mPragmaValues;
+
+};
+
+static Script * setTLS(Script *sc) {
+    ScriptTLSStruct * tls = (ScriptTLSStruct *)pthread_getspecific(Context::gThreadTLSKey);
+    rsAssert(tls);
+    Script *old = tls->mScript;
+    tls->mScript = sc;
+    return old;
+}
+
+
+// Input: cacheDir
+// Input: resName
+// Input: extName
+//
+// Note: cacheFile = resName + extName
+//
+// Output: Returns cachePath == cacheDir + cacheFile
+static char *genCacheFileName(const char *cacheDir,
+                              const char *resName,
+                              const char *extName) {
+    char cachePath[512];
+    char cacheFile[sizeof(cachePath)];
+    const size_t kBufLen = sizeof(cachePath) - 1;
+
+    cacheFile[0] = '\0';
+    // Note: resName today is usually something like
+    //       "/com.android.fountain:raw/fountain"
+    if (resName[0] != '/') {
+        // Get the absolute path of the raw/***.bc file.
+
+        // Generate the absolute path.  This doesn't do everything it
+        // should, e.g. if resName is "./out/whatever" it doesn't crunch
+        // the leading "./" out because this if-block is not triggered,
+        // but it'll make do.
+        //
+        if (getcwd(cacheFile, kBufLen) == NULL) {
+            LOGE("Can't get CWD while opening raw/***.bc file\n");
+            return NULL;
+        }
+        // Append "/" at the end of cacheFile so far.
+        strncat(cacheFile, "/", kBufLen);
+    }
+
+    // cacheFile = resName + extName
+    //
+    strncat(cacheFile, resName, kBufLen);
+    if (extName != NULL) {
+        // TODO(srhines): strncat() is a bit dangerous
+        strncat(cacheFile, extName, kBufLen);
+    }
+
+    // Turn the path into a flat filename by replacing
+    // any slashes after the first one with '@' characters.
+    char *cp = cacheFile + 1;
+    while (*cp != '\0') {
+        if (*cp == '/') {
+            *cp = '@';
+        }
+        cp++;
+    }
+
+    // Tack on the file name for the actual cache file path.
+    strncpy(cachePath, cacheDir, kBufLen);
+    strncat(cachePath, cacheFile, kBufLen);
+
+    LOGV("Cache file for '%s' '%s' is '%s'\n", resName, extName, cachePath);
+    return strdup(cachePath);
+}
+
+bool rsdScriptInit(const Context *rsc,
+                     ScriptC *script,
+                     char const *resName,
+                     char const *cacheDir,
+                     uint8_t const *bitcode,
+                     size_t bitcodeSize,
+                     uint32_t flags,
+                     RsHalSymbolLookupFunc lookupFunc) {
+    //LOGE("rsdScriptCreate %p %p %p %p %i %i %p", rsc, resName, cacheDir, bitcode, bitcodeSize, flags, lookupFunc);
+
+    char *cachePath = NULL;
+    uint32_t objectSlotCount = 0;
+
+    DrvScript *drv = (DrvScript *)calloc(1, sizeof(DrvScript));
+    if (drv == NULL) {
+        return false;
+    }
+    script->mHal.drv = drv;
+
+    drv->mBccScript = bccCreateScript();
+    script->mHal.info.isThreadable = true;
+    drv->mScriptText = bitcode;
+    drv->mScriptTextLength = bitcodeSize;
+
+    //LOGE("mBccScript %p", script->mBccScript);
+
+    if (bccRegisterSymbolCallback(drv->mBccScript, lookupFunc, script) != 0) {
+        LOGE("bcc: FAILS to register symbol callback");
+        goto error;
+    }
+
+    if (bccReadBC(drv->mBccScript,
+                  resName,
+                  (char const *)drv->mScriptText,
+                  drv->mScriptTextLength, 0) != 0) {
+        LOGE("bcc: FAILS to read bitcode");
+        return NULL;
+    }
+
+#if 1
+    if (bccLinkFile(drv->mBccScript, "/system/lib/libclcore.bc", 0) != 0) {
+        LOGE("bcc: FAILS to link bitcode");
+        return NULL;
+    }
+#endif
+    cachePath = genCacheFileName(cacheDir, resName, ".oBCC");
+
+    if (bccPrepareExecutable(drv->mBccScript, cachePath, 0) != 0) {
+        LOGE("bcc: FAILS to prepare executable");
+        return NULL;
+    }
+
+    free(cachePath);
+
+    drv->mRoot = reinterpret_cast<int (*)()>(bccGetFuncAddr(drv->mBccScript, "root"));
+    drv->mInit = reinterpret_cast<void (*)()>(bccGetFuncAddr(drv->mBccScript, "init"));
+
+    drv->mInvokeFunctionCount = bccGetExportFuncCount(drv->mBccScript);
+    if (drv->mInvokeFunctionCount <= 0)
+        drv->mInvokeFunctions = NULL;
+    else {
+        drv->mInvokeFunctions = (InvokeFunc_t*) calloc(drv->mInvokeFunctionCount, sizeof(InvokeFunc_t));
+        bccGetExportFuncList(drv->mBccScript, drv->mInvokeFunctionCount, (void **) drv->mInvokeFunctions);
+    }
+
+    drv->mFieldCount = bccGetExportVarCount(drv->mBccScript);
+    if (drv->mFieldCount <= 0) {
+        drv->mFieldAddress = NULL;
+        drv->mFieldIsObject = NULL;
+    } else {
+        drv->mFieldAddress = (void **) calloc(drv->mFieldCount, sizeof(void *));
+        drv->mFieldIsObject = (bool *) calloc(drv->mFieldCount, sizeof(bool));
+        bccGetExportVarList(drv->mBccScript, drv->mFieldCount, (void **) drv->mFieldAddress);
+    }
+
+    objectSlotCount = bccGetObjectSlotCount(drv->mBccScript);
+    if (objectSlotCount) {
+        uint32_t * slots = new uint32_t[objectSlotCount];
+        bccGetObjectSlotList(drv->mBccScript, objectSlotCount, slots);
+        for (uint32_t ct=0; ct < objectSlotCount; ct++) {
+            drv->mFieldIsObject[slots[ct]] = true;
+        }
+        delete [] slots;
+    }
+
+    uint32_t mPragmaCount;
+    const char ** mPragmaKeys;
+    const char ** mPragmaValues;
+
+    const static int pragmaMax = 16;
+    drv->mPragmaCount = bccGetPragmaCount(drv->mBccScript);
+    if (drv->mPragmaCount <= 0) {
+        drv->mPragmaKeys = NULL;
+        drv->mPragmaValues = NULL;
+    } else {
+        drv->mPragmaKeys = (const char **) calloc(drv->mFieldCount, sizeof(const char *));
+        drv->mPragmaValues = (const char **) calloc(drv->mFieldCount, sizeof(const char *));
+        bccGetPragmaList(drv->mBccScript, drv->mPragmaCount, drv->mPragmaKeys, drv->mPragmaValues);
+    }
+
+
+
+    // Copy info over to runtime
+    script->mHal.info.exportedFunctionCount = drv->mInvokeFunctionCount;
+    script->mHal.info.exportedVariableCount = drv->mFieldCount;
+    script->mHal.info.exportedPragmaCount = drv->mPragmaCount;
+    script->mHal.info.exportedPragmaKeyList = drv->mPragmaKeys;
+    script->mHal.info.exportedPragmaValueList = drv->mPragmaValues;
+    script->mHal.info.root = drv->mRoot;
+
+
+    return true;
+
+error:
+
+    free(drv);
+    return false;
+
+}
+
+typedef struct {
+    Context *rsc;
+    Script *script;
+    const Allocation * ain;
+    Allocation * aout;
+    const void * usr;
+
+    uint32_t mSliceSize;
+    volatile int mSliceNum;
+
+    const uint8_t *ptrIn;
+    uint32_t eStrideIn;
+    uint8_t *ptrOut;
+    uint32_t eStrideOut;
+
+    uint32_t xStart;
+    uint32_t xEnd;
+    uint32_t yStart;
+    uint32_t yEnd;
+    uint32_t zStart;
+    uint32_t zEnd;
+    uint32_t arrayStart;
+    uint32_t arrayEnd;
+
+    uint32_t dimX;
+    uint32_t dimY;
+    uint32_t dimZ;
+    uint32_t dimArray;
+} MTLaunchStruct;
+typedef int (*rs_t)(const void *, void *, const void *, uint32_t, uint32_t, uint32_t, uint32_t);
+
+static void wc_xy(void *usr, uint32_t idx) {
+    MTLaunchStruct *mtls = (MTLaunchStruct *)usr;
+
+    while (1) {
+        uint32_t slice = (uint32_t)android_atomic_inc(&mtls->mSliceNum);
+        uint32_t yStart = mtls->yStart + slice * mtls->mSliceSize;
+        uint32_t yEnd = yStart + mtls->mSliceSize;
+        yEnd = rsMin(yEnd, mtls->yEnd);
+        if (yEnd <= yStart) {
+            return;
+        }
+
+        //LOGE("usr idx %i, x %i,%i  y %i,%i", idx, mtls->xStart, mtls->xEnd, yStart, yEnd);
+        //LOGE("usr ptr in %p,  out %p", mtls->ptrIn, mtls->ptrOut);
+        for (uint32_t y = yStart; y < yEnd; y++) {
+            uint32_t offset = mtls->dimX * y;
+            uint8_t *xPtrOut = mtls->ptrOut + (mtls->eStrideOut * offset);
+            const uint8_t *xPtrIn = mtls->ptrIn + (mtls->eStrideIn * offset);
+
+            for (uint32_t x = mtls->xStart; x < mtls->xEnd; x++) {
+                ((rs_t)mtls->script->mHal.info.root) (xPtrIn, xPtrOut, mtls->usr, x, y, 0, 0);
+                xPtrIn += mtls->eStrideIn;
+                xPtrOut += mtls->eStrideOut;
+            }
+        }
+    }
+}
+
+static void wc_x(void *usr, uint32_t idx) {
+    MTLaunchStruct *mtls = (MTLaunchStruct *)usr;
+
+    while (1) {
+        uint32_t slice = (uint32_t)android_atomic_inc(&mtls->mSliceNum);
+        uint32_t xStart = mtls->xStart + slice * mtls->mSliceSize;
+        uint32_t xEnd = xStart + mtls->mSliceSize;
+        xEnd = rsMin(xEnd, mtls->xEnd);
+        if (xEnd <= xStart) {
+            return;
+        }
+
+        //LOGE("usr idx %i, x %i,%i  y %i,%i", idx, mtls->xStart, mtls->xEnd, yStart, yEnd);
+        //LOGE("usr ptr in %p,  out %p", mtls->ptrIn, mtls->ptrOut);
+        uint8_t *xPtrOut = mtls->ptrOut + (mtls->eStrideOut * xStart);
+        const uint8_t *xPtrIn = mtls->ptrIn + (mtls->eStrideIn * xStart);
+        for (uint32_t x = xStart; x < xEnd; x++) {
+            ((rs_t)mtls->script->mHal.info.root) (xPtrIn, xPtrOut, mtls->usr, x, 0, 0, 0);
+            xPtrIn += mtls->eStrideIn;
+            xPtrOut += mtls->eStrideOut;
+        }
+    }
+}
+
+void rsdScriptInvokeForEach(const Context *rsc,
+                            Script *s,
+                            const Allocation * ain,
+                            Allocation * aout,
+                            const void * usr,
+                            uint32_t usrLen,
+                            const RsScriptCall *sc) {
+
+    RsHal * dc = (RsHal *)rsc->mHal.drv;
+
+    MTLaunchStruct mtls;
+    memset(&mtls, 0, sizeof(mtls));
+
+    if (ain) {
+        mtls.dimX = ain->getType()->getDimX();
+        mtls.dimY = ain->getType()->getDimY();
+        mtls.dimZ = ain->getType()->getDimZ();
+        //mtls.dimArray = ain->getType()->getDimArray();
+    } else if (aout) {
+        mtls.dimX = aout->getType()->getDimX();
+        mtls.dimY = aout->getType()->getDimY();
+        mtls.dimZ = aout->getType()->getDimZ();
+        //mtls.dimArray = aout->getType()->getDimArray();
+    } else {
+        rsc->setError(RS_ERROR_BAD_SCRIPT, "rsForEach called with null allocations");
+        return;
+    }
+
+    if (!sc || (sc->xEnd == 0)) {
+        mtls.xEnd = mtls.dimX;
+    } else {
+        rsAssert(sc->xStart < mtls.dimX);
+        rsAssert(sc->xEnd <= mtls.dimX);
+        rsAssert(sc->xStart < sc->xEnd);
+        mtls.xStart = rsMin(mtls.dimX, sc->xStart);
+        mtls.xEnd = rsMin(mtls.dimX, sc->xEnd);
+        if (mtls.xStart >= mtls.xEnd) return;
+    }
+
+    if (!sc || (sc->yEnd == 0)) {
+        mtls.yEnd = mtls.dimY;
+    } else {
+        rsAssert(sc->yStart < mtls.dimY);
+        rsAssert(sc->yEnd <= mtls.dimY);
+        rsAssert(sc->yStart < sc->yEnd);
+        mtls.yStart = rsMin(mtls.dimY, sc->yStart);
+        mtls.yEnd = rsMin(mtls.dimY, sc->yEnd);
+        if (mtls.yStart >= mtls.yEnd) return;
+    }
+
+    mtls.xEnd = rsMax((uint32_t)1, mtls.xEnd);
+    mtls.yEnd = rsMax((uint32_t)1, mtls.yEnd);
+    mtls.zEnd = rsMax((uint32_t)1, mtls.zEnd);
+    mtls.arrayEnd = rsMax((uint32_t)1, mtls.arrayEnd);
+
+    rsAssert(ain->getType()->getDimZ() == 0);
+
+    Context *mrsc = (Context *)rsc;
+    Script * oldTLS = setTLS(s);
+
+    mtls.rsc = mrsc;
+    mtls.ain = ain;
+    mtls.aout = aout;
+    mtls.script = s;
+    mtls.usr = usr;
+    mtls.mSliceSize = 10;
+    mtls.mSliceNum = 0;
+
+    mtls.ptrIn = NULL;
+    mtls.eStrideIn = 0;
+    if (ain) {
+        mtls.ptrIn = (const uint8_t *)ain->getPtr();
+        mtls.eStrideIn = ain->getType()->getElementSizeBytes();
+    }
+
+    mtls.ptrOut = NULL;
+    mtls.eStrideOut = 0;
+    if (aout) {
+        mtls.ptrOut = (uint8_t *)aout->getPtr();
+        mtls.eStrideOut = aout->getType()->getElementSizeBytes();
+    }
+
+    if ((dc->mWorkers.mCount > 1) && s->mHal.info.isThreadable) {
+        if (mtls.dimY > 1) {
+            rsdLaunchThreads(mrsc, wc_xy, &mtls);
+        } else {
+            rsdLaunchThreads(mrsc, wc_x, &mtls);
+        }
+
+        //LOGE("launch 1");
+    } else {
+        //LOGE("launch 3");
+        for (uint32_t ar = mtls.arrayStart; ar < mtls.arrayEnd; ar++) {
+            for (uint32_t z = mtls.zStart; z < mtls.zEnd; z++) {
+                for (uint32_t y = mtls.yStart; y < mtls.yEnd; y++) {
+                    uint32_t offset = mtls.dimX * mtls.dimY * mtls.dimZ * ar +
+                                      mtls.dimX * mtls.dimY * z +
+                                      mtls.dimX * y;
+                    uint8_t *xPtrOut = mtls.ptrOut + (mtls.eStrideOut * offset);
+                    const uint8_t *xPtrIn = mtls.ptrIn + (mtls.eStrideIn * offset);
+
+                    for (uint32_t x = mtls.xStart; x < mtls.xEnd; x++) {
+                        ((rs_t)s->mHal.info.root) (xPtrIn, xPtrOut, usr, x, y, z, ar);
+                        xPtrIn += mtls.eStrideIn;
+                        xPtrOut += mtls.eStrideOut;
+                    }
+                }
+            }
+        }
+    }
+
+    setTLS(oldTLS);
+}
+
+
+int rsdScriptInvokeRoot(const Context *dc, Script *script) {
+    DrvScript *drv = (DrvScript *)script->mHal.drv;
+
+    Script * oldTLS = setTLS(script);
+    int ret = drv->mRoot();
+    setTLS(oldTLS);
+
+    return ret;
+}
+
+void rsdScriptInvokeInit(const Context *dc, Script *script) {
+    DrvScript *drv = (DrvScript *)script->mHal.drv;
+
+    if (drv->mInit) {
+        drv->mInit();
+    }
+}
+
+
+void rsdScriptInvokeFunction(const Context *dc, Script *script,
+                            uint32_t slot,
+                            const void *params,
+                            size_t paramLength) {
+    DrvScript *drv = (DrvScript *)script->mHal.drv;
+    //LOGE("invoke %p %p %i %p %i", dc, script, slot, params, paramLength);
+
+    Script * oldTLS = setTLS(script);
+    ((void (*)(const void *, uint32_t))
+        drv->mInvokeFunctions[slot])(params, paramLength);
+    setTLS(oldTLS);
+}
+
+void rsdScriptSetGlobalVar(const Context *dc, const Script *script,
+                           uint32_t slot, void *data, size_t dataLength) {
+    DrvScript *drv = (DrvScript *)script->mHal.drv;
+    //rsAssert(!script->mFieldIsObject[slot]);
+    //LOGE("setGlobalVar %p %p %i %p %i", dc, script, slot, data, dataLength);
+
+    int32_t *destPtr = ((int32_t **)drv->mFieldAddress)[slot];
+    if (!destPtr) {
+        //LOGV("Calling setVar on slot = %i which is null", slot);
+        return;
+    }
+
+    memcpy(destPtr, data, dataLength);
+}
+
+void rsdScriptSetGlobalBind(const Context *dc, const Script *script, uint32_t slot, void *data) {
+    DrvScript *drv = (DrvScript *)script->mHal.drv;
+    //rsAssert(!script->mFieldIsObject[slot]);
+    //LOGE("setGlobalBind %p %p %i %p", dc, script, slot, data);
+
+    int32_t *destPtr = ((int32_t **)drv->mFieldAddress)[slot];
+    if (!destPtr) {
+        //LOGV("Calling setVar on slot = %i which is null", slot);
+        return;
+    }
+
+    memcpy(destPtr, &data, sizeof(void *));
+}
+
+void rsdScriptSetGlobalObj(const Context *dc, const Script *script, uint32_t slot, ObjectBase *data) {
+    DrvScript *drv = (DrvScript *)script->mHal.drv;
+    //rsAssert(script->mFieldIsObject[slot]);
+    //LOGE("setGlobalObj %p %p %i %p", dc, script, slot, data);
+
+    int32_t *destPtr = ((int32_t **)drv->mFieldAddress)[slot];
+    if (!destPtr) {
+        //LOGV("Calling setVar on slot = %i which is null", slot);
+        return;
+    }
+
+    rsiSetObject((ObjectBase **)destPtr, data);
+}
+
+void rsdScriptDestroy(const Context *dc, Script *script) {
+    DrvScript *drv = (DrvScript *)script->mHal.drv;
+
+    if (drv->mFieldAddress) {
+        for (size_t ct=0; ct < drv->mFieldCount; ct++) {
+            if (drv->mFieldIsObject[ct]) {
+                rsiClearObject((ObjectBase **)drv->mFieldAddress[ct]);
+            }
+        }
+        delete [] drv->mFieldAddress;
+        delete [] drv->mFieldIsObject;
+        drv->mFieldAddress = NULL;
+        drv->mFieldIsObject = NULL;
+        drv->mFieldCount = 0;
+    }
+
+    if (drv->mInvokeFunctions) {
+        delete [] drv->mInvokeFunctions;
+        drv->mInvokeFunctions = NULL;
+        drv->mInvokeFunctionCount = 0;
+    }
+    free(drv);
+    script->mHal.drv = NULL;
+
+}
+
+
diff --git a/libs/rs/driver/rsdBcc.h b/libs/rs/driver/rsdBcc.h
new file mode 100644
index 0000000..6723a36
--- /dev/null
+++ b/libs/rs/driver/rsdBcc.h
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef RSD_BCC_H
+#define RSD_BCC_H
+
+#include <rs_hal.h>
+
+
+bool rsdScriptInit(const android::renderscript::Context *, android::renderscript::ScriptC *,
+                   char const *resName, char const *cacheDir,
+                   uint8_t const *bitcode, size_t bitcodeSize,
+                   uint32_t flags, android::renderscript::RsHalSymbolLookupFunc lookupFunc);
+void rsdScriptInvokeFunction(const android::renderscript::Context *dc,
+                             android::renderscript::Script *script,
+                             uint32_t slot,
+                             const void *params,
+                             size_t paramLength);
+
+void rsdScriptInvokeForEach(const android::renderscript::Context *rsc,
+                            android::renderscript::Script *s,
+                            const android::renderscript::Allocation * ain,
+                            android::renderscript::Allocation * aout,
+                            const void * usr,
+                            uint32_t usrLen,
+                            const RsScriptCall *sc);
+
+int rsdScriptInvokeRoot(const android::renderscript::Context *dc,
+                        android::renderscript::Script *script);
+void rsdScriptInvokeInit(const android::renderscript::Context *dc,
+                         android::renderscript::Script *script);
+
+void rsdScriptSetGlobalVar(const android::renderscript::Context *,
+                           const android::renderscript::Script *,
+                           uint32_t slot, void *data, size_t dataLen);
+void rsdScriptSetGlobalBind(const android::renderscript::Context *,
+                            const android::renderscript::Script *,
+                            uint32_t slot, void *data);
+void rsdScriptSetGlobalObj(const android::renderscript::Context *,
+                           const android::renderscript::Script *,
+                           uint32_t slot, android::renderscript::ObjectBase *data);
+
+void rsdScriptSetGlobal(const android::renderscript::Context *dc,
+                        const android::renderscript::Script *script,
+                        uint32_t slot,
+                        void *data,
+                        size_t dataLength);
+void rsdScriptGetGlobal(const android::renderscript::Context *dc,
+                        const android::renderscript::Script *script,
+                        uint32_t slot,
+                        void *data,
+                        size_t dataLength);
+void rsdScriptDestroy(const android::renderscript::Context *dc,
+                      android::renderscript::Script *script);
+
+
+#endif
diff --git a/libs/rs/driver/rsdCore.cpp b/libs/rs/driver/rsdCore.cpp
new file mode 100644
index 0000000..6546110
--- /dev/null
+++ b/libs/rs/driver/rsdCore.cpp
@@ -0,0 +1,186 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "rsdCore.h"
+#include "rsdBcc.h"
+
+#include <malloc.h>
+#include "rsContext.h"
+
+#include <sys/types.h>
+#include <sys/resource.h>
+#include <sched.h>
+#include <cutils/properties.h>
+#include <cutils/sched_policy.h>
+#include <sys/syscall.h>
+#include <string.h>
+
+using namespace android;
+using namespace android::renderscript;
+
+static void Shutdown(Context *rsc);
+static void SetPriority(const Context *rsc, int32_t priority);
+
+static RsdHalFunctions FunctionTable = {
+    Shutdown,
+    NULL,
+    SetPriority,
+    {
+        rsdScriptInit,
+        rsdScriptInvokeFunction,
+        rsdScriptInvokeRoot,
+        rsdScriptInvokeForEach,
+        rsdScriptInvokeInit,
+        rsdScriptSetGlobalVar,
+        rsdScriptSetGlobalBind,
+        rsdScriptSetGlobalObj,
+        rsdScriptDestroy
+    }
+};
+
+
+
+static void * HelperThreadProc(void *vrsc) {
+    Context *rsc = static_cast<Context *>(vrsc);
+    RsHal *dc = (RsHal *)rsc->mHal.drv;
+
+
+    uint32_t idx = (uint32_t)android_atomic_inc(&dc->mWorkers.mLaunchCount);
+
+    //LOGV("RS helperThread starting %p idx=%i", rsc, idx);
+
+    dc->mWorkers.mLaunchSignals[idx].init();
+    dc->mWorkers.mNativeThreadId[idx] = gettid();
+
+#if 0
+    typedef struct {uint64_t bits[1024 / 64]; } cpu_set_t;
+    cpu_set_t cpuset;
+    memset(&cpuset, 0, sizeof(cpuset));
+    cpuset.bits[idx / 64] |= 1ULL << (idx % 64);
+    int ret = syscall(241, rsc->mWorkers.mNativeThreadId[idx],
+              sizeof(cpuset), &cpuset);
+    LOGE("SETAFFINITY ret = %i %s", ret, EGLUtils::strerror(ret));
+#endif
+
+    int status = pthread_setspecific(rsc->gThreadTLSKey, rsc->mTlsStruct);
+    if (status) {
+        LOGE("pthread_setspecific %i", status);
+    }
+
+    while (!dc->mExit) {
+        dc->mWorkers.mLaunchSignals[idx].wait();
+        if (dc->mWorkers.mLaunchCallback) {
+           dc->mWorkers.mLaunchCallback(dc->mWorkers.mLaunchData, idx);
+        }
+        android_atomic_dec(&dc->mWorkers.mRunningCount);
+        dc->mWorkers.mCompleteSignal.set();
+    }
+
+    //LOGV("RS helperThread exited %p idx=%i", rsc, idx);
+    return NULL;
+}
+
+void rsdLaunchThreads(Context *rsc, WorkerCallback_t cbk, void *data) {
+    RsHal *dc = (RsHal *)rsc->mHal.drv;
+
+    dc->mWorkers.mLaunchData = data;
+    dc->mWorkers.mLaunchCallback = cbk;
+    android_atomic_release_store(dc->mWorkers.mCount, &dc->mWorkers.mRunningCount);
+    for (uint32_t ct = 0; ct < dc->mWorkers.mCount; ct++) {
+        dc->mWorkers.mLaunchSignals[ct].set();
+    }
+    while (android_atomic_acquire_load(&dc->mWorkers.mRunningCount) != 0) {
+        dc->mWorkers.mCompleteSignal.wait();
+    }
+}
+
+bool rsdHalInit(Context *rsc, uint32_t version_major, uint32_t version_minor) {
+    rsc->mHal.funcs = FunctionTable;
+
+    RsHal *dc = (RsHal *)calloc(1, sizeof(RsHal));
+    if (!dc) {
+        LOGE("Calloc for driver hal failed.");
+        return false;
+    }
+    rsc->mHal.drv = dc;
+
+
+    int cpu = sysconf(_SC_NPROCESSORS_ONLN);
+    LOGV("RS Launching thread(s), reported CPU count %i", cpu);
+    if (cpu < 2) cpu = 0;
+
+    dc->mWorkers.mCount = (uint32_t)cpu;
+    dc->mWorkers.mThreadId = (pthread_t *) calloc(dc->mWorkers.mCount, sizeof(pthread_t));
+    dc->mWorkers.mNativeThreadId = (pid_t *) calloc(dc->mWorkers.mCount, sizeof(pid_t));
+    dc->mWorkers.mLaunchSignals = new Signal[dc->mWorkers.mCount];
+    dc->mWorkers.mLaunchCallback = NULL;
+
+    dc->mWorkers.mCompleteSignal.init();
+
+    android_atomic_release_store(dc->mWorkers.mCount, &dc->mWorkers.mRunningCount);
+    android_atomic_release_store(0, &dc->mWorkers.mLaunchCount);
+
+    int status;
+    pthread_attr_t threadAttr;
+    status = pthread_attr_init(&threadAttr);
+    if (status) {
+        LOGE("Failed to init thread attribute.");
+        return false;
+    }
+
+    for (uint32_t ct=0; ct < dc->mWorkers.mCount; ct++) {
+        status = pthread_create(&dc->mWorkers.mThreadId[ct], &threadAttr, HelperThreadProc, rsc);
+        if (status) {
+            dc->mWorkers.mCount = ct;
+            LOGE("Created fewer than expected number of RS threads.");
+            break;
+        }
+    }
+    while (android_atomic_acquire_load(&dc->mWorkers.mRunningCount) != 0) {
+        usleep(100);
+    }
+
+    pthread_attr_destroy(&threadAttr);
+    return true;
+}
+
+
+void SetPriority(const Context *rsc, int32_t priority) {
+    RsHal *dc = (RsHal *)rsc->mHal.drv;
+    for (uint32_t ct=0; ct < dc->mWorkers.mCount; ct++) {
+        setpriority(PRIO_PROCESS, dc->mWorkers.mNativeThreadId[ct], priority);
+    }
+}
+
+void Shutdown(Context *rsc) {
+    RsHal *dc = (RsHal *)rsc->mHal.drv;
+
+    dc->mExit = true;
+    dc->mWorkers.mLaunchData = NULL;
+    dc->mWorkers.mLaunchCallback = NULL;
+    android_atomic_release_store(dc->mWorkers.mCount, &dc->mWorkers.mRunningCount);
+    for (uint32_t ct = 0; ct < dc->mWorkers.mCount; ct++) {
+        dc->mWorkers.mLaunchSignals[ct].set();
+    }
+    int status;
+    void *res;
+    for (uint32_t ct = 0; ct < dc->mWorkers.mCount; ct++) {
+        status = pthread_join(dc->mWorkers.mThreadId[ct], &res);
+    }
+    rsAssert(android_atomic_acquire_load(&dc->mWorkers.mRunningCount) == 0);
+}
+
+
diff --git a/libs/rs/driver/rsdCore.h b/libs/rs/driver/rsdCore.h
new file mode 100644
index 0000000..02b2fbc
--- /dev/null
+++ b/libs/rs/driver/rsdCore.h
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef RSD_CORE_H
+#define RSD_CORE_H
+
+#include <rs_hal.h>
+#include <bcc/bcc.h>
+
+#include "rsMutex.h"
+#include "rsSignal.h"
+
+
+typedef void (* InvokeFunc_t)(void);
+typedef void (*WorkerCallback_t)(void *usr, uint32_t idx);
+
+typedef struct RsHalRec {
+    uint32_t version_major;
+    uint32_t version_minor;
+
+    struct Workers {
+        volatile int mRunningCount;
+        volatile int mLaunchCount;
+        uint32_t mCount;
+        pthread_t *mThreadId;
+        pid_t *mNativeThreadId;
+        android::renderscript::Signal mCompleteSignal;
+
+        android::renderscript::Signal *mLaunchSignals;
+        WorkerCallback_t mLaunchCallback;
+        void *mLaunchData;
+    };
+    Workers mWorkers;
+    bool mExit;
+} RsHal;
+
+
+
+void rsdLaunchThreads(android::renderscript::Context *rsc, WorkerCallback_t cbk, void *data);
+
+#endif
+
diff --git a/libs/rs/rs.spec b/libs/rs/rs.spec
index 7e23cec..bbb6200 100644
--- a/libs/rs/rs.spec
+++ b/libs/rs/rs.spec
@@ -181,10 +181,6 @@
 	}
 
 
-ScriptCBegin {
-	}
-
-
 ScriptSetTimeZone {
 	param RsScript s
 	param const char * timeZone
@@ -246,15 +242,11 @@
 	}
 
 
-ScriptCSetText {
-	param const char * text
-	param uint32_t length
-	}
-
 ScriptCCreate {
-        param const char * packageName
         param const char * resName
         param const char * cacheDir
+	param const char * text
+	param uint32_t length
 	ret RsScript
 	}
 
diff --git a/libs/rs/rsAllocation.cpp b/libs/rs/rsAllocation.cpp
index ec03a15..b8ddb0b 100644
--- a/libs/rs/rsAllocation.cpp
+++ b/libs/rs/rsAllocation.cpp
@@ -29,21 +29,22 @@
     : ObjectBase(rsc) {
     init(rsc, type);
 
-    mUsageFlags = usages;
-    mMipmapControl = mc;
+    mHal.state.usageFlags = usages;
+    mHal.state.mipmapControl = mc;
 
     allocScriptMemory();
-    if (mType->getElement()->getHasReferences()) {
-        memset(mPtr, 0, mType->getSizeBytes());
+    if (mHal.state.type->getElement()->getHasReferences()) {
+        memset(mHal.state.mallocPtr, 0, mHal.state.type->getSizeBytes());
     }
-    if (!mPtr) {
+    if (!mHal.state.mallocPtr) {
         LOGE("Allocation::Allocation, alloc failure");
     }
 }
 
 
 void Allocation::init(Context *rsc, const Type *type) {
-    mPtr = NULL;
+    memset(&mHal, 0, sizeof(mHal));
+    mHal.state.mipmapControl = RS_ALLOCATION_MIPMAP_NONE;
 
     mCpuWrite = false;
     mCpuRead = false;
@@ -52,8 +53,6 @@
 
     mReadWriteRatio = 0;
     mUpdateSize = 0;
-    mUsageFlags = 0;
-    mMipmapControl = RS_ALLOCATION_MIPMAP_NONE;
 
     mTextureID = 0;
     mBufferID = 0;
@@ -62,16 +61,25 @@
     mUserBitmapCallback = NULL;
     mUserBitmapCallbackData = NULL;
 
-    mType.set(type);
-    rsAssert(type);
+    mHal.state.type.set(type);
+    updateCache();
+}
 
-    mPtr = NULL;
+void Allocation::updateCache() {
+    const Type *type = mHal.state.type.get();
+    mHal.state.dimensionX = type->getDimX();
+    mHal.state.dimensionY = type->getDimY();
+    mHal.state.dimensionZ = type->getDimZ();
+    mHal.state.hasFaces = type->getDimFaces();
+    mHal.state.hasMipmaps = type->getDimLOD();
+    mHal.state.elementSizeBytes = type->getElementSizeBytes();
+    mHal.state.hasReferences = mHal.state.type->getElement()->getHasReferences();
 }
 
 Allocation::~Allocation() {
     if (mUserBitmapCallback != NULL) {
         mUserBitmapCallback(mUserBitmapCallbackData);
-        mPtr = NULL;
+        mHal.state.mallocPtr = NULL;
     }
     freeScriptMemory();
 #ifndef ANDROID_RS_SERIALIZE
@@ -105,14 +113,14 @@
 }
 
 void Allocation::deferedUploadToTexture(const Context *rsc) {
-    mUsageFlags |= RS_ALLOCATION_USAGE_GRAPHICS_TEXTURE;
+    mHal.state.usageFlags |= RS_ALLOCATION_USAGE_GRAPHICS_TEXTURE;
     mUploadDefered = true;
 }
 
 uint32_t Allocation::getGLTarget() const {
 #ifndef ANDROID_RS_SERIALIZE
     if (getIsTexture()) {
-        if (mType->getDimFaces()) {
+        if (mHal.state.type->getDimFaces()) {
             return GL_TEXTURE_CUBE_MAP;
         } else {
             return GL_TEXTURE_2D;
@@ -126,14 +134,14 @@
 }
 
 void Allocation::allocScriptMemory() {
-    rsAssert(!mPtr);
-    mPtr = malloc(mType->getSizeBytes());
+    rsAssert(!mHal.state.mallocPtr);
+    mHal.state.mallocPtr = malloc(mHal.state.type->getSizeBytes());
 }
 
 void Allocation::freeScriptMemory() {
-    if (mPtr) {
-        free(mPtr);
-        mPtr = NULL;
+    if (mHal.state.mallocPtr) {
+        free(mHal.state.mallocPtr);
+        mHal.state.mallocPtr = NULL;
     }
 }
 
@@ -153,15 +161,15 @@
 
 void Allocation::uploadToTexture(const Context *rsc) {
 #ifndef ANDROID_RS_SERIALIZE
-    mUsageFlags |= RS_ALLOCATION_USAGE_GRAPHICS_TEXTURE;
-    GLenum type = mType->getElement()->getComponent().getGLType();
-    GLenum format = mType->getElement()->getComponent().getGLFormat();
+    mHal.state.usageFlags |= RS_ALLOCATION_USAGE_GRAPHICS_TEXTURE;
+    GLenum type = mHal.state.type->getElement()->getComponent().getGLType();
+    GLenum format = mHal.state.type->getElement()->getComponent().getGLFormat();
 
     if (!type || !format) {
         return;
     }
 
-    if (!mPtr) {
+    if (!mHal.state.mallocPtr) {
         return;
     }
 
@@ -184,7 +192,7 @@
 
     upload2DTexture(isFirstUpload);
 
-    if (!(mUsageFlags & RS_ALLOCATION_USAGE_SCRIPT)) {
+    if (!(mHal.state.usageFlags & RS_ALLOCATION_USAGE_SCRIPT)) {
         freeScriptMemory();
     }
 
@@ -207,14 +215,14 @@
                                  uint32_t lod, RsAllocationCubemapFace face,
                                  uint32_t w, uint32_t h) {
 #ifndef ANDROID_RS_SERIALIZE
-    GLenum type = mType->getElement()->getComponent().getGLType();
-    GLenum format = mType->getElement()->getComponent().getGLFormat();
+    GLenum type = mHal.state.type->getElement()->getComponent().getGLType();
+    GLenum format = mHal.state.type->getElement()->getComponent().getGLFormat();
     GLenum target = (GLenum)getGLTarget();
     rsAssert(mTextureID);
     glBindTexture(target, mTextureID);
     glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
     GLenum t = GL_TEXTURE_2D;
-    if (mType->getDimFaces()) {
+    if (mHal.state.hasFaces) {
         t = gFaceOrder[face];
     }
     glTexSubImage2D(t, lod, xoff, yoff, w, h, format, type, ptr);
@@ -223,57 +231,57 @@
 
 void Allocation::upload2DTexture(bool isFirstUpload) {
 #ifndef ANDROID_RS_SERIALIZE
-    GLenum type = mType->getElement()->getComponent().getGLType();
-    GLenum format = mType->getElement()->getComponent().getGLFormat();
+    GLenum type = mHal.state.type->getElement()->getComponent().getGLType();
+    GLenum format = mHal.state.type->getElement()->getComponent().getGLFormat();
 
     GLenum target = (GLenum)getGLTarget();
     glBindTexture(target, mTextureID);
     glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
 
     uint32_t faceCount = 1;
-    if (mType->getDimFaces()) {
+    if (mHal.state.hasFaces) {
         faceCount = 6;
     }
 
     for (uint32_t face = 0; face < faceCount; face ++) {
-        for (uint32_t lod = 0; lod < mType->getLODCount(); lod++) {
-            const uint8_t *p = (const uint8_t *)mPtr;
-            p += mType->getLODFaceOffset(lod, (RsAllocationCubemapFace)face, 0, 0);
+        for (uint32_t lod = 0; lod < mHal.state.type->getLODCount(); lod++) {
+            const uint8_t *p = (const uint8_t *)mHal.state.mallocPtr;
+            p += mHal.state.type->getLODFaceOffset(lod, (RsAllocationCubemapFace)face, 0, 0);
 
             GLenum t = GL_TEXTURE_2D;
-            if (mType->getDimFaces()) {
+            if (mHal.state.hasFaces) {
                 t = gFaceOrder[face];
             }
 
             if (isFirstUpload) {
                 glTexImage2D(t, lod, format,
-                             mType->getLODDimX(lod), mType->getLODDimY(lod),
+                             mHal.state.type->getLODDimX(lod), mHal.state.type->getLODDimY(lod),
                              0, format, type, p);
             } else {
                 glTexSubImage2D(t, lod, 0, 0,
-                                mType->getLODDimX(lod), mType->getLODDimY(lod),
+                                mHal.state.type->getLODDimX(lod), mHal.state.type->getLODDimY(lod),
                                 format, type, p);
             }
         }
     }
 
-    if (mMipmapControl == RS_ALLOCATION_MIPMAP_ON_SYNC_TO_TEXTURE) {
+    if (mHal.state.mipmapControl == RS_ALLOCATION_MIPMAP_ON_SYNC_TO_TEXTURE) {
         glGenerateMipmap(target);
     }
 #endif //ANDROID_RS_SERIALIZE
 }
 
 void Allocation::deferedUploadToBufferObject(const Context *rsc) {
-    mUsageFlags |= RS_ALLOCATION_USAGE_GRAPHICS_VERTEX;
+    mHal.state.usageFlags |= RS_ALLOCATION_USAGE_GRAPHICS_VERTEX;
     mUploadDefered = true;
 }
 
 void Allocation::uploadToBufferObject(const Context *rsc) {
 #ifndef ANDROID_RS_SERIALIZE
-    rsAssert(!mType->getDimY());
-    rsAssert(!mType->getDimZ());
+    rsAssert(!mHal.state.type->getDimY());
+    rsAssert(!mHal.state.type->getDimZ());
 
-    mUsageFlags |= RS_ALLOCATION_USAGE_GRAPHICS_VERTEX;
+    mHal.state.usageFlags |= RS_ALLOCATION_USAGE_GRAPHICS_VERTEX;
 
     if (!mBufferID) {
         glGenBuffers(1, &mBufferID);
@@ -285,7 +293,7 @@
     }
     GLenum target = (GLenum)getGLTarget();
     glBindBuffer(target, mBufferID);
-    glBufferData(target, mType->getSizeBytes(), getPtr(), GL_DYNAMIC_DRAW);
+    glBufferData(target, mHal.state.type->getSizeBytes(), getPtr(), GL_DYNAMIC_DRAW);
     glBindBuffer(target, 0);
     rsc->checkError("Allocation::uploadToBufferObject");
 #endif //ANDROID_RS_SERIALIZE
@@ -298,23 +306,23 @@
 }
 
 void Allocation::read(void *data) {
-    memcpy(data, mPtr, mType->getSizeBytes());
+    memcpy(data, mHal.state.mallocPtr, mHal.state.type->getSizeBytes());
 }
 
 void Allocation::data(Context *rsc, uint32_t xoff, uint32_t lod,
                          uint32_t count, const void *data, uint32_t sizeBytes) {
-    uint32_t eSize = mType->getElementSizeBytes();
-    uint8_t * ptr = static_cast<uint8_t *>(mPtr);
+    uint32_t eSize = mHal.state.type->getElementSizeBytes();
+    uint8_t * ptr = static_cast<uint8_t *>(mHal.state.mallocPtr);
     ptr += eSize * xoff;
     uint32_t size = count * eSize;
 
     if (size != sizeBytes) {
         LOGE("Allocation::subData called with mismatched size expected %i, got %i", size, sizeBytes);
-        mType->dumpLOGV("type info");
+        mHal.state.type->dumpLOGV("type info");
         return;
     }
 
-    if (mType->getElement()->getHasReferences()) {
+    if (mHal.state.hasReferences) {
         incRefs(data, count);
         decRefs(ptr, count);
     }
@@ -326,9 +334,9 @@
 
 void Allocation::data(Context *rsc, uint32_t xoff, uint32_t yoff, uint32_t lod, RsAllocationCubemapFace face,
              uint32_t w, uint32_t h, const void *data, uint32_t sizeBytes) {
-    uint32_t eSize = mType->getElementSizeBytes();
+    uint32_t eSize = mHal.state.elementSizeBytes;
     uint32_t lineSize = eSize * w;
-    uint32_t destW = mType->getDimX();
+    uint32_t destW = mHal.state.dimensionX;
 
     //LOGE("data2d %p,  %i %i %i %i %i %i %p %i", this, xoff, yoff, lod, face, w, h, data, sizeBytes);
 
@@ -338,14 +346,14 @@
         return;
     }
 
-    if (mPtr) {
+    if (mHal.state.mallocPtr) {
         const uint8_t *src = static_cast<const uint8_t *>(data);
-        uint8_t *dst = static_cast<uint8_t *>(mPtr);
-        dst += mType->getLODFaceOffset(lod, face, xoff, yoff);
+        uint8_t *dst = static_cast<uint8_t *>(mHal.state.mallocPtr);
+        dst += mHal.state.type->getLODFaceOffset(lod, face, xoff, yoff);
 
         //LOGE("            %p  %p  %i  ", dst, src, eSize);
         for (uint32_t line=yoff; line < (yoff+h); line++) {
-            if (mType->getElement()->getHasReferences()) {
+            if (mHal.state.hasReferences) {
                 incRefs(src, w);
                 decRefs(dst, w);
             }
@@ -367,24 +375,24 @@
 
 void Allocation::elementData(Context *rsc, uint32_t x, const void *data,
                                 uint32_t cIdx, uint32_t sizeBytes) {
-    uint32_t eSize = mType->getElementSizeBytes();
-    uint8_t * ptr = static_cast<uint8_t *>(mPtr);
+    uint32_t eSize = mHal.state.elementSizeBytes;
+    uint8_t * ptr = static_cast<uint8_t *>(mHal.state.mallocPtr);
     ptr += eSize * x;
 
-    if (cIdx >= mType->getElement()->getFieldCount()) {
+    if (cIdx >= mHal.state.type->getElement()->getFieldCount()) {
         LOGE("Error Allocation::subElementData component %i out of range.", cIdx);
         rsc->setError(RS_ERROR_BAD_VALUE, "subElementData component out of range.");
         return;
     }
 
-    if (x >= mType->getDimX()) {
+    if (x >= mHal.state.dimensionX) {
         LOGE("Error Allocation::subElementData X offset %i out of range.", x);
         rsc->setError(RS_ERROR_BAD_VALUE, "subElementData X offset out of range.");
         return;
     }
 
-    const Element * e = mType->getElement()->getField(cIdx);
-    ptr += mType->getElement()->getFieldOffsetBytes(cIdx);
+    const Element * e = mHal.state.type->getElement()->getField(cIdx);
+    ptr += mHal.state.type->getElement()->getFieldOffsetBytes(cIdx);
 
     if (sizeBytes != e->getSizeBytes()) {
         LOGE("Error Allocation::subElementData data size %i does not match field size %zu.", sizeBytes, e->getSizeBytes());
@@ -404,30 +412,30 @@
 
 void Allocation::elementData(Context *rsc, uint32_t x, uint32_t y,
                                 const void *data, uint32_t cIdx, uint32_t sizeBytes) {
-    uint32_t eSize = mType->getElementSizeBytes();
-    uint8_t * ptr = static_cast<uint8_t *>(mPtr);
-    ptr += eSize * (x + y * mType->getDimX());
+    uint32_t eSize = mHal.state.elementSizeBytes;
+    uint8_t * ptr = static_cast<uint8_t *>(mHal.state.mallocPtr);
+    ptr += eSize * (x + y * mHal.state.dimensionX);
 
-    if (x >= mType->getDimX()) {
+    if (x >= mHal.state.dimensionX) {
         LOGE("Error Allocation::subElementData X offset %i out of range.", x);
         rsc->setError(RS_ERROR_BAD_VALUE, "subElementData X offset out of range.");
         return;
     }
 
-    if (y >= mType->getDimY()) {
+    if (y >= mHal.state.dimensionY) {
         LOGE("Error Allocation::subElementData X offset %i out of range.", x);
         rsc->setError(RS_ERROR_BAD_VALUE, "subElementData X offset out of range.");
         return;
     }
 
-    if (cIdx >= mType->getElement()->getFieldCount()) {
+    if (cIdx >= mHal.state.type->getElement()->getFieldCount()) {
         LOGE("Error Allocation::subElementData component %i out of range.", cIdx);
         rsc->setError(RS_ERROR_BAD_VALUE, "subElementData component out of range.");
         return;
     }
 
-    const Element * e = mType->getElement()->getField(cIdx);
-    ptr += mType->getElement()->getFieldOffsetBytes(cIdx);
+    const Element * e = mHal.state.type->getElement()->getField(cIdx);
+    ptr += mHal.state.type->getElement()->getFieldOffsetBytes(cIdx);
 
     if (sizeBytes != e->getSizeBytes()) {
         LOGE("Error Allocation::subElementData data size %i does not match field size %zu.", sizeBytes, e->getSizeBytes());
@@ -468,15 +476,15 @@
 
     String8 s(prefix);
     s.append(" type ");
-    if (mType.get()) {
-        mType->dumpLOGV(s.string());
+    if (mHal.state.type.get()) {
+        mHal.state.type->dumpLOGV(s.string());
     }
 
     LOGV("%s allocation ptr=%p mCpuWrite=%i, mCpuRead=%i, mGpuWrite=%i, mGpuRead=%i",
-          prefix, mPtr, mCpuWrite, mCpuRead, mGpuWrite, mGpuRead);
+          prefix, mHal.state.mallocPtr, mCpuWrite, mCpuRead, mGpuWrite, mGpuRead);
 
     LOGV("%s allocation mUsageFlags=0x04%x, mMipmapControl=0x%04x, mTextureID=%i, mBufferID=%i",
-          prefix, mUsageFlags, mMipmapControl, mTextureID, mBufferID);
+          prefix, mHal.state.usageFlags, mHal.state.mipmapControl, mTextureID, mBufferID);
 }
 
 void Allocation::serialize(OStream *stream) const {
@@ -488,13 +496,13 @@
 
     // First thing we need to serialize is the type object since it will be needed
     // to initialize the class
-    mType->serialize(stream);
+    mHal.state.type->serialize(stream);
 
-    uint32_t dataSize = mType->getSizeBytes();
+    uint32_t dataSize = mHal.state.type->getSizeBytes();
     // Write how much data we are storing
     stream->addU32(dataSize);
     // Now write the data
-    stream->addByteArray(mPtr, dataSize);
+    stream->addByteArray(mHal.state.mallocPtr, dataSize);
 }
 
 Allocation *Allocation::createFromStream(Context *rsc, IStream *stream) {
@@ -544,7 +552,7 @@
 
 void Allocation::incRefs(const void *ptr, size_t ct, size_t startOff) const {
     const uint8_t *p = static_cast<const uint8_t *>(ptr);
-    const Element *e = mType->getElement();
+    const Element *e = mHal.state.type->getElement();
     uint32_t stride = e->getSizeBytes();
 
     p += stride * startOff;
@@ -557,7 +565,7 @@
 
 void Allocation::decRefs(const void *ptr, size_t ct, size_t startOff) const {
     const uint8_t *p = static_cast<const uint8_t *>(ptr);
-    const Element *e = mType->getElement();
+    const Element *e = mHal.state.type->getElement();
     uint32_t stride = e->getSizeBytes();
 
     p += stride * startOff;
@@ -572,24 +580,26 @@
 }
 
 void Allocation::resize1D(Context *rsc, uint32_t dimX) {
-    Type *t = mType->cloneAndResize1D(rsc, dimX);
+    Type *t = mHal.state.type->cloneAndResize1D(rsc, dimX);
 
-    uint32_t oldDimX = mType->getDimX();
+    uint32_t oldDimX = mHal.state.dimensionX;
     if (dimX == oldDimX) {
         return;
     }
 
     if (dimX < oldDimX) {
-        decRefs(mPtr, oldDimX - dimX, dimX);
+        decRefs(mHal.state.mallocPtr, oldDimX - dimX, dimX);
     }
-    mPtr = realloc(mPtr, t->getSizeBytes());
+    mHal.state.mallocPtr = realloc(mHal.state.mallocPtr, t->getSizeBytes());
 
     if (dimX > oldDimX) {
-        const Element *e = mType->getElement();
+        const Element *e = mHal.state.type->getElement();
         uint32_t stride = e->getSizeBytes();
-        memset(((uint8_t *)mPtr) + stride * oldDimX, 0, stride * (dimX - oldDimX));
+        memset(((uint8_t *)mHal.state.mallocPtr) + stride * oldDimX, 0, stride * (dimX - oldDimX));
     }
-    mType.set(t);
+
+    mHal.state.type.set(t);
+    updateCache();
 }
 
 void Allocation::resize2D(Context *rsc, uint32_t dimX, uint32_t dimY) {
diff --git a/libs/rs/rsAllocation.h b/libs/rs/rsAllocation.h
index 4f5d5a8..e63140c 100644
--- a/libs/rs/rsAllocation.h
+++ b/libs/rs/rsAllocation.h
@@ -29,10 +29,35 @@
     // The graphics equilivent of malloc.  The allocation contains a structure of elements.
 
 public:
+    struct Hal {
+        void * drv;
+
+        struct State {
+            ObjectBaseRef<const Type> type;
+            void * mallocPtr;
+
+            uint32_t usageFlags;
+            RsAllocationMipmapControl mipmapControl;
+
+            // Cached fields from the Type and Element
+            // to prevent pointer chasing in critical loops.
+            uint32_t dimensionX;
+            uint32_t dimensionY;
+            uint32_t dimensionZ;
+            uint32_t elementSizeBytes;
+            bool hasMipmaps;
+            bool hasFaces;
+            bool hasReferences;
+        };
+        State state;
+    };
+    Hal mHal;
+
     Allocation(Context *rsc, const Type *, uint32_t usages,
                RsAllocationMipmapControl mc = RS_ALLOCATION_MIPMAP_NONE);
 
     virtual ~Allocation();
+    void updateCache();
 
     void setCpuWritable(bool);
     void setGpuWritable(bool);
@@ -41,8 +66,8 @@
 
     bool fixAllocation();
 
-    void * getPtr() const {return mPtr;}
-    const Type * getType() const {return mType.get();}
+    void * getPtr() const {return mHal.state.mallocPtr;}
+    const Type * getType() const {return mHal.state.type.get();}
 
     void syncAll(Context *rsc, RsAllocationUsageType src);
 
@@ -88,13 +113,13 @@
     virtual void uploadCheck(Context *rsc);
 
     bool getIsScript() const {
-        return (mUsageFlags & RS_ALLOCATION_USAGE_SCRIPT) != 0;
+        return (mHal.state.usageFlags & RS_ALLOCATION_USAGE_SCRIPT) != 0;
     }
     bool getIsTexture() const {
-        return (mUsageFlags & RS_ALLOCATION_USAGE_GRAPHICS_TEXTURE) != 0;
+        return (mHal.state.usageFlags & RS_ALLOCATION_USAGE_GRAPHICS_TEXTURE) != 0;
     }
     bool getIsBufferObject() const {
-        return (mUsageFlags & RS_ALLOCATION_USAGE_GRAPHICS_VERTEX) != 0;
+        return (mHal.state.usageFlags & RS_ALLOCATION_USAGE_GRAPHICS_VERTEX) != 0;
     }
 
     void incRefs(const void *ptr, size_t ct, size_t startOff = 0) const;
@@ -102,14 +127,11 @@
 
     void sendDirty() const;
     bool getHasGraphicsMipmaps() const {
-        return mMipmapControl != RS_ALLOCATION_MIPMAP_NONE;
+        return mHal.state.mipmapControl != RS_ALLOCATION_MIPMAP_NONE;
     }
 
 
 protected:
-    ObjectBaseRef<const Type> mType;
-    void * mPtr;
-
     Vector<const Program *> mToDirtyList;
 
     // Is we have a non-null user bitmap callback we do not own the bits and
@@ -123,9 +145,6 @@
     bool mGpuWrite;
     bool mGpuRead;
 
-    uint32_t mUsageFlags;
-    RsAllocationMipmapControl mMipmapControl;
-
     // more usage hint data from the application
     // which can be used by a driver to pick the best memory type.
     // Likely ignored for now
diff --git a/libs/rs/rsContext.cpp b/libs/rs/rsContext.cpp
index 4a5620d..c761c75 100644
--- a/libs/rs/rsContext.cpp
+++ b/libs/rs/rsContext.cpp
@@ -429,6 +429,8 @@
     mStateFont.getFontColor(&oldR, &oldG, &oldB, &oldA);
     uint32_t bufferLen = strlen(buffer);
 
+    ObjectBaseRef<Font> lastFont(getFont());
+    setFont(NULL);
     float shadowCol = 0.1f;
     mStateFont.setFontColor(shadowCol, shadowCol, shadowCol, 1.0f);
     mStateFont.renderText(buffer, bufferLen, 5, getHeight() - 6);
@@ -436,6 +438,7 @@
     mStateFont.setFontColor(1.0f, 0.7f, 0.0f, 1.0f);
     mStateFont.renderText(buffer, bufferLen, 4, getHeight() - 7);
 
+    setFont(lastFont.get());
     mStateFont.setFontColor(oldR, oldG, oldB, oldA);
 }
 
@@ -551,56 +554,6 @@
     mExit = true;
 }
 
-void * Context::helperThreadProc(void *vrsc) {
-     Context *rsc = static_cast<Context *>(vrsc);
-     uint32_t idx = (uint32_t)android_atomic_inc(&rsc->mWorkers.mLaunchCount);
-
-     //LOGV("RS helperThread starting %p idx=%i", rsc, idx);
-
-     rsc->mWorkers.mLaunchSignals[idx].init();
-     rsc->mWorkers.mNativeThreadId[idx] = gettid();
-
-#if 0
-     typedef struct {uint64_t bits[1024 / 64]; } cpu_set_t;
-     cpu_set_t cpuset;
-     memset(&cpuset, 0, sizeof(cpuset));
-     cpuset.bits[idx / 64] |= 1ULL << (idx % 64);
-     int ret = syscall(241, rsc->mWorkers.mNativeThreadId[idx],
-               sizeof(cpuset), &cpuset);
-     LOGE("SETAFFINITY ret = %i %s", ret, EGLUtils::strerror(ret));
-#endif
-
-     setpriority(PRIO_PROCESS, rsc->mWorkers.mNativeThreadId[idx], rsc->mThreadPriority);
-     int status = pthread_setspecific(rsc->gThreadTLSKey, rsc->mTlsStruct);
-     if (status) {
-         LOGE("pthread_setspecific %i", status);
-     }
-
-     while (!rsc->mExit) {
-         rsc->mWorkers.mLaunchSignals[idx].wait();
-         if (rsc->mWorkers.mLaunchCallback) {
-            rsc->mWorkers.mLaunchCallback(rsc->mWorkers.mLaunchData, idx);
-         }
-         android_atomic_dec(&rsc->mWorkers.mRunningCount);
-         rsc->mWorkers.mCompleteSignal.set();
-     }
-
-     //LOGV("RS helperThread exited %p idx=%i", rsc, idx);
-     return NULL;
-}
-
-void Context::launchThreads(WorkerCallback_t cbk, void *data) {
-    mWorkers.mLaunchData = data;
-    mWorkers.mLaunchCallback = cbk;
-    mWorkers.mRunningCount = (int)mWorkers.mCount;
-    for (uint32_t ct = 0; ct < mWorkers.mCount; ct++) {
-        mWorkers.mLaunchSignals[ct].set();
-    }
-    while (mWorkers.mRunningCount) {
-        mWorkers.mCompleteSignal.wait();
-    }
-}
-
 void Context::setPriority(int32_t p) {
     // Note: If we put this in the proper "background" policy
     // the wallpapers can become completly unresponsive at times.
@@ -617,9 +570,6 @@
     }
 #else
     setpriority(PRIO_PROCESS, mNativeThreadId, p);
-    for (uint32_t ct=0; ct < mWorkers.mCount; ct++) {
-        setpriority(PRIO_PROCESS, mWorkers.mNativeThreadId[ct], p);
-    }
 #endif
 }
 
@@ -630,6 +580,7 @@
     mPaused = false;
     mObjHead = NULL;
     mError = RS_ERROR_NONE;
+    mDPI = 96;
 }
 
 Context * Context::createContext(Device *dev, const RsSurfaceConfig *sc) {
@@ -684,15 +635,12 @@
     timerInit();
     timerSet(RS_TIMER_INTERNAL);
 
-    int cpu = sysconf(_SC_NPROCESSORS_ONLN);
-    LOGV("RS Launching thread(s), reported CPU count %i", cpu);
-    if (cpu < 2) cpu = 0;
+    if (!rsdHalInit(this, 0, 0)) {
+        LOGE("Hal init failed");
+        return false;
+    }
+    mHal.funcs.setPriority(this, mThreadPriority);
 
-    mWorkers.mCount = (uint32_t)cpu;
-    mWorkers.mThreadId = (pthread_t *) calloc(mWorkers.mCount, sizeof(pthread_t));
-    mWorkers.mNativeThreadId = (pid_t *) calloc(mWorkers.mCount, sizeof(pid_t));
-    mWorkers.mLaunchSignals = new Signal[mWorkers.mCount];
-    mWorkers.mLaunchCallback = NULL;
     status = pthread_create(&mThreadId, &threadAttr, threadProc, this);
     if (status) {
         LOGE("Failed to start rs context thread.");
@@ -703,20 +651,10 @@
     }
 
     if (mError != RS_ERROR_NONE) {
+        LOGE("Errors during thread init");
         return false;
     }
 
-    mWorkers.mCompleteSignal.init();
-    mWorkers.mRunningCount = 0;
-    mWorkers.mLaunchCount = 0;
-    for (uint32_t ct=0; ct < mWorkers.mCount; ct++) {
-        status = pthread_create(&mWorkers.mThreadId[ct], &threadAttr, helperThreadProc, this);
-        if (status) {
-            mWorkers.mCount = ct;
-            LOGE("Created fewer than expected number of RS threads.");
-            break;
-        }
-    }
     pthread_attr_destroy(&threadAttr);
     return true;
 }
@@ -733,17 +671,10 @@
     mIO.shutdown();
     int status = pthread_join(mThreadId, &res);
 
-    // Cleanup compute threads.
-    mWorkers.mLaunchData = NULL;
-    mWorkers.mLaunchCallback = NULL;
-    mWorkers.mRunningCount = (int)mWorkers.mCount;
-    for (uint32_t ct = 0; ct < mWorkers.mCount; ct++) {
-        mWorkers.mLaunchSignals[ct].set();
+
+    if (mHal.funcs.shutdownDriver) {
+        mHal.funcs.shutdownDriver(this);
     }
-    for (uint32_t ct = 0; ct < mWorkers.mCount; ct++) {
-        status = pthread_join(mWorkers.mThreadId[ct], &res);
-    }
-    rsAssert(!mWorkers.mRunningCount);
 
     // Global structure cleanup.
     pthread_mutex_lock(&gInitMutex);
@@ -1075,10 +1006,12 @@
     return rsc;
 }
 
-RsContext rsContextCreateGL(RsDevice vdev, uint32_t version, RsSurfaceConfig sc) {
+RsContext rsContextCreateGL(RsDevice vdev, uint32_t version,
+                            RsSurfaceConfig sc, uint32_t dpi) {
     LOGV("rsContextCreateGL %p", vdev);
     Device * dev = static_cast<Device *>(vdev);
     Context *rsc = Context::createContext(dev, &sc);
+    rsc->setDPI(dpi);
     LOGV("rsContextCreateGL ret %p ", rsc);
     return rsc;
 }
diff --git a/libs/rs/rsContext.h b/libs/rs/rsContext.h
index c5e32a6..72574a60 100644
--- a/libs/rs/rsContext.h
+++ b/libs/rs/rsContext.h
@@ -22,6 +22,8 @@
 #include "rsAllocation.h"
 #include "rsMesh.h"
 
+#include "rs_hal.h"
+
 #ifndef ANDROID_RS_SERIALIZE
 #include "rsMutex.h"
 #include "rsThreadIO.h"
@@ -71,6 +73,13 @@
 
 class Context {
 public:
+    struct Hal {
+        void * drv;
+
+        RsdHalFunctions funcs;
+    };
+    Hal mHal;
+
     static Context * createContext(Device *, const RsSurfaceConfig *sc);
     ~Context();
 
@@ -81,11 +90,6 @@
     // Library mutex (for providing thread-safe calls from the runtime)
     static pthread_mutex_t gLibMutex;
 
-    struct ScriptTLSStruct {
-        Context * mContext;
-        Script * mScript;
-    };
-
     class PushState {
     public:
         PushState(Context *);
@@ -103,9 +107,6 @@
     ScriptTLSStruct *mTlsStruct;
     RsSurfaceConfig mUserSurfaceConfig;
 
-    typedef void (*WorkerCallback_t)(void *usr, uint32_t idx);
-
-    //StructuredAllocationContext mStateAllocation;
     ElementState mStateElement;
     TypeState mStateType;
     SamplerState mStateSampler;
@@ -216,8 +217,8 @@
     uint32_t getMaxVertexUniformVectors() const {return mGL.mMaxVertexUniformVectors;}
     uint32_t getMaxVertexAttributes() const {return mGL.mMaxVertexAttribs;}
 
-    void launchThreads(WorkerCallback_t cbk, void *data);
-    uint32_t getWorkerPoolSize() const {return (uint32_t)mWorkers.mCount;}
+    uint32_t getDPI() const {return mDPI;}
+    void setDPI(uint32_t dpi) {mDPI = dpi;}
 
 protected:
     Device *mDev;
@@ -258,6 +259,7 @@
         float EXT_texture_max_aniso;
     } mGL;
 
+    uint32_t mDPI;
     uint32_t mWidth;
     uint32_t mHeight;
     int32_t mThreadPriority;
@@ -271,20 +273,6 @@
     pthread_t mThreadId;
     pid_t mNativeThreadId;
 
-    struct Workers {
-        volatile int mRunningCount;
-        volatile int mLaunchCount;
-        uint32_t mCount;
-        pthread_t *mThreadId;
-        pid_t *mNativeThreadId;
-        Signal mCompleteSignal;
-
-        Signal *mLaunchSignals;
-        WorkerCallback_t mLaunchCallback;
-        void *mLaunchData;
-    };
-    Workers mWorkers;
-
     ObjectBaseRef<Script> mRootScript;
     ObjectBaseRef<ProgramFragment> mFragment;
     ObjectBaseRef<ProgramVertex> mVertex;
diff --git a/libs/rs/rsFont.cpp b/libs/rs/rsFont.cpp
index 1c1bc98..01dbab8 100644
--- a/libs/rs/rsFont.cpp
+++ b/libs/rs/rsFont.cpp
@@ -733,7 +733,7 @@
             String8 fullPath(getenv("ANDROID_ROOT"));
             fullPath += fontsDir;
 
-            mDefault.set(Font::create(mRSC, fullPath.string(), 16, 96));
+            mDefault.set(Font::create(mRSC, fullPath.string(), 8, mRSC->getDPI()));
         }
         currentFont = mDefault.get();
     }
diff --git a/libs/rs/rsScript.cpp b/libs/rs/rsScript.cpp
index afee2a3..b84014f 100644
--- a/libs/rs/rsScript.cpp
+++ b/libs/rs/rsScript.cpp
@@ -21,6 +21,7 @@
 
 Script::Script(Context *rsc) : ObjectBase(rsc) {
     memset(&mEnviroment, 0, sizeof(mEnviroment));
+    memset(&mHal, 0, sizeof(mHal));
 
     mSlots = NULL;
     mTypes = NULL;
@@ -37,48 +38,38 @@
     }
 }
 
-void Script::initSlots() {
-    if (mEnviroment.mFieldCount > 0) {
-        mSlots = new ObjectBaseRef<Allocation>[mEnviroment.mFieldCount];
-        mTypes = new ObjectBaseRef<const Type>[mEnviroment.mFieldCount];
-    }
-}
-
 void Script::setSlot(uint32_t slot, Allocation *a) {
-    if (slot >= mEnviroment.mFieldCount) {
+    //LOGE("setSlot %i %p", slot, a);
+    if (slot >= mHal.info.exportedVariableCount) {
         LOGE("Script::setSlot unable to set allocation, invalid slot index");
         return;
     }
 
     mSlots[slot].set(a);
+    if (a != NULL) {
+        mRSC->mHal.funcs.script.setGlobalBind(mRSC, this, slot, a->getPtr());
+    } else {
+        mRSC->mHal.funcs.script.setGlobalBind(mRSC, this, slot, NULL);
+    }
 }
 
 void Script::setVar(uint32_t slot, const void *val, uint32_t len) {
-    int32_t *destPtr = ((int32_t **)mEnviroment.mFieldAddress)[slot];
-    if (destPtr) {
-        //LOGE("setVar f1  %f", ((const float *)destPtr)[0]);
-        //LOGE("setVar %p %i", destPtr, len);
-        memcpy(destPtr, val, len);
-        //LOGE("setVar f2  %f", ((const float *)destPtr)[0]);
-    } else {
-        //if (rsc->props.mLogScripts) {
-            LOGV("Calling setVar on slot = %i which is null", slot);
-        //}
+    //LOGE("setVar %i %p %i", slot, val, len);
+    if (slot >= mHal.info.exportedVariableCount) {
+        LOGE("Script::setVar unable to set allocation, invalid slot index");
+        return;
     }
+    mRSC->mHal.funcs.script.setGlobalVar(mRSC, this, slot, (void *)val, len);
 }
 
 void Script::setVarObj(uint32_t slot, ObjectBase *val) {
-    ObjectBase **destPtr = ((ObjectBase ***)mEnviroment.mFieldAddress)[slot];
-
-    if (destPtr) {
-        if (val != NULL) {
-            val->incSysRef();
-        }
-        if (*destPtr) {
-            (*destPtr)->decSysRef();
-        }
-        *destPtr = val;
+    //LOGE("setVarObj %i %p", slot, val);
+    if (slot >= mHal.info.exportedVariableCount) {
+        LOGE("Script::setVarObj unable to set allocation, invalid slot index");
+        return;
     }
+    //LOGE("setvarobj  %i %p", slot, val);
+    mRSC->mHal.funcs.script.setGlobalObj(mRSC, this, slot, val);
 }
 
 namespace android {
diff --git a/libs/rs/rsScript.h b/libs/rs/rsScript.h
index bad095b..671fbe6 100644
--- a/libs/rs/rsScript.h
+++ b/libs/rs/rsScript.h
@@ -31,6 +31,45 @@
 
 class Script : public ObjectBase {
 public:
+    struct Hal {
+        void * drv;
+
+        struct State {
+            ObjectBaseRef<const Type> type;
+            void * mallocPtr;
+
+            uint32_t usageFlags;
+            RsAllocationMipmapControl mipmapControl;
+
+            // Cached fields from the Type and Element
+            // to prevent pointer chasing in critical loops.
+            uint32_t dimensionX;
+            uint32_t dimensionY;
+            uint32_t dimensionZ;
+            uint32_t elementSizeBytes;
+            bool hasMipmaps;
+            bool hasFaces;
+            bool hasReferences;
+        };
+        State state;
+
+        struct DriverInfo {
+            int mVersionMajor;
+            int mVersionMinor;
+
+            size_t exportedVariableCount;
+            size_t exportedFunctionCount;
+            size_t exportedPragmaCount;
+            char const **exportedPragmaKeyList;
+            char const **exportedPragmaValueList;
+
+            int (* root)();
+            bool isThreadable;
+        };
+        DriverInfo info;
+    };
+    Hal mHal;
+
     typedef void (* InvokeFunc_t)(void);
 
     Script(Context *);
@@ -45,16 +84,6 @@
         ObjectBaseRef<ProgramFragment> mFragment;
         ObjectBaseRef<ProgramRaster> mRaster;
         ObjectBaseRef<ProgramStore> mFragmentStore;
-
-        uint32_t mInvokeFunctionCount;
-        InvokeFunc_t *mInvokeFunctions;
-        uint32_t mFieldCount;
-        void ** mFieldAddress;
-
-        char * mScriptText;
-        uint32_t mScriptTextLength;
-
-        bool mIsThreadable;
     };
     Enviroment_t mEnviroment;
 
diff --git a/libs/rs/rsScriptC.cpp b/libs/rs/rsScriptC.cpp
index e12926b..d5c486b 100644
--- a/libs/rs/rsScriptC.cpp
+++ b/libs/rs/rsScriptC.cpp
@@ -19,9 +19,6 @@
 #include "rsMatrix.h"
 #include "utils/Timers.h"
 #include "utils/StopWatch.h"
-extern "C" {
-#include "libdex/ZipArchive.h"
-}
 
 #include <GLES/gl.h>
 #include <GLES/glext.h>
@@ -36,94 +33,18 @@
     Context * rsc = tls->mContext; \
     ScriptC * sc = (ScriptC *) tls->mScript
 
-// Input: cacheDir
-// Input: resName
-// Input: extName
-//
-// Note: cacheFile = resName + extName
-//
-// Output: Returns cachePath == cacheDir + cacheFile
-char *genCacheFileName(const char *cacheDir,
-                       const char *resName,
-                       const char *extName) {
-    char cachePath[512];
-    char cacheFile[sizeof(cachePath)];
-    const size_t kBufLen = sizeof(cachePath) - 1;
-
-    cacheFile[0] = '\0';
-    // Note: resName today is usually something like
-    //       "/com.android.fountain:raw/fountain"
-    if (resName[0] != '/') {
-        // Get the absolute path of the raw/***.bc file.
-
-        // Generate the absolute path.  This doesn't do everything it
-        // should, e.g. if resName is "./out/whatever" it doesn't crunch
-        // the leading "./" out because this if-block is not triggered,
-        // but it'll make do.
-        //
-        if (getcwd(cacheFile, kBufLen) == NULL) {
-            LOGE("Can't get CWD while opening raw/***.bc file\n");
-            return NULL;
-        }
-        // Append "/" at the end of cacheFile so far.
-        strncat(cacheFile, "/", kBufLen);
-    }
-
-    // cacheFile = resName + extName
-    //
-    strncat(cacheFile, resName, kBufLen);
-    if (extName != NULL) {
-        // TODO(srhines): strncat() is a bit dangerous
-        strncat(cacheFile, extName, kBufLen);
-    }
-
-    // Turn the path into a flat filename by replacing
-    // any slashes after the first one with '@' characters.
-    char *cp = cacheFile + 1;
-    while (*cp != '\0') {
-        if (*cp == '/') {
-            *cp = '@';
-        }
-        cp++;
-    }
-
-    // Tack on the file name for the actual cache file path.
-    strncpy(cachePath, cacheDir, kBufLen);
-    strncat(cachePath, cacheFile, kBufLen);
-
-    LOGV("Cache file for '%s' '%s' is '%s'\n", resName, extName, cachePath);
-    return strdup(cachePath);
-}
-
 ScriptC::ScriptC(Context *rsc) : Script(rsc) {
-    mBccScript = NULL;
-    memset(&mProgram, 0, sizeof(mProgram));
 }
 
 ScriptC::~ScriptC() {
-    if (mBccScript) {
-        if (mProgram.mObjectSlotList) {
-            for (size_t ct=0; ct < mProgram.mObjectSlotCount; ct++) {
-                setVarObj(mProgram.mObjectSlotList[ct], NULL);
-            }
-            delete [] mProgram.mObjectSlotList;
-            mProgram.mObjectSlotList = NULL;
-            mProgram.mObjectSlotCount = 0;
-        }
-
-
-        LOGD(">>>> ~ScriptC  bccDisposeScript(%p)", mBccScript);
-        bccDisposeScript(mBccScript);
-    }
-    free(mEnviroment.mScriptText);
-    mEnviroment.mScriptText = NULL;
+    mRSC->mHal.funcs.script.destroy(mRSC, this);
 }
 
 void ScriptC::setupScript(Context *rsc) {
     mEnviroment.mStartTimeMillis
                 = nanoseconds_to_milliseconds(systemTime(SYSTEM_TIME_MONOTONIC));
 
-    for (uint32_t ct=0; ct < mEnviroment.mFieldCount; ct++) {
+    for (uint32_t ct=0; ct < mHal.info.exportedVariableCount; ct++) {
         if (mSlots[ct].get() && !mTypes[ct].get()) {
             mTypes[ct].set(mSlots[ct]->getType());
         }
@@ -134,27 +55,17 @@
         if (mSlots[ct].get()) {
             ptr = mSlots[ct]->getPtr();
         }
-        void **dest = ((void ***)mEnviroment.mFieldAddress)[ct];
 
-        if (rsc->props.mLogScripts) {
-            if (mSlots[ct].get() != NULL) {
-                LOGV("%p ScriptC::setupScript slot=%i  dst=%p  src=%p  type=%p", rsc, ct, dest, ptr, mSlots[ct]->getType());
-            } else {
-                LOGV("%p ScriptC::setupScript slot=%i  dst=%p  src=%p  type=null", rsc, ct, dest, ptr);
-            }
-        }
-
-        if (dest) {
-            *dest = ptr;
-        }
+        rsc->mHal.funcs.script.setGlobalBind(rsc, this, ct, ptr);
     }
 }
 
 const Allocation *ScriptC::ptrToAllocation(const void *ptr) const {
+    //LOGE("ptr to alloc %p", ptr);
     if (!ptr) {
         return NULL;
     }
-    for (uint32_t ct=0; ct < mEnviroment.mFieldCount; ct++) {
+    for (uint32_t ct=0; ct < mHal.info.exportedVariableCount; ct++) {
         if (!mSlots[ct].get())
             continue;
         if (mSlots[ct]->getPtr() == ptr) {
@@ -165,15 +76,6 @@
     return NULL;
 }
 
-Script * ScriptC::setTLS(Script *sc) {
-    Context::ScriptTLSStruct * tls = (Context::ScriptTLSStruct *)
-                                  pthread_getspecific(Context::gThreadTLSKey);
-    rsAssert(tls);
-    Script *old = tls->mScript;
-    tls->mScript = sc;
-    return old;
-}
-
 void ScriptC::setupGLState(Context *rsc) {
     if (mEnviroment.mFragmentStore.get()) {
         rsc->setProgramStore(mEnviroment.mFragmentStore.get());
@@ -190,7 +92,7 @@
 }
 
 uint32_t ScriptC::run(Context *rsc) {
-    if (mProgram.mRoot == NULL) {
+    if (mHal.info.root == NULL) {
         rsc->setError(RS_ERROR_BAD_SCRIPT, "Attempted to run bad script");
         return 0;
     }
@@ -199,235 +101,45 @@
     setupScript(rsc);
 
     uint32_t ret = 0;
-    Script * oldTLS = setTLS(this);
 
     if (rsc->props.mLogScripts) {
-        LOGV("%p ScriptC::run invoking root,  ptr %p", rsc, mProgram.mRoot);
+        LOGV("%p ScriptC::run invoking root,  ptr %p", rsc, mHal.info.root);
     }
 
-    ret = mProgram.mRoot();
+    ret = rsc->mHal.funcs.script.invokeRoot(rsc, this);
 
     if (rsc->props.mLogScripts) {
         LOGV("%p ScriptC::run invoking complete, ret=%i", rsc, ret);
     }
 
-    setTLS(oldTLS);
     return ret;
 }
 
-typedef struct {
-    Context *rsc;
-    ScriptC *script;
-    const Allocation * ain;
-    Allocation * aout;
-    const void * usr;
-
-    uint32_t mSliceSize;
-    volatile int mSliceNum;
-
-    const uint8_t *ptrIn;
-    uint32_t eStrideIn;
-    uint8_t *ptrOut;
-    uint32_t eStrideOut;
-
-    uint32_t xStart;
-    uint32_t xEnd;
-    uint32_t yStart;
-    uint32_t yEnd;
-    uint32_t zStart;
-    uint32_t zEnd;
-    uint32_t arrayStart;
-    uint32_t arrayEnd;
-
-    uint32_t dimX;
-    uint32_t dimY;
-    uint32_t dimZ;
-    uint32_t dimArray;
-} MTLaunchStruct;
-typedef int (*rs_t)(const void *, void *, const void *, uint32_t, uint32_t, uint32_t, uint32_t);
-
-static void wc_xy(void *usr, uint32_t idx) {
-    MTLaunchStruct *mtls = (MTLaunchStruct *)usr;
-
-    while (1) {
-        uint32_t slice = (uint32_t)android_atomic_inc(&mtls->mSliceNum);
-        uint32_t yStart = mtls->yStart + slice * mtls->mSliceSize;
-        uint32_t yEnd = yStart + mtls->mSliceSize;
-        yEnd = rsMin(yEnd, mtls->yEnd);
-        if (yEnd <= yStart) {
-            return;
-        }
-
-        //LOGE("usr idx %i, x %i,%i  y %i,%i", idx, mtls->xStart, mtls->xEnd, yStart, yEnd);
-        //LOGE("usr ptr in %p,  out %p", mtls->ptrIn, mtls->ptrOut);
-        for (uint32_t y = yStart; y < yEnd; y++) {
-            uint32_t offset = mtls->dimX * y;
-            uint8_t *xPtrOut = mtls->ptrOut + (mtls->eStrideOut * offset);
-            const uint8_t *xPtrIn = mtls->ptrIn + (mtls->eStrideIn * offset);
-
-            for (uint32_t x = mtls->xStart; x < mtls->xEnd; x++) {
-                ((rs_t)mtls->script->mProgram.mRoot) (xPtrIn, xPtrOut, mtls->usr, x, y, 0, 0);
-                xPtrIn += mtls->eStrideIn;
-                xPtrOut += mtls->eStrideOut;
-            }
-        }
-    }
-}
-
-static void wc_x(void *usr, uint32_t idx) {
-    MTLaunchStruct *mtls = (MTLaunchStruct *)usr;
-
-    while (1) {
-        uint32_t slice = (uint32_t)android_atomic_inc(&mtls->mSliceNum);
-        uint32_t xStart = mtls->xStart + slice * mtls->mSliceSize;
-        uint32_t xEnd = xStart + mtls->mSliceSize;
-        xEnd = rsMin(xEnd, mtls->xEnd);
-        if (xEnd <= xStart) {
-            return;
-        }
-
-        //LOGE("usr idx %i, x %i,%i  y %i,%i", idx, mtls->xStart, mtls->xEnd, yStart, yEnd);
-        //LOGE("usr ptr in %p,  out %p", mtls->ptrIn, mtls->ptrOut);
-        uint8_t *xPtrOut = mtls->ptrOut + (mtls->eStrideOut * xStart);
-        const uint8_t *xPtrIn = mtls->ptrIn + (mtls->eStrideIn * xStart);
-        for (uint32_t x = xStart; x < xEnd; x++) {
-            ((rs_t)mtls->script->mProgram.mRoot) (xPtrIn, xPtrOut, mtls->usr, x, 0, 0, 0);
-            xPtrIn += mtls->eStrideIn;
-            xPtrOut += mtls->eStrideOut;
-        }
-    }
-}
 
 void ScriptC::runForEach(Context *rsc,
                          const Allocation * ain,
                          Allocation * aout,
                          const void * usr,
                          const RsScriptCall *sc) {
-    MTLaunchStruct mtls;
-    memset(&mtls, 0, sizeof(mtls));
+
     Context::PushState ps(rsc);
 
-    if (ain) {
-        mtls.dimX = ain->getType()->getDimX();
-        mtls.dimY = ain->getType()->getDimY();
-        mtls.dimZ = ain->getType()->getDimZ();
-        //mtls.dimArray = ain->getType()->getDimArray();
-    } else if (aout) {
-        mtls.dimX = aout->getType()->getDimX();
-        mtls.dimY = aout->getType()->getDimY();
-        mtls.dimZ = aout->getType()->getDimZ();
-        //mtls.dimArray = aout->getType()->getDimArray();
-    } else {
-        rsc->setError(RS_ERROR_BAD_SCRIPT, "rsForEach called with null allocations");
-        return;
-    }
-
-    if (!sc || (sc->xEnd == 0)) {
-        mtls.xEnd = mtls.dimX;
-    } else {
-        rsAssert(sc->xStart < mtls.dimX);
-        rsAssert(sc->xEnd <= mtls.dimX);
-        rsAssert(sc->xStart < sc->xEnd);
-        mtls.xStart = rsMin(mtls.dimX, sc->xStart);
-        mtls.xEnd = rsMin(mtls.dimX, sc->xEnd);
-        if (mtls.xStart >= mtls.xEnd) return;
-    }
-
-    if (!sc || (sc->yEnd == 0)) {
-        mtls.yEnd = mtls.dimY;
-    } else {
-        rsAssert(sc->yStart < mtls.dimY);
-        rsAssert(sc->yEnd <= mtls.dimY);
-        rsAssert(sc->yStart < sc->yEnd);
-        mtls.yStart = rsMin(mtls.dimY, sc->yStart);
-        mtls.yEnd = rsMin(mtls.dimY, sc->yEnd);
-        if (mtls.yStart >= mtls.yEnd) return;
-    }
-
-    mtls.xEnd = rsMax((uint32_t)1, mtls.xEnd);
-    mtls.yEnd = rsMax((uint32_t)1, mtls.yEnd);
-    mtls.zEnd = rsMax((uint32_t)1, mtls.zEnd);
-    mtls.arrayEnd = rsMax((uint32_t)1, mtls.arrayEnd);
-
-    rsAssert(ain->getType()->getDimZ() == 0);
-
     setupGLState(rsc);
     setupScript(rsc);
-    Script * oldTLS = setTLS(this);
-
-    mtls.rsc = rsc;
-    mtls.ain = ain;
-    mtls.aout = aout;
-    mtls.script = this;
-    mtls.usr = usr;
-    mtls.mSliceSize = 10;
-    mtls.mSliceNum = 0;
-
-    mtls.ptrIn = NULL;
-    mtls.eStrideIn = 0;
-    if (ain) {
-        mtls.ptrIn = (const uint8_t *)ain->getPtr();
-        mtls.eStrideIn = ain->getType()->getElementSizeBytes();
-    }
-
-    mtls.ptrOut = NULL;
-    mtls.eStrideOut = 0;
-    if (aout) {
-        mtls.ptrOut = (uint8_t *)aout->getPtr();
-        mtls.eStrideOut = aout->getType()->getElementSizeBytes();
-    }
-
-    if ((rsc->getWorkerPoolSize() > 1) && mEnviroment.mIsThreadable) {
-        if (mtls.dimY > 1) {
-            rsc->launchThreads(wc_xy, &mtls);
-        } else {
-            rsc->launchThreads(wc_x, &mtls);
-        }
-
-        //LOGE("launch 1");
-    } else {
-        //LOGE("launch 3");
-        for (uint32_t ar = mtls.arrayStart; ar < mtls.arrayEnd; ar++) {
-            for (uint32_t z = mtls.zStart; z < mtls.zEnd; z++) {
-                for (uint32_t y = mtls.yStart; y < mtls.yEnd; y++) {
-                    uint32_t offset = mtls.dimX * mtls.dimY * mtls.dimZ * ar +
-                                      mtls.dimX * mtls.dimY * z +
-                                      mtls.dimX * y;
-                    uint8_t *xPtrOut = mtls.ptrOut + (mtls.eStrideOut * offset);
-                    const uint8_t *xPtrIn = mtls.ptrIn + (mtls.eStrideIn * offset);
-
-                    for (uint32_t x = mtls.xStart; x < mtls.xEnd; x++) {
-                        ((rs_t)mProgram.mRoot) (xPtrIn, xPtrOut, usr, x, y, z, ar);
-                        xPtrIn += mtls.eStrideIn;
-                        xPtrOut += mtls.eStrideOut;
-                    }
-                }
-            }
-        }
-    }
-
-    setTLS(oldTLS);
+    rsc->mHal.funcs.script.invokeForEach(rsc, this, ain, aout, usr, 0, sc);
 }
 
 void ScriptC::Invoke(Context *rsc, uint32_t slot, const void *data, uint32_t len) {
-    if ((slot >= mEnviroment.mInvokeFunctionCount) ||
-        (mEnviroment.mInvokeFunctions[slot] == NULL)) {
+    if (slot >= mHal.info.exportedFunctionCount) {
         rsc->setError(RS_ERROR_BAD_SCRIPT, "Calling invoke on bad script");
         return;
     }
     setupScript(rsc);
-    Script * oldTLS = setTLS(this);
 
     if (rsc->props.mLogScripts) {
-        LOGV("%p ScriptC::Invoke invoking slot %i,  ptr %p", rsc, slot, mEnviroment.mInvokeFunctions[slot]);
+        LOGV("%p ScriptC::Invoke invoking slot %i,  ptr %p", rsc, slot, this);
     }
-    ((void (*)(const void *, uint32_t))
-        mEnviroment.mInvokeFunctions[slot])(data, len);
-    if (rsc->props.mLogScripts) {
-        LOGV("%p ScriptC::Invoke complete", rsc);
-    }
-
-    setTLS(oldTLS);
+    rsc->mHal.funcs.script.invokeFunction(rsc, this, slot, data, len);
 }
 
 ScriptCState::ScriptCState() {
@@ -440,9 +152,9 @@
     const ScriptCState::SymbolTable_t *sym;
     ScriptC *s = (ScriptC *)pContext;
     if (!strcmp(name, "__isThreadable")) {
-      return (void*) s->mEnviroment.mIsThreadable;
+      return (void*) s->mHal.info.isThreadable;
     } else if (!strcmp(name, "__clearThreadable")) {
-      s->mEnviroment.mIsThreadable = false;
+      s->mHal.info.isThreadable = false;
       return NULL;
     }
     sym = ScriptCState::lookupSymbol(name);
@@ -453,7 +165,7 @@
         sym = ScriptCState::lookupSymbolGL(name);
     }
     if (sym) {
-        s->mEnviroment.mIsThreadable &= sym->threadable;
+        s->mHal.info.isThreadable &= sym->threadable;
         return sym->mPtr;
     }
     LOGE("ScriptC sym lookup failed for %s", name);
@@ -465,144 +177,86 @@
 extern unsigned rs_runtime_lib_bc_size;
 #endif
 
-bool ScriptCState::runCompiler(Context *rsc,
-                               ScriptC *s,
-                               const char *resName,
-                               const char *cacheDir) {
-    s->mBccScript = bccCreateScript();
+bool ScriptC::runCompiler(Context *rsc,
+                          const char *resName,
+                          const char *cacheDir,
+                          const uint8_t *bitcode,
+                          size_t bitcodeLen) {
 
-    s->mEnviroment.mIsThreadable = true;
+    //LOGE("runCompiler %p %p %p %p %p %i", rsc, this, resName, cacheDir, bitcode, bitcodeLen);
 
-    if (bccRegisterSymbolCallback(s->mBccScript, symbolLookup, s) != 0) {
-        LOGE("bcc: FAILS to register symbol callback");
-        return false;
-    }
+    rsc->mHal.funcs.script.scriptInit(rsc, this, resName, cacheDir, bitcode, bitcodeLen, 0, symbolLookup);
 
-    if (bccReadBC(s->mBccScript,
-                  resName,
-                  s->mEnviroment.mScriptText,
-                  s->mEnviroment.mScriptTextLength, 0) != 0) {
-        LOGE("bcc: FAILS to read bitcode");
-        return false;
-    }
+    mEnviroment.mFragment.set(rsc->getDefaultProgramFragment());
+    mEnviroment.mVertex.set(rsc->getDefaultProgramVertex());
+    mEnviroment.mFragmentStore.set(rsc->getDefaultProgramStore());
+    mEnviroment.mRaster.set(rsc->getDefaultProgramRaster());
 
-#if 1
-    if (bccLinkFile(s->mBccScript, "/system/lib/libclcore.bc", 0) != 0) {
-        LOGE("bcc: FAILS to link bitcode");
-        return false;
-    }
-#endif
-    char *cachePath = genCacheFileName(cacheDir, resName, ".oBCC");
+    rsc->mHal.funcs.script.invokeInit(rsc, this);
 
-    if (bccPrepareExecutable(s->mBccScript, cachePath, 0) != 0) {
-        LOGE("bcc: FAILS to prepare executable");
-        return false;
-    }
-
-    free(cachePath);
-
-    s->mProgram.mRoot = reinterpret_cast<int (*)()>(bccGetFuncAddr(s->mBccScript, "root"));
-    s->mProgram.mInit = reinterpret_cast<void (*)()>(bccGetFuncAddr(s->mBccScript, "init"));
-
-    if (s->mProgram.mInit) {
-        s->mProgram.mInit();
-    }
-
-    s->mEnviroment.mInvokeFunctionCount = bccGetExportFuncCount(s->mBccScript);
-    if (s->mEnviroment.mInvokeFunctionCount <= 0)
-        s->mEnviroment.mInvokeFunctions = NULL;
-    else {
-        s->mEnviroment.mInvokeFunctions = (Script::InvokeFunc_t*) calloc(s->mEnviroment.mInvokeFunctionCount, sizeof(Script::InvokeFunc_t));
-        bccGetExportFuncList(s->mBccScript, s->mEnviroment.mInvokeFunctionCount, (void **) s->mEnviroment.mInvokeFunctions);
-    }
-
-    s->mEnviroment.mFieldCount = bccGetExportVarCount(s->mBccScript);
-    if (s->mEnviroment.mFieldCount <= 0)
-        s->mEnviroment.mFieldAddress = NULL;
-    else {
-        s->mEnviroment.mFieldAddress = (void **) calloc(s->mEnviroment.mFieldCount, sizeof(void *));
-        bccGetExportVarList(s->mBccScript, s->mEnviroment.mFieldCount, (void **) s->mEnviroment.mFieldAddress);
-        s->initSlots();
-    }
-
-    s->mEnviroment.mFragment.set(rsc->getDefaultProgramFragment());
-    s->mEnviroment.mVertex.set(rsc->getDefaultProgramVertex());
-    s->mEnviroment.mFragmentStore.set(rsc->getDefaultProgramStore());
-    s->mEnviroment.mRaster.set(rsc->getDefaultProgramRaster());
-
-    const static int pragmaMax = 16;
-    size_t pragmaCount = bccGetPragmaCount(s->mBccScript);
-    char const *keys[pragmaMax];
-    char const *values[pragmaMax];
-    bccGetPragmaList(s->mBccScript, pragmaMax, keys, values);
-
-    for (size_t i=0; i < pragmaCount; ++i) {
+    for (size_t i=0; i < mHal.info.exportedPragmaCount; ++i) {
+        const char * key = mHal.info.exportedPragmaKeyList[i];
+        const char * value = mHal.info.exportedPragmaValueList[i];
         //LOGE("pragma %s %s", keys[i], values[i]);
-        if (!strcmp(keys[i], "version")) {
-            if (!strcmp(values[i], "1")) {
+        if (!strcmp(key, "version")) {
+            if (!strcmp(value, "1")) {
                 continue;
             }
-            LOGE("Invalid version pragma value: %s\n", values[i]);
+            LOGE("Invalid version pragma value: %s\n", value);
             return false;
         }
 
-        if (!strcmp(keys[i], "stateVertex")) {
-            if (!strcmp(values[i], "default")) {
+        if (!strcmp(key, "stateVertex")) {
+            if (!strcmp(value, "default")) {
                 continue;
             }
-            if (!strcmp(values[i], "parent")) {
-                s->mEnviroment.mVertex.clear();
+            if (!strcmp(value, "parent")) {
+                mEnviroment.mVertex.clear();
                 continue;
             }
-            LOGE("Unrecognized value %s passed to stateVertex", values[i]);
+            LOGE("Unrecognized value %s passed to stateVertex", value);
             return false;
         }
 
-        if (!strcmp(keys[i], "stateRaster")) {
-            if (!strcmp(values[i], "default")) {
+        if (!strcmp(key, "stateRaster")) {
+            if (!strcmp(value, "default")) {
                 continue;
             }
-            if (!strcmp(values[i], "parent")) {
-                s->mEnviroment.mRaster.clear();
+            if (!strcmp(value, "parent")) {
+                mEnviroment.mRaster.clear();
                 continue;
             }
-            LOGE("Unrecognized value %s passed to stateRaster", values[i]);
+            LOGE("Unrecognized value %s passed to stateRaster", value);
             return false;
         }
 
-        if (!strcmp(keys[i], "stateFragment")) {
-            if (!strcmp(values[i], "default")) {
+        if (!strcmp(key, "stateFragment")) {
+            if (!strcmp(value, "default")) {
                 continue;
             }
-            if (!strcmp(values[i], "parent")) {
-                s->mEnviroment.mFragment.clear();
+            if (!strcmp(value, "parent")) {
+                mEnviroment.mFragment.clear();
                 continue;
             }
-            LOGE("Unrecognized value %s passed to stateFragment", values[i]);
+            LOGE("Unrecognized value %s passed to stateFragment", value);
             return false;
         }
 
-        if (!strcmp(keys[i], "stateStore")) {
-            if (!strcmp(values[i], "default")) {
+        if (!strcmp(key, "stateStore")) {
+            if (!strcmp(value, "default")) {
                 continue;
             }
-            if (!strcmp(values[i], "parent")) {
-                s->mEnviroment.mFragmentStore.clear();
+            if (!strcmp(value, "parent")) {
+                mEnviroment.mFragmentStore.clear();
                 continue;
             }
-            LOGE("Unrecognized value %s passed to stateStore", values[i]);
+            LOGE("Unrecognized value %s passed to stateStore", value);
             return false;
         }
     }
 
-    size_t objectSlotCount = bccGetObjectSlotCount(s->mBccScript);
-    uint32_t *objectSlots = NULL;
-    if (objectSlotCount) {
-        objectSlots = new uint32_t[objectSlotCount];
-        bccGetObjectSlotList(s->mBccScript, objectSlotCount, objectSlots);
-        s->mProgram.mObjectSlotList = objectSlots;
-        s->mProgram.mObjectSlotCount = objectSlotCount;
-    }
+    mSlots = new ObjectBaseRef<Allocation>[mHal.info.exportedVariableCount];
+    mTypes = new ObjectBaseRef<const Type>[mHal.info.exportedVariableCount];
 
     return true;
 }
@@ -610,39 +264,19 @@
 namespace android {
 namespace renderscript {
 
-void rsi_ScriptCBegin(Context * rsc) {
-}
-
-void rsi_ScriptCSetText(Context *rsc, const char *text, uint32_t len) {
-    ScriptCState *ss = &rsc->mScriptC;
-
-    char *t = (char *)malloc(len + 1);
-    memcpy(t, text, len);
-    t[len] = 0;
-    ss->mScriptText = t;
-    ss->mScriptLen = len;
-}
-
-
 RsScript rsi_ScriptCCreate(Context *rsc,
-                           const char *packageName /* deprecated */,
-                           const char *resName,
-                           const char *cacheDir)
+                           const char *resName, const char *cacheDir,
+                           const char *text, uint32_t len)
 {
-    ScriptCState *ss = &rsc->mScriptC;
-
     ScriptC *s = new ScriptC(rsc);
-    s->mEnviroment.mScriptText = ss->mScriptText;
-    s->mEnviroment.mScriptTextLength = ss->mScriptLen;
-    ss->mScriptText = NULL;
-    ss->mScriptLen = 0;
-    s->incUserRef();
 
-    if (!ss->runCompiler(rsc, s, resName, cacheDir)) {
+    if (!s->runCompiler(rsc, resName, cacheDir, (uint8_t *)text, len)) {
         // Error during compile, destroy s and return null.
         delete s;
         return NULL;
     }
+
+    s->incUserRef();
     return s;
 }
 
diff --git a/libs/rs/rsScriptC.h b/libs/rs/rsScriptC.h
index 2c74b5b..2edeb9b 100644
--- a/libs/rs/rsScriptC.h
+++ b/libs/rs/rsScriptC.h
@@ -21,7 +21,6 @@
 
 #include "RenderScriptEnv.h"
 
-struct BCCOpaqueScript;
 
 // ---------------------------------------------------------------------------
 namespace android {
@@ -36,21 +35,6 @@
     ScriptC(Context *);
     virtual ~ScriptC();
 
-    struct Program_t {
-        int mVersionMajor;
-        int mVersionMinor;
-
-        RunScript_t mRoot;
-        VoidFunc_t mInit;
-
-        uint32_t * mObjectSlotList;
-        uint32_t mObjectSlotCount;
-    };
-
-
-    Program_t mProgram;
-
-    BCCOpaqueScript *mBccScript;
 
     const Allocation *ptrToAllocation(const void *) const;
 
@@ -69,7 +53,10 @@
     virtual RsA3DClassID getClassId() const { return RS_A3D_CLASS_ID_SCRIPT_C; }
     static Type *createFromStream(Context *rsc, IStream *stream) { return NULL; }
 
-protected:
+    bool runCompiler(Context *rsc, const char *resName, const char *cacheDir,
+                     const uint8_t *bitcode, size_t bitcodeLen);
+
+//protected:
     void setupScript(Context *);
     void setupGLState(Context *);
     Script * setTLS(Script *);
@@ -83,8 +70,6 @@
     char * mScriptText;
     size_t mScriptLen;
 
-    bool runCompiler(Context *rsc, ScriptC *s, const char *resName, const char *cacheDir);
-
     struct SymbolTable_t {
         const char * mName;
         void * mPtr;
diff --git a/libs/rs/rsScriptC_Lib.cpp b/libs/rs/rsScriptC_Lib.cpp
index 7c64184..4e8cbdc 100644
--- a/libs/rs/rsScriptC_Lib.cpp
+++ b/libs/rs/rsScriptC_Lib.cpp
@@ -25,8 +25,8 @@
 using namespace android;
 using namespace android::renderscript;
 
-#define GET_TLS()  Context::ScriptTLSStruct * tls = \
-    (Context::ScriptTLSStruct *)pthread_getspecific(Context::gThreadTLSKey); \
+#define GET_TLS()  ScriptTLSStruct * tls = \
+    (ScriptTLSStruct *)pthread_getspecific(Context::gThreadTLSKey); \
     Context * rsc = tls->mContext; \
     ScriptC * sc = (ScriptC *) tls->mScript
 
@@ -141,90 +141,74 @@
 //
 //////////////////////////////////////////////////////////////////////////////
 
-static uint32_t SC_allocGetDimX(RsAllocation va) {
-    const Allocation *a = static_cast<const Allocation *>(va);
+static uint32_t SC_allocGetDimX(Allocation *a) {
     CHECK_OBJ(a);
-    //LOGE("SC_allocGetDimX a=%p  type=%p", a, a->getType());
-    return a->getType()->getDimX();
+    return a->mHal.state.dimensionX;
 }
 
-static uint32_t SC_allocGetDimY(RsAllocation va) {
-    const Allocation *a = static_cast<const Allocation *>(va);
+static uint32_t SC_allocGetDimY(Allocation *a) {
     CHECK_OBJ(a);
-    return a->getType()->getDimY();
+    return a->mHal.state.dimensionY;
 }
 
-static uint32_t SC_allocGetDimZ(RsAllocation va) {
-    const Allocation *a = static_cast<const Allocation *>(va);
+static uint32_t SC_allocGetDimZ(Allocation *a) {
     CHECK_OBJ(a);
-    return a->getType()->getDimZ();
+    return a->mHal.state.dimensionZ;
 }
 
-static uint32_t SC_allocGetDimLOD(RsAllocation va) {
-    const Allocation *a = static_cast<const Allocation *>(va);
+static uint32_t SC_allocGetDimLOD(Allocation *a) {
     CHECK_OBJ(a);
-    return a->getType()->getDimLOD();
+    return a->mHal.state.hasMipmaps;
 }
 
-static uint32_t SC_allocGetDimFaces(RsAllocation va) {
-    const Allocation *a = static_cast<const Allocation *>(va);
+static uint32_t SC_allocGetDimFaces(Allocation *a) {
     CHECK_OBJ(a);
-    return a->getType()->getDimFaces();
+    return a->mHal.state.hasFaces;
 }
 
-static const void * SC_getElementAtX(RsAllocation va, uint32_t x) {
-    const Allocation *a = static_cast<const Allocation *>(va);
+static const void * SC_getElementAtX(Allocation *a, uint32_t x) {
     CHECK_OBJ(a);
-    const Type *t = a->getType();
-    CHECK_OBJ(t);
     const uint8_t *p = (const uint8_t *)a->getPtr();
-    return &p[t->getElementSizeBytes() * x];
+    return &p[a->mHal.state.elementSizeBytes * x];
 }
 
-static const void * SC_getElementAtXY(RsAllocation va, uint32_t x, uint32_t y) {
-    const Allocation *a = static_cast<const Allocation *>(va);
+static const void * SC_getElementAtXY(Allocation *a, uint32_t x, uint32_t y) {
     CHECK_OBJ(a);
-    const Type *t = a->getType();
-    CHECK_OBJ(t);
     const uint8_t *p = (const uint8_t *)a->getPtr();
-    return &p[t->getElementSizeBytes() * (x + y*t->getDimX())];
+    return &p[a->mHal.state.elementSizeBytes * (x + y * a->mHal.state.dimensionX)];
 }
 
-static const void * SC_getElementAtXYZ(RsAllocation va, uint32_t x, uint32_t y, uint32_t z) {
-    const Allocation *a = static_cast<const Allocation *>(va);
+static const void * SC_getElementAtXYZ(Allocation *a, uint32_t x, uint32_t y, uint32_t z) {
     CHECK_OBJ(a);
-    const Type *t = a->getType();
-    CHECK_OBJ(t);
     const uint8_t *p = (const uint8_t *)a->getPtr();
-    return &p[t->getElementSizeBytes() * (x + y*t->getDimX())];
+    return &p[a->mHal.state.elementSizeBytes * (x + y * a->mHal.state.dimensionX +
+              z * a->mHal.state.dimensionX * a->mHal.state.dimensionY)];
 }
 
-static void SC_setObject(void **vdst, void * vsrc) {
-    //LOGE("SC_setObject  %p,%p  %p", vdst, *vdst, vsrc);
-    if (vsrc) {
-        CHECK_OBJ(vsrc);
-        static_cast<ObjectBase *>(vsrc)->incSysRef();
+void android::renderscript::rsiSetObject(ObjectBase **dst, ObjectBase * src) {
+    //LOGE("rsiSetObject  %p,%p  %p", vdst, *vdst, vsrc);
+    if (src) {
+        CHECK_OBJ(src);
+        src->incSysRef();
     }
-    if (vdst[0]) {
-        CHECK_OBJ(vdst[0]);
-        static_cast<ObjectBase *>(vdst[0])->decSysRef();
+    if (dst[0]) {
+        CHECK_OBJ(dst[0]);
+        dst[0]->decSysRef();
     }
-    *vdst = vsrc;
-    //LOGE("SC_setObject *");
+    *dst = src;
 }
 
-static void SC_clearObject(void **vdst) {
-    //LOGE("SC_clearObject  %p,%p", vdst, *vdst);
-    if (vdst[0]) {
-        CHECK_OBJ(vdst[0]);
-        static_cast<ObjectBase *>(vdst[0])->decSysRef();
+void android::renderscript::rsiClearObject(ObjectBase **dst) {
+    //LOGE("rsiClearObject  %p,%p", vdst, *vdst);
+    if (dst[0]) {
+        CHECK_OBJ(dst[0]);
+        dst[0]->decSysRef();
     }
-    *vdst = NULL;
-    //LOGE("SC_clearObject *");
+    *dst = NULL;
 }
 
-static bool SC_isObject(RsAllocation vsrc) {
-    return vsrc != NULL;
+bool android::renderscript::rsiIsObject(const ObjectBase *src) {
+    return src != NULL;
 }
 
 static void SC_debugF(const char *s, float f) {
@@ -873,49 +857,49 @@
     { "_Z14rsGetElementAt13rs_allocationjj", (void *)&SC_getElementAtXY, true },
     { "_Z14rsGetElementAt13rs_allocationjjj", (void *)&SC_getElementAtXYZ, true },
 
-    { "_Z11rsSetObjectP10rs_elementS_", (void *)&SC_setObject, true },
-    { "_Z13rsClearObjectP10rs_element", (void *)&SC_clearObject, true },
-    { "_Z10rsIsObject10rs_element", (void *)&SC_isObject, true },
+    { "_Z11rsSetObjectP10rs_elementS_", (void *)&rsiSetObject, true },
+    { "_Z13rsClearObjectP10rs_element", (void *)&rsiClearObject, true },
+    { "_Z10rsIsObject10rs_element", (void *)&rsiIsObject, true },
 
-    { "_Z11rsSetObjectP7rs_typeS_", (void *)&SC_setObject, true },
-    { "_Z13rsClearObjectP7rs_type", (void *)&SC_clearObject, true },
-    { "_Z10rsIsObject7rs_type", (void *)&SC_isObject, true },
+    { "_Z11rsSetObjectP7rs_typeS_", (void *)&rsiSetObject, true },
+    { "_Z13rsClearObjectP7rs_type", (void *)&rsiClearObject, true },
+    { "_Z10rsIsObject7rs_type", (void *)&rsiIsObject, true },
 
-    { "_Z11rsSetObjectP13rs_allocationS_", (void *)&SC_setObject, true },
-    { "_Z13rsClearObjectP13rs_allocation", (void *)&SC_clearObject, true },
-    { "_Z10rsIsObject13rs_allocation", (void *)&SC_isObject, true },
+    { "_Z11rsSetObjectP13rs_allocationS_", (void *)&rsiSetObject, true },
+    { "_Z13rsClearObjectP13rs_allocation", (void *)&rsiClearObject, true },
+    { "_Z10rsIsObject13rs_allocation", (void *)&rsiIsObject, true },
 
-    { "_Z11rsSetObjectP10rs_samplerS_", (void *)&SC_setObject, true },
-    { "_Z13rsClearObjectP10rs_sampler", (void *)&SC_clearObject, true },
-    { "_Z10rsIsObject10rs_sampler", (void *)&SC_isObject, true },
+    { "_Z11rsSetObjectP10rs_samplerS_", (void *)&rsiSetObject, true },
+    { "_Z13rsClearObjectP10rs_sampler", (void *)&rsiClearObject, true },
+    { "_Z10rsIsObject10rs_sampler", (void *)&rsiIsObject, true },
 
-    { "_Z11rsSetObjectP9rs_scriptS_", (void *)&SC_setObject, true },
-    { "_Z13rsClearObjectP9rs_script", (void *)&SC_clearObject, true },
-    { "_Z10rsIsObject9rs_script", (void *)&SC_isObject, true },
+    { "_Z11rsSetObjectP9rs_scriptS_", (void *)&rsiSetObject, true },
+    { "_Z13rsClearObjectP9rs_script", (void *)&rsiClearObject, true },
+    { "_Z10rsIsObject9rs_script", (void *)&rsiIsObject, true },
 
-    { "_Z11rsSetObjectP7rs_meshS_", (void *)&SC_setObject, true },
-    { "_Z13rsClearObjectP7rs_mesh", (void *)&SC_clearObject, true },
-    { "_Z10rsIsObject7rs_mesh", (void *)&SC_isObject, true },
+    { "_Z11rsSetObjectP7rs_meshS_", (void *)&rsiSetObject, true },
+    { "_Z13rsClearObjectP7rs_mesh", (void *)&rsiClearObject, true },
+    { "_Z10rsIsObject7rs_mesh", (void *)&rsiIsObject, true },
 
-    { "_Z11rsSetObjectP19rs_program_fragmentS_", (void *)&SC_setObject, true },
-    { "_Z13rsClearObjectP19rs_program_fragment", (void *)&SC_clearObject, true },
-    { "_Z10rsIsObject19rs_program_fragment", (void *)&SC_isObject, true },
+    { "_Z11rsSetObjectP19rs_program_fragmentS_", (void *)&rsiSetObject, true },
+    { "_Z13rsClearObjectP19rs_program_fragment", (void *)&rsiClearObject, true },
+    { "_Z10rsIsObject19rs_program_fragment", (void *)&rsiIsObject, true },
 
-    { "_Z11rsSetObjectP17rs_program_vertexS_", (void *)&SC_setObject, true },
-    { "_Z13rsClearObjectP17rs_program_vertex", (void *)&SC_clearObject, true },
-    { "_Z10rsIsObject17rs_program_vertex", (void *)&SC_isObject, true },
+    { "_Z11rsSetObjectP17rs_program_vertexS_", (void *)&rsiSetObject, true },
+    { "_Z13rsClearObjectP17rs_program_vertex", (void *)&rsiClearObject, true },
+    { "_Z10rsIsObject17rs_program_vertex", (void *)&rsiIsObject, true },
 
-    { "_Z11rsSetObjectP17rs_program_rasterS_", (void *)&SC_setObject, true },
-    { "_Z13rsClearObjectP17rs_program_raster", (void *)&SC_clearObject, true },
-    { "_Z10rsIsObject17rs_program_raster", (void *)&SC_isObject, true },
+    { "_Z11rsSetObjectP17rs_program_rasterS_", (void *)&rsiSetObject, true },
+    { "_Z13rsClearObjectP17rs_program_raster", (void *)&rsiClearObject, true },
+    { "_Z10rsIsObject17rs_program_raster", (void *)&rsiIsObject, true },
 
-    { "_Z11rsSetObjectP16rs_program_storeS_", (void *)&SC_setObject, true },
-    { "_Z13rsClearObjectP16rs_program_store", (void *)&SC_clearObject, true },
-    { "_Z10rsIsObject16rs_program_store", (void *)&SC_isObject, true },
+    { "_Z11rsSetObjectP16rs_program_storeS_", (void *)&rsiSetObject, true },
+    { "_Z13rsClearObjectP16rs_program_store", (void *)&rsiClearObject, true },
+    { "_Z10rsIsObject16rs_program_store", (void *)&rsiIsObject, true },
 
-    { "_Z11rsSetObjectP7rs_fontS_", (void *)&SC_setObject, true },
-    { "_Z13rsClearObjectP7rs_font", (void *)&SC_clearObject, true },
-    { "_Z10rsIsObject7rs_font", (void *)&SC_isObject, true },
+    { "_Z11rsSetObjectP7rs_fontS_", (void *)&rsiSetObject, true },
+    { "_Z13rsClearObjectP7rs_font", (void *)&rsiClearObject, true },
+    { "_Z10rsIsObject7rs_font", (void *)&rsiIsObject, true },
 
 
     { "_Z21rsAllocationMarkDirty13rs_allocation", (void *)&SC_allocationMarkDirty, true },
@@ -961,46 +945,46 @@
     { "_Z22rsSendToClientBlockingiPKvj", (void *)&SC_toClientBlocking2, false },
 
     // matrix
-    { "_Z20rsMatrixLoadIdentityP12rs_matrix4x4", (void *)&SC_MatrixLoadIdentity_4x4, false },
-    { "_Z20rsMatrixLoadIdentityP12rs_matrix3x3", (void *)&SC_MatrixLoadIdentity_3x3, false },
-    { "_Z20rsMatrixLoadIdentityP12rs_matrix2x2", (void *)&SC_MatrixLoadIdentity_2x2, false },
+    { "_Z20rsMatrixLoadIdentityP12rs_matrix4x4", (void *)&SC_MatrixLoadIdentity_4x4, true },
+    { "_Z20rsMatrixLoadIdentityP12rs_matrix3x3", (void *)&SC_MatrixLoadIdentity_3x3, true },
+    { "_Z20rsMatrixLoadIdentityP12rs_matrix2x2", (void *)&SC_MatrixLoadIdentity_2x2, true },
 
-    { "_Z12rsMatrixLoadP12rs_matrix4x4PKf", (void *)&SC_MatrixLoad_4x4_f, false },
-    { "_Z12rsMatrixLoadP12rs_matrix3x3PKf", (void *)&SC_MatrixLoad_3x3_f, false },
-    { "_Z12rsMatrixLoadP12rs_matrix2x2PKf", (void *)&SC_MatrixLoad_2x2_f, false },
+    { "_Z12rsMatrixLoadP12rs_matrix4x4PKf", (void *)&SC_MatrixLoad_4x4_f, true },
+    { "_Z12rsMatrixLoadP12rs_matrix3x3PKf", (void *)&SC_MatrixLoad_3x3_f, true },
+    { "_Z12rsMatrixLoadP12rs_matrix2x2PKf", (void *)&SC_MatrixLoad_2x2_f, true },
 
-    { "_Z12rsMatrixLoadP12rs_matrix4x4PKS_", (void *)&SC_MatrixLoad_4x4_4x4, false },
-    { "_Z12rsMatrixLoadP12rs_matrix4x4PK12rs_matrix3x3", (void *)&SC_MatrixLoad_4x4_3x3, false },
-    { "_Z12rsMatrixLoadP12rs_matrix4x4PK12rs_matrix2x2", (void *)&SC_MatrixLoad_4x4_2x2, false },
-    { "_Z12rsMatrixLoadP12rs_matrix3x3PKS_", (void *)&SC_MatrixLoad_3x3_3x3, false },
-    { "_Z12rsMatrixLoadP12rs_matrix2x2PKS_", (void *)&SC_MatrixLoad_2x2_2x2, false },
+    { "_Z12rsMatrixLoadP12rs_matrix4x4PKS_", (void *)&SC_MatrixLoad_4x4_4x4, true },
+    { "_Z12rsMatrixLoadP12rs_matrix4x4PK12rs_matrix3x3", (void *)&SC_MatrixLoad_4x4_3x3, true },
+    { "_Z12rsMatrixLoadP12rs_matrix4x4PK12rs_matrix2x2", (void *)&SC_MatrixLoad_4x4_2x2, true },
+    { "_Z12rsMatrixLoadP12rs_matrix3x3PKS_", (void *)&SC_MatrixLoad_3x3_3x3, true },
+    { "_Z12rsMatrixLoadP12rs_matrix2x2PKS_", (void *)&SC_MatrixLoad_2x2_2x2, true },
 
-    { "_Z18rsMatrixLoadRotateP12rs_matrix4x4ffff", (void *)&SC_MatrixLoadRotate, false },
-    { "_Z17rsMatrixLoadScaleP12rs_matrix4x4fff", (void *)&SC_MatrixLoadScale, false },
-    { "_Z21rsMatrixLoadTranslateP12rs_matrix4x4fff", (void *)&SC_MatrixLoadTranslate, false },
-    { "_Z14rsMatrixRotateP12rs_matrix4x4ffff", (void *)&SC_MatrixRotate, false },
-    { "_Z13rsMatrixScaleP12rs_matrix4x4fff", (void *)&SC_MatrixScale, false },
-    { "_Z17rsMatrixTranslateP12rs_matrix4x4fff", (void *)&SC_MatrixTranslate, false },
+    { "_Z18rsMatrixLoadRotateP12rs_matrix4x4ffff", (void *)&SC_MatrixLoadRotate, true },
+    { "_Z17rsMatrixLoadScaleP12rs_matrix4x4fff", (void *)&SC_MatrixLoadScale, true },
+    { "_Z21rsMatrixLoadTranslateP12rs_matrix4x4fff", (void *)&SC_MatrixLoadTranslate, true },
+    { "_Z14rsMatrixRotateP12rs_matrix4x4ffff", (void *)&SC_MatrixRotate, true },
+    { "_Z13rsMatrixScaleP12rs_matrix4x4fff", (void *)&SC_MatrixScale, true },
+    { "_Z17rsMatrixTranslateP12rs_matrix4x4fff", (void *)&SC_MatrixTranslate, true },
 
-    { "_Z20rsMatrixLoadMultiplyP12rs_matrix4x4PKS_S2_", (void *)&SC_MatrixLoadMultiply_4x4_4x4_4x4, false },
-    { "_Z16rsMatrixMultiplyP12rs_matrix4x4PKS_", (void *)&SC_MatrixMultiply_4x4_4x4, false },
-    { "_Z20rsMatrixLoadMultiplyP12rs_matrix3x3PKS_S2_", (void *)&SC_MatrixLoadMultiply_3x3_3x3_3x3, false },
-    { "_Z16rsMatrixMultiplyP12rs_matrix3x3PKS_", (void *)&SC_MatrixMultiply_3x3_3x3, false },
-    { "_Z20rsMatrixLoadMultiplyP12rs_matrix2x2PKS_S2_", (void *)&SC_MatrixLoadMultiply_2x2_2x2_2x2, false },
-    { "_Z16rsMatrixMultiplyP12rs_matrix2x2PKS_", (void *)&SC_MatrixMultiply_2x2_2x2, false },
+    { "_Z20rsMatrixLoadMultiplyP12rs_matrix4x4PKS_S2_", (void *)&SC_MatrixLoadMultiply_4x4_4x4_4x4, true },
+    { "_Z16rsMatrixMultiplyP12rs_matrix4x4PKS_", (void *)&SC_MatrixMultiply_4x4_4x4, true },
+    { "_Z20rsMatrixLoadMultiplyP12rs_matrix3x3PKS_S2_", (void *)&SC_MatrixLoadMultiply_3x3_3x3_3x3, true },
+    { "_Z16rsMatrixMultiplyP12rs_matrix3x3PKS_", (void *)&SC_MatrixMultiply_3x3_3x3, true },
+    { "_Z20rsMatrixLoadMultiplyP12rs_matrix2x2PKS_S2_", (void *)&SC_MatrixLoadMultiply_2x2_2x2_2x2, true },
+    { "_Z16rsMatrixMultiplyP12rs_matrix2x2PKS_", (void *)&SC_MatrixMultiply_2x2_2x2, true },
 
-    { "_Z17rsMatrixLoadOrthoP12rs_matrix4x4ffffff", (void *)&SC_MatrixLoadOrtho, false },
-    { "_Z19rsMatrixLoadFrustumP12rs_matrix4x4ffffff", (void *)&SC_MatrixLoadFrustum, false },
-    { "_Z23rsMatrixLoadPerspectiveP12rs_matrix4x4ffff", (void *)&SC_MatrixLoadPerspective, false },
+    { "_Z17rsMatrixLoadOrthoP12rs_matrix4x4ffffff", (void *)&SC_MatrixLoadOrtho, true },
+    { "_Z19rsMatrixLoadFrustumP12rs_matrix4x4ffffff", (void *)&SC_MatrixLoadFrustum, true },
+    { "_Z23rsMatrixLoadPerspectiveP12rs_matrix4x4ffff", (void *)&SC_MatrixLoadPerspective, true },
 
-    { "_Z15rsMatrixInverseP12rs_matrix4x4", (void *)&SC_MatrixInverse_4x4, false },
-    { "_Z24rsMatrixInverseTransposeP12rs_matrix4x4", (void *)&SC_MatrixInverseTranspose_4x4, false },
-    { "_Z17rsMatrixTransposeP12rs_matrix4x4", (void *)&SC_MatrixTranspose_4x4, false },
-    { "_Z17rsMatrixTransposeP12rs_matrix4x4", (void *)&SC_MatrixTranspose_3x3, false },
-    { "_Z17rsMatrixTransposeP12rs_matrix4x4", (void *)&SC_MatrixTranspose_2x2, false },
+    { "_Z15rsMatrixInverseP12rs_matrix4x4", (void *)&SC_MatrixInverse_4x4, true },
+    { "_Z24rsMatrixInverseTransposeP12rs_matrix4x4", (void *)&SC_MatrixInverseTranspose_4x4, true },
+    { "_Z17rsMatrixTransposeP12rs_matrix4x4", (void *)&SC_MatrixTranspose_4x4, true },
+    { "_Z17rsMatrixTransposeP12rs_matrix4x4", (void *)&SC_MatrixTranspose_3x3, true },
+    { "_Z17rsMatrixTransposeP12rs_matrix4x4", (void *)&SC_MatrixTranspose_2x2, true },
 
     { "_Z9rsForEach9rs_script13rs_allocationS0_PKv", (void *)&SC_ForEach, false },
-    //{ "_Z9rsForEach9rs_script13rs_allocationS0_PKv", (void *)&SC_ForEach2, true },
+    //{ "_Z9rsForEach9rs_script13rs_allocationS0_PKv", (void *)&SC_ForEach2, false },
 
 ////////////////////////////////////////////////////////////////////
 
@@ -1021,3 +1005,4 @@
     }
     return NULL;
 }
+
diff --git a/libs/rs/rsScriptC_LibGL.cpp b/libs/rs/rsScriptC_LibGL.cpp
index 15426bc..4047049 100644
--- a/libs/rs/rsScriptC_LibGL.cpp
+++ b/libs/rs/rsScriptC_LibGL.cpp
@@ -32,8 +32,8 @@
 using namespace android;
 using namespace android::renderscript;
 
-#define GET_TLS()  Context::ScriptTLSStruct * tls = \
-    (Context::ScriptTLSStruct *)pthread_getspecific(Context::gThreadTLSKey); \
+#define GET_TLS()  ScriptTLSStruct * tls = \
+    (ScriptTLSStruct *)pthread_getspecific(Context::gThreadTLSKey); \
     Context * rsc = tls->mContext; \
     ScriptC * sc = (ScriptC *) tls->mScript
 
diff --git a/libs/rs/rs_hal.h b/libs/rs/rs_hal.h
new file mode 100644
index 0000000..17983ce
--- /dev/null
+++ b/libs/rs/rs_hal.h
@@ -0,0 +1,104 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef RS_HAL_H
+#define RS_HAL_H
+
+#include <RenderScriptDefines.h>
+
+namespace android {
+namespace renderscript {
+
+class Context;
+class ObjectBase;
+class Element;
+class Type;
+class Allocation;
+class Script;
+class ScriptC;
+
+
+typedef void *(*RsHalSymbolLookupFunc)(void *usrptr, char const *symbolName);
+
+typedef struct ScriptTLSStructRec {
+    Context * mContext;
+    Script * mScript;
+} ScriptTLSStruct;
+
+
+/**
+ * Script management functions
+ */
+typedef struct {
+    void (*shutdownDriver)(Context *);
+    void (*getVersion)(unsigned int *major, unsigned int *minor);
+    void (*setPriority)(const Context *, int32_t priority);
+
+
+
+    struct {
+        bool (*scriptInit)(const Context *rsc, ScriptC *s,
+                           char const *resName,
+                           char const *cacheDir,
+                           uint8_t const *bitcode,
+                           size_t bitcodeSize,
+                           uint32_t flags,
+                           RsHalSymbolLookupFunc lookupFunc);
+
+        void (*invokeFunction)(const Context *rsc, Script *s,
+                               uint32_t slot,
+                               const void *params,
+                               size_t paramLength);
+        int (*invokeRoot)(const Context *rsc, Script *s);
+        void (*invokeForEach)(const Context *rsc,
+                              Script *s,
+                              const Allocation * ain,
+                              Allocation * aout,
+                              const void * usr,
+                              uint32_t usrLen,
+                              const RsScriptCall *sc);
+        void (*invokeInit)(const Context *rsc, Script *s);
+
+        void (*setGlobalVar)(const Context *rsc, const Script *s,
+                             uint32_t slot,
+                             void *data,
+                             size_t dataLength);
+        void (*setGlobalBind)(const Context *rsc, const Script *s,
+                              uint32_t slot,
+                              void *data);
+        void (*setGlobalObj)(const Context *rsc, const Script *s,
+                             uint32_t slot,
+                             ObjectBase *data);
+
+        void (*destroy)(const Context *rsc, Script *s);
+    } script;
+
+
+
+} RsdHalFunctions;
+
+void rsiSetObject(ObjectBase **vdst, ObjectBase * vsrc);
+void rsiClearObject(ObjectBase **vdst);
+bool rsiIsObject(const ObjectBase *vdst);
+
+}
+}
+
+
+bool rsdHalInit(android::renderscript::Context *, uint32_t version_major, uint32_t version_minor);
+
+#endif
+
diff --git a/libs/surfaceflinger_client/ISurfaceComposer.cpp b/libs/surfaceflinger_client/ISurfaceComposer.cpp
index 01ae23f..8951c3f 100644
--- a/libs/surfaceflinger_client/ISurfaceComposer.cpp
+++ b/libs/surfaceflinger_client/ISurfaceComposer.cpp
@@ -25,9 +25,11 @@
 #include <binder/IPCThreadState.h>
 #include <binder/IServiceManager.h>
 
+#include <surfaceflinger/ISurfaceComposer.h>
+
 #include <ui/DisplayInfo.h>
 
-#include <surfaceflinger/ISurfaceComposer.h>
+#include <utils/Log.h>
 
 // ---------------------------------------------------------------------------
 
@@ -178,6 +180,40 @@
         data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
         remote()->transact(BnSurfaceComposer::SIGNAL, data, &reply, IBinder::FLAG_ONEWAY);
     }
+
+    virtual bool authenticateSurface(const sp<ISurface>& surface) const
+    {
+        Parcel data, reply;
+        int err = NO_ERROR;
+        err = data.writeInterfaceToken(
+                ISurfaceComposer::getInterfaceDescriptor());
+        if (err != NO_ERROR) {
+            LOGE("ISurfaceComposer::authenticateSurface: error writing "
+                    "interface descriptor: %s (%d)", strerror(-err), -err);
+            return false;
+        }
+        err = data.writeStrongBinder(surface->asBinder());
+        if (err != NO_ERROR) {
+            LOGE("ISurfaceComposer::authenticateSurface: error writing strong "
+                    "binder to parcel: %s (%d)", strerror(-err), -err);
+            return false;
+        }
+        err = remote()->transact(BnSurfaceComposer::AUTHENTICATE_SURFACE, data,
+                &reply);
+        if (err != NO_ERROR) {
+            LOGE("ISurfaceComposer::authenticateSurface: error performing "
+                    "transaction: %s (%d)", strerror(-err), -err);
+            return false;
+        }
+        int32_t result = 0;
+        err = reply.readInt32(&result);
+        if (err != NO_ERROR) {
+            LOGE("ISurfaceComposer::authenticateSurface: error retrieving "
+                    "result: %s (%d)", strerror(-err), -err);
+            return false;
+        }
+        return result != 0;
+    }
 };
 
 IMPLEMENT_META_INTERFACE(SurfaceComposer, "android.ui.ISurfaceComposer");
@@ -273,6 +309,12 @@
             status_t res = turnElectronBeamOn(mode);
             reply->writeInt32(res);
         } break;
+        case AUTHENTICATE_SURFACE: {
+            CHECK_INTERFACE(ISurfaceComposer, data, reply);
+            sp<ISurface> surface = interface_cast<ISurface>(data.readStrongBinder());
+            int32_t result = authenticateSurface(surface) ? 1 : 0;
+            reply->writeInt32(result);
+        } break;
         default:
             return BBinder::onTransact(code, data, reply, flags);
     }
diff --git a/libs/surfaceflinger_client/Surface.cpp b/libs/surfaceflinger_client/Surface.cpp
index 818114a..0dfbf01 100644
--- a/libs/surfaceflinger_client/Surface.cpp
+++ b/libs/surfaceflinger_client/Surface.cpp
@@ -712,6 +712,14 @@
     case NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS:
         *value = MIN_UNDEQUEUED_BUFFERS;
         return NO_ERROR;
+    case NATIVE_WINDOW_QUEUES_TO_WINDOW_COMPOSER: {
+        sp<ISurfaceComposer> sf(ComposerService::getComposerService());
+        *value = sf->authenticateSurface(mSurface) ? 1 : 0;
+        return NO_ERROR;
+    }
+    case NATIVE_WINDOW_CONCRETE_TYPE:
+        *value = NATIVE_WINDOW_SURFACE;
+        return NO_ERROR;
     }
     return BAD_VALUE;
 }
@@ -745,6 +753,9 @@
     case NATIVE_WINDOW_SET_BUFFERS_TRANSFORM:
         res = dispatch_set_buffers_transform( args );
         break;
+    case NATIVE_WINDOW_SET_BUFFERS_TIMESTAMP:
+        res = dispatch_set_buffers_timestamp( args );
+        break;
     default:
         res = NAME_NOT_FOUND;
         break;
@@ -784,6 +795,11 @@
     return setBuffersTransform(transform);
 }
 
+int Surface::dispatch_set_buffers_timestamp(va_list args) {
+    int64_t timestamp = va_arg(args, int64_t);
+    return setBuffersTimestamp(timestamp);
+}
+
 void Surface::setUsage(uint32_t reqUsage)
 {
     Mutex::Autolock _l(mSurfaceLock);
@@ -902,6 +918,13 @@
     return NO_ERROR;
 }
 
+int Surface::setBuffersTimestamp(int64_t timestamp)
+{
+    // Surface doesn't really have anything meaningful to do with timestamps
+    // so they'll just be dropped here.
+    return NO_ERROR;
+}
+
 // ----------------------------------------------------------------------------
 
 int Surface::getConnectedApi() const
diff --git a/libs/surfaceflinger_client/tests/Android.mk b/libs/surfaceflinger_client/tests/Android.mk
index 5053e7d..212b8e7 100644
--- a/libs/surfaceflinger_client/tests/Android.mk
+++ b/libs/surfaceflinger_client/tests/Android.mk
@@ -1 +1,53 @@
+# Build the unit tests.
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+ifneq ($(TARGET_SIMULATOR),true)
+
+# Build the unit tests.
+test_src_files := \
+    Surface_test.cpp \
+
+shared_libraries := \
+	libcutils \
+	libutils \
+	libbinder \
+	libsurfaceflinger_client \
+	libstlport \
+
+static_libraries := \
+	libgtest \
+	libgtest_main \
+
+c_includes := \
+    bionic \
+    bionic/libstdc++/include \
+    external/gtest/include \
+    external/stlport/stlport \
+
+module_tags := tests
+
+$(foreach file,$(test_src_files), \
+    $(eval include $(CLEAR_VARS)) \
+    $(eval LOCAL_SHARED_LIBRARIES := $(shared_libraries)) \
+    $(eval LOCAL_STATIC_LIBRARIES := $(static_libraries)) \
+    $(eval LOCAL_C_INCLUDES := $(c_includes)) \
+    $(eval LOCAL_SRC_FILES := $(file)) \
+    $(eval LOCAL_MODULE := $(notdir $(file:%.cpp=%))) \
+    $(eval LOCAL_MODULE_TAGS := $(module_tags)) \
+    $(eval include $(BUILD_EXECUTABLE)) \
+)
+
+# Build the manual test programs.
 include $(call all-subdir-makefiles)
+
+endif
+
+# Include subdirectory makefiles
+# ============================================================
+
+# If we're building with ONE_SHOT_MAKEFILE (mm, mmm), then what the framework
+# team really wants is to build the stuff defined by this makefile.
+ifeq (,$(ONE_SHOT_MAKEFILE))
+include $(call first-makefiles-under,$(LOCAL_PATH))
+endif
diff --git a/libs/surfaceflinger_client/tests/Surface_test.cpp b/libs/surfaceflinger_client/tests/Surface_test.cpp
new file mode 100644
index 0000000..fd07479
--- /dev/null
+++ b/libs/surfaceflinger_client/tests/Surface_test.cpp
@@ -0,0 +1,141 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <gtest/gtest.h>
+
+#include <binder/IMemory.h>
+#include <surfaceflinger/ISurfaceComposer.h>
+#include <surfaceflinger/Surface.h>
+#include <surfaceflinger/SurfaceComposerClient.h>
+#include <utils/String8.h>
+
+namespace android {
+
+class SurfaceTest : public ::testing::Test {
+protected:
+    virtual void SetUp() {
+        mComposerClient = new SurfaceComposerClient;
+        ASSERT_EQ(NO_ERROR, mComposerClient->initCheck());
+
+        mSurfaceControl = mComposerClient->createSurface(getpid(),
+                String8("Test Surface"), 0, 32, 32, PIXEL_FORMAT_RGB_888, 0);
+
+        ASSERT_TRUE(mSurfaceControl != NULL);
+        ASSERT_TRUE(mSurfaceControl->isValid());
+
+        ASSERT_EQ(NO_ERROR, mComposerClient->openTransaction());
+        ASSERT_EQ(NO_ERROR, mSurfaceControl->setLayer(30000));
+        ASSERT_EQ(NO_ERROR, mSurfaceControl->show());
+        ASSERT_EQ(NO_ERROR, mComposerClient->closeTransaction());
+
+        mSurface = mSurfaceControl->getSurface();
+        ASSERT_TRUE(mSurface != NULL);
+    }
+
+    virtual void TearDown() {
+        mComposerClient->dispose();
+    }
+
+    sp<Surface> mSurface;
+    sp<SurfaceComposerClient> mComposerClient;
+    sp<SurfaceControl> mSurfaceControl;
+};
+
+TEST_F(SurfaceTest, QueuesToWindowComposerIsTrueWhenVisible) {
+    sp<ANativeWindow> anw(mSurface);
+    int result = -123;
+    int err = anw->query(anw.get(), NATIVE_WINDOW_QUEUES_TO_WINDOW_COMPOSER,
+            &result);
+    EXPECT_EQ(NO_ERROR, err);
+    EXPECT_EQ(1, result);
+}
+
+TEST_F(SurfaceTest, QueuesToWindowComposerIsTrueWhenPurgatorized) {
+    mSurfaceControl.clear();
+
+    sp<ANativeWindow> anw(mSurface);
+    int result = -123;
+    int err = anw->query(anw.get(), NATIVE_WINDOW_QUEUES_TO_WINDOW_COMPOSER,
+            &result);
+    EXPECT_EQ(NO_ERROR, err);
+    EXPECT_EQ(1, result);
+}
+
+// This test probably doesn't belong here.
+TEST_F(SurfaceTest, ScreenshotsOfProtectedBuffersFail) {
+    sp<ANativeWindow> anw(mSurface);
+
+    // Verify the screenshot works with no protected buffers.
+    sp<IMemoryHeap> heap;
+    uint32_t w=0, h=0;
+    PixelFormat fmt=0;
+    sp<ISurfaceComposer> sf(ComposerService::getComposerService());
+    ASSERT_EQ(NO_ERROR, sf->captureScreen(0, &heap, &w, &h, &fmt, 64, 64, 0,
+            40000));
+    ASSERT_TRUE(heap != NULL);
+
+    // Set the PROTECTED usage bit and verify that the screenshot fails.  Note
+    // that we need to dequeue a buffer in order for it to actually get
+    // allocated in SurfaceFlinger.
+    ASSERT_EQ(NO_ERROR, native_window_set_usage(anw.get(),
+            GRALLOC_USAGE_PROTECTED));
+    ASSERT_EQ(NO_ERROR, native_window_set_buffer_count(anw.get(), 3));
+    android_native_buffer_t* buf = 0;
+    for (int i = 0; i < 4; i++) {
+        // Loop to make sure SurfaceFlinger has retired a protected buffer.
+        ASSERT_EQ(NO_ERROR, anw->dequeueBuffer(anw.get(), &buf));
+        ASSERT_EQ(NO_ERROR, anw->lockBuffer(anw.get(), buf));
+        ASSERT_EQ(NO_ERROR, anw->queueBuffer(anw.get(), buf));
+    }
+    heap = 0;
+    w = h = fmt = 0;
+    ASSERT_EQ(INVALID_OPERATION, sf->captureScreen(0, &heap, &w, &h, &fmt,
+            64, 64, 0, 40000));
+    ASSERT_TRUE(heap == NULL);
+
+    // XXX: This should not be needed, but it seems that the new buffers don't
+    // correctly show up after the upcoming dequeue/lock/queue loop without it.
+    // We should look into this at some point.
+    ASSERT_EQ(NO_ERROR, native_window_set_buffer_count(anw.get(), 3));
+
+    // Un-set the PROTECTED usage bit and verify that the screenshot works
+    // again.  Note that we have to change the buffers geometry to ensure that
+    // the buffers get reallocated, as the new usage bits are a subset of the
+    // old.
+    ASSERT_EQ(NO_ERROR, native_window_set_usage(anw.get(), 0));
+    ASSERT_EQ(NO_ERROR, native_window_set_buffers_geometry(anw.get(), 32, 32, 0));
+    for (int i = 0; i < 4; i++) {
+        // Loop to make sure SurfaceFlinger has retired a protected buffer.
+        ASSERT_EQ(NO_ERROR, anw->dequeueBuffer(anw.get(), &buf));
+        ASSERT_EQ(NO_ERROR, anw->lockBuffer(anw.get(), buf));
+        ASSERT_EQ(NO_ERROR, anw->queueBuffer(anw.get(), buf));
+    }
+    heap = 0;
+    w = h = fmt = 0;
+    ASSERT_EQ(NO_ERROR, sf->captureScreen(0, &heap, &w, &h, &fmt, 64, 64, 0,
+            40000));
+    ASSERT_TRUE(heap != NULL);
+}
+
+TEST_F(SurfaceTest, ConcreteTypeIsSurface) {
+    sp<ANativeWindow> anw(mSurface);
+    int result = -123;
+    int err = anw->query(anw.get(), NATIVE_WINDOW_CONCRETE_TYPE, &result);
+    EXPECT_EQ(NO_ERROR, err);
+    EXPECT_EQ(NATIVE_WINDOW_SURFACE, result);
+}
+
+}
diff --git a/libs/ui/FramebufferNativeWindow.cpp b/libs/ui/FramebufferNativeWindow.cpp
index 0702d49..dc223f9 100644
--- a/libs/ui/FramebufferNativeWindow.cpp
+++ b/libs/ui/FramebufferNativeWindow.cpp
@@ -286,6 +286,9 @@
         case NATIVE_WINDOW_FORMAT:
             *value = fb->format;
             return NO_ERROR;
+        case NATIVE_WINDOW_CONCRETE_TYPE:
+            *value = NATIVE_WINDOW_FRAMEBUFFER;
+            return NO_ERROR;
     }
     *value = 0;
     return BAD_VALUE;
diff --git a/libs/ui/Input.cpp b/libs/ui/Input.cpp
index 0ed0866..440ec00 100644
--- a/libs/ui/Input.cpp
+++ b/libs/ui/Input.cpp
@@ -7,8 +7,12 @@
 
 //#define LOG_NDEBUG 0
 
+// Log debug messages about keymap probing.
 #define DEBUG_PROBE 0
 
+// Log debug messages about velocity tracking.
+#define DEBUG_VELOCITY 0
+
 #include <stdlib.h>
 #include <unistd.h>
 #include <ctype.h>
@@ -329,6 +333,27 @@
             "cannot contain more than %d axis values.", axis, int(MAX_AXES));
 }
 
+bool PointerCoords::operator==(const PointerCoords& other) const {
+    if (bits != other.bits) {
+        return false;
+    }
+    uint32_t count = __builtin_popcountll(bits);
+    for (uint32_t i = 0; i < count; i++) {
+        if (values[i] != other.values[i]) {
+            return false;
+        }
+    }
+    return true;
+}
+
+void PointerCoords::copyFrom(const PointerCoords& other) {
+    bits = other.bits;
+    uint32_t count = __builtin_popcountll(bits);
+    for (uint32_t i = 0; i < count; i++) {
+        values[i] = other.values[i];
+    }
+}
+
 
 // --- MotionEvent ---
 
@@ -444,6 +469,16 @@
     return value;
 }
 
+ssize_t MotionEvent::findPointerIndex(int32_t pointerId) const {
+    size_t pointerCount = mPointerIds.size();
+    for (size_t i = 0; i < pointerCount; i++) {
+        if (mPointerIds.itemAt(i) == pointerId) {
+            return i;
+        }
+    }
+    return -1;
+}
+
 void MotionEvent::offsetLocation(float xOffset, float yOffset) {
     mXOffset += xOffset;
     mYOffset += yOffset;
@@ -634,6 +669,208 @@
 }
 
 
+// --- VelocityTracker ---
+
+VelocityTracker::VelocityTracker() {
+    clear();
+}
+
+void VelocityTracker::clear() {
+    mIndex = 0;
+    mMovements[0].idBits.clear();
+    mActivePointerId = -1;
+}
+
+void VelocityTracker::clearPointers(BitSet32 idBits) {
+    BitSet32 remainingIdBits(mMovements[mIndex].idBits.value & ~idBits.value);
+    mMovements[mIndex].idBits = remainingIdBits;
+
+    if (mActivePointerId >= 0 && idBits.hasBit(mActivePointerId)) {
+        mActivePointerId = !remainingIdBits.isEmpty() ? remainingIdBits.firstMarkedBit() : -1;
+    }
+}
+
+void VelocityTracker::addMovement(nsecs_t eventTime, BitSet32 idBits, const Position* positions) {
+    if (++mIndex == HISTORY_SIZE) {
+        mIndex = 0;
+    }
+
+    while (idBits.count() > MAX_POINTERS) {
+        idBits.clearBit(idBits.lastMarkedBit());
+    }
+
+    Movement& movement = mMovements[mIndex];
+    movement.eventTime = eventTime;
+    movement.idBits = idBits;
+    uint32_t count = idBits.count();
+    for (uint32_t i = 0; i < count; i++) {
+        movement.positions[i] = positions[i];
+    }
+
+    if (mActivePointerId < 0 || !idBits.hasBit(mActivePointerId)) {
+        mActivePointerId = count != 0 ? idBits.firstMarkedBit() : -1;
+    }
+
+#if DEBUG_VELOCITY
+    LOGD("VelocityTracker: addMovement eventTime=%lld, idBits=0x%08x, activePointerId=%d",
+            eventTime, idBits.value, mActivePointerId);
+    for (BitSet32 iterBits(idBits); !iterBits.isEmpty(); ) {
+        uint32_t id = iterBits.firstMarkedBit();
+        uint32_t index = idBits.getIndexOfBit(id);
+        iterBits.clearBit(id);
+        float vx, vy;
+        bool available = getVelocity(id, &vx, &vy);
+        if (available) {
+            LOGD("  %d: position (%0.3f, %0.3f), vx=%0.3f, vy=%0.3f, speed=%0.3f",
+                    id, positions[index].x, positions[index].y, vx, vy, sqrtf(vx * vx + vy * vy));
+        } else {
+            assert(vx == 0 && vy == 0);
+            LOGD("  %d: position (%0.3f, %0.3f), velocity not available",
+                    id, positions[index].x, positions[index].y);
+        }
+    }
+#endif
+}
+
+void VelocityTracker::addMovement(const MotionEvent* event) {
+    int32_t actionMasked = event->getActionMasked();
+
+    switch (actionMasked) {
+    case AMOTION_EVENT_ACTION_DOWN:
+        // Clear all pointers on down before adding the new movement.
+        clear();
+        break;
+    case AMOTION_EVENT_ACTION_POINTER_DOWN: {
+        // Start a new movement trace for a pointer that just went down.
+        // We do this on down instead of on up because the client may want to query the
+        // final velocity for a pointer that just went up.
+        BitSet32 downIdBits;
+        downIdBits.markBit(event->getActionIndex());
+        clearPointers(downIdBits);
+        break;
+    }
+    case AMOTION_EVENT_ACTION_OUTSIDE:
+    case AMOTION_EVENT_ACTION_CANCEL:
+    case AMOTION_EVENT_ACTION_SCROLL:
+    case AMOTION_EVENT_ACTION_UP:
+    case AMOTION_EVENT_ACTION_POINTER_UP:
+        // Ignore these actions because they do not convey any new information about
+        // pointer movement.  We also want to preserve the last known velocity of the pointers.
+        // Note that ACTION_UP and ACTION_POINTER_UP always report the last known position
+        // of the pointers that went up.  ACTION_POINTER_UP does include the new position of
+        // pointers that remained down but we will also receive an ACTION_MOVE with this
+        // information if any of them actually moved.  Since we don't know how many pointers
+        // will be going up at once it makes sense to just wait for the following ACTION_MOVE
+        // before adding the movement.
+        return;
+    }
+
+    size_t pointerCount = event->getPointerCount();
+    if (pointerCount > MAX_POINTERS) {
+        pointerCount = MAX_POINTERS;
+    }
+
+    BitSet32 idBits;
+    for (size_t i = 0; i < pointerCount; i++) {
+        idBits.markBit(event->getPointerId(i));
+    }
+
+    nsecs_t eventTime;
+    Position positions[pointerCount];
+
+    size_t historySize = event->getHistorySize();
+    for (size_t h = 0; h < historySize; h++) {
+        eventTime = event->getHistoricalEventTime(h);
+        for (size_t i = 0; i < pointerCount; i++) {
+            positions[i].x = event->getHistoricalX(i, h);
+            positions[i].y = event->getHistoricalY(i, h);
+        }
+        addMovement(eventTime, idBits, positions);
+    }
+
+    eventTime = event->getEventTime();
+    for (size_t i = 0; i < pointerCount; i++) {
+        positions[i].x = event->getX(i);
+        positions[i].y = event->getY(i);
+    }
+    addMovement(eventTime, idBits, positions);
+}
+
+bool VelocityTracker::getVelocity(uint32_t id, float* outVx, float* outVy) const {
+    const Movement& newestMovement = mMovements[mIndex];
+    if (newestMovement.idBits.hasBit(id)) {
+        // Find the oldest sample that contains the pointer and that is not older than MAX_AGE.
+        nsecs_t minTime = newestMovement.eventTime - MAX_AGE;
+        uint32_t oldestIndex = mIndex;
+        uint32_t numTouches = 1;
+        do {
+            uint32_t nextOldestIndex = (oldestIndex == 0 ? HISTORY_SIZE : oldestIndex) - 1;
+            const Movement& nextOldestMovement = mMovements[nextOldestIndex];
+            if (!nextOldestMovement.idBits.hasBit(id)
+                    || nextOldestMovement.eventTime < minTime) {
+                break;
+            }
+            oldestIndex = nextOldestIndex;
+        } while (++numTouches < HISTORY_SIZE);
+
+        // Calculate an exponentially weighted moving average of the velocity estimate
+        // at different points in time measured relative to the oldest sample.
+        // This is essentially an IIR filter.  Newer samples are weighted more heavily
+        // than older samples.  Samples at equal time points are weighted more or less
+        // equally.
+        //
+        // One tricky problem is that the sample data may be poorly conditioned.
+        // Sometimes samples arrive very close together in time which can cause us to
+        // overestimate the velocity at that time point.  Most samples might be measured
+        // 16ms apart but some consecutive samples could be only 0.5sm apart because
+        // the hardware or driver reports them irregularly or in bursts.
+        float accumVx = 0;
+        float accumVy = 0;
+        uint32_t index = oldestIndex;
+        uint32_t samplesUsed = 0;
+        const Movement& oldestMovement = mMovements[oldestIndex];
+        const Position& oldestPosition =
+                oldestMovement.positions[oldestMovement.idBits.getIndexOfBit(id)];
+        nsecs_t lastDuration = 0;
+        while (numTouches-- > 1) {
+            if (++index == HISTORY_SIZE) {
+                index = 0;
+            }
+            const Movement& movement = mMovements[index];
+            nsecs_t duration = movement.eventTime - oldestMovement.eventTime;
+
+            // If the duration between samples is small, we may significantly overestimate
+            // the velocity.  Consequently, we impose a minimum duration constraint on the
+            // samples that we include in the calculation.
+            if (duration >= MIN_DURATION) {
+                const Position& position = movement.positions[movement.idBits.getIndexOfBit(id)];
+                float scale = 1000000000.0f / duration; // one over time delta in seconds
+                float vx = (position.x - oldestPosition.x) * scale;
+                float vy = (position.y - oldestPosition.y) * scale;
+
+                accumVx = (accumVx * lastDuration + vx * duration) / (duration + lastDuration);
+                accumVy = (accumVy * lastDuration + vy * duration) / (duration + lastDuration);
+
+                lastDuration = duration;
+                samplesUsed += 1;
+            }
+        }
+
+        // Make sure we used at least one sample.
+        if (samplesUsed != 0) {
+            *outVx = accumVx;
+            *outVy = accumVy;
+            return true;
+        }
+    }
+
+    // No data available for this pointer.
+    *outVx = 0;
+    *outVy = 0;
+    return false;
+}
+
+
 // --- InputDeviceInfo ---
 
 InputDeviceInfo::InputDeviceInfo() {
@@ -657,23 +894,30 @@
     mMotionRanges.clear();
 }
 
-const InputDeviceInfo::MotionRange* InputDeviceInfo::getMotionRange(int32_t axis) const {
-    ssize_t index = mMotionRanges.indexOfKey(axis);
-    return index >= 0 ? & mMotionRanges.valueAt(index) : NULL;
+const InputDeviceInfo::MotionRange* InputDeviceInfo::getMotionRange(
+        int32_t axis, uint32_t source) const {
+    size_t numRanges = mMotionRanges.size();
+    for (size_t i = 0; i < numRanges; i++) {
+        const MotionRange& range = mMotionRanges.itemAt(i);
+        if (range.axis == axis && range.source == source) {
+            return &range;
+        }
+    }
+    return NULL;
 }
 
 void InputDeviceInfo::addSource(uint32_t source) {
     mSources |= source;
 }
 
-void InputDeviceInfo::addMotionRange(int32_t axis, float min, float max,
+void InputDeviceInfo::addMotionRange(int32_t axis, uint32_t source, float min, float max,
         float flat, float fuzz) {
-    MotionRange range = { min, max, flat, fuzz };
-    addMotionRange(axis, range);
+    MotionRange range = { axis, source, min, max, flat, fuzz };
+    mMotionRanges.add(range);
 }
 
-void InputDeviceInfo::addMotionRange(int32_t axis, const MotionRange& range) {
-    mMotionRanges.add(axis, range);
+void InputDeviceInfo::addMotionRange(const MotionRange& range) {
+    mMotionRanges.add(range);
 }
 
 } // namespace android
diff --git a/libs/ui/InputTransport.cpp b/libs/ui/InputTransport.cpp
index 5c57a76..9d1b8b9 100644
--- a/libs/ui/InputTransport.cpp
+++ b/libs/ui/InputTransport.cpp
@@ -406,7 +406,7 @@
 
     for (size_t i = 0; i < pointerCount; i++) {
         mSharedMessage->motion.pointerIds[i] = pointerIds[i];
-        mSharedMessage->motion.sampleData[0].coords[i] = pointerCoords[i];
+        mSharedMessage->motion.sampleData[0].coords[i].copyFrom(pointerCoords[i]);
     }
 
     // Cache essential information about the motion event to ensure that a malicious consumer
@@ -475,7 +475,7 @@
 
     mMotionEventSampleDataTail->eventTime = eventTime;
     for (size_t i = 0; i < mMotionEventPointerCount; i++) {
-        mMotionEventSampleDataTail->coords[i] = pointerCoords[i];
+        mMotionEventSampleDataTail->coords[i].copyFrom(pointerCoords[i]);
     }
     mMotionEventSampleDataTail = newTail;
 
diff --git a/libs/ui/KeyLayoutMap.cpp b/libs/ui/KeyLayoutMap.cpp
index 2ed0e66..8626a03 100644
--- a/libs/ui/KeyLayoutMap.cpp
+++ b/libs/ui/KeyLayoutMap.cpp
@@ -113,20 +113,23 @@
     return NO_ERROR;
 }
 
-status_t KeyLayoutMap::mapAxis(int32_t scanCode, int32_t* axis) const {
+status_t KeyLayoutMap::mapAxis(int32_t scanCode, AxisInfo* outAxisInfo) const {
     ssize_t index = mAxes.indexOfKey(scanCode);
     if (index < 0) {
 #if DEBUG_MAPPING
         LOGD("mapAxis: scanCode=%d ~ Failed.", scanCode);
 #endif
-        *axis = -1;
         return NAME_NOT_FOUND;
     }
 
-    *axis = mAxes.valueAt(index);
+    *outAxisInfo = mAxes.valueAt(index);
 
 #if DEBUG_MAPPING
-    LOGD("mapAxis: scanCode=%d ~ Result axis=%d.", scanCode, *axis);
+    LOGD("mapAxis: scanCode=%d ~ Result mode=%d, axis=%d, highAxis=%d, "
+            "splitValue=%d, flatOverride=%d.",
+            scanCode,
+            outAxisInfo->mode, outAxisInfo->axis, outAxisInfo->highAxis,
+            outAxisInfo->splitValue, outAxisInfo->flatOverride);
 #endif
     return NO_ERROR;
 }
@@ -249,19 +252,89 @@
         return BAD_VALUE;
     }
 
+    AxisInfo axisInfo;
+
     mTokenizer->skipDelimiters(WHITESPACE);
-    String8 axisToken = mTokenizer->nextToken(WHITESPACE);
-    int32_t axis = getAxisByLabel(axisToken.string());
-    if (axis < 0) {
-        LOGE("%s: Expected axis label, got '%s'.", mTokenizer->getLocation().string(),
-                axisToken.string());
-        return BAD_VALUE;
+    String8 token = mTokenizer->nextToken(WHITESPACE);
+    if (token == "invert") {
+        axisInfo.mode = AxisInfo::MODE_INVERT;
+
+        mTokenizer->skipDelimiters(WHITESPACE);
+        String8 axisToken = mTokenizer->nextToken(WHITESPACE);
+        axisInfo.axis = getAxisByLabel(axisToken.string());
+        if (axisInfo.axis < 0) {
+            LOGE("%s: Expected inverted axis label, got '%s'.",
+                    mTokenizer->getLocation().string(), axisToken.string());
+            return BAD_VALUE;
+        }
+    } else if (token == "split") {
+        axisInfo.mode = AxisInfo::MODE_SPLIT;
+
+        mTokenizer->skipDelimiters(WHITESPACE);
+        String8 splitToken = mTokenizer->nextToken(WHITESPACE);
+        axisInfo.splitValue = int32_t(strtol(splitToken.string(), &end, 0));
+        if (*end) {
+            LOGE("%s: Expected split value, got '%s'.",
+                    mTokenizer->getLocation().string(), splitToken.string());
+            return BAD_VALUE;
+        }
+
+        mTokenizer->skipDelimiters(WHITESPACE);
+        String8 lowAxisToken = mTokenizer->nextToken(WHITESPACE);
+        axisInfo.axis = getAxisByLabel(lowAxisToken.string());
+        if (axisInfo.axis < 0) {
+            LOGE("%s: Expected low axis label, got '%s'.",
+                    mTokenizer->getLocation().string(), lowAxisToken.string());
+            return BAD_VALUE;
+        }
+
+        mTokenizer->skipDelimiters(WHITESPACE);
+        String8 highAxisToken = mTokenizer->nextToken(WHITESPACE);
+        axisInfo.highAxis = getAxisByLabel(highAxisToken.string());
+        if (axisInfo.highAxis < 0) {
+            LOGE("%s: Expected high axis label, got '%s'.",
+                    mTokenizer->getLocation().string(), highAxisToken.string());
+            return BAD_VALUE;
+        }
+    } else {
+        axisInfo.axis = getAxisByLabel(token.string());
+        if (axisInfo.axis < 0) {
+            LOGE("%s: Expected axis label, 'split' or 'invert', got '%s'.",
+                    mTokenizer->getLocation().string(), token.string());
+            return BAD_VALUE;
+        }
+    }
+
+    for (;;) {
+        mTokenizer->skipDelimiters(WHITESPACE);
+        if (mTokenizer->isEol()) {
+            break;
+        }
+        String8 keywordToken = mTokenizer->nextToken(WHITESPACE);
+        if (keywordToken == "flat") {
+            mTokenizer->skipDelimiters(WHITESPACE);
+            String8 flatToken = mTokenizer->nextToken(WHITESPACE);
+            axisInfo.flatOverride = int32_t(strtol(flatToken.string(), &end, 0));
+            if (*end) {
+                LOGE("%s: Expected flat value, got '%s'.",
+                        mTokenizer->getLocation().string(), flatToken.string());
+                return BAD_VALUE;
+            }
+        } else {
+            LOGE("%s: Expected keyword 'flat', got '%s'.",
+                    mTokenizer->getLocation().string(), keywordToken.string());
+            return BAD_VALUE;
+        }
     }
 
 #if DEBUG_PARSER
-    LOGD("Parsed axis: scanCode=%d, axis=%d.", scanCode, axis);
+    LOGD("Parsed axis: scanCode=%d, mode=%d, axis=%d, highAxis=%d, "
+            "splitValue=%d, flatOverride=%d.",
+            scanCode,
+            axisInfo.mode, axisInfo.axis, axisInfo.highAxis,
+            axisInfo.splitValue, axisInfo.flatOverride);
 #endif
-    mMap->mAxes.add(scanCode, axis);
+    mMap->mAxes.add(scanCode, axisInfo);
     return NO_ERROR;
 }
 
diff --git a/libs/ui/Region.cpp b/libs/ui/Region.cpp
index 1994f6a..a060a5f 100644
--- a/libs/ui/Region.cpp
+++ b/libs/ui/Region.cpp
@@ -56,6 +56,9 @@
 Region::Region(const Region& rhs)
     : mBounds(rhs.mBounds), mStorage(rhs.mStorage)
 {
+#if VALIDATE_REGIONS
+    validate(rhs, "rhs copy-ctor");
+#endif
 }
 
 Region::Region(const Rect& rhs)
@@ -76,7 +79,8 @@
 Region& Region::operator = (const Region& rhs)
 {
 #if VALIDATE_REGIONS
-    validate(rhs, "operator=");
+    validate(*this, "this->operator=");
+    validate(rhs, "rhs.operator=");
 #endif
     mBounds = rhs.mBounds;
     mStorage = rhs.mStorage;
@@ -366,6 +370,12 @@
         const Region& lhs,
         const Region& rhs, int dx, int dy)
 {
+#if VALIDATE_REGIONS
+    validate(lhs, "boolean_operation (before): lhs");
+    validate(rhs, "boolean_operation (before): rhs");
+    validate(dst, "boolean_operation (before): dst");
+#endif
+
     size_t lhs_count;
     Rect const * const lhs_rects = lhs.getArray(&lhs_count);
 
diff --git a/libs/usb/Android.mk b/libs/usb/Android.mk
index b4e1fbf..129828f 100644
--- a/libs/usb/Android.mk
+++ b/libs/usb/Android.mk
@@ -1,5 +1,5 @@
 #
-# Copyright (C) 2008 The Android Open Source Project
+# Copyright (C) 2011 The Android Open Source Project
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
 # you may not use this file except in compliance with the License.
diff --git a/libs/usb/src/com/android/future/usb/UsbAccessory.java b/libs/usb/src/com/android/future/usb/UsbAccessory.java
index cdd2b73..0f965d7 100644
--- a/libs/usb/src/com/android/future/usb/UsbAccessory.java
+++ b/libs/usb/src/com/android/future/usb/UsbAccessory.java
@@ -19,18 +19,22 @@
 /**
  * A class representing a USB accessory.
  */
-public final class UsbAccessory {
+public class UsbAccessory {
 
     private final String mManufacturer;
     private final String mModel;
-    private final String mType;
+    private final String mDescription;
     private final String mVersion;
+    private final String mUri;
+    private final String mSerial;
 
     /* package */ UsbAccessory(android.hardware.usb.UsbAccessory accessory) {
         mManufacturer = accessory.getManufacturer();
         mModel = accessory.getModel();
-        mType = accessory.getType();
+        mDescription = accessory.getDescription();
         mVersion = accessory.getVersion();
+        mUri = accessory.getUri();
+        mSerial = accessory.getSerial();
     }
 
     /**
@@ -52,12 +56,12 @@
     }
 
     /**
-     * Returns the type of the accessory.
+     * Returns a user visible description of the accessory.
      *
-     * @return the accessory type
+     * @return the accessory description
      */
-    public String getType() {
-        return mType;
+    public String getDescription() {
+        return mDescription;
     }
 
     /**
@@ -69,6 +73,28 @@
         return mVersion;
     }
 
+    /**
+     * Returns the URI for the accessory.
+     * This is an optional URI that might show information about the accessory
+     * or provide the option to download an application for the accessory
+     *
+     * @return the accessory URI
+     */
+    public String getUri() {
+        return mUri;
+    }
+
+    /**
+     * Returns the unique serial number for the accessory.
+     * This is an optional serial number that can be used to differentiate
+     * between individual accessories of the same model and manufacturer
+     *
+     * @return the unique serial number
+     */
+    public String getSerial() {
+        return mSerial;
+    }
+
     private static boolean compare(String s1, String s2) {
         if (s1 == null) return (s2 == null);
         return s1.equals(s2);
@@ -80,17 +106,31 @@
             UsbAccessory accessory = (UsbAccessory)obj;
             return (compare(mManufacturer, accessory.getManufacturer()) &&
                     compare(mModel, accessory.getModel()) &&
-                    compare(mType, accessory.getType()) &&
-                    compare(mVersion, accessory.getVersion()));
+                    compare(mDescription, accessory.getDescription()) &&
+                    compare(mVersion, accessory.getVersion()) &&
+                    compare(mUri, accessory.getUri()) &&
+                    compare(mSerial, accessory.getSerial()));
         }
         return false;
     }
 
     @Override
+    public int hashCode() {
+        return ((mManufacturer == null ? 0 : mManufacturer.hashCode()) ^
+                (mModel == null ? 0 : mModel.hashCode()) ^
+                (mDescription == null ? 0 : mDescription.hashCode()) ^
+                (mVersion == null ? 0 : mVersion.hashCode()) ^
+                (mUri == null ? 0 : mUri.hashCode()) ^
+                (mSerial == null ? 0 : mSerial.hashCode()));
+    }
+
+    @Override
     public String toString() {
         return "UsbAccessory[mManufacturer=" + mManufacturer +
                             ", mModel=" + mModel +
-                            ", mType=" + mType +
-                            ", mVersion=" + mVersion + "]";
+                            ", mDescription=" + mDescription +
+                            ", mVersion=" + mVersion +
+                            ", mUri=" + mUri +
+                            ", mSerial=" + mSerial + "]";
     }
 }
diff --git a/libs/usb/src/com/android/future/usb/UsbManager.java b/libs/usb/src/com/android/future/usb/UsbManager.java
index f74b291..d424b63 100644
--- a/libs/usb/src/com/android/future/usb/UsbManager.java
+++ b/libs/usb/src/com/android/future/usb/UsbManager.java
@@ -17,6 +17,7 @@
 
 package com.android.future.usb;
 
+import android.app.PendingIntent;
 import android.content.Context;
 import android.content.Intent;
 import android.hardware.usb.IUsbManager;
@@ -55,28 +56,39 @@
     public static final String ACTION_USB_ACCESSORY_DETACHED =
             "android.hardware.usb.action.USB_ACCESSORY_DETACHED";
 
+    /**
+     * Name of extra added to the {@link android.app.PendingIntent}
+     * passed into {#requestPermission} or {#requestPermission}
+     * containing a boolean value indicating whether the user granted permission or not.
+     */
+    public static final String EXTRA_PERMISSION_GRANTED = "permission";
+
+    private final Context mContext;
     private final IUsbManager mService;
 
-    private UsbManager(IUsbManager service) {
+    private UsbManager(Context context, IUsbManager service) {
+        mContext = context;
         mService = service;
     }
 
     /**
      * Returns a new instance of this class.
      *
+     * @param context the caller's {@link android.content.Context}
      * @return UsbManager instance.
      */
-    public static UsbManager getInstance() {
+    public static UsbManager getInstance(Context context) {
         IBinder b = ServiceManager.getService(Context.USB_SERVICE);
-        return new UsbManager(IUsbManager.Stub.asInterface(b));
+        return new UsbManager(context, IUsbManager.Stub.asInterface(b));
     }
 
     /**
      * Returns the {@link com.google.android.usb.UsbAccessory} for
      * a {@link #ACTION_USB_ACCESSORY_ATTACHED} or {@link #ACTION_USB_ACCESSORY_ATTACHED}
-     * broadcast Intent
+     * broadcast Intent. This can also be used to retrieve the accessory from the result
+     * of a call to {#requestPermission}.
      *
-     * @return UsbAccessory for the broadcast.
+     * @return UsbAccessory for the intent.
      */
     public static UsbAccessory getAccessory(Intent intent) {
         android.hardware.usb.UsbAccessory accessory =
@@ -118,10 +130,57 @@
         try {
             return mService.openAccessory(new android.hardware.usb.UsbAccessory(
                     accessory.getManufacturer(),accessory.getModel(),
-                    accessory.getType(), accessory.getVersion()));
+                    accessory.getDescription(), accessory.getVersion(),
+                    accessory.getUri(), accessory.getSerial()));
         } catch (RemoteException e) {
             Log.e(TAG, "RemoteException in openAccessory" , e);
             return null;
         }
     }
+
+    /**
+     * Returns true if the caller has permission to access the accessory.
+     * Permission might have been granted temporarily via
+     * {@link #requestPermission(android.hardware.usb.UsbAccessory} or
+     * by the user choosing the caller as the default application for the accessory.
+     *
+     * @param accessory to check permissions for
+     * @return true if caller has permission
+     */
+    public boolean hasPermission(UsbAccessory accessory) {
+        try {
+            return mService.hasAccessoryPermission(new android.hardware.usb.UsbAccessory(
+                    accessory.getManufacturer(),accessory.getModel(),
+                    accessory.getDescription(), accessory.getVersion(),
+                    accessory.getUri(), accessory.getSerial()));
+        } catch (RemoteException e) {
+            Log.e(TAG, "RemoteException in hasPermission", e);
+            return false;
+        }
+    }
+
+    /**
+     * Requests temporary permission for the given package to access the accessory.
+     * This may result in a system dialog being displayed to the user
+     * if permission had not already been granted.
+     * Success or failure is returned via the {@link android.app.PendingIntent} pi.
+     * The boolean extra {@link #EXTRA_PERMISSION_GRANTED} will be attached to the
+     * PendingIntent to indicate success or failure.
+     * If successful, this grants the caller permission to access the device only
+     * until the device is disconnected.
+     *
+     * @param accessory to request permissions for
+     * @param pi PendingIntent for returning result
+     */
+    public void requestPermission(UsbAccessory accessory, PendingIntent pi) {
+        try {
+            mService.requestAccessoryPermission(new android.hardware.usb.UsbAccessory(
+                    accessory.getManufacturer(),accessory.getModel(),
+                    accessory.getDescription(), accessory.getVersion(),
+                    accessory.getUri(), accessory.getSerial()),
+                    mContext.getPackageName(), pi);
+        } catch (RemoteException e) {
+            Log.e(TAG, "RemoteException in requestPermission", e);
+        }
+    }
 }
diff --git a/libs/usb/tests/AccessoryChat/Android.mk b/libs/usb/tests/AccessoryChat/Android.mk
index 98b6090..77b8424 100644
--- a/libs/usb/tests/AccessoryChat/Android.mk
+++ b/libs/usb/tests/AccessoryChat/Android.mk
@@ -1,3 +1,19 @@
+#
+# Copyright (C) 2011 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
 LOCAL_PATH:= $(call my-dir)
 include $(CLEAR_VARS)
 
@@ -5,7 +21,7 @@
 
 LOCAL_SRC_FILES := $(call all-subdir-java-files)
 
-LOCAL_PACKAGE_NAME := AccessoryChatGB
+LOCAL_PACKAGE_NAME := AccessoryChat
 
 LOCAL_JAVA_LIBRARIES := com.android.future.usb.accessory
 
diff --git a/libs/usb/tests/AccessoryChat/AndroidManifest.xml b/libs/usb/tests/AccessoryChat/AndroidManifest.xml
index 97e2ade..802b715 100644
--- a/libs/usb/tests/AccessoryChat/AndroidManifest.xml
+++ b/libs/usb/tests/AccessoryChat/AndroidManifest.xml
@@ -1,10 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2011 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
         package="com.android.accessorychat">
 
-    <application>
+    <application android:label="Accessory Chat">
         <uses-library android:name="com.android.future.usb.accessory" />
 
-        <activity android:name="AccessoryChat" android:label="Accessory Chat GB">
+        <activity android:name="AccessoryChat" android:label="Accessory Chat">
             <intent-filter>
                 <action android:name="android.intent.action.MAIN" />
                 <category android:name="android.intent.category.DEFAULT" />
diff --git a/libs/usb/tests/AccessoryChat/accessorychat/accessorychat.c b/libs/usb/tests/AccessoryChat/accessorychat/accessorychat.c
index 94cc0ce..85b52dd 100644
--- a/libs/usb/tests/AccessoryChat/accessorychat/accessorychat.c
+++ b/libs/usb/tests/AccessoryChat/accessorychat/accessorychat.c
@@ -24,6 +24,7 @@
 #include <fcntl.h>
 #include <errno.h>
 #include <pthread.h>
+#include <time.h>
 
 #include <usbhost/usbhost.h>
 #include <linux/usb/f_accessory.h>
@@ -65,9 +66,20 @@
     return NULL;
 }
 
+static void milli_sleep(int millis) {
+    struct timespec tm;
+
+    tm.tv_sec = 0;
+    tm.tv_nsec = millis * 1000000;
+    nanosleep(&tm, NULL);
+}
+
 static void send_string(struct usb_device *device, int index, const char* string) {
     int ret = usb_device_control_transfer(device, USB_DIR_OUT | USB_TYPE_VENDOR,
             ACCESSORY_SEND_STRING, 0, index, (void *)string, strlen(string) + 1, 0);
+
+    // some devices can't handle back-to-back requests, so delay a bit
+    milli_sleep(10);
 }
 
 static int usb_device_added(const char *devname, void* client_data) {
@@ -133,10 +145,20 @@
         } else {
             printf("Found possible android device - attempting to switch to accessory mode\n");
 
+            uint16_t protocol;
+            ret = usb_device_control_transfer(device, USB_DIR_IN | USB_TYPE_VENDOR,
+                    ACCESSORY_GET_PROTOCOL, 0, 0, &protocol, sizeof(protocol), 0);
+            if (ret == 2)
+                printf("device supports protocol version %d\n", protocol);
+            else
+                fprintf(stderr, "failed to read protocol version\n");
+
             send_string(device, ACCESSORY_STRING_MANUFACTURER, "Google, Inc.");
             send_string(device, ACCESSORY_STRING_MODEL, "AccessoryChat");
-            send_string(device, ACCESSORY_STRING_TYPE, "Sample Program");
+            send_string(device, ACCESSORY_STRING_DESCRIPTION, "Accessory Chat");
             send_string(device, ACCESSORY_STRING_VERSION, "1.0");
+            send_string(device, ACCESSORY_STRING_URI, "http://www.android.com");
+            send_string(device, ACCESSORY_STRING_SERIAL, "1234567890");
 
             ret = usb_device_control_transfer(device, USB_DIR_OUT | USB_TYPE_VENDOR,
                     ACCESSORY_START, 0, 0, 0, 0, 0);
diff --git a/libs/usb/tests/AccessoryChat/src/com/android/accessorychat/AccessoryChat.java b/libs/usb/tests/AccessoryChat/src/com/android/accessorychat/AccessoryChat.java
index 5cf02c7..c3f4fa3 100644
--- a/libs/usb/tests/AccessoryChat/src/com/android/accessorychat/AccessoryChat.java
+++ b/libs/usb/tests/AccessoryChat/src/com/android/accessorychat/AccessoryChat.java
@@ -17,9 +17,11 @@
 package com.android.accessorychat;
 
 import android.app.Activity;
+import android.app.PendingIntent;
 import android.content.BroadcastReceiver;
 import android.content.Context;
 import android.content.Intent;
+import android.content.IntentFilter;
 import android.os.Bundle;
 import android.os.Handler;
 import android.os.Message;
@@ -42,18 +44,47 @@
 public class AccessoryChat extends Activity implements Runnable, TextView.OnEditorActionListener {
 
     private static final String TAG = "AccessoryChat";
-    TextView mLog;
-    EditText mEditText;
-    ParcelFileDescriptor mFileDescriptor;
-    FileInputStream mInputStream;
-    FileOutputStream mOutputStream;
+
+    private static final String ACTION_USB_PERMISSION =
+            "com.android.accessorychat.action.USB_PERMISSION";
+
+    private TextView mLog;
+    private EditText mEditText;
+    private ParcelFileDescriptor mFileDescriptor;
+    private FileInputStream mInputStream;
+    private FileOutputStream mOutputStream;
+    private UsbManager mUsbManager;
+    private PendingIntent mPermissionIntent;
+    private boolean mPermissionRequestPending;
 
     private static final int MESSAGE_LOG = 1;
 
+   private final BroadcastReceiver mUsbReceiver = new BroadcastReceiver() {
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            if (ACTION_USB_PERMISSION.equals(intent.getAction())) {
+                synchronized (this) {
+                    UsbAccessory accessory = UsbManager.getAccessory(intent);
+                    if (intent.getBooleanExtra(UsbManager.EXTRA_PERMISSION_GRANTED, false)) {
+                        openAccessory(accessory);
+                    } else {
+                        Log.d(TAG, "permission denied for accessory " + accessory);
+                    }
+                    mPermissionRequestPending = false;
+                }
+            }
+        }
+    };
+
     @Override
     public void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
 
+        mUsbManager = UsbManager.getInstance(this);
+        mPermissionIntent = PendingIntent.getBroadcast(this, 0, new Intent(ACTION_USB_PERMISSION), 0);
+        IntentFilter filter = new IntentFilter(ACTION_USB_PERMISSION);
+        registerReceiver(mUsbReceiver, filter);
+
         setContentView(R.layout.accessory_chat);
         mLog = (TextView)findViewById(R.id.log);
         mEditText = (EditText)findViewById(R.id.message);
@@ -66,21 +97,20 @@
 
         Intent intent = getIntent();
         Log.d(TAG, "intent: " + intent);
-        UsbManager manager = UsbManager.getInstance();
-        UsbAccessory[] accessories = manager.getAccessoryList();
+        UsbAccessory[] accessories = mUsbManager.getAccessoryList();
         UsbAccessory accessory = (accessories == null ? null : accessories[0]);
         if (accessory != null) {
-            mFileDescriptor = manager.openAccessory(accessory);
-            if (mFileDescriptor != null) {
-                FileDescriptor fd = mFileDescriptor.getFileDescriptor();
-                mInputStream = new FileInputStream(fd);
-                mOutputStream = new FileOutputStream(fd);
-                Thread thread = new Thread(null, this, "AccessoryChat");
-                thread.start();
+            if (mUsbManager.hasPermission(accessory)) {
+                openAccessory(accessory);
             } else {
-                Log.d(TAG, "openAccessory fail");
+                synchronized (mUsbReceiver) {
+                    if (!mPermissionRequestPending) {
+                        mUsbManager.requestPermission(accessory, mPermissionIntent);
+                        mPermissionRequestPending = true;
+                    }
+                }
             }
-        } else {
+         } else {
             Log.d(TAG, "mAccessory is null");
         }
     }
@@ -100,9 +130,25 @@
 
     @Override
     public void onDestroy() {
+        unregisterReceiver(mUsbReceiver);
        super.onDestroy();
     }
 
+    private void openAccessory(UsbAccessory accessory) {
+        Log.d(TAG, "openAccessory: " + accessory);
+        mFileDescriptor = mUsbManager.openAccessory(accessory);
+        if (mFileDescriptor != null) {
+            FileDescriptor fd = mFileDescriptor.getFileDescriptor();
+            mInputStream = new FileInputStream(fd);
+            mOutputStream = new FileOutputStream(fd);
+            Thread thread = new Thread(null, this, "AccessoryChat");
+            thread.start();
+            Log.d(TAG, "openAccessory succeeded");
+        } else {
+            Log.d(TAG, "openAccessory fail");
+        }
+    }
+
     public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
         if (actionId == EditorInfo.IME_ACTION_DONE && mOutputStream != null) {
             try {
diff --git a/libs/utils/AssetManager.cpp b/libs/utils/AssetManager.cpp
index e09e755..6e57d93 100644
--- a/libs/utils/AssetManager.cpp
+++ b/libs/utils/AssetManager.cpp
@@ -36,6 +36,7 @@
 #include <dirent.h>
 #include <errno.h>
 #include <assert.h>
+#include <strings.h>
 
 using namespace android;
 
@@ -1764,4 +1765,3 @@
 
     return mZipPath.size()-1;
 }
-
diff --git a/libs/utils/Looper.cpp b/libs/utils/Looper.cpp
index 18f858b..d5dd126 100644
--- a/libs/utils/Looper.cpp
+++ b/libs/utils/Looper.cpp
@@ -218,14 +218,10 @@
     // Adjust the timeout based on when the next message is due.
     if (timeoutMillis != 0 && mNextMessageUptime != LLONG_MAX) {
         nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
-        if (mNextMessageUptime <= now) {
-            timeoutMillis = 0;
-        } else {
-            uint64_t delay = (mNextMessageUptime - now + 999999LL) / 1000000LL;
-            if (delay < INT_MAX
-                    && (timeoutMillis < 0 || int(delay) < timeoutMillis)) {
-                timeoutMillis = int(delay);
-            }
+        int messageTimeoutMillis = toMillisecondTimeoutDelay(now, mNextMessageUptime);
+        if (messageTimeoutMillis >= 0
+                && (timeoutMillis < 0 || messageTimeoutMillis < timeoutMillis)) {
+            timeoutMillis = messageTimeoutMillis;
         }
 #if DEBUG_POLL_AND_WAKE
         LOGD("%p ~ pollOnce - next message in %lldns, adjusted timeout: timeoutMillis=%d",
@@ -444,12 +440,11 @@
                 return result;
             }
 
-            nsecs_t timeoutNanos = endTime - systemTime(SYSTEM_TIME_MONOTONIC);
-            if (timeoutNanos <= 0) {
+            nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
+            timeoutMillis = toMillisecondTimeoutDelay(now, endTime);
+            if (timeoutMillis == 0) {
                 return ALOOPER_POLL_TIMEOUT;
             }
-
-            timeoutMillis = int(nanoseconds_to_milliseconds(timeoutNanos + 999999LL));
         }
     }
 }
diff --git a/libs/utils/Timers.cpp b/libs/utils/Timers.cpp
index 784f035..64a29f5 100644
--- a/libs/utils/Timers.cpp
+++ b/libs/utils/Timers.cpp
@@ -26,6 +26,7 @@
 #include <sys/time.h>
 #include <time.h>
 #include <errno.h>
+#include <limits.h>
 
 #ifdef HAVE_WIN32_THREADS
 #include <windows.h>
@@ -53,6 +54,23 @@
 #endif
 }
 
+int toMillisecondTimeoutDelay(nsecs_t referenceTime, nsecs_t timeoutTime)
+{
+    int timeoutDelayMillis;
+    if (timeoutTime > referenceTime) {
+        uint64_t timeoutDelay = uint64_t(timeoutTime - referenceTime);
+        if (timeoutDelay > uint64_t((INT_MAX - 1) * 1000000LL)) {
+            timeoutDelayMillis = -1;
+        } else {
+            timeoutDelayMillis = (timeoutDelay + 999999LL) / 1000000LL;
+        }
+    } else {
+        timeoutDelayMillis = 0;
+    }
+    return timeoutDelayMillis;
+}
+
+
 /*
  * ===========================================================================
  *      DurationTimer
diff --git a/media/java/android/media/AudioService.java b/media/java/android/media/AudioService.java
index 5a73d2d..9d0cba3 100644
--- a/media/java/android/media/AudioService.java
+++ b/media/java/android/media/AudioService.java
@@ -110,6 +110,8 @@
     private static final int MSG_PLAY_SOUND_EFFECT = 7;
     private static final int MSG_BTA2DP_DOCK_TIMEOUT = 8;
     private static final int MSG_LOAD_SOUND_EFFECTS = 9;
+    private static final int MSG_SET_FORCE_USE = 10;
+
 
     private static final int BTA2DP_DOCK_TIMEOUT_MILLIS = 8000;
 
@@ -805,7 +807,7 @@
             if (mode != mMode) {
 
                 // automatically handle audio focus for mode changes
-                handleFocusForCalls(mMode, mode);
+                handleFocusForCalls(mMode, mode, cb);
 
                 if (AudioSystem.setPhoneState(mode) == AudioSystem.AUDIO_STATUS_OK) {
                     mMode = mode;
@@ -864,7 +866,7 @@
     }
 
     /** pre-condition: oldMode != newMode */
-    private void handleFocusForCalls(int oldMode, int newMode) {
+    private void handleFocusForCalls(int oldMode, int newMode, IBinder cb) {
         // if ringing
         if (newMode == AudioSystem.MODE_RINGTONE) {
             // if not ringing silently
@@ -872,8 +874,8 @@
             if (ringVolume > 0) {
                 // request audio focus for the communication focus entry
                 requestAudioFocus(AudioManager.STREAM_RING,
-                        AudioManager.AUDIOFOCUS_GAIN_TRANSIENT,
-                        null, null /* both allowed to be null only for this clientId */,
+                        AudioManager.AUDIOFOCUS_GAIN_TRANSIENT, cb,
+                        null /* IAudioFocusDispatcher allowed to be null only for this clientId */,
                         IN_VOICE_COMM_FOCUS_ID /*clientId*/);
 
             }
@@ -884,8 +886,8 @@
             // request audio focus for the communication focus entry
             // (it's ok if focus was already requested during ringing)
             requestAudioFocus(AudioManager.STREAM_RING,
-                    AudioManager.AUDIOFOCUS_GAIN_TRANSIENT,
-                    null, null /* both allowed to be null only for this clientId */,
+                    AudioManager.AUDIOFOCUS_GAIN_TRANSIENT, cb,
+                    null /* IAudioFocusDispatcher allowed to be null only for this clientId */,
                     IN_VOICE_COMM_FOCUS_ID /*clientId*/);
         }
         // if exiting call
@@ -1170,22 +1172,15 @@
         if (!checkAudioSettingsPermission("setSpeakerphoneOn()")) {
             return;
         }
-        if (on) {
-            AudioSystem.setForceUse(AudioSystem.FOR_COMMUNICATION, AudioSystem.FORCE_SPEAKER);
-            mForcedUseForComm = AudioSystem.FORCE_SPEAKER;
-        } else {
-            AudioSystem.setForceUse(AudioSystem.FOR_COMMUNICATION, AudioSystem.FORCE_NONE);
-            mForcedUseForComm = AudioSystem.FORCE_NONE;
-        }
+        mForcedUseForComm = on ? AudioSystem.FORCE_SPEAKER : AudioSystem.FORCE_NONE;
+
+        sendMsg(mAudioHandler, MSG_SET_FORCE_USE, SHARED_MSG, SENDMSG_QUEUE,
+                AudioSystem.FOR_COMMUNICATION, mForcedUseForComm, null, 0);
     }
 
     /** @see AudioManager#isSpeakerphoneOn() */
     public boolean isSpeakerphoneOn() {
-        if (mForcedUseForComm == AudioSystem.FORCE_SPEAKER) {
-            return true;
-        } else {
-            return false;
-        }
+        return (mForcedUseForComm == AudioSystem.FORCE_SPEAKER);
     }
 
     /** @see AudioManager#setBluetoothScoOn() */
@@ -1193,24 +1188,17 @@
         if (!checkAudioSettingsPermission("setBluetoothScoOn()")) {
             return;
         }
-        if (on) {
-            AudioSystem.setForceUse(AudioSystem.FOR_COMMUNICATION, AudioSystem.FORCE_BT_SCO);
-            AudioSystem.setForceUse(AudioSystem.FOR_RECORD, AudioSystem.FORCE_BT_SCO);
-            mForcedUseForComm = AudioSystem.FORCE_BT_SCO;
-        } else {
-            AudioSystem.setForceUse(AudioSystem.FOR_COMMUNICATION, AudioSystem.FORCE_NONE);
-            AudioSystem.setForceUse(AudioSystem.FOR_RECORD, AudioSystem.FORCE_NONE);
-            mForcedUseForComm = AudioSystem.FORCE_NONE;
-        }
+        mForcedUseForComm = on ? AudioSystem.FORCE_BT_SCO : AudioSystem.FORCE_NONE;
+
+        sendMsg(mAudioHandler, MSG_SET_FORCE_USE, SHARED_MSG, SENDMSG_QUEUE,
+                AudioSystem.FOR_COMMUNICATION, mForcedUseForComm, null, 0);
+        sendMsg(mAudioHandler, MSG_SET_FORCE_USE, SHARED_MSG, SENDMSG_QUEUE,
+                AudioSystem.FOR_RECORD, mForcedUseForComm, null, 0);
     }
 
     /** @see AudioManager#isBluetoothScoOn() */
     public boolean isBluetoothScoOn() {
-        if (mForcedUseForComm == AudioSystem.FORCE_BT_SCO) {
-            return true;
-        } else {
-            return false;
-        }
+        return (mForcedUseForComm == AudioSystem.FORCE_BT_SCO);
     }
 
     /** @see AudioManager#startBluetoothSco() */
@@ -1935,6 +1923,10 @@
             }
         }
 
+        private void setForceUse(int usage, int config) {
+            AudioSystem.setForceUse(usage, config);
+        }
+
         @Override
         public void handleMessage(Message msg) {
             int baseMsgWhat = getMsgBase(msg.what);
@@ -2026,6 +2018,10 @@
                     // msg.obj  == address of BTA2DP device
                     makeA2dpDeviceUnavailableNow( (String) msg.obj );
                     break;
+
+                case MSG_SET_FORCE_USE:
+                    setForceUse(msg.arg1, msg.arg2);
+                    break;
             }
         }
     }
@@ -2547,10 +2543,9 @@
         // the main stream type for the audio focus request is currently not used. It may
         // potentially be used to handle multiple stream type-dependent audio focuses.
 
-        // we need a valid binder callback for clients other than the AudioService's phone
-        // state listener
-        if (!IN_VOICE_COMM_FOCUS_ID.equals(clientId) && ((cb == null) || !cb.pingBinder())) {
-            Log.i(TAG, " AudioFocus  DOA client for requestAudioFocus(), exiting");
+        // we need a valid binder callback for clients
+        if (!cb.pingBinder()) {
+            Log.e(TAG, " AudioFocus DOA client for requestAudioFocus(), aborting.");
             return AudioManager.AUDIOFOCUS_REQUEST_FAILED;
         }
 
@@ -2591,17 +2586,14 @@
         }//synchronized(mAudioFocusLock)
 
         // handle the potential premature death of the new holder of the focus
-        // (premature death == death before abandoning focus) for a client which is not the
-        // AudioService's phone state listener
-        if (!IN_VOICE_COMM_FOCUS_ID.equals(clientId)) {
-            // Register for client death notification
-            AudioFocusDeathHandler afdh = new AudioFocusDeathHandler(cb);
-            try {
-                cb.linkToDeath(afdh, 0);
-            } catch (RemoteException e) {
-                // client has already died!
-                Log.w(TAG, "AudioFocus  requestAudioFocus() could not link to "+cb+" binder death");
-            }
+        // (premature death == death before abandoning focus)
+        // Register for client death notification
+        AudioFocusDeathHandler afdh = new AudioFocusDeathHandler(cb);
+        try {
+            cb.linkToDeath(afdh, 0);
+        } catch (RemoteException e) {
+            // client has already died!
+            Log.w(TAG, "AudioFocus  requestAudioFocus() could not link to "+cb+" binder death");
         }
 
         return AudioManager.AUDIOFOCUS_REQUEST_GRANTED;
diff --git a/media/java/android/media/MediaMetadataRetriever.java b/media/java/android/media/MediaMetadataRetriever.java
index 77e939e..60085b5 100644
--- a/media/java/android/media/MediaMetadataRetriever.java
+++ b/media/java/android/media/MediaMetadataRetriever.java
@@ -26,6 +26,8 @@
 import java.io.FileNotFoundException;
 import java.io.IOException;
 
+import java.util.Map;
+
 /**
  * MediaMetadataRetriever class provides a unified interface for retrieving
  * frame and meta data from an input media file.
@@ -56,7 +58,19 @@
      * @throws IllegalArgumentException If the path is invalid.
      */
     public native void setDataSource(String path) throws IllegalArgumentException;
-    
+
+    /**
+     * Sets the data source (URI) to use. Call this
+     * method before the rest of the methods in this class. This method may be
+     * time-consuming.
+     *
+     * @param uri The URI of the input media.
+     * @param headers the headers to be sent together with the request for the data
+     * @throws IllegalArgumentException If the URI is invalid.
+     */
+    public native void setDataSource(String uri, Map<String, String> headers)
+        throws IllegalArgumentException;
+
     /**
      * Sets the data source (FileDescriptor) to use.  It is the caller's
      * responsibility to close the file descriptor. It is safe to do so as soon
@@ -398,5 +412,25 @@
      * The metadata key to retrieve the music album compilation status.
      */
     public static final int METADATA_KEY_COMPILATION     = 15;
+    /**
+     * If this key exists the media contains audio content.
+     */
+    public static final int METADATA_KEY_HAS_AUDIO       = 16;
+    /**
+     * If this key exists the media contains video content.
+     */
+    public static final int METADATA_KEY_HAS_VIDEO       = 17;
+    /**
+     * If the media contains video, this key retrieves its width.
+     */
+    public static final int METADATA_KEY_VIDEO_WIDTH     = 18;
+    /**
+     * If the media contains video, this key retrieves its height.
+     */
+    public static final int METADATA_KEY_VIDEO_HEIGHT    = 19;
+    /**
+     * This key retrieves the average bitrate (in bits/sec), if available.
+     */
+    public static final int METADATA_KEY_BITRATE         = 20;
     // Add more here...
 }
diff --git a/media/java/android/media/MediaPlayer.java b/media/java/android/media/MediaPlayer.java
index 8b29ea84..fcbe59e 100644
--- a/media/java/android/media/MediaPlayer.java
+++ b/media/java/android/media/MediaPlayer.java
@@ -623,6 +623,11 @@
      * being played. Note that if a SurfaceTexture is used, the value
      * set via setScreenOnWhilePlaying has no effect.
      *
+     * The timestamps provided by {@link SurfaceTexture#getTimestamp()} for a
+     * SurfaceTexture set as the video sink have an unspecified zero point,
+     * and cannot be directly compared between different media sources or different
+     * instances of the same media source, or across multiple runs of the same
+     * program.
      * @hide
      */
     public void setTexture(SurfaceTexture st) {
diff --git a/media/java/android/media/MediaScanner.java b/media/java/android/media/MediaScanner.java
index 74d65d1..6b9f2fb 100644
--- a/media/java/android/media/MediaScanner.java
+++ b/media/java/android/media/MediaScanner.java
@@ -1585,6 +1585,17 @@
     private static native final void native_init();
     private native final void native_setup();
     private native final void native_finalize();
+
+    /**
+     * Releases resouces associated with this MediaScanner object.
+     * It is considered good practice to call this method when
+     * one is done using the MediaScanner object. After this method
+     * is called, the MediaScanner object can no longer be used.
+     */
+    public void release() {
+        native_finalize();
+    }
+
     @Override
     protected void finalize() {
         mContext.getContentResolver().releaseProvider(mMediaProvider);
diff --git a/media/java/android/media/audiofx/AudioEffect.java b/media/java/android/media/audiofx/AudioEffect.java
index d3e9a49..39c6d3e 100644
--- a/media/java/android/media/audiofx/AudioEffect.java
+++ b/media/java/android/media/audiofx/AudioEffect.java
@@ -573,27 +573,16 @@
      *
      * @param param the identifier of the parameter to set
      * @param value the new value for the specified parameter
-     * @return {@link #SUCCESS} in case of success, {@link #ERROR_BAD_VALUE},
-     *         {@link #ERROR_NO_MEMORY}, {@link #ERROR_INVALID_OPERATION} or
-     *         {@link #ERROR_DEAD_OBJECT} in case of failure When called, value.length
-     *         indicates the maximum size of the returned parameters value. When
-     *         returning, value.length is updated with the actual size of the
-     *         returned value.
+     * @return the number of meaningful bytes in value array in case of success or
+     *  {@link #ERROR_BAD_VALUE}, {@link #ERROR_NO_MEMORY}, {@link #ERROR_INVALID_OPERATION}
+     *  or {@link #ERROR_DEAD_OBJECT} in case of failure.
      * @throws IllegalStateException
      * @hide
      */
     public int getParameter(byte[] param, byte[] value)
             throws IllegalStateException {
         checkState("getParameter()");
-        int[] vSize = new int[1];
-        vSize[0] = value.length;
-        int status = native_getParameter(param.length, param, vSize, value);
-        if (value.length > vSize[0]) {
-            byte[] resizedValue = new byte[vSize[0]];
-            System.arraycopy(value, 0, resizedValue, 0, vSize[0]);
-            value = resizedValue;
-        }
-        return status;
+        return native_getParameter(param.length, param, value.length, value);
     }
 
     /**
@@ -615,6 +604,7 @@
      * array of 1 or 2 integers
      *
      * @see #getParameter(byte[], byte[])
+     * In case of success, returns the number of meaningful integers in value array.
      * @hide
      */
     public int getParameter(int param, int[] value)
@@ -628,9 +618,14 @@
 
         int status = getParameter(p, v);
 
-        value[0] = byteArrayToInt(v);
-        if (v.length > 4) {
-            value[1] = byteArrayToInt(v, 4);
+        if (status == 4 || status == 8) {
+            value[0] = byteArrayToInt(v);
+            if (status == 8) {
+                value[1] = byteArrayToInt(v, 4);
+            }
+            status /= 4;
+        } else {
+            status = ERROR;
         }
         return status;
     }
@@ -640,6 +635,7 @@
      * array of 1 or 2 short integers
      *
      * @see #getParameter(byte[], byte[])
+     * In case of success, returns the number of meaningful short integers in value array.
      * @hide
      */
     public int getParameter(int param, short[] value)
@@ -653,9 +649,14 @@
 
         int status = getParameter(p, v);
 
-        value[0] = byteArrayToShort(v);
-        if (v.length > 2) {
-            value[1] = byteArrayToShort(v, 2);
+        if (status == 2 || status == 4) {
+            value[0] = byteArrayToShort(v);
+            if (status == 4) {
+                value[1] = byteArrayToShort(v, 2);
+            }
+            status /= 2;
+        } else {
+            status = ERROR;
         }
         return status;
     }
@@ -665,6 +666,7 @@
      * the value is also an array of 1 or 2 integers
      *
      * @see #getParameter(byte[], byte[])
+     * In case of success, the returns the number of meaningful integers in value array.
      * @hide
      */
     public int getParameter(int[] param, int[] value)
@@ -681,9 +683,14 @@
 
         int status = getParameter(p, v);
 
-        value[0] = byteArrayToInt(v);
-        if (v.length > 4) {
-            value[1] = byteArrayToInt(v, 4);
+        if (status == 4 || status == 8) {
+            value[0] = byteArrayToInt(v);
+            if (status == 8) {
+                value[1] = byteArrayToInt(v, 4);
+            }
+            status /= 4;
+        } else {
+            status = ERROR;
         }
         return status;
     }
@@ -693,6 +700,7 @@
      * the value is an array of 1 or 2 short integers
      *
      * @see #getParameter(byte[], byte[])
+     * In case of success, returns the number of meaningful short integers in value array.
      * @hide
      */
     public int getParameter(int[] param, short[] value)
@@ -709,9 +717,14 @@
 
         int status = getParameter(p, v);
 
-        value[0] = byteArrayToShort(v);
-        if (v.length > 2) {
-            value[1] = byteArrayToShort(v, 2);
+        if (status == 2 || status == 4) {
+            value[0] = byteArrayToShort(v);
+            if (status == 4) {
+                value[1] = byteArrayToShort(v, 2);
+            }
+            status /= 2;
+        } else {
+            status = ERROR;
         }
         return status;
     }
@@ -740,24 +753,14 @@
     /**
      * Send a command to the effect engine. This method is intended to send
      * proprietary commands to a particular effect implementation.
-     *
+     * In case of success, returns the number of meaningful bytes in reply array.
+     * In case of failure, the returned value is negative and implementation specific.
      * @hide
      */
     public int command(int cmdCode, byte[] command, byte[] reply)
             throws IllegalStateException {
         checkState("command()");
-        int[] replySize = new int[1];
-        replySize[0] = reply.length;
-
-        int status = native_command(cmdCode, command.length, command,
-                replySize, reply);
-
-        if (reply.length > replySize[0]) {
-            byte[] resizedReply = new byte[replySize[0]];
-            System.arraycopy(reply, 0, resizedReply, 0, replySize[0]);
-            reply = resizedReply;
-        }
-        return status;
+        return native_command(cmdCode, command.length, command, reply.length, reply);
     }
 
     // --------------------------------------------------------------------------
@@ -1145,10 +1148,10 @@
             int vsize, byte[] value);
 
     private native final int native_getParameter(int psize, byte[] param,
-            int[] vsize, byte[] value);
+            int vsize, byte[] value);
 
     private native final int native_command(int cmdCode, int cmdSize,
-            byte[] cmdData, int[] repSize, byte[] repData);
+            byte[] cmdData, int repSize, byte[] repData);
 
     private static native Object[] native_query_effects();
 
@@ -1172,23 +1175,30 @@
      * @hide
      */
     public void checkStatus(int status) {
-        switch (status) {
-        case AudioEffect.SUCCESS:
-            break;
-        case AudioEffect.ERROR_BAD_VALUE:
-            throw (new IllegalArgumentException(
-                    "AudioEffect: bad parameter value"));
-        case AudioEffect.ERROR_INVALID_OPERATION:
-            throw (new UnsupportedOperationException(
-                    "AudioEffect: invalid parameter operation"));
-        default:
-            throw (new RuntimeException("AudioEffect: set/get parameter error"));
+        if (isError(status)) {
+            switch (status) {
+            case AudioEffect.ERROR_BAD_VALUE:
+                throw (new IllegalArgumentException(
+                        "AudioEffect: bad parameter value"));
+            case AudioEffect.ERROR_INVALID_OPERATION:
+                throw (new UnsupportedOperationException(
+                        "AudioEffect: invalid parameter operation"));
+            default:
+                throw (new RuntimeException("AudioEffect: set/get parameter error"));
+            }
         }
     }
 
     /**
      * @hide
      */
+    public static boolean isError(int status) {
+        return (status < 0);
+    }
+
+    /**
+     * @hide
+     */
     public int byteArrayToInt(byte[] valueBuf) {
         return byteArrayToInt(valueBuf, 0);
 
diff --git a/media/java/android/media/videoeditor/AudioTrack.java b/media/java/android/media/videoeditor/AudioTrack.java
index b2f547b..2de82f2 100755
--- a/media/java/android/media/videoeditor/AudioTrack.java
+++ b/media/java/android/media/videoeditor/AudioTrack.java
@@ -49,7 +49,6 @@
     private final int mAudioType;
     private final int mAudioBitrate;
     private final int mAudioSamplingFrequency;
-
     /**
      *  Ducking variables
      */
@@ -127,11 +126,17 @@
                int duckThreshold, int duckedTrackVolume,
             String audioWaveformFilename) throws IOException {
         Properties properties = null;
+
         File file = new File(filename);
         if (!file.exists()) {
             throw new IOException(filename + " not found ! ");
         }
 
+        /*Compare file_size with 2GB*/
+        if (VideoEditor.MAX_SUPPORTED_FILE_SIZE <= file.length()) {
+            throw new IllegalArgumentException("File size is more than 2GB");
+        }
+
         if (editor instanceof VideoEditorImpl) {
             mMANativeHelper = ((VideoEditorImpl)editor).getNativeContext();
         } else {
@@ -140,7 +145,7 @@
         try {
           properties = mMANativeHelper.getMediaProperties(filename);
         } catch (Exception e) {
-            throw new IllegalArgumentException("Unsupported file or file not found");
+            throw new IllegalArgumentException(e.getMessage() + " : " + filename);
         }
         switch (mMANativeHelper.getFileType(properties.fileType)) {
             case MediaProperties.FILE_3GP:
diff --git a/media/java/android/media/videoeditor/MediaItem.java b/media/java/android/media/videoeditor/MediaItem.java
index dfe0bae..8c4841f 100755
--- a/media/java/android/media/videoeditor/MediaItem.java
+++ b/media/java/android/media/videoeditor/MediaItem.java
@@ -131,6 +131,15 @@
         if (filename == null) {
             throw new IllegalArgumentException("MediaItem : filename is null");
         }
+        File file = new File(filename);
+        if (!file.exists()) {
+            throw new IOException(filename + " not found ! ");
+        }
+
+        /*Compare file_size with 2GB*/
+        if (VideoEditor.MAX_SUPPORTED_FILE_SIZE <= file.length()) {
+            throw new IllegalArgumentException("File size is more than 2GB");
+        }
         mUniqueId = mediaItemId;
         mFilename = filename;
         mRenderingMode = renderingMode;
diff --git a/media/java/android/media/videoeditor/MediaVideoItem.java b/media/java/android/media/videoeditor/MediaVideoItem.java
index c91d796..4758de6 100755
--- a/media/java/android/media/videoeditor/MediaVideoItem.java
+++ b/media/java/android/media/videoeditor/MediaVideoItem.java
@@ -115,7 +115,7 @@
         try {
              properties = mMANativeHelper.getMediaProperties(filename);
         } catch ( Exception e) {
-            throw new IllegalArgumentException("Unsupported file or file not found: " + filename);
+            throw new IllegalArgumentException(e.getMessage() + " : " + filename);
         }
 
         switch (mMANativeHelper.getFileType(properties.fileType)) {
diff --git a/media/java/android/media/videoeditor/Transition.java b/media/java/android/media/videoeditor/Transition.java
index 3e8fe94..fa9d26d 100755
--- a/media/java/android/media/videoeditor/Transition.java
+++ b/media/java/android/media/videoeditor/Transition.java
@@ -131,6 +131,11 @@
         if (durationMs > getMaximumDuration()) {
             throw new IllegalArgumentException("The duration is too large");
         }
+        if (afterMediaItem != null) {
+            mNativeHelper = afterMediaItem.getNativeContext();
+        }else {
+            mNativeHelper = beforeMediaItem.getNativeContext();
+        }
     }
 
     /**
diff --git a/media/java/android/media/videoeditor/TransitionAlpha.java b/media/java/android/media/videoeditor/TransitionAlpha.java
index f7d17cb..22788d4 100755
--- a/media/java/android/media/videoeditor/TransitionAlpha.java
+++ b/media/java/android/media/videoeditor/TransitionAlpha.java
@@ -104,13 +104,6 @@
         mWidth = dbo.outWidth;
         mHeight = dbo.outHeight;
 
-        if (afterMediaItem != null) {
-            mNativeHelper = afterMediaItem.getNativeContext();
-        }else {
-            mNativeHelper = beforeMediaItem.getNativeContext();
-        }
-
-
         mRGBMaskFile = String.format(mNativeHelper.getProjectPath() +
                 "/" + "mask" + transitionId+ ".rgb");
 
diff --git a/media/java/android/media/videoeditor/VideoEditor.java b/media/java/android/media/videoeditor/VideoEditor.java
index 122dc8d..59e4540 100755
--- a/media/java/android/media/videoeditor/VideoEditor.java
+++ b/media/java/android/media/videoeditor/VideoEditor.java
@@ -68,6 +68,11 @@
     public final static int DURATION_OF_STORYBOARD = -1;
 
     /**
+     *  Maximum supported file size
+     */
+    public static final long MAX_SUPPORTED_FILE_SIZE = 2147483648L;
+
+    /**
      * This listener interface is used by the VideoEditor to emit preview
      * progress notifications. This callback should be invoked after the number
      * of frames specified by
diff --git a/media/java/android/media/videoeditor/VideoEditorImpl.java b/media/java/android/media/videoeditor/VideoEditorImpl.java
index 7e1f73a..2105deb 100755
--- a/media/java/android/media/videoeditor/VideoEditorImpl.java
+++ b/media/java/android/media/videoeditor/VideoEditorImpl.java
@@ -119,7 +119,6 @@
     private static final String ATTR_OVERLAY_FRAME_HEIGHT = "overlay_frame_height";
     private static final String ATTR_OVERLAY_RESIZED_RGB_FRAME_WIDTH = "resized_RGBframe_width";
     private static final String ATTR_OVERLAY_RESIZED_RGB_FRAME_HEIGHT = "resized_RGBframe_height";
-
     private static final int ENGINE_ACCESS_MAX_TIMEOUT_MS = 500;
     /*
      *  Instance variables
@@ -437,6 +436,12 @@
                 throw new IllegalArgumentException(message);
             }
         }
+        computeTimelineDuration();
+        final long audioBitrate = MediaArtistNativeHelper.Bitrate.BR_96_KBPS;
+        final long fileSize = (mDurationMs * (bitrate + audioBitrate)) / 8000;
+        if (MAX_SUPPORTED_FILE_SIZE <= fileSize) {
+            throw new IllegalStateException("Export Size is more than 2GB");
+        }
 
         boolean semAcquireDone = false;
         try {
@@ -899,6 +904,10 @@
             throw new IllegalArgumentException("Surface could not be retrieved from Surface holder");
         }
 
+        if (surface.isValid() == false) {
+            throw new IllegalStateException("Surface is not valid");
+        }
+
         if (timeMs < 0) {
             throw new IllegalArgumentException("requested time not correct");
         } else if (timeMs > mDurationMs) {
@@ -1622,6 +1631,10 @@
             throw new IllegalArgumentException("Surface could not be retrieved from surface holder");
         }
 
+        if (surface.isValid() == false) {
+            throw new IllegalStateException("Surface is not valid");
+        }
+
         if (listener == null) {
             throw new IllegalArgumentException();
         }
@@ -1858,6 +1871,10 @@
             throw new IllegalArgumentException("Surface could not be retrieved from surface holder");
         }
 
+        if (surface.isValid() == false) {
+            throw new IllegalStateException("Surface is not valid");
+        }
+
         if (mMANativeHelper != null) {
             mMANativeHelper.clearPreviewSurface(surface);
         } else {
diff --git a/media/java/android/mtp/MtpConstants.java b/media/java/android/mtp/MtpConstants.java
index ad67bb9..d245f588 100644
--- a/media/java/android/mtp/MtpConstants.java
+++ b/media/java/android/mtp/MtpConstants.java
@@ -271,7 +271,7 @@
 
     /**
       * Returns true if the object is abstract (that is, it has no representation
-      * in the underlying file system.
+      * in the underlying file system).
       *
       * @param format the format of the object
       * @return true if the object is abstract
diff --git a/media/java/android/mtp/MtpDatabase.java b/media/java/android/mtp/MtpDatabase.java
index 98de2f7..b4a4689 100644
--- a/media/java/android/mtp/MtpDatabase.java
+++ b/media/java/android/mtp/MtpDatabase.java
@@ -20,6 +20,7 @@
 import android.content.ContentValues;
 import android.content.IContentProvider;
 import android.content.Intent;
+import android.content.SharedPreferences;
 import android.database.Cursor;
 import android.database.sqlite.SQLiteDatabase;
 import android.media.MediaScanner;
@@ -62,8 +63,8 @@
     // true if the database has been modified in the current MTP session
     private boolean mDatabaseModified;
 
-    // database for writable MTP device properties
-    private SQLiteDatabase mDevicePropDb;
+    // SharedPreferences for writable MTP device properties
+    private SharedPreferences mDeviceProperties;
     private static final int DEVICE_PROPERTIES_DATABASE_VERSION = 1;
 
     // FIXME - this should be passed in via the constructor
@@ -96,9 +97,6 @@
     private static final String PARENT_FORMAT_WHERE = PARENT_WHERE + " AND "
                                             + Files.FileColumns.FORMAT + "=?";
 
-    private static final String[] DEVICE_PROPERTY_PROJECTION = new String[] { "_id", "value" };
-    private  static final String DEVICE_PROPERTY_WHERE = "code=?";
-
     private final MediaScanner mMediaScanner;
 
     static {
@@ -114,7 +112,7 @@
         mMediaStoragePath = storagePath;
         mObjectsUri = Files.getMtpObjectsUri(volumeName);
         mMediaScanner = new MediaScanner(context);
-        openDevicePropertiesDatabase(context);
+        initDeviceProperties(context);
     }
 
     @Override
@@ -126,19 +124,38 @@
         }
     }
 
-    private void openDevicePropertiesDatabase(Context context) {
-        mDevicePropDb = context.openOrCreateDatabase("device-properties", Context.MODE_PRIVATE, null);
-        int version = mDevicePropDb.getVersion();
+    private void initDeviceProperties(Context context) {
+        final String devicePropertiesName = "device-properties";
+        mDeviceProperties = context.getSharedPreferences(devicePropertiesName, Context.MODE_PRIVATE);
+        File databaseFile = context.getDatabasePath(devicePropertiesName);
 
-        // initialize if necessary
-        if (version != DEVICE_PROPERTIES_DATABASE_VERSION) {
-            mDevicePropDb.execSQL("CREATE TABLE properties (" +
-                    "_id INTEGER PRIMARY KEY AUTOINCREMENT," +
-                    "code INTEGER UNIQUE ON CONFLICT REPLACE," +
-                    "value TEXT" +
-                    ");");
-            mDevicePropDb.execSQL("CREATE INDEX property_index ON properties (code);");
-            mDevicePropDb.setVersion(DEVICE_PROPERTIES_DATABASE_VERSION);
+        if (databaseFile.exists()) {
+            // for backward compatibility - read device properties from sqlite database
+            // and migrate them to shared prefs
+            SQLiteDatabase db = null;
+            Cursor c = null;
+            try {
+                db = context.openOrCreateDatabase("device-properties", Context.MODE_PRIVATE, null);
+                if (db != null) {
+                    c = db.query("properties", new String[] { "_id", "code", "value" },
+                            null, null, null, null, null);
+                    if (c != null) {
+                        SharedPreferences.Editor e = mDeviceProperties.edit();
+                        while (c.moveToNext()) {
+                            String name = c.getString(1);
+                            String value = c.getString(2);
+                            e.putString(name, value);
+                        }
+                        e.commit();
+                    }
+                }
+            } catch (Exception e) {
+                Log.e(TAG, "failed to migrate device properties", e);
+            } finally {
+                if (c != null) c.close();
+                if (db != null) db.close();
+            }
+            databaseFile.delete();
         }
     }
 
@@ -567,30 +584,15 @@
         switch (property) {
             case MtpConstants.DEVICE_PROPERTY_SYNCHRONIZATION_PARTNER:
             case MtpConstants.DEVICE_PROPERTY_DEVICE_FRIENDLY_NAME:
-                // writable string properties kept in our device property database
-                Cursor c = null;
-                try {
-                    c = mDevicePropDb.query("properties", DEVICE_PROPERTY_PROJECTION,
-                        DEVICE_PROPERTY_WHERE, new String[] {  Integer.toString(property) },
-                        null, null, null);
-
-                    if (c != null && c.moveToNext()) {
-                        String value = c.getString(1);
-                        int length = value.length();
-                        if (length > 255) {
-                            length = 255;
-                        }
-                        value.getChars(0, length, outStringValue, 0);
-                        outStringValue[length] = 0;
-                    } else {
-                        outStringValue[0] = 0;
-                    }
-                    return MtpConstants.RESPONSE_OK;
-                } finally {
-                    if (c != null) {
-                        c.close();
-                    }
+                // writable string properties kept in shared preferences
+                String value = mDeviceProperties.getString(Integer.toString(property), "");
+                int length = value.length();
+                if (length > 255) {
+                    length = 255;
                 }
+                value.getChars(0, length, outStringValue, 0);
+                outStringValue[length] = 0;
+                return MtpConstants.RESPONSE_OK;
 
             case MtpConstants.DEVICE_PROPERTY_IMAGE_SIZE:
                 // use screen size as max image size
@@ -612,16 +614,11 @@
         switch (property) {
             case MtpConstants.DEVICE_PROPERTY_SYNCHRONIZATION_PARTNER:
             case MtpConstants.DEVICE_PROPERTY_DEVICE_FRIENDLY_NAME:
-                // writable string properties kept in our device property database
-                try {
-                    ContentValues values = new ContentValues();
-                    values.put("code", property);
-                    values.put("value", stringValue);
-                    mDevicePropDb.insert("properties", "code", values);
-                    return MtpConstants.RESPONSE_OK;
-                } catch (Exception e) {
-                    return MtpConstants.RESPONSE_GENERAL_ERROR;
-                }
+                // writable string properties kept in shared prefs
+                SharedPreferences.Editor e = mDeviceProperties.edit();
+                e.putString(Integer.toString(property), stringValue);
+                return (e.commit() ? MtpConstants.RESPONSE_OK
+                        : MtpConstants.RESPONSE_GENERAL_ERROR);
         }
 
         return MtpConstants.RESPONSE_DEVICE_PROP_NOT_SUPPORTED;
diff --git a/media/java/android/mtp/MtpDevice.java b/media/java/android/mtp/MtpDevice.java
index 22961d7f..af37c9e 100644
--- a/media/java/android/mtp/MtpDevice.java
+++ b/media/java/android/mtp/MtpDevice.java
@@ -17,7 +17,7 @@
 package android.mtp;
 
 import android.hardware.usb.UsbDevice;
-import android.hardware.usb.UsbManager;
+import android.hardware.usb.UsbDeviceConnection;
 import android.os.ParcelFileDescriptor;
 import android.util.Log;
 
@@ -44,17 +44,20 @@
     }
 
     /**
-     * Opens the MTP or PTP device and return an {@link android.mtp.MtpDevice} for it.
+     * Opens the MTP device.  Once the device is open it takes ownership of the
+     * {@link android.hardware.usb.UsbDeviceConnection}.  
+     * The connection will be closed when you call {@link #close()}
+     * The connection will also be closed if this method fails.
      *
-     * @param manager reference to {@link android.hardware.usb.UsbManager}
+     * @param connection an open {@link android.hardware.usb.UsbDeviceConnection} for the device
      * @return true if the device was successfully opened.
      */
-    public boolean open(UsbManager manager) {
-        if (manager.openDevice(mDevice)) {
-            return native_open(mDevice.getDeviceName(), mDevice.getFileDescriptor());
-        } else {
-            return false;
+    public boolean open(UsbDeviceConnection connection) {
+        boolean result = native_open(mDevice.getDeviceName(), connection.getFileDescriptor());
+        if (!result) {
+            connection.close();
         }
+        return result;
     }
 
     /**
@@ -195,7 +198,7 @@
      * @param objectHandle handle of the object to query
      * @return the object's storage unit ID
      */
-    public long getStorageID(int objectHandle) {
+    public long getStorageId(int objectHandle) {
         return native_get_storage_id(objectHandle);
     }
 
diff --git a/media/java/android/mtp/MtpServer.java b/media/java/android/mtp/MtpServer.java
index fe734e1..006fa6d 100644
--- a/media/java/android/mtp/MtpServer.java
+++ b/media/java/android/mtp/MtpServer.java
@@ -24,6 +24,9 @@
  */
 public class MtpServer {
 
+    private final Object mLock = new Object();
+    private boolean mStarted;
+
     private static final String TAG = "MtpServer";
 
     static {
@@ -35,11 +38,19 @@
     }
 
     public void start() {
-        native_start();
+        synchronized (mLock) {
+            native_start();
+            mStarted = true;
+        }
     }
 
     public void stop() {
-        native_stop();
+        synchronized (mLock) {
+            if (mStarted) {
+                native_stop();
+                mStarted = false;
+            }
+        }
     }
 
     public void sendObjectAdded(int handle) {
diff --git a/media/jni/android_media_MediaMetadataRetriever.cpp b/media/jni/android_media_MediaMetadataRetriever.cpp
index 3d7dbf9..5d9a3c5 100644
--- a/media/jni/android_media_MediaMetadataRetriever.cpp
+++ b/media/jni/android_media_MediaMetadataRetriever.cpp
@@ -37,6 +37,7 @@
     jclass bitmapClazz;
     jfieldID nativeBitmap;
     jmethodID createBitmapMethod;
+    jmethodID createScaledBitmapMethod;
     jclass configClazz;
     jmethodID createConfigMethod;
 };
@@ -76,32 +77,123 @@
     env->SetIntField(thiz, fields.context, retriever);
 }
 
-static void android_media_MediaMetadataRetriever_setDataSource(JNIEnv *env, jobject thiz, jstring path)
-{
+static void
+android_media_MediaMetadataRetriever_setDataSourceAndHeaders(
+        JNIEnv *env, jobject thiz, jstring path, jobject headers) {
     LOGV("setDataSource");
     MediaMetadataRetriever* retriever = getRetriever(env, thiz);
     if (retriever == 0) {
-        jniThrowException(env, "java/lang/IllegalStateException", "No retriever available");
-        return;
-    }
-    if (!path) {
-        jniThrowException(env, "java/lang/IllegalArgumentException", "Null pointer");
+        jniThrowException(
+                env,
+                "java/lang/IllegalStateException", "No retriever available");
+
         return;
     }
 
-    const char *pathStr = env->GetStringUTFChars(path, NULL);
-    if (!pathStr) {  // OutOfMemoryError exception already thrown
+    if (!path) {
+        jniThrowException(
+                env, "java/lang/IllegalArgumentException", "Null pointer");
+
         return;
     }
 
+    const char *tmp = env->GetStringUTFChars(path, NULL);
+    if (!tmp) {  // OutOfMemoryError exception already thrown
+        return;
+    }
+
+    String8 pathStr(tmp);
+
+    env->ReleaseStringUTFChars(path, tmp);
+    tmp = NULL;
+
     // Don't let somebody trick us in to reading some random block of memory
-    if (strncmp("mem://", pathStr, 6) == 0) {
-        jniThrowException(env, "java/lang/IllegalArgumentException", "Invalid pathname");
+    if (strncmp("mem://", pathStr.string(), 6) == 0) {
+        jniThrowException(
+                env, "java/lang/IllegalArgumentException", "Invalid pathname");
         return;
     }
 
-    process_media_retriever_call(env, retriever->setDataSource(pathStr), "java/lang/RuntimeException", "setDataSource failed");
-    env->ReleaseStringUTFChars(path, pathStr);
+    // headers is a Map<String, String>.
+    // We build a similar KeyedVector out of it.
+    KeyedVector<String8, String8> headersVector;
+    if (headers) {
+        // Get the Map's entry Set.
+        jclass mapClass = env->FindClass("java/util/Map");
+
+        jmethodID entrySet =
+            env->GetMethodID(mapClass, "entrySet", "()Ljava/util/Set;");
+
+        jobject set = env->CallObjectMethod(headers, entrySet);
+        // Obtain an iterator over the Set
+        jclass setClass = env->FindClass("java/util/Set");
+
+        jmethodID iterator =
+            env->GetMethodID(setClass, "iterator", "()Ljava/util/Iterator;");
+
+        jobject iter = env->CallObjectMethod(set, iterator);
+        // Get the Iterator method IDs
+        jclass iteratorClass = env->FindClass("java/util/Iterator");
+        jmethodID hasNext = env->GetMethodID(iteratorClass, "hasNext", "()Z");
+
+        jmethodID next =
+            env->GetMethodID(iteratorClass, "next", "()Ljava/lang/Object;");
+
+        // Get the Entry class method IDs
+        jclass entryClass = env->FindClass("java/util/Map$Entry");
+
+        jmethodID getKey =
+            env->GetMethodID(entryClass, "getKey", "()Ljava/lang/Object;");
+
+        jmethodID getValue =
+            env->GetMethodID(entryClass, "getValue", "()Ljava/lang/Object;");
+
+        // Iterate over the entry Set
+        while (env->CallBooleanMethod(iter, hasNext)) {
+            jobject entry = env->CallObjectMethod(iter, next);
+            jstring key = (jstring) env->CallObjectMethod(entry, getKey);
+            jstring value = (jstring) env->CallObjectMethod(entry, getValue);
+
+            const char* keyStr = env->GetStringUTFChars(key, NULL);
+            if (!keyStr) {  // Out of memory
+                return;
+            }
+
+            const char* valueStr = env->GetStringUTFChars(value, NULL);
+            if (!valueStr) {  // Out of memory
+                return;
+            }
+
+            headersVector.add(String8(keyStr), String8(valueStr));
+
+            env->DeleteLocalRef(entry);
+            env->ReleaseStringUTFChars(key, keyStr);
+            env->DeleteLocalRef(key);
+            env->ReleaseStringUTFChars(value, valueStr);
+            env->DeleteLocalRef(value);
+      }
+
+      env->DeleteLocalRef(entryClass);
+      env->DeleteLocalRef(iteratorClass);
+      env->DeleteLocalRef(iter);
+      env->DeleteLocalRef(setClass);
+      env->DeleteLocalRef(set);
+      env->DeleteLocalRef(mapClass);
+    }
+
+    process_media_retriever_call(
+            env,
+            retriever->setDataSource(
+                pathStr.string(), headers ? &headersVector : NULL),
+
+            "java/lang/RuntimeException",
+            "setDataSource failed");
+}
+
+static void android_media_MediaMetadataRetriever_setDataSource(
+        JNIEnv *env, jobject thiz, jstring path) {
+    android_media_MediaMetadataRetriever_setDataSourceAndHeaders(
+            env, thiz, path, NULL);
 }
 
 static void android_media_MediaMetadataRetriever_setDataSourceFD(JNIEnv *env, jobject thiz, jobject fileDescriptor, jlong offset, jlong length)
@@ -219,12 +311,14 @@
                         SkBitmap::kRGB_565_Config);
 
     size_t width, height;
+    bool swapWidthAndHeight = false;
     if (videoFrame->mRotationAngle == 90 || videoFrame->mRotationAngle == 270) {
-        width = videoFrame->mDisplayHeight;
-        height = videoFrame->mDisplayWidth;
+        width = videoFrame->mHeight;
+        height = videoFrame->mWidth;
+        swapWidthAndHeight = true;
     } else {
-        width = videoFrame->mDisplayWidth;
-        height = videoFrame->mDisplayHeight;
+        width = videoFrame->mWidth;
+        height = videoFrame->mHeight;
     }
 
     jobject jBitmap = env->CallStaticObjectMethod(
@@ -240,11 +334,30 @@
     bitmap->lockPixels();
     rotate((uint16_t*)bitmap->getPixels(),
            (uint16_t*)((char*)videoFrame + sizeof(VideoFrame)),
-           videoFrame->mDisplayWidth,
-           videoFrame->mDisplayHeight,
+           videoFrame->mWidth,
+           videoFrame->mHeight,
            videoFrame->mRotationAngle);
     bitmap->unlockPixels();
 
+    if (videoFrame->mDisplayWidth  != videoFrame->mWidth ||
+        videoFrame->mDisplayHeight != videoFrame->mHeight) {
+        size_t displayWidth = videoFrame->mDisplayWidth;
+        size_t displayHeight = videoFrame->mDisplayHeight;
+        if (swapWidthAndHeight) {
+            displayWidth = videoFrame->mDisplayHeight;
+            displayHeight = videoFrame->mDisplayWidth;
+        }
+        LOGV("Bitmap dimension is scaled from %dx%d to %dx%d",
+                width, height, displayWidth, displayHeight);
+        jobject scaledBitmap = env->CallStaticObjectMethod(fields.bitmapClazz,
+                                    fields.createScaledBitmapMethod,
+                                    jBitmap,
+                                    displayWidth,
+                                    displayHeight,
+                                    true);
+        return scaledBitmap;
+    }
+
     return jBitmap;
 }
 
@@ -352,6 +465,15 @@
                 "Can't find Bitmap.createBitmap(int, int, Config)  method");
         return;
     }
+    fields.createScaledBitmapMethod =
+            env->GetStaticMethodID(fields.bitmapClazz, "createScaledBitmap",
+                    "(Landroid/graphics/Bitmap;IIZ)"
+                    "Landroid/graphics/Bitmap;");
+    if (fields.createScaledBitmapMethod == NULL) {
+        jniThrowException(env, "java/lang/RuntimeException",
+                "Can't find Bitmap.createScaledBitmap(Bitmap, int, int, boolean)  method");
+        return;
+    }
     fields.nativeBitmap = env->GetFieldID(fields.bitmapClazz, "mNativeBitmap", "I");
     if (fields.nativeBitmap == NULL) {
         jniThrowException(env, "java/lang/RuntimeException",
@@ -388,6 +510,7 @@
 // JNI mapping between Java methods and native methods
 static JNINativeMethod nativeMethods[] = {
         {"setDataSource",   "(Ljava/lang/String;)V", (void *)android_media_MediaMetadataRetriever_setDataSource},
+        {"setDataSource",   "(Ljava/lang/String;Ljava/util/Map;)V", (void *)android_media_MediaMetadataRetriever_setDataSourceAndHeaders},
         {"setDataSource",   "(Ljava/io/FileDescriptor;JJ)V", (void *)android_media_MediaMetadataRetriever_setDataSourceFD},
         {"_getFrameAtTime", "(JI)Landroid/graphics/Bitmap;", (void *)android_media_MediaMetadataRetriever_getFrameAtTime},
         {"extractMetadata", "(I)Ljava/lang/String;", (void *)android_media_MediaMetadataRetriever_extractMetadata},
diff --git a/media/jni/android_media_MediaScanner.cpp b/media/jni/android_media_MediaScanner.cpp
index a5176fa..9d7bf2c 100644
--- a/media/jni/android_media_MediaScanner.cpp
+++ b/media/jni/android_media_MediaScanner.cpp
@@ -1,4 +1,4 @@
-/* //device/libs/media_jni/MediaScanner.cpp
+/*
 **
 ** Copyright 2007, The Android Open Source Project
 **
@@ -15,36 +15,37 @@
 ** limitations under the License.
 */
 
-#define LOG_TAG "MediaScanner"
-#include "utils/Log.h"
-
-#include <media/mediascanner.h>
-#include <stdio.h>
-#include <assert.h>
-#include <limits.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <cutils/properties.h>
+//#define LOG_NDEBUG 0
+#define LOG_TAG "MediaScannerJNI"
+#include <utils/Log.h>
 #include <utils/threads.h>
+#include <media/mediascanner.h>
+#include <media/stagefright/StagefrightMediaScanner.h>
 
 #include "jni.h"
 #include "JNIHelp.h"
 #include "android_runtime/AndroidRuntime.h"
 
-#include <media/stagefright/StagefrightMediaScanner.h>
-
-// ----------------------------------------------------------------------------
-
 using namespace android;
 
-// ----------------------------------------------------------------------------
+
+static const char* const kClassMediaScannerClient =
+        "android/media/MediaScannerClient";
+
+static const char* const kClassMediaScanner =
+        "android/media/MediaScanner";
+
+static const char* const kRunTimeException =
+        "java/lang/RuntimeException";
+
+static const char* const kIllegalArgumentException =
+        "java/lang/IllegalArgumentException";
 
 struct fields_t {
     jfieldID    context;
 };
 static fields_t fields;
-
-// ----------------------------------------------------------------------------
+static Mutex sLock;
 
 class MyMediaScannerClient : public MediaScannerClient
 {
@@ -56,33 +57,53 @@
             mHandleStringTagMethodID(0),
             mSetMimeTypeMethodID(0)
     {
-        jclass mediaScannerClientInterface = env->FindClass("android/media/MediaScannerClient");
+        LOGV("MyMediaScannerClient constructor");
+        jclass mediaScannerClientInterface =
+                env->FindClass(kClassMediaScannerClient);
+
         if (mediaScannerClientInterface == NULL) {
-            fprintf(stderr, "android/media/MediaScannerClient not found\n");
-        }
-        else {
-            mScanFileMethodID = env->GetMethodID(mediaScannerClientInterface, "scanFile",
-                                                     "(Ljava/lang/String;JJZ)V");
-            mHandleStringTagMethodID = env->GetMethodID(mediaScannerClientInterface, "handleStringTag",
-                                                     "(Ljava/lang/String;Ljava/lang/String;)V");
-            mSetMimeTypeMethodID = env->GetMethodID(mediaScannerClientInterface, "setMimeType",
-                                                     "(Ljava/lang/String;)V");
-            mAddNoMediaFolderMethodID = env->GetMethodID(mediaScannerClientInterface, "addNoMediaFolder",
-                                                     "(Ljava/lang/String;)V");
+            LOGE("Class %s not found", kClassMediaScannerClient);
+        } else {
+            mScanFileMethodID = env->GetMethodID(
+                                    mediaScannerClientInterface,
+                                    "scanFile",
+                                    "(Ljava/lang/String;JJZ)V");
+
+            mHandleStringTagMethodID = env->GetMethodID(
+                                    mediaScannerClientInterface,
+                                    "handleStringTag",
+                                    "(Ljava/lang/String;Ljava/lang/String;)V");
+
+            mSetMimeTypeMethodID = env->GetMethodID(
+                                    mediaScannerClientInterface,
+                                    "setMimeType",
+                                    "(Ljava/lang/String;)V");
+
+            mAddNoMediaFolderMethodID = env->GetMethodID(
+                                    mediaScannerClientInterface,
+                                    "addNoMediaFolder",
+                                    "(Ljava/lang/String;)V");
         }
     }
-    
+
     virtual ~MyMediaScannerClient()
     {
+        LOGV("MyMediaScannerClient destructor");
         mEnv->DeleteGlobalRef(mClient);
     }
-    
-    // returns true if it succeeded, false if an exception occured in the Java code
+
+    // Returns true if it succeeded, false if an exception occured
+    // in the Java code
     virtual bool scanFile(const char* path, long long lastModified,
             long long fileSize, bool isDirectory)
     {
+        LOGV("scanFile: path(%s), time(%lld), size(%lld) and isDir(%d)",
+            path, lastModified, fileSize, isDirectory);
+
         jstring pathStr;
-        if ((pathStr = mEnv->NewStringUTF(path)) == NULL) return false;
+        if ((pathStr = mEnv->NewStringUTF(path)) == NULL) {
+            return false;
+        }
 
         mEnv->CallVoidMethod(mClient, mScanFileMethodID, pathStr, lastModified,
                 fileSize, isDirectory);
@@ -91,25 +112,36 @@
         return (!mEnv->ExceptionCheck());
     }
 
-    // returns true if it succeeded, false if an exception occured in the Java code
+    // Returns true if it succeeded, false if an exception occured
+    // in the Java code
     virtual bool handleStringTag(const char* name, const char* value)
     {
+        LOGV("handleStringTag: name(%s) and value(%s)", name, value);
         jstring nameStr, valueStr;
-        if ((nameStr = mEnv->NewStringUTF(name)) == NULL) return false;
-        if ((valueStr = mEnv->NewStringUTF(value)) == NULL) return false;
+        if ((nameStr = mEnv->NewStringUTF(name)) == NULL) {
+            return false;
+        }
+        if ((valueStr = mEnv->NewStringUTF(value)) == NULL) {
+            return false;
+        }
 
-        mEnv->CallVoidMethod(mClient, mHandleStringTagMethodID, nameStr, valueStr);
+        mEnv->CallVoidMethod(
+            mClient, mHandleStringTagMethodID, nameStr, valueStr);
 
         mEnv->DeleteLocalRef(nameStr);
         mEnv->DeleteLocalRef(valueStr);
         return (!mEnv->ExceptionCheck());
     }
 
-    // returns true if it succeeded, false if an exception occured in the Java code
+    // Returns true if it succeeded, false if an exception occured
+    // in the Java code
     virtual bool setMimeType(const char* mimeType)
     {
+        LOGV("setMimeType: %s", mimeType);
         jstring mimeTypeStr;
-        if ((mimeTypeStr = mEnv->NewStringUTF(mimeType)) == NULL) return false;
+        if ((mimeTypeStr = mEnv->NewStringUTF(mimeType)) == NULL) {
+            return false;
+        }
 
         mEnv->CallVoidMethod(mClient, mSetMimeTypeMethodID, mimeTypeStr);
 
@@ -117,11 +149,15 @@
         return (!mEnv->ExceptionCheck());
     }
 
-    // returns true if it succeeded, false if an exception occured in the Java code
+    // Returns true if it succeeded, false if an exception occured
+    // in the Java code
     virtual bool addNoMediaFolder(const char* path)
     {
+        LOGV("addNoMediaFolder: path(%s)", path);
         jstring pathStr;
-        if ((pathStr = mEnv->NewStringUTF(path)) == NULL) return false;
+        if ((pathStr = mEnv->NewStringUTF(path)) == NULL) {
+            return false;
+        }
 
         mEnv->CallVoidMethod(mClient, mAddNoMediaFolderMethodID, pathStr);
 
@@ -133,33 +169,51 @@
 private:
     JNIEnv *mEnv;
     jobject mClient;
-    jmethodID mScanFileMethodID; 
-    jmethodID mHandleStringTagMethodID; 
+    jmethodID mScanFileMethodID;
+    jmethodID mHandleStringTagMethodID;
     jmethodID mSetMimeTypeMethodID;
     jmethodID mAddNoMediaFolderMethodID;
 };
 
 
-// ----------------------------------------------------------------------------
-
 static bool ExceptionCheck(void* env)
 {
+    LOGV("ExceptionCheck");
     return ((JNIEnv *)env)->ExceptionCheck();
 }
 
-static void
-android_media_MediaScanner_processDirectory(JNIEnv *env, jobject thiz, jstring path, jobject client)
+// Call this method with sLock hold
+static MediaScanner *getNativeScanner_l(JNIEnv* env, jobject thiz)
 {
-    MediaScanner *mp = (MediaScanner *)env->GetIntField(thiz, fields.context);
+    return (MediaScanner *) env->GetIntField(thiz, fields.context);
+}
+
+// Call this method with sLock hold
+static void setNativeScanner_l(JNIEnv* env, jobject thiz, MediaScanner *s)
+{
+    env->SetIntField(thiz, fields.context, (int)s);
+}
+
+static void
+android_media_MediaScanner_processDirectory(
+        JNIEnv *env, jobject thiz, jstring path, jobject client)
+{
+    LOGV("processDirectory");
+    Mutex::Autolock l(sLock);
+    MediaScanner *mp = getNativeScanner_l(env, thiz);
+    if (mp == NULL) {
+        jniThrowException(env, kRunTimeException, "No scanner available");
+        return;
+    }
 
     if (path == NULL) {
-        jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
+        jniThrowException(env, kIllegalArgumentException, NULL);
         return;
     }
 
     const char *pathStr = env->GetStringUTFChars(path, NULL);
     if (pathStr == NULL) {  // Out of memory
-        jniThrowException(env, "java/lang/RuntimeException", "Out of memory");
+        jniThrowException(env, kRunTimeException, "Out of memory");
         return;
     }
 
@@ -169,24 +223,35 @@
 }
 
 static void
-android_media_MediaScanner_processFile(JNIEnv *env, jobject thiz, jstring path, jstring mimeType, jobject client)
+android_media_MediaScanner_processFile(
+        JNIEnv *env, jobject thiz, jstring path,
+        jstring mimeType, jobject client)
 {
-    MediaScanner *mp = (MediaScanner *)env->GetIntField(thiz, fields.context);
+    LOGV("processFile");
+
+    // Lock already hold by processDirectory
+    MediaScanner *mp = getNativeScanner_l(env, thiz);
+    if (mp == NULL) {
+        jniThrowException(env, kRunTimeException, "No scanner available");
+        return;
+    }
 
     if (path == NULL) {
-        jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
+        jniThrowException(env, kIllegalArgumentException, NULL);
         return;
     }
-    
+
     const char *pathStr = env->GetStringUTFChars(path, NULL);
     if (pathStr == NULL) {  // Out of memory
-        jniThrowException(env, "java/lang/RuntimeException", "Out of memory");
+        jniThrowException(env, kRunTimeException, "Out of memory");
         return;
     }
-    const char *mimeTypeStr = (mimeType ? env->GetStringUTFChars(mimeType, NULL) : NULL);
+
+    const char *mimeTypeStr =
+        (mimeType ? env->GetStringUTFChars(mimeType, NULL) : NULL);
     if (mimeType && mimeTypeStr == NULL) {  // Out of memory
         env->ReleaseStringUTFChars(path, pathStr);
-        jniThrowException(env, "java/lang/RuntimeException", "Out of memory");
+        jniThrowException(env, kRunTimeException, "Out of memory");
         return;
     }
 
@@ -199,17 +264,24 @@
 }
 
 static void
-android_media_MediaScanner_setLocale(JNIEnv *env, jobject thiz, jstring locale)
+android_media_MediaScanner_setLocale(
+        JNIEnv *env, jobject thiz, jstring locale)
 {
-    MediaScanner *mp = (MediaScanner *)env->GetIntField(thiz, fields.context);
+    LOGV("setLocale");
+    Mutex::Autolock l(sLock);
+    MediaScanner *mp = getNativeScanner_l(env, thiz);
+    if (mp == NULL) {
+        jniThrowException(env, kRunTimeException, "No scanner available");
+        return;
+    }
 
     if (locale == NULL) {
-        jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
+        jniThrowException(env, kIllegalArgumentException, NULL);
         return;
     }
     const char *localeStr = env->GetStringUTFChars(locale, NULL);
     if (localeStr == NULL) {  // Out of memory
-        jniThrowException(env, "java/lang/RuntimeException", "Out of memory");
+        jniThrowException(env, kRunTimeException, "Out of memory");
         return;
     }
     mp->setLocale(localeStr);
@@ -218,12 +290,19 @@
 }
 
 static jbyteArray
-android_media_MediaScanner_extractAlbumArt(JNIEnv *env, jobject thiz, jobject fileDescriptor)
+android_media_MediaScanner_extractAlbumArt(
+        JNIEnv *env, jobject thiz, jobject fileDescriptor)
 {
-    MediaScanner *mp = (MediaScanner *)env->GetIntField(thiz, fields.context);
+    LOGV("extractAlbumArt");
+    Mutex::Autolock l(sLock);
+    MediaScanner *mp = getNativeScanner_l(env, thiz);
+    if (mp == NULL) {
+        jniThrowException(env, kRunTimeException, "No scanner available");
+        return NULL;
+    }
 
     if (fileDescriptor == NULL) {
-        jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
+        jniThrowException(env, kIllegalArgumentException, NULL);
         return NULL;
     }
 
@@ -233,14 +312,14 @@
         return NULL;
     }
     long len = *((long*)data);
-    
+
     jbyteArray array = env->NewByteArray(len);
     if (array != NULL) {
         jbyte* bytes = env->GetByteArrayElements(array, NULL);
         memcpy(bytes, data + 4, len);
         env->ReleaseByteArrayElements(array, bytes, 0);
     }
-    
+
 done:
     free(data);
     // if NewByteArray() returned NULL, an out-of-memory
@@ -256,17 +335,18 @@
 static void
 android_media_MediaScanner_native_init(JNIEnv *env)
 {
-     jclass clazz;
-
-    clazz = env->FindClass("android/media/MediaScanner");
+    LOGV("native_init");
+    jclass clazz = env->FindClass(kClassMediaScanner);
     if (clazz == NULL) {
-        jniThrowException(env, "java/lang/RuntimeException", "Can't find android/media/MediaScanner");
+        const char* err = "Can't find android/media/MediaScanner";
+        jniThrowException(env, kRunTimeException, err);
         return;
     }
 
     fields.context = env->GetFieldID(clazz, "mNativeContext", "I");
     if (fields.context == NULL) {
-        jniThrowException(env, "java/lang/RuntimeException", "Can't find MediaScanner.mNativeContext");
+        const char* err = "Can't find MediaScanner.mNativeContext";
+        jniThrowException(env, kRunTimeException, err);
         return;
     }
 }
@@ -274,10 +354,11 @@
 static void
 android_media_MediaScanner_native_setup(JNIEnv *env, jobject thiz)
 {
+    LOGV("native_setup");
     MediaScanner *mp = new StagefrightMediaScanner;
 
     if (mp == NULL) {
-        jniThrowException(env, "java/lang/RuntimeException", "Out of memory");
+        jniThrowException(env, kRunTimeException, "Out of memory");
         return;
     }
 
@@ -287,38 +368,66 @@
 static void
 android_media_MediaScanner_native_finalize(JNIEnv *env, jobject thiz)
 {
-    MediaScanner *mp = (MediaScanner *)env->GetIntField(thiz, fields.context);
-
-    //printf("##### android_media_MediaScanner_native_finalize: ctx=0x%p\n", ctx);
-
-    if (mp == 0)
+    LOGV("native_finalize");
+    Mutex::Autolock l(sLock);
+    MediaScanner *mp = getNativeScanner_l(env, thiz);
+    if (mp == 0) {
         return;
-
+    }
     delete mp;
+    setNativeScanner_l(env, thiz, 0);
 }
 
-// ----------------------------------------------------------------------------
-
 static JNINativeMethod gMethods[] = {
-    {"processDirectory",  "(Ljava/lang/String;Landroid/media/MediaScannerClient;)V",
-                                                        (void *)android_media_MediaScanner_processDirectory},
-    {"processFile",       "(Ljava/lang/String;Ljava/lang/String;Landroid/media/MediaScannerClient;)V",
-                                                        (void *)android_media_MediaScanner_processFile},
-    {"setLocale",         "(Ljava/lang/String;)V",      (void *)android_media_MediaScanner_setLocale},
-    {"extractAlbumArt",   "(Ljava/io/FileDescriptor;)[B",     (void *)android_media_MediaScanner_extractAlbumArt},
-    {"native_init",        "()V",                      (void *)android_media_MediaScanner_native_init},
-    {"native_setup",        "()V",                      (void *)android_media_MediaScanner_native_setup},
-    {"native_finalize",     "()V",                      (void *)android_media_MediaScanner_native_finalize},
-};
+    {
+        "processDirectory",
+        "(Ljava/lang/String;Landroid/media/MediaScannerClient;)V",
+        (void *)android_media_MediaScanner_processDirectory
+    },
 
-static const char* const kClassPathName = "android/media/MediaScanner";
+    {
+        "processFile",
+        "(Ljava/lang/String;Ljava/lang/String;Landroid/media/MediaScannerClient;)V",
+        (void *)android_media_MediaScanner_processFile
+    },
+
+    {
+        "setLocale",
+        "(Ljava/lang/String;)V",
+        (void *)android_media_MediaScanner_setLocale
+    },
+
+    {
+        "extractAlbumArt",
+        "(Ljava/io/FileDescriptor;)[B",
+        (void *)android_media_MediaScanner_extractAlbumArt
+    },
+
+    {
+        "native_init",
+        "()V",
+        (void *)android_media_MediaScanner_native_init
+    },
+
+    {
+        "native_setup",
+        "()V",
+        (void *)android_media_MediaScanner_native_setup
+    },
+
+    {
+        "native_finalize",
+        "()V",
+        (void *)android_media_MediaScanner_native_finalize
+    },
+};
 
 // This function only registers the native methods, and is called from
 // JNI_OnLoad in android_media_MediaPlayer.cpp
 int register_android_media_MediaScanner(JNIEnv *env)
 {
     return AndroidRuntime::registerNativeMethods(env,
-                "android/media/MediaScanner", gMethods, NELEM(gMethods));
+                kClassMediaScanner, gMethods, NELEM(gMethods));
 }
 
 
diff --git a/media/jni/android_mtp_MtpDevice.cpp b/media/jni/android_mtp_MtpDevice.cpp
index fd32665..f5fcb4e 100644
--- a/media/jni/android_mtp_MtpDevice.cpp
+++ b/media/jni/android_mtp_MtpDevice.cpp
@@ -311,9 +311,9 @@
     if (objectInfo->mName)
         env->SetObjectField(info, field_objectInfo_name, env->NewStringUTF(objectInfo->mName));
     if (objectInfo->mDateCreated)
-        env->SetLongField(info, field_objectInfo_dateCreated, objectInfo->mDateCreated);
+        env->SetLongField(info, field_objectInfo_dateCreated, objectInfo->mDateCreated * 1000LL);
     if (objectInfo->mDateModified)
-        env->SetLongField(info, field_objectInfo_dateModified, objectInfo->mDateModified);
+        env->SetLongField(info, field_objectInfo_dateModified, objectInfo->mDateModified * 1000LL);
     if (objectInfo->mKeywords)
         env->SetObjectField(info, field_objectInfo_keywords,
             env->NewStringUTF(objectInfo->mKeywords));
diff --git a/media/jni/audioeffect/android_media_AudioEffect.cpp b/media/jni/audioeffect/android_media_AudioEffect.cpp
index cb2f0f9..e71e727 100644
--- a/media/jni/audioeffect/android_media_AudioEffect.cpp
+++ b/media/jni/audioeffect/android_media_AudioEffect.cpp
@@ -570,12 +570,11 @@
 
 static jint
 android_media_AudioEffect_native_getParameter(JNIEnv *env,
-        jobject thiz, int psize, jbyteArray pJavaParam,
-        jintArray pJavaValueSize, jbyteArray pJavaValue) {
+        jobject thiz, jint psize, jbyteArray pJavaParam,
+        jint vsize, jbyteArray pJavaValue) {
     // retrieve the AudioEffect object
     jbyte* lpParam = NULL;
     jbyte* lpValue = NULL;
-    jbyte* lpValueSize = NULL;
     jint lStatus = AUDIOEFFECT_ERROR_BAD_VALUE;
     effect_param_t *p;
     int voffset;
@@ -589,7 +588,7 @@
         return AUDIOEFFECT_ERROR_NO_INIT;
     }
 
-    if (psize == 0 || pJavaValueSize == NULL || pJavaParam == NULL || pJavaValue == NULL) {
+    if (psize == 0 || vsize == 0 || pJavaParam == NULL || pJavaValue == NULL) {
         return AUDIOEFFECT_ERROR_BAD_VALUE;
     }
 
@@ -607,26 +606,18 @@
         goto getParameter_Exit;
     }
 
-    // get the pointer for the value size from the java array
-    lpValueSize = (jbyte *) env->GetPrimitiveArrayCritical(pJavaValueSize, NULL);
-    if (lpValueSize == NULL) {
-        LOGE("getParameter: Error retrieving value size pointer");
-        goto getParameter_Exit;
-    }
-
     voffset = ((psize - 1) / sizeof(int) + 1) * sizeof(int);
-    p = (effect_param_t *) malloc(sizeof(effect_param_t) + voffset
-            + lpValueSize[0]);
+    p = (effect_param_t *) malloc(sizeof(effect_param_t) + voffset + vsize);
     memcpy(p->data, lpParam, psize);
     p->psize = psize;
-    p->vsize = lpValueSize[0];
+    p->vsize = vsize;
 
     lStatus = lpAudioEffect->getParameter(p);
     if (lStatus == NO_ERROR) {
         lStatus = p->status;
         if (lStatus == NO_ERROR) {
             memcpy(lpValue, p->data + voffset, p->vsize);
-            lpValueSize[0] = p->vsize;
+            vsize = p->vsize;
         }
     }
 
@@ -640,19 +631,18 @@
     if (lpValue != NULL) {
         env->ReleasePrimitiveArrayCritical(pJavaValue, lpValue, 0);
     }
-    if (lpValueSize != NULL) {
-        env->ReleasePrimitiveArrayCritical(pJavaValueSize, lpValueSize, 0);
-    }
 
+    if (lStatus == NO_ERROR) {
+        return vsize;
+    }
     return translateError(lStatus);
 }
 
 static jint android_media_AudioEffect_native_command(JNIEnv *env, jobject thiz,
-        jint cmdCode, jint cmdSize, jbyteArray jCmdData, jintArray jReplySize,
+        jint cmdCode, jint cmdSize, jbyteArray jCmdData, jint replySize,
         jbyteArray jReplyData) {
     jbyte* pCmdData = NULL;
     jbyte* pReplyData = NULL;
-    jint* pReplySize = NULL;
     jint lStatus = AUDIOEFFECT_ERROR_BAD_VALUE;
 
     // retrieve the AudioEffect object
@@ -665,7 +655,7 @@
         return AUDIOEFFECT_ERROR_NO_INIT;
     }
 
-    if ((cmdSize != 0 && jCmdData == NULL) || (jReplySize != NULL && jReplyData == NULL)) {
+    if ((cmdSize != 0 && jCmdData == NULL) || (replySize != 0 && jReplyData == NULL)) {
         return AUDIOEFFECT_ERROR_BAD_VALUE;
     }
 
@@ -678,17 +668,8 @@
         }
     }
 
-    // get the pointer for the reply size from the java array
-    if (jReplySize != NULL) {
-        pReplySize = (jint *) env->GetPrimitiveArrayCritical(jReplySize, NULL);
-        if (pReplySize == NULL) {
-            LOGE("setParameter: Error retrieving reply pointer");
-            goto command_Exit;
-        }
-    }
-
     // get the pointer for the reply from the java array
-    if (pReplySize != NULL && pReplySize[0] != 0 && jReplyData != NULL) {
+    if (replySize != 0 && jReplyData != NULL) {
         pReplyData = (jbyte *) env->GetPrimitiveArrayCritical(jReplyData, NULL);
         if (pReplyData == NULL) {
             LOGE("setParameter: Error retrieving reply pointer");
@@ -699,7 +680,7 @@
     lStatus = translateError(lpAudioEffect->command((uint32_t)cmdCode,
                                                     (uint32_t)cmdSize,
                                                     pCmdData,
-                                                    (uint32_t *)pReplySize,
+                                                    (uint32_t *)&replySize,
                                                     pReplyData));
 
 command_Exit:
@@ -710,10 +691,10 @@
     if (pReplyData != NULL) {
         env->ReleasePrimitiveArrayCritical(jReplyData, pReplyData, 0);
     }
-    if (pReplySize != NULL) {
-        env->ReleasePrimitiveArrayCritical(jReplySize, pReplySize, 0);
-    }
 
+    if (lStatus == NO_ERROR) {
+        return replySize;
+    }
     return lStatus;
 }
 
@@ -803,8 +784,8 @@
     {"native_getEnabled",    "()Z",      (void *)android_media_AudioEffect_native_getEnabled},
     {"native_hasControl",    "()Z",      (void *)android_media_AudioEffect_native_hasControl},
     {"native_setParameter",  "(I[BI[B)I",  (void *)android_media_AudioEffect_native_setParameter},
-    {"native_getParameter",  "(I[B[I[B)I",  (void *)android_media_AudioEffect_native_getParameter},
-    {"native_command",       "(II[B[I[B)I", (void *)android_media_AudioEffect_native_command},
+    {"native_getParameter",  "(I[BI[B)I",  (void *)android_media_AudioEffect_native_getParameter},
+    {"native_command",       "(II[BI[B)I", (void *)android_media_AudioEffect_native_command},
     {"native_query_effects", "()[Ljava/lang/Object;", (void *)android_media_AudioEffect_native_queryEffects},
 };
 
diff --git a/media/jni/mediaeditor/Android.mk b/media/jni/mediaeditor/Android.mk
index 6a7116c..283b4ea 100755
--- a/media/jni/mediaeditor/Android.mk
+++ b/media/jni/mediaeditor/Android.mk
@@ -68,9 +68,6 @@
     -DUSE_STAGEFRIGHT_READERS \
     -DUSE_STAGEFRIGHT_3GPP_READER
 
-
-LOCAL_LDFLAGS += -fuse-ld=bfd
-
 LOCAL_STATIC_LIBRARIES := \
     libvideoeditor_core \
     libstagefright_color_conversion \
@@ -82,10 +79,6 @@
 
 LOCAL_MODULE:= libvideoeditor_jni
 
-# Don't prelink this library.  For more efficient code, you may want
-# to add this library to the prelink map and set this to true.
-LOCAL_PRELINK_MODULE := false
-
 LOCAL_MODULE_TAGS := optional
 
 include $(BUILD_SHARED_LIBRARY)
diff --git a/media/jni/mediaeditor/VideoEditorMain.cpp b/media/jni/mediaeditor/VideoEditorMain.cpp
index 8cda14e..11e2a5e 100755
--- a/media/jni/mediaeditor/VideoEditorMain.cpp
+++ b/media/jni/mediaeditor/VideoEditorMain.cpp
@@ -557,6 +557,10 @@
 
     Surface* const p = (Surface*)pEnv->GetIntField(surface, surface_native);
     sp<Surface> previewSurface = sp<Surface>(p);
+    // Validate the mSurface's mNativeSurface field
+    videoEditJava_checkAndThrowIllegalStateException(&needToBeLoaded, pEnv,
+                                                (NULL == previewSurface.get()),
+                                                "mNativeSurface is null");
 
     frameStr.pBuffer = M4OSA_NULL;
     frameStr.timeMs = 0;
@@ -634,6 +638,10 @@
 
     Surface* const p = (Surface*)pEnv->GetIntField(mSurface, surface_native);
     sp<Surface> previewSurface = sp<Surface>(p);
+    // Validate the mSurface's mNativeSurface field
+    videoEditJava_checkAndThrowIllegalStateException(&needToBeLoaded, pEnv,
+                                                (NULL == previewSurface.get()),
+                                                "mNativeSurface is null");
 
     /* Determine the total number of clips, total duration*/
     uiNumberOfClipsInStoryBoard = pContext->pEditSettings->uiClipNumber;
@@ -2058,6 +2066,10 @@
     Surface* const p = (Surface*)pEnv->GetIntField(mSurface, surface_native);
 
     sp<Surface> previewSurface = sp<Surface>(p);
+    // Validate the mSurface's mNativeSurface field
+    videoEditJava_checkAndThrowIllegalStateException(&needToBeLoaded, pEnv,
+                                                (NULL == previewSurface.get()),
+                                                "mNativeSurface is null");
 
     result =  pContext->mPreviewController->setSurface(previewSurface);
     videoEditJava_checkAndThrowRuntimeException(&needToBeLoaded, pEnv,
diff --git a/media/jni/mediaeditor/VideoEditorOsal.cpp b/media/jni/mediaeditor/VideoEditorOsal.cpp
index 423e93f..035f59a 100755
--- a/media/jni/mediaeditor/VideoEditorOsal.cpp
+++ b/media/jni/mediaeditor/VideoEditorOsal.cpp
@@ -207,6 +207,7 @@
     VIDEOEDIT_OSAL_RESULT_INIT(M4MCS_ERR_AUDIOBITRATE_TOO_HIGH                        ),
     VIDEOEDIT_OSAL_RESULT_INIT(M4MCS_ERR_OUTPUT_FILE_SIZE_TOO_SMALL                   ),
     VIDEOEDIT_OSAL_RESULT_INIT(M4MCS_ERR_NOMORE_SPACE                                 ),
+    VIDEOEDIT_OSAL_RESULT_INIT(M4MCS_ERR_FILE_DRM_PROTECTED                           ),
 
     // M4READER_Common.h
     VIDEOEDIT_OSAL_RESULT_INIT(M4ERR_READER_UNKNOWN_STREAM_TYPE                       ),
diff --git a/media/jni/mediaeditor/VideoEditorPropertiesMain.cpp b/media/jni/mediaeditor/VideoEditorPropertiesMain.cpp
index 73a7c9c..3b795ce 100755
--- a/media/jni/mediaeditor/VideoEditorPropertiesMain.cpp
+++ b/media/jni/mediaeditor/VideoEditorPropertiesMain.cpp
@@ -204,10 +204,17 @@
                 result = getClipProperties(
                         pEnv, thiz, pFile, clipType, pClipProperties);
 
-                // Check if the creation succeeded.
-                videoEditJava_checkAndThrowIllegalArgumentException(
-                        &gotten, pEnv,(M4NO_ERROR != result),
-                        "Invalid File or File not found");
+                if (M4MCS_ERR_FILE_DRM_PROTECTED == result) {
+                    // Check if the creation succeeded.
+                    videoEditJava_checkAndThrowIllegalArgumentException(
+                            &gotten, pEnv,(M4NO_ERROR != result),
+                            "Invalid File - DRM Protected ");
+                } else {
+                    // Check if the creation succeeded.
+                    videoEditJava_checkAndThrowIllegalArgumentException(
+                            &gotten, pEnv,(M4NO_ERROR != result),
+                            "Invalid File or File not found ");
+                }
 
                 /**
                  * Max resolution supported is 1280 x 720.
diff --git a/media/libeffects/lvm/lib/Android.mk b/media/libeffects/lvm/lib/Android.mk
index ff34707..f49267e 100644
--- a/media/libeffects/lvm/lib/Android.mk
+++ b/media/libeffects/lvm/lib/Android.mk
@@ -105,7 +105,7 @@
 
 LOCAL_MODULE:= libmusicbundle
 
-LOCAL_PRELINK_MODULE := false
+
 
 LOCAL_C_INCLUDES += \
     $(LOCAL_PATH)/Eq/lib \
@@ -168,7 +168,7 @@
 
 LOCAL_MODULE:= libreverb
 
-LOCAL_PRELINK_MODULE := false
+
 
 LOCAL_C_INCLUDES += \
     $(LOCAL_PATH)/Reverb/lib \
diff --git a/media/libeffects/lvm/wrapper/Android.mk b/media/libeffects/lvm/wrapper/Android.mk
index 2e9b9b4..99cfdfa 100644
--- a/media/libeffects/lvm/wrapper/Android.mk
+++ b/media/libeffects/lvm/wrapper/Android.mk
@@ -13,7 +13,7 @@
 
 LOCAL_MODULE_PATH := $(TARGET_OUT_SHARED_LIBRARIES)/soundfx
 
-LOCAL_PRELINK_MODULE := false
+
 
 LOCAL_STATIC_LIBRARIES += libmusicbundle
 
@@ -47,7 +47,7 @@
 
 LOCAL_MODULE_PATH := $(TARGET_OUT_SHARED_LIBRARIES)/soundfx
 
-LOCAL_PRELINK_MODULE := false
+
 
 LOCAL_STATIC_LIBRARIES += libreverb
 
diff --git a/media/libeffects/visualizer/Android.mk b/media/libeffects/visualizer/Android.mk
index e6ff654..3a0f438 100644
--- a/media/libeffects/visualizer/Android.mk
+++ b/media/libeffects/visualizer/Android.mk
@@ -25,6 +25,6 @@
 LOCAL_C_INCLUDES := \
 	$(call include-path-for, graphics corecg)
 
-LOCAL_PRELINK_MODULE := false
+
 
 include $(BUILD_SHARED_LIBRARY)
diff --git a/media/libmedia/Android.mk b/media/libmedia/Android.mk
index fd4c6c6..a04fbd2 100644
--- a/media/libmedia/Android.mk
+++ b/media/libmedia/Android.mk
@@ -33,6 +33,7 @@
     IEffectClient.cpp \
     AudioEffect.cpp \
     Visualizer.cpp \
+    MemoryLeakTrackUtil.cpp \
     fixedfft.cpp.arm
 
 LOCAL_SHARED_LIBRARIES := \
diff --git a/media/libmedia/AudioRecord.cpp b/media/libmedia/AudioRecord.cpp
index 1d6ffa0..cee1c75 100644
--- a/media/libmedia/AudioRecord.cpp
+++ b/media/libmedia/AudioRecord.cpp
@@ -128,6 +128,9 @@
 {
 
     LOGV("set(): sampleRate %d, channels %d, frameCount %d",sampleRate, channels, frameCount);
+
+    AutoMutex lock(mLock);
+
     if (mAudioRecord != 0) {
         return INVALID_OPERATION;
     }
@@ -183,7 +186,7 @@
     mSessionId = sessionId;
 
     // create the IAudioRecord
-    status = openRecord(sampleRate, format, channelCount,
+    status = openRecord_l(sampleRate, format, channelCount,
                         frameCount, flags, input);
     if (status != NO_ERROR) {
         return status;
@@ -282,21 +285,31 @@
      }
 
     AutoMutex lock(mLock);
+    // acquire a strong reference on the IAudioRecord and IMemory so that they cannot be destroyed
+    // while we are accessing the cblk
+    sp <IAudioRecord> audioRecord = mAudioRecord;
+    sp <IMemory> iMem = mCblkMemory;
+    audio_track_cblk_t* cblk = mCblk;
     if (mActive == 0) {
         mActive = 1;
-        ret = mAudioRecord->start();
-        if (ret == DEAD_OBJECT) {
-            LOGV("start() dead IAudioRecord: creating a new one");
-            ret = openRecord(mCblk->sampleRate, mFormat, mChannelCount,
-                    mFrameCount, mFlags, getInput());
-            if (ret == NO_ERROR) {
-                ret = mAudioRecord->start();
+
+        cblk->lock.lock();
+        if (!(cblk->flags & CBLK_INVALID_MSK)) {
+            cblk->lock.unlock();
+            ret = mAudioRecord->start();
+            cblk->lock.lock();
+            if (ret == DEAD_OBJECT) {
+                cblk->flags |= CBLK_INVALID_MSK;
             }
         }
+        if (cblk->flags & CBLK_INVALID_MSK) {
+            ret = restoreRecord_l(cblk);
+        }
+        cblk->lock.unlock();
         if (ret == NO_ERROR) {
-            mNewPosition = mCblk->user + mUpdatePeriod;
-            mCblk->bufferTimeoutMs = MAX_RUN_TIMEOUT_MS;
-            mCblk->waitTimeMs = 0;
+            mNewPosition = cblk->user + mUpdatePeriod;
+            cblk->bufferTimeoutMs = MAX_RUN_TIMEOUT_MS;
+            cblk->waitTimeMs = 0;
             if (t != 0) {
                t->run("ClientRecordThread", THREAD_PRIORITY_AUDIO_CLIENT);
             } else {
@@ -353,6 +366,7 @@
 
 uint32_t AudioRecord::getSampleRate()
 {
+    AutoMutex lock(mLock);
     return mCblk->sampleRate;
 }
 
@@ -400,6 +414,7 @@
 {
     if (position == 0) return BAD_VALUE;
 
+    AutoMutex lock(mLock);
     *position = mCblk->user;
 
     return NO_ERROR;
@@ -415,7 +430,8 @@
 
 // -------------------------------------------------------------------------
 
-status_t AudioRecord::openRecord(
+// must be called with mLock held
+status_t AudioRecord::openRecord_l(
         uint32_t sampleRate,
         int format,
         int channelCount,
@@ -459,6 +475,7 @@
 
 status_t AudioRecord::obtainBuffer(Buffer* audioBuffer, int32_t waitCount)
 {
+    AutoMutex lock(mLock);
     int active;
     status_t result;
     audio_track_cblk_t* cblk = mCblk;
@@ -483,7 +500,19 @@
                 cblk->lock.unlock();
                 return WOULD_BLOCK;
             }
-            result = cblk->cv.waitRelative(cblk->lock, milliseconds(waitTimeMs));
+            if (!(cblk->flags & CBLK_INVALID_MSK)) {
+                mLock.unlock();
+                result = cblk->cv.waitRelative(cblk->lock, milliseconds(waitTimeMs));
+                cblk->lock.unlock();
+                mLock.lock();
+                if (mActive == 0) {
+                    return status_t(STOPPED);
+                }
+                cblk->lock.lock();
+            }
+            if (cblk->flags & CBLK_INVALID_MSK) {
+                goto create_new_record;
+            }
             if (__builtin_expect(result!=NO_ERROR, false)) {
                 cblk->waitTimeMs += waitTimeMs;
                 if (cblk->waitTimeMs >= cblk->bufferTimeoutMs) {
@@ -491,16 +520,17 @@
                             "user=%08x, server=%08x", cblk->user, cblk->server);
                     cblk->lock.unlock();
                     result = mAudioRecord->start();
-                    if (result == DEAD_OBJECT) {
-                        LOGW("obtainBuffer() dead IAudioRecord: creating a new one");
-                        result = openRecord(cblk->sampleRate, mFormat, mChannelCount,
-                                            mFrameCount, mFlags, getInput());
-                        if (result == NO_ERROR) {
-                            cblk = mCblk;
-                            mAudioRecord->start();
-                        }
-                    }
                     cblk->lock.lock();
+                    if (result == DEAD_OBJECT) {
+                        cblk->flags |= CBLK_INVALID_MSK;
+create_new_record:
+                        result = AudioRecord::restoreRecord_l(cblk);
+                    }
+                    if (result != NO_ERROR) {
+                        LOGW("obtainBuffer create Track error %d", result);
+                        cblk->lock.unlock();
+                        return result;
+                    }
                     cblk->waitTimeMs = 0;
                 }
                 if (--waitCount == 0) {
@@ -540,12 +570,19 @@
 
 void AudioRecord::releaseBuffer(Buffer* audioBuffer)
 {
-    audio_track_cblk_t* cblk = mCblk;
-    cblk->stepUser(audioBuffer->frameCount);
+    AutoMutex lock(mLock);
+    mCblk->stepUser(audioBuffer->frameCount);
 }
 
 audio_io_handle_t AudioRecord::getInput()
 {
+    AutoMutex lock(mLock);
+    return getInput_l();
+}
+
+// must be called with mLock held
+audio_io_handle_t AudioRecord::getInput_l()
+{
     mInput = AudioSystem::getInput(mInputSource,
                                 mCblk->sampleRate,
                                 mFormat, mChannels,
@@ -573,6 +610,12 @@
         return BAD_VALUE;
     }
 
+    mLock.lock();
+    // acquire a strong reference on the IAudioRecord and IMemory so that they cannot be destroyed
+    // while we are accessing the cblk
+    sp <IAudioRecord> audioRecord = mAudioRecord;
+    sp <IMemory> iMem = mCblkMemory;
+    mLock.unlock();
 
     do {
 
@@ -613,9 +656,17 @@
     uint32_t frames = mRemainingFrames;
     size_t readSize;
 
+    mLock.lock();
+    // acquire a strong reference on the IAudioRecord and IMemory so that they cannot be destroyed
+    // while we are accessing the cblk
+    sp <IAudioRecord> audioRecord = mAudioRecord;
+    sp <IMemory> iMem = mCblkMemory;
+    audio_track_cblk_t* cblk = mCblk;
+    mLock.unlock();
+
     // Manage marker callback
     if (!mMarkerReached && (mMarkerPosition > 0)) {
-        if (mCblk->user >= mMarkerPosition) {
+        if (cblk->user >= mMarkerPosition) {
             mCbf(EVENT_MARKER, mUserData, (void *)&mMarkerPosition);
             mMarkerReached = true;
         }
@@ -623,7 +674,7 @@
 
     // Manage new position callback
     if (mUpdatePeriod > 0) {
-        while (mCblk->user >= mNewPosition) {
+        while (cblk->user >= mNewPosition) {
             mCbf(EVENT_NEW_POS, mUserData, (void *)&mNewPosition);
             mNewPosition += mUpdatePeriod;
         }
@@ -669,11 +720,14 @@
 
 
     // Manage overrun callback
-    if (mActive && (mCblk->framesAvailable_l() == 0)) {
-        LOGV("Overrun user: %x, server: %x, flags %04x", mCblk->user, mCblk->server, mCblk->flags);
-        if ((mCblk->flags & CBLK_UNDERRUN_MSK) == CBLK_UNDERRUN_OFF) {
+    if (mActive && (cblk->framesAvailable() == 0)) {
+        LOGV("Overrun user: %x, server: %x, flags %04x", cblk->user, cblk->server, cblk->flags);
+        AutoMutex _l(cblk->lock);
+        if ((cblk->flags & CBLK_UNDERRUN_MSK) == CBLK_UNDERRUN_OFF) {
+            cblk->flags |= CBLK_UNDERRUN_ON;
+            cblk->lock.unlock();
             mCbf(EVENT_OVERRUN, mUserData, 0);
-            mCblk->flags |= CBLK_UNDERRUN_ON;
+            cblk->lock.lock();
         }
     }
 
@@ -685,6 +739,69 @@
     return true;
 }
 
+// must be called with mLock and cblk.lock held. Callers must also hold strong references on
+// the IAudioRecord and IMemory in case they are recreated here.
+// If the IAudioRecord is successfully restored, the cblk pointer is updated
+status_t AudioRecord::restoreRecord_l(audio_track_cblk_t*& cblk)
+{
+    status_t result;
+
+    if (!(cblk->flags & CBLK_RESTORING_MSK)) {
+        LOGW("dead IAudioRecord, creating a new one");
+
+        cblk->flags |= CBLK_RESTORING_ON;
+        // signal old cblk condition so that other threads waiting for available buffers stop
+        // waiting now
+        cblk->cv.broadcast();
+        cblk->lock.unlock();
+
+        // if the new IAudioRecord is created, openRecord_l() will modify the
+        // following member variables: mAudioRecord, mCblkMemory and mCblk.
+        // It will also delete the strong references on previous IAudioRecord and IMemory
+        result = openRecord_l(cblk->sampleRate, mFormat, mChannelCount,
+                mFrameCount, mFlags, getInput_l());
+        if (result == NO_ERROR) {
+            result = mAudioRecord->start();
+        }
+        if (result != NO_ERROR) {
+            mActive = false;
+        }
+
+        // signal old cblk condition for other threads waiting for restore completion
+        cblk->lock.lock();
+        cblk->flags |= CBLK_RESTORED_MSK;
+        cblk->cv.broadcast();
+        cblk->lock.unlock();
+    } else {
+        if (!(cblk->flags & CBLK_RESTORED_MSK)) {
+            LOGW("dead IAudioRecord, waiting for a new one to be created");
+            mLock.unlock();
+            result = cblk->cv.waitRelative(cblk->lock, milliseconds(RESTORE_TIMEOUT_MS));
+            cblk->lock.unlock();
+            mLock.lock();
+        } else {
+            LOGW("dead IAudioRecord, already restored");
+            result = NO_ERROR;
+            cblk->lock.unlock();
+        }
+        if (result != NO_ERROR || mActive == 0) {
+            result = status_t(STOPPED);
+        }
+    }
+    LOGV("restoreRecord_l() status %d mActive %d cblk %p, old cblk %p flags %08x old flags %08x",
+         result, mActive, mCblk, cblk, mCblk->flags, cblk->flags);
+
+    if (result == NO_ERROR) {
+        // from now on we switch to the newly created cblk
+        cblk = mCblk;
+    }
+    cblk->lock.lock();
+
+    LOGW_IF(result != NO_ERROR, "restoreRecord_l() error %d", result);
+
+    return result;
+}
+
 // =========================================================================
 
 AudioRecord::ClientRecordThread::ClientRecordThread(AudioRecord& receiver, bool bCanCallJava)
diff --git a/media/libmedia/AudioTrack.cpp b/media/libmedia/AudioTrack.cpp
index c1bed59..fb2ee0f 100644
--- a/media/libmedia/AudioTrack.cpp
+++ b/media/libmedia/AudioTrack.cpp
@@ -148,6 +148,7 @@
 
     LOGV_IF(sharedBuffer != 0, "sharedBuffer: %p, size: %d", sharedBuffer->pointer(), sharedBuffer->size());
 
+    AutoMutex lock(mLock);
     if (mAudioTrack != 0) {
         LOGE("Track already in use");
         return INVALID_OPERATION;
@@ -211,8 +212,15 @@
     mAuxEffectId = 0;
 
     // create the IAudioTrack
-    status_t status = createTrack(streamType, sampleRate, format, channelCount,
-                                  frameCount, flags, sharedBuffer, output, true);
+    status_t status = createTrack_l(streamType,
+                                  sampleRate,
+                                  format,
+                                  channelCount,
+                                  frameCount,
+                                  flags,
+                                  sharedBuffer,
+                                  output,
+                                  true);
 
     if (status != NO_ERROR) {
         return status;
@@ -312,37 +320,38 @@
      }
 
     AutoMutex lock(mLock);
+    // acquire a strong reference on the IMemory and IAudioTrack so that they cannot be destroyed
+    // while we are accessing the cblk
+    sp <IAudioTrack> audioTrack = mAudioTrack;
+    sp <IMemory> iMem = mCblkMemory;
+    audio_track_cblk_t* cblk = mCblk;
+
     if (mActive == 0) {
         mActive = 1;
-        mNewPosition = mCblk->server + mUpdatePeriod;
-        mCblk->bufferTimeoutMs = MAX_STARTUP_TIMEOUT_MS;
-        mCblk->waitTimeMs = 0;
-        mCblk->flags &= ~CBLK_DISABLED_ON;
+        mNewPosition = cblk->server + mUpdatePeriod;
+        cblk->lock.lock();
+        cblk->bufferTimeoutMs = MAX_STARTUP_TIMEOUT_MS;
+        cblk->waitTimeMs = 0;
+        cblk->flags &= ~CBLK_DISABLED_ON;
         if (t != 0) {
            t->run("AudioTrackThread", THREAD_PRIORITY_AUDIO_CLIENT);
         } else {
             setpriority(PRIO_PROCESS, 0, THREAD_PRIORITY_AUDIO_CLIENT);
         }
 
-        if (mCblk->flags & CBLK_INVALID_MSK) {
-            LOGW("start() track %p invalidated, creating a new one", this);
-            // no need to clear the invalid flag as this cblk will not be used anymore
-            // force new track creation
-            status = DEAD_OBJECT;
-        } else {
+        LOGV("start %p before lock cblk %p", this, mCblk);
+        if (!(cblk->flags & CBLK_INVALID_MSK)) {
+            cblk->lock.unlock();
             status = mAudioTrack->start();
-        }
-        if (status == DEAD_OBJECT) {
-            LOGV("start() dead IAudioTrack: creating a new one");
-            status = createTrack(mStreamType, mCblk->sampleRate, mFormat, mChannelCount,
-                                 mFrameCount, mFlags, mSharedBuffer, getOutput(), false);
-            if (status == NO_ERROR) {
-                status = mAudioTrack->start();
-                if (status == NO_ERROR) {
-                    mNewPosition = mCblk->server + mUpdatePeriod;
-                }
+            cblk->lock.lock();
+            if (status == DEAD_OBJECT) {
+                cblk->flags |= CBLK_INVALID_MSK;
             }
         }
+        if (cblk->flags & CBLK_INVALID_MSK) {
+            status = restoreTrack_l(cblk, true);
+        }
+        cblk->lock.unlock();
         if (status != NO_ERROR) {
             LOGV("start() failed");
             mActive = 0;
@@ -375,14 +384,14 @@
         mAudioTrack->stop();
         // Cancel loops (If we are in the middle of a loop, playback
         // would not stop until loopCount reaches 0).
-        setLoop(0, 0, 0);
+        setLoop_l(0, 0, 0);
         // the playback head position will reset to 0, so if a marker is set, we need
         // to activate it again
         mMarkerReached = false;
         // Force flush if a shared buffer is used otherwise audioflinger
         // will not stop before end of buffer is reached.
         if (mSharedBuffer != 0) {
-            flush();
+            flush_l();
         }
         if (t != 0) {
             t->requestExit();
@@ -403,6 +412,13 @@
 
 void AudioTrack::flush()
 {
+    AutoMutex lock(mLock);
+    flush_l();
+}
+
+// must be called with mLock held
+void AudioTrack::flush_l()
+{
     LOGV("flush");
 
     // clear playback marker and periodic update counter
@@ -445,6 +461,7 @@
         return BAD_VALUE;
     }
 
+    AutoMutex lock(mLock);
     mVolume[LEFT] = left;
     mVolume[RIGHT] = right;
 
@@ -470,6 +487,7 @@
     if (level > 1.0f) {
         return BAD_VALUE;
     }
+    AutoMutex lock(mLock);
 
     mSendLevel = level;
 
@@ -495,17 +513,26 @@
     // Resampler implementation limits input sampling rate to 2 x output sampling rate.
     if (rate <= 0 || rate > afSamplingRate*2 ) return BAD_VALUE;
 
+    AutoMutex lock(mLock);
     mCblk->sampleRate = rate;
     return NO_ERROR;
 }
 
 uint32_t AudioTrack::getSampleRate()
 {
+    AutoMutex lock(mLock);
     return mCblk->sampleRate;
 }
 
 status_t AudioTrack::setLoop(uint32_t loopStart, uint32_t loopEnd, int loopCount)
 {
+    AutoMutex lock(mLock);
+    return setLoop_l(loopStart, loopEnd, loopCount);
+}
+
+// must be called with mLock held
+status_t AudioTrack::setLoop_l(uint32_t loopStart, uint32_t loopEnd, int loopCount)
+{
     audio_track_cblk_t* cblk = mCblk;
 
     Mutex::Autolock _l(cblk->lock);
@@ -519,12 +546,13 @@
     }
 
     if (loopStart >= loopEnd ||
-        loopEnd - loopStart > cblk->frameCount) {
+        loopEnd - loopStart > cblk->frameCount ||
+        cblk->server > loopStart) {
         LOGE("setLoop invalid value: loopStart %d, loopEnd %d, loopCount %d, framecount %d, user %d", loopStart, loopEnd, loopCount, cblk->frameCount, cblk->user);
         return BAD_VALUE;
     }
 
-    if ((mSharedBuffer != 0) && (loopEnd   > cblk->frameCount)) {
+    if ((mSharedBuffer != 0) && (loopEnd > cblk->frameCount)) {
         LOGE("setLoop invalid value: loop markers beyond data: loopStart %d, loopEnd %d, framecount %d",
             loopStart, loopEnd, cblk->frameCount);
         return BAD_VALUE;
@@ -540,6 +568,7 @@
 
 status_t AudioTrack::getLoop(uint32_t *loopStart, uint32_t *loopEnd, int *loopCount)
 {
+    AutoMutex lock(mLock);
     if (loopStart != 0) {
         *loopStart = mCblk->loopStart;
     }
@@ -599,6 +628,7 @@
 
 status_t AudioTrack::setPosition(uint32_t position)
 {
+    AutoMutex lock(mLock);
     Mutex::Autolock _l(mCblk->lock);
 
     if (!stopped()) return INVALID_OPERATION;
@@ -614,7 +644,7 @@
 status_t AudioTrack::getPosition(uint32_t *position)
 {
     if (position == 0) return BAD_VALUE;
-
+    AutoMutex lock(mLock);
     *position = mCblk->server;
 
     return NO_ERROR;
@@ -622,9 +652,11 @@
 
 status_t AudioTrack::reload()
 {
+    AutoMutex lock(mLock);
+
     if (!stopped()) return INVALID_OPERATION;
 
-    flush();
+    flush_l();
 
     mCblk->stepUser(mCblk->frameCount);
 
@@ -633,6 +665,13 @@
 
 audio_io_handle_t AudioTrack::getOutput()
 {
+    AutoMutex lock(mLock);
+    return getOutput_l();
+}
+
+// must be called with mLock held
+audio_io_handle_t AudioTrack::getOutput_l()
+{
     return AudioSystem::getOutput((AudioSystem::stream_type)mStreamType,
             mCblk->sampleRate, mFormat, mChannels, (AudioSystem::output_flags)mFlags);
 }
@@ -654,7 +693,8 @@
 
 // -------------------------------------------------------------------------
 
-status_t AudioTrack::createTrack(
+// must be called with mLock held
+status_t AudioTrack::createTrack_l(
         int streamType,
         uint32_t sampleRate,
         int format,
@@ -774,6 +814,7 @@
 
 status_t AudioTrack::obtainBuffer(Buffer* audioBuffer, int32_t waitCount)
 {
+    AutoMutex lock(mLock);
     int active;
     status_t result;
     audio_track_cblk_t* cblk = mCblk;
@@ -785,6 +826,12 @@
 
     uint32_t framesAvail = cblk->framesAvailable();
 
+    cblk->lock.lock();
+    if (cblk->flags & CBLK_INVALID_MSK) {
+        goto create_new_track;
+    }
+    cblk->lock.unlock();
+
     if (framesAvail == 0) {
         cblk->lock.lock();
         goto start_loop_here;
@@ -800,12 +847,17 @@
                 return WOULD_BLOCK;
             }
             if (!(cblk->flags & CBLK_INVALID_MSK)) {
+                mLock.unlock();
                 result = cblk->cv.waitRelative(cblk->lock, milliseconds(waitTimeMs));
-            }
-            if (cblk->flags & CBLK_INVALID_MSK) {
-                LOGW("obtainBuffer() track %p invalidated, creating a new one", this);
-                // no need to clear the invalid flag as this cblk will not be used anymore
                 cblk->lock.unlock();
+                mLock.lock();
+                if (mActive == 0) {
+                    return status_t(STOPPED);
+                }
+                cblk->lock.lock();
+            }
+
+            if (cblk->flags & CBLK_INVALID_MSK) {
                 goto create_new_track;
             }
             if (__builtin_expect(result!=NO_ERROR, false)) {
@@ -819,18 +871,17 @@
                         //unlock cblk mutex before calling mAudioTrack->start() (see issue #1617140)
                         cblk->lock.unlock();
                         result = mAudioTrack->start();
-                        if (result == DEAD_OBJECT) {
-                            LOGW("obtainBuffer() dead IAudioTrack: creating a new one");
-create_new_track:
-                            result = createTrack(mStreamType, cblk->sampleRate, mFormat, mChannelCount,
-                                                 mFrameCount, mFlags, mSharedBuffer, getOutput(), false);
-                            if (result == NO_ERROR) {
-                                cblk = mCblk;
-                                cblk->bufferTimeoutMs = MAX_RUN_TIMEOUT_MS;
-                                mAudioTrack->start();
-                            }
-                        }
                         cblk->lock.lock();
+                        if (result == DEAD_OBJECT) {
+                            cblk->flags |= CBLK_INVALID_MSK;
+create_new_track:
+                            result = restoreTrack_l(cblk, false);
+                        }
+                        if (result != NO_ERROR) {
+                            LOGW("obtainBuffer create Track error %d", result);
+                            cblk->lock.unlock();
+                            return result;
+                        }
                     }
                     cblk->waitTimeMs = 0;
                 }
@@ -848,10 +899,15 @@
     }
 
     // restart track if it was disabled by audioflinger due to previous underrun
-    if (cblk->flags & CBLK_DISABLED_MSK) {
-        cblk->flags &= ~CBLK_DISABLED_ON;
-        LOGW("obtainBuffer() track %p disabled, restarting", this);
-        mAudioTrack->start();
+    if (mActive && (cblk->flags & CBLK_DISABLED_MSK)) {
+        AutoMutex _l(cblk->lock);
+        if (mActive && (cblk->flags & CBLK_DISABLED_MSK)) {
+            cblk->flags &= ~CBLK_DISABLED_ON;
+            cblk->lock.unlock();
+            LOGW("obtainBuffer() track %p disabled, restarting", this);
+            mAudioTrack->start();
+            cblk->lock.lock();
+        }
     }
 
     cblk->waitTimeMs = 0;
@@ -883,8 +939,8 @@
 
 void AudioTrack::releaseBuffer(Buffer* audioBuffer)
 {
-    audio_track_cblk_t* cblk = mCblk;
-    cblk->stepUser(audioBuffer->frameCount);
+    AutoMutex lock(mLock);
+    mCblk->stepUser(audioBuffer->frameCount);
 }
 
 // -------------------------------------------------------------------------
@@ -903,12 +959,20 @@
 
     LOGV("write %p: %d bytes, mActive=%d", this, userSize, mActive);
 
+    // acquire a strong reference on the IMemory and IAudioTrack so that they cannot be destroyed
+    // while we are accessing the cblk
+    mLock.lock();
+    sp <IAudioTrack> audioTrack = mAudioTrack;
+    sp <IMemory> iMem = mCblkMemory;
+    mLock.unlock();
+
     ssize_t written = 0;
     const int8_t *src = (const int8_t *)buffer;
     Buffer audioBuffer;
+    size_t frameSz = (size_t)frameSize();
 
     do {
-        audioBuffer.frameCount = userSize/frameSize();
+        audioBuffer.frameCount = userSize/frameSz;
 
         // Calling obtainBuffer() with a negative wait count causes
         // an (almost) infinite wait time.
@@ -940,7 +1004,7 @@
         written += toWrite;
 
         releaseBuffer(&audioBuffer);
-    } while (userSize);
+    } while (userSize >= frameSz);
 
     return written;
 }
@@ -953,21 +1017,32 @@
     uint32_t frames;
     size_t writtenSize;
 
+    mLock.lock();
+    // acquire a strong reference on the IMemory and IAudioTrack so that they cannot be destroyed
+    // while we are accessing the cblk
+    sp <IAudioTrack> audioTrack = mAudioTrack;
+    sp <IMemory> iMem = mCblkMemory;
+    audio_track_cblk_t* cblk = mCblk;
+    mLock.unlock();
+
     // Manage underrun callback
-    if (mActive && (mCblk->framesReady() == 0)) {
-        LOGV("Underrun user: %x, server: %x, flags %04x", mCblk->user, mCblk->server, mCblk->flags);
-        if ((mCblk->flags & CBLK_UNDERRUN_MSK) == CBLK_UNDERRUN_OFF) {
+    if (mActive && (cblk->framesReady() == 0)) {
+        LOGV("Underrun user: %x, server: %x, flags %04x", cblk->user, cblk->server, cblk->flags);
+        AutoMutex _l(cblk->lock);
+        if ((cblk->flags & CBLK_UNDERRUN_MSK) == CBLK_UNDERRUN_OFF) {
+            cblk->flags |= CBLK_UNDERRUN_ON;
+            cblk->lock.unlock();
             mCbf(EVENT_UNDERRUN, mUserData, 0);
-            if (mCblk->server == mCblk->frameCount) {
+            if (cblk->server == cblk->frameCount) {
                 mCbf(EVENT_BUFFER_END, mUserData, 0);
             }
-            mCblk->flags |= CBLK_UNDERRUN_ON;
+            cblk->lock.lock();
             if (mSharedBuffer != 0) return false;
         }
     }
 
     // Manage loop end callback
-    while (mLoopCount > mCblk->loopCount) {
+    while (mLoopCount > cblk->loopCount) {
         int loopCount = -1;
         mLoopCount--;
         if (mLoopCount >= 0) loopCount = mLoopCount;
@@ -977,7 +1052,7 @@
 
     // Manage marker callback
     if (!mMarkerReached && (mMarkerPosition > 0)) {
-        if (mCblk->server >= mMarkerPosition) {
+        if (cblk->server >= mMarkerPosition) {
             mCbf(EVENT_MARKER, mUserData, (void *)&mMarkerPosition);
             mMarkerReached = true;
         }
@@ -985,7 +1060,7 @@
 
     // Manage new position callback
     if (mUpdatePeriod > 0) {
-        while (mCblk->server >= mNewPosition) {
+        while (cblk->server >= mNewPosition) {
             mCbf(EVENT_NEW_POS, mUserData, (void *)&mNewPosition);
             mNewPosition += mUpdatePeriod;
         }
@@ -1068,6 +1143,95 @@
     return true;
 }
 
+// must be called with mLock and cblk.lock held. Callers must also hold strong references on
+// the IAudioTrack and IMemory in case they are recreated here.
+// If the IAudioTrack is successfully restored, the cblk pointer is updated
+status_t AudioTrack::restoreTrack_l(audio_track_cblk_t*& cblk, bool fromStart)
+{
+    status_t result;
+
+    if (!(cblk->flags & CBLK_RESTORING_MSK)) {
+        LOGW("dead IAudioTrack, creating a new one from %s",
+             fromStart ? "start()" : "obtainBuffer()");
+
+        cblk->flags |= CBLK_RESTORING_ON;
+
+        // signal old cblk condition so that other threads waiting for available buffers stop
+        // waiting now
+        cblk->cv.broadcast();
+        cblk->lock.unlock();
+
+        // if the new IAudioTrack is created, createTrack_l() will modify the
+        // following member variables: mAudioTrack, mCblkMemory and mCblk.
+        // It will also delete the strong references on previous IAudioTrack and IMemory
+        result = createTrack_l(mStreamType,
+                               cblk->sampleRate,
+                               mFormat,
+                               mChannelCount,
+                               mFrameCount,
+                               mFlags,
+                               mSharedBuffer,
+                               getOutput_l(),
+                               false);
+
+        if (result == NO_ERROR) {
+            // restore write index and set other indexes to reflect empty buffer status
+            mCblk->user = cblk->user;
+            mCblk->server = cblk->user;
+            mCblk->userBase = cblk->user;
+            mCblk->serverBase = cblk->user;
+            // restore loop: this is not guaranteed to succeed if new frame count is not
+            // compatible with loop length
+            setLoop_l(cblk->loopStart, cblk->loopEnd, cblk->loopCount);
+            if (!fromStart) {
+                mCblk->bufferTimeoutMs = MAX_RUN_TIMEOUT_MS;
+            }
+            if (mActive) {
+                result = mAudioTrack->start();
+            }
+            if (fromStart && result == NO_ERROR) {
+                mNewPosition = mCblk->server + mUpdatePeriod;
+            }
+        }
+        if (result != NO_ERROR) {
+            mActive = false;
+        }
+
+        // signal old cblk condition for other threads waiting for restore completion
+        cblk->lock.lock();
+        cblk->flags |= CBLK_RESTORED_MSK;
+        cblk->cv.broadcast();
+        cblk->lock.unlock();
+    } else {
+        if (!(cblk->flags & CBLK_RESTORED_MSK)) {
+            LOGW("dead IAudioTrack, waiting for a new one");
+            mLock.unlock();
+            result = cblk->cv.waitRelative(cblk->lock, milliseconds(RESTORE_TIMEOUT_MS));
+            cblk->lock.unlock();
+            mLock.lock();
+        } else {
+            LOGW("dead IAudioTrack, already restored");
+            result = NO_ERROR;
+            cblk->lock.unlock();
+        }
+        if (result != NO_ERROR || mActive == 0) {
+            result = status_t(STOPPED);
+        }
+    }
+    LOGV("restoreTrack_l() status %d mActive %d cblk %p, old cblk %p flags %08x old flags %08x",
+         result, mActive, mCblk, cblk, mCblk->flags, cblk->flags);
+
+    if (result == NO_ERROR) {
+        // from now on we switch to the newly created cblk
+        cblk = mCblk;
+    }
+    cblk->lock.lock();
+
+    LOGW_IF(result != NO_ERROR, "restoreTrack_l() error %d", result);
+
+    return result;
+}
+
 status_t AudioTrack::dump(int fd, const Vector<String16>& args) const
 {
 
@@ -1142,7 +1306,12 @@
     this->user = u;
 
     // Clear flow control error condition as new data has been written/read to/from buffer.
-    flags &= ~CBLK_UNDERRUN_MSK;
+    if (flags & CBLK_UNDERRUN_MSK) {
+        AutoMutex _l(lock);
+        if (flags & CBLK_UNDERRUN_MSK) {
+            flags &= ~CBLK_UNDERRUN_MSK;
+        }
+    }
 
     return u;
 }
@@ -1197,7 +1366,9 @@
 
     this->server = s;
 
-    cv.signal();
+    if (!(flags & CBLK_INVALID_MSK)) {
+        cv.signal();
+    }
     lock.unlock();
     return true;
 }
diff --git a/media/libmedia/IMediaMetadataRetriever.cpp b/media/libmedia/IMediaMetadataRetriever.cpp
index d5298c9..ebe821f 100644
--- a/media/libmedia/IMediaMetadataRetriever.cpp
+++ b/media/libmedia/IMediaMetadataRetriever.cpp
@@ -20,6 +20,7 @@
 #include <binder/Parcel.h>
 #include <SkBitmap.h>
 #include <media/IMediaMetadataRetriever.h>
+#include <utils/String8.h>
 
 // The binder is supposed to propagate the scheduler group across
 // the binder interface so that remote calls are executed with
@@ -102,11 +103,24 @@
         remote()->transact(DISCONNECT, data, &reply);
     }
 
-    status_t setDataSource(const char* srcUrl)
+    status_t setDataSource(
+            const char *srcUrl, const KeyedVector<String8, String8> *headers)
     {
         Parcel data, reply;
         data.writeInterfaceToken(IMediaMetadataRetriever::getInterfaceDescriptor());
         data.writeCString(srcUrl);
+
+        if (headers == NULL) {
+            data.writeInt32(0);
+        } else {
+            // serialize the headers
+            data.writeInt32(headers->size());
+            for (size_t i = 0; i < headers->size(); ++i) {
+                data.writeString8(headers->keyAt(i));
+                data.writeString8(headers->valueAt(i));
+            }
+        }
+
         remote()->transact(SET_DATA_SOURCE_URL, data, &reply);
         return reply.readInt32();
     }
@@ -188,7 +202,18 @@
         case SET_DATA_SOURCE_URL: {
             CHECK_INTERFACE(IMediaMetadataRetriever, data, reply);
             const char* srcUrl = data.readCString();
-            reply->writeInt32(setDataSource(srcUrl));
+
+            KeyedVector<String8, String8> headers;
+            int32_t numHeaders = data.readInt32();
+            for (int i = 0; i < numHeaders; ++i) {
+                String8 key = data.readString8();
+                String8 value = data.readString8();
+                headers.add(key, value);
+            }
+
+            reply->writeInt32(
+                    setDataSource(srcUrl, numHeaders > 0 ? &headers : NULL));
+
             return NO_ERROR;
         } break;
         case SET_DATA_SOURCE_FD: {
diff --git a/media/libmedia/IOMX.cpp b/media/libmedia/IOMX.cpp
index d6a1757..d3aab08 100644
--- a/media/libmedia/IOMX.cpp
+++ b/media/libmedia/IOMX.cpp
@@ -1,3 +1,19 @@
+/*
+ * Copyright (c) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
 //#define LOG_NDEBUG 0
 #define LOG_TAG "IOMX"
 #include <utils/Log.h>
diff --git a/media/libmedia/MediaProfiles.cpp b/media/libmedia/MediaProfiles.cpp
index 7fb7aed..e6f3a33 100644
--- a/media/libmedia/MediaProfiles.cpp
+++ b/media/libmedia/MediaProfiles.cpp
@@ -721,6 +721,11 @@
     createDefaultCamcorderTimeLapseHighProfiles(&highTimeLapseProfile, &highSpecificTimeLapseProfile);
     profiles->mCamcorderProfiles.add(highTimeLapseProfile);
     profiles->mCamcorderProfiles.add(highSpecificTimeLapseProfile);
+
+    // For emulator and other legacy devices which does not have a
+    // media_profiles.xml file, We assume that the default camera id
+    // is 0 and that is the only camera available.
+    profiles->mCameraIds.push(0);
 }
 
 /*static*/ void
diff --git a/media/libmedia/MemoryLeakTrackUtil.cpp b/media/libmedia/MemoryLeakTrackUtil.cpp
new file mode 100644
index 0000000..6a108ae
--- /dev/null
+++ b/media/libmedia/MemoryLeakTrackUtil.cpp
@@ -0,0 +1,169 @@
+/*
+ * Copyright 2011, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <media/MemoryLeakTrackUtil.h>
+
+#include <stdio.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+/*
+ * The code here originally resided in MediaPlayerService.cpp and was
+ * shamelessly copied over to support memory leak tracking from
+ * multiple places.
+ */
+namespace android {
+
+#if defined(__arm__)
+
+extern "C" void get_malloc_leak_info(uint8_t** info, size_t* overallSize,
+        size_t* infoSize, size_t* totalMemory, size_t* backtraceSize);
+
+extern "C" void free_malloc_leak_info(uint8_t* info);
+
+// Use the String-class below instead of String8 to allocate all memory
+// beforehand and not reenter the heap while we are examining it...
+struct MyString8 {
+    static const size_t MAX_SIZE = 256 * 1024;
+
+    MyString8()
+        : mPtr((char *)malloc(MAX_SIZE)) {
+        *mPtr = '\0';
+    }
+
+    ~MyString8() {
+        free(mPtr);
+    }
+
+    void append(const char *s) {
+        strcat(mPtr, s);
+    }
+
+    const char *string() const {
+        return mPtr;
+    }
+
+    size_t size() const {
+        return strlen(mPtr);
+    }
+
+private:
+    char *mPtr;
+
+    MyString8(const MyString8 &);
+    MyString8 &operator=(const MyString8 &);
+};
+
+void dumpMemoryAddresses(int fd)
+{
+    const size_t SIZE = 256;
+    char buffer[SIZE];
+    MyString8 result;
+
+    typedef struct {
+        size_t size;
+        size_t dups;
+        intptr_t * backtrace;
+    } AllocEntry;
+
+    uint8_t *info = NULL;
+    size_t overallSize = 0;
+    size_t infoSize = 0;
+    size_t totalMemory = 0;
+    size_t backtraceSize = 0;
+
+    get_malloc_leak_info(&info, &overallSize, &infoSize, &totalMemory, &backtraceSize);
+    if (info) {
+        uint8_t *ptr = info;
+        size_t count = overallSize / infoSize;
+
+        snprintf(buffer, SIZE, " Allocation count %i\n", count);
+        result.append(buffer);
+        snprintf(buffer, SIZE, " Total memory %i\n", totalMemory);
+        result.append(buffer);
+
+        AllocEntry * entries = new AllocEntry[count];
+
+        for (size_t i = 0; i < count; i++) {
+            // Each entry should be size_t, size_t, intptr_t[backtraceSize]
+            AllocEntry *e = &entries[i];
+
+            e->size = *reinterpret_cast<size_t *>(ptr);
+            ptr += sizeof(size_t);
+
+            e->dups = *reinterpret_cast<size_t *>(ptr);
+            ptr += sizeof(size_t);
+
+            e->backtrace = reinterpret_cast<intptr_t *>(ptr);
+            ptr += sizeof(intptr_t) * backtraceSize;
+        }
+
+        // Now we need to sort the entries.  They come sorted by size but
+        // not by stack trace which causes problems using diff.
+        bool moved;
+        do {
+            moved = false;
+            for (size_t i = 0; i < (count - 1); i++) {
+                AllocEntry *e1 = &entries[i];
+                AllocEntry *e2 = &entries[i+1];
+
+                bool swap = e1->size < e2->size;
+                if (e1->size == e2->size) {
+                    for(size_t j = 0; j < backtraceSize; j++) {
+                        if (e1->backtrace[j] == e2->backtrace[j]) {
+                            continue;
+                        }
+                        swap = e1->backtrace[j] < e2->backtrace[j];
+                        break;
+                    }
+                }
+                if (swap) {
+                    AllocEntry t = entries[i];
+                    entries[i] = entries[i+1];
+                    entries[i+1] = t;
+                    moved = true;
+                }
+            }
+        } while (moved);
+
+        for (size_t i = 0; i < count; i++) {
+            AllocEntry *e = &entries[i];
+
+            snprintf(buffer, SIZE, "size %8i, dup %4i, ", e->size, e->dups);
+            result.append(buffer);
+            for (size_t ct = 0; (ct < backtraceSize) && e->backtrace[ct]; ct++) {
+                if (ct) {
+                    result.append(", ");
+                }
+                snprintf(buffer, SIZE, "0x%08x", e->backtrace[ct]);
+                result.append(buffer);
+            }
+            result.append("\n");
+        }
+
+        delete[] entries;
+        free_malloc_leak_info(info);
+    }
+
+    write(fd, result.string(), result.size());
+}
+
+#else
+// Does nothing
+void dumpMemoryAddresses(int fd) {}
+
+#endif
+}  // namespace android
diff --git a/media/libmedia/mediametadataretriever.cpp b/media/libmedia/mediametadataretriever.cpp
index 8dfcb3b..cee06ab 100644
--- a/media/libmedia/mediametadataretriever.cpp
+++ b/media/libmedia/mediametadataretriever.cpp
@@ -92,7 +92,8 @@
     }
 }
 
-status_t MediaMetadataRetriever::setDataSource(const char* srcUrl)
+status_t MediaMetadataRetriever::setDataSource(
+        const char *srcUrl, const KeyedVector<String8, String8> *headers)
 {
     LOGV("setDataSource");
     Mutex::Autolock _l(mLock);
@@ -105,7 +106,7 @@
         return UNKNOWN_ERROR;
     }
     LOGV("data source (%s)", srcUrl);
-    return mRetriever->setDataSource(srcUrl);
+    return mRetriever->setDataSource(srcUrl, headers);
 }
 
 status_t MediaMetadataRetriever::setDataSource(int fd, int64_t offset, int64_t length)
diff --git a/media/libmediaplayerservice/MediaPlayerService.cpp b/media/libmediaplayerservice/MediaPlayerService.cpp
index a42cca5..5eecbde 100644
--- a/media/libmediaplayerservice/MediaPlayerService.cpp
+++ b/media/libmediaplayerservice/MediaPlayerService.cpp
@@ -51,6 +51,7 @@
 #include <media/MediaMetadataRetrieverInterface.h>
 #include <media/Metadata.h>
 #include <media/AudioTrack.h>
+#include <media/MemoryLeakTrackUtil.h>
 
 #include <private/android_filesystem_config.h>
 
@@ -392,139 +393,6 @@
 #endif
 }
 
-#if defined(__arm__)
-extern "C" void get_malloc_leak_info(uint8_t** info, size_t* overallSize,
-        size_t* infoSize, size_t* totalMemory, size_t* backtraceSize);
-extern "C" void free_malloc_leak_info(uint8_t* info);
-
-// Use the String-class below instead of String8 to allocate all memory
-// beforehand and not reenter the heap while we are examining it...
-struct MyString8 {
-    static const size_t MAX_SIZE = 256 * 1024;
-
-    MyString8()
-        : mPtr((char *)malloc(MAX_SIZE)) {
-        *mPtr = '\0';
-    }
-
-    ~MyString8() {
-        free(mPtr);
-    }
-
-    void append(const char *s) {
-        strcat(mPtr, s);
-    }
-
-    const char *string() const {
-        return mPtr;
-    }
-
-    size_t size() const {
-        return strlen(mPtr);
-    }
-
-private:
-    char *mPtr;
-
-    MyString8(const MyString8 &);
-    MyString8 &operator=(const MyString8 &);
-};
-
-void memStatus(int fd, const Vector<String16>& args)
-{
-    const size_t SIZE = 256;
-    char buffer[SIZE];
-    MyString8 result;
-
-    typedef struct {
-        size_t size;
-        size_t dups;
-        intptr_t * backtrace;
-    } AllocEntry;
-
-    uint8_t *info = NULL;
-    size_t overallSize = 0;
-    size_t infoSize = 0;
-    size_t totalMemory = 0;
-    size_t backtraceSize = 0;
-
-    get_malloc_leak_info(&info, &overallSize, &infoSize, &totalMemory, &backtraceSize);
-    if (info) {
-        uint8_t *ptr = info;
-        size_t count = overallSize / infoSize;
-
-        snprintf(buffer, SIZE, " Allocation count %i\n", count);
-        result.append(buffer);
-        snprintf(buffer, SIZE, " Total memory %i\n", totalMemory);
-        result.append(buffer);
-
-        AllocEntry * entries = new AllocEntry[count];
-
-        for (size_t i = 0; i < count; i++) {
-            // Each entry should be size_t, size_t, intptr_t[backtraceSize]
-            AllocEntry *e = &entries[i];
-
-            e->size = *reinterpret_cast<size_t *>(ptr);
-            ptr += sizeof(size_t);
-
-            e->dups = *reinterpret_cast<size_t *>(ptr);
-            ptr += sizeof(size_t);
-
-            e->backtrace = reinterpret_cast<intptr_t *>(ptr);
-            ptr += sizeof(intptr_t) * backtraceSize;
-        }
-
-        // Now we need to sort the entries.  They come sorted by size but
-        // not by stack trace which causes problems using diff.
-        bool moved;
-        do {
-            moved = false;
-            for (size_t i = 0; i < (count - 1); i++) {
-                AllocEntry *e1 = &entries[i];
-                AllocEntry *e2 = &entries[i+1];
-
-                bool swap = e1->size < e2->size;
-                if (e1->size == e2->size) {
-                    for(size_t j = 0; j < backtraceSize; j++) {
-                        if (e1->backtrace[j] == e2->backtrace[j]) {
-                            continue;
-                        }
-                        swap = e1->backtrace[j] < e2->backtrace[j];
-                        break;
-                    }
-                }
-                if (swap) {
-                    AllocEntry t = entries[i];
-                    entries[i] = entries[i+1];
-                    entries[i+1] = t;
-                    moved = true;
-                }
-            }
-        } while (moved);
-
-        for (size_t i = 0; i < count; i++) {
-            AllocEntry *e = &entries[i];
-
-            snprintf(buffer, SIZE, "size %8i, dup %4i, ", e->size, e->dups);
-            result.append(buffer);
-            for (size_t ct = 0; (ct < backtraceSize) && e->backtrace[ct]; ct++) {
-                if (ct) {
-                    result.append(", ");
-                }
-                snprintf(buffer, SIZE, "0x%08x", e->backtrace[ct]);
-                result.append(buffer);
-            }
-            result.append("\n");
-        }
-
-        delete[] entries;
-        free_malloc_leak_info(info);
-    }
-
-    write(fd, result.string(), result.size());
-}
-#endif
-
 status_t MediaPlayerService::dump(int fd, const Vector<String16>& args)
 {
     const size_t SIZE = 256;
@@ -623,7 +491,6 @@
             result.append("\n");
         }
 
-#if defined(__arm__)
         bool dumpMem = false;
         for (size_t i = 0; i < args.size(); i++) {
             if (args[i] == String16("-m")) {
@@ -631,9 +498,8 @@
             }
         }
         if (dumpMem) {
-            memStatus(fd, args);
+            dumpMemoryAddresses(fd);
         }
-#endif
     }
     write(fd, result.string(), result.size());
     return NO_ERROR;
@@ -744,7 +610,8 @@
         return TEST_PLAYER;
     }
 
-    if (!strncasecmp("http://", url, 7)) {
+    if (!strncasecmp("http://", url, 7)
+            || !strncasecmp("https://", url, 8)) {
         size_t len = strlen(url);
         if (len >= 5 && !strcasecmp(".m3u8", &url[len - 5])) {
             return NU_PLAYER;
diff --git a/media/libmediaplayerservice/MetadataRetrieverClient.cpp b/media/libmediaplayerservice/MetadataRetrieverClient.cpp
index 5fcf2a7..8f776b4 100644
--- a/media/libmediaplayerservice/MetadataRetrieverClient.cpp
+++ b/media/libmediaplayerservice/MetadataRetrieverClient.cpp
@@ -120,7 +120,8 @@
     return p;
 }
 
-status_t MetadataRetrieverClient::setDataSource(const char *url)
+status_t MetadataRetrieverClient::setDataSource(
+        const char *url, const KeyedVector<String8, String8> *headers)
 {
     LOGV("setDataSource(%s)", url);
     Mutex::Autolock lock(mLock);
@@ -131,7 +132,7 @@
     LOGV("player type = %d", playerType);
     sp<MediaMetadataRetrieverBase> p = createRetriever(playerType);
     if (p == NULL) return NO_INIT;
-    status_t ret = p->setDataSource(url);
+    status_t ret = p->setDataSource(url, headers);
     if (ret == NO_ERROR) mRetriever = p;
     return ret;
 }
diff --git a/media/libmediaplayerservice/MetadataRetrieverClient.h b/media/libmediaplayerservice/MetadataRetrieverClient.h
index b834715..f08f933 100644
--- a/media/libmediaplayerservice/MetadataRetrieverClient.h
+++ b/media/libmediaplayerservice/MetadataRetrieverClient.h
@@ -41,7 +41,10 @@
     // Implements IMediaMetadataRetriever interface
     // These methods are called in IMediaMetadataRetriever.cpp?
     virtual void                    disconnect();
-    virtual status_t                setDataSource(const char *url);
+
+    virtual status_t                setDataSource(
+            const char *url, const KeyedVector<String8, String8> *headers);
+
     virtual status_t                setDataSource(int fd, int64_t offset, int64_t length);
     virtual sp<IMemory>             getFrameAtTime(int64_t timeUs, int option);
     virtual sp<IMemory>             extractAlbumArt();
diff --git a/media/libmediaplayerservice/MidiMetadataRetriever.cpp b/media/libmediaplayerservice/MidiMetadataRetriever.cpp
index ad95fac..aaf2d18 100644
--- a/media/libmediaplayerservice/MidiMetadataRetriever.cpp
+++ b/media/libmediaplayerservice/MidiMetadataRetriever.cpp
@@ -35,7 +35,8 @@
     mMetadataValues[0][0] = '\0';
 }
 
-status_t MidiMetadataRetriever::setDataSource(const char *url)
+status_t MidiMetadataRetriever::setDataSource(
+        const char *url, const KeyedVector<String8, String8> *headers)
 {
     LOGV("setDataSource: %s", url? url: "NULL pointer");
     Mutex::Autolock lock(mLock);
@@ -43,8 +44,7 @@
     if (mMidiPlayer == 0) {
         mMidiPlayer = new MidiFile();
     }
-    // TODO: support headers in MetadataRetriever interface!
-    return mMidiPlayer->setDataSource(url, NULL /* headers */);
+    return mMidiPlayer->setDataSource(url, headers);
 }
 
 status_t MidiMetadataRetriever::setDataSource(int fd, int64_t offset, int64_t length)
diff --git a/media/libmediaplayerservice/MidiMetadataRetriever.h b/media/libmediaplayerservice/MidiMetadataRetriever.h
index 73ff347..4cee42d 100644
--- a/media/libmediaplayerservice/MidiMetadataRetriever.h
+++ b/media/libmediaplayerservice/MidiMetadataRetriever.h
@@ -31,7 +31,9 @@
                                    MidiMetadataRetriever() {}
                                    ~MidiMetadataRetriever() {}
 
-    virtual status_t                setDataSource(const char *url);
+    virtual status_t                setDataSource(
+            const char *url, const KeyedVector<String8, String8> *headers);
+
     virtual status_t                setDataSource(int fd, int64_t offset, int64_t length);
     virtual const char*             extractMetadata(int keyCode);
 
diff --git a/media/libmediaplayerservice/StagefrightPlayer.cpp b/media/libmediaplayerservice/StagefrightPlayer.cpp
index e277121..c5cbd23 100644
--- a/media/libmediaplayerservice/StagefrightPlayer.cpp
+++ b/media/libmediaplayerservice/StagefrightPlayer.cpp
@@ -1,3 +1,19 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
 //#define LOG_NDEBUG 0
 #define LOG_TAG "StagefrightPlayer"
 #include <utils/Log.h>
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp
index 369a3a8..828e008 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp
@@ -198,18 +198,21 @@
 }
 
 void NuPlayer::Renderer::onDrainAudioQueue() {
-    uint32_t numFramesPlayed;
-    CHECK_EQ(mAudioSink->getPosition(&numFramesPlayed), (status_t)OK);
 
-    ssize_t numFramesAvailableToWrite =
-        mAudioSink->frameCount() - (mNumFramesWritten - numFramesPlayed);
+    for (;;) {
+        uint32_t numFramesPlayed;
+        CHECK_EQ(mAudioSink->getPosition(&numFramesPlayed), (status_t)OK);
 
-    CHECK_GE(numFramesAvailableToWrite, 0);
+        ssize_t numFramesAvailableToWrite =
+            mAudioSink->frameCount() - (mNumFramesWritten - numFramesPlayed);
 
-    size_t numBytesAvailableToWrite =
-        numFramesAvailableToWrite * mAudioSink->frameSize();
+        size_t numBytesAvailableToWrite =
+            numFramesAvailableToWrite * mAudioSink->frameSize();
 
-    while (numBytesAvailableToWrite > 0) {
+        if (numBytesAvailableToWrite == 0) {
+            break;
+        }
+
         if (mAudioQueue.empty()) {
             break;
         }
@@ -264,10 +267,10 @@
         if (entry->mOffset == entry->mBuffer->size()) {
             entry->mNotifyConsumed->post();
             mAudioQueue.erase(mAudioQueue.begin());
+
             entry = NULL;
         }
 
-        numBytesAvailableToWrite -= copy;
         mNumFramesWritten += copy / mAudioSink->frameSize();
     }
 
diff --git a/media/libstagefright/ACodec.cpp b/media/libstagefright/ACodec.cpp
index d590ab9..346d0bb 100644
--- a/media/libstagefright/ACodec.cpp
+++ b/media/libstagefright/ACodec.cpp
@@ -1,3 +1,19 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
 //#define LOG_NDEBUG 0
 #define LOG_TAG "ACodec"
 
diff --git a/media/libstagefright/AMRWriter.cpp b/media/libstagefright/AMRWriter.cpp
index 0db3d1d..b10d52c 100644
--- a/media/libstagefright/AMRWriter.cpp
+++ b/media/libstagefright/AMRWriter.cpp
@@ -37,7 +37,7 @@
       mPaused(false),
       mResumed(false) {
 
-    mFd = open(filename, O_CREAT | O_LARGEFILE | O_TRUNC);
+    mFd = open(filename, O_CREAT | O_LARGEFILE | O_TRUNC | O_RDWR);
     if (mFd >= 0) {
         mInitCheck = OK;
     }
@@ -269,7 +269,7 @@
     }
 
     if (stoppedPrematurely) {
-        notify(MEDIA_RECORDER_EVENT_INFO, MEDIA_RECORDER_INFO_COMPLETION_STATUS, UNKNOWN_ERROR);
+        notify(MEDIA_RECORDER_EVENT_INFO, MEDIA_RECORDER_TRACK_INFO_COMPLETION_STATUS, UNKNOWN_ERROR);
     }
 
     close(mFd);
diff --git a/media/libstagefright/Android.mk b/media/libstagefright/Android.mk
index 88069e9..e445b74 100644
--- a/media/libstagefright/Android.mk
+++ b/media/libstagefright/Android.mk
@@ -19,6 +19,7 @@
         ESDS.cpp                          \
         FileSource.cpp                    \
         FLACExtractor.cpp                 \
+        HTTPBase.cpp                      \
         HTTPStream.cpp                    \
         JPEGSource.cpp                    \
         MP3Extractor.cpp                  \
@@ -75,7 +76,7 @@
         libdrmframework  \
         libcrypto        \
         libssl           \
-        libgui
+        libgui           \
 
 LOCAL_STATIC_LIBRARIES := \
         libstagefright_color_conversion \
@@ -101,6 +102,60 @@
         libstagefright_g711dec \
         libFLAC \
 
+################################################################################
+
+# The following was shamelessly copied from external/webkit/Android.mk and
+# currently must follow the same logic to determine how webkit was built and
+# if it's safe to link against libchromium.net
+
+# V8 also requires an ARMv7 CPU, and since we must use jsc, we cannot
+# use the Chrome http stack either.
+ifneq ($(strip $(ARCH_ARM_HAVE_ARMV7A)),true)
+  USE_ALT_HTTP := true
+endif
+
+# See if the user has specified a stack they want to use
+HTTP_STACK = $(HTTP)
+# We default to the Chrome HTTP stack.
+DEFAULT_HTTP = chrome
+ALT_HTTP = android
+
+ifneq ($(HTTP_STACK),chrome)
+  ifneq ($(HTTP_STACK),android)
+    # No HTTP stack is specified, pickup the one we want as default.
+    ifeq ($(USE_ALT_HTTP),true)
+      HTTP_STACK = $(ALT_HTTP)
+    else
+      HTTP_STACK = $(DEFAULT_HTTP)
+    endif
+  endif
+endif
+
+ifeq ($(HTTP_STACK),chrome)
+
+LOCAL_SHARED_LIBRARIES += \
+        liblog           \
+        libicuuc         \
+        libicui18n       \
+        libz             \
+        libdl            \
+
+LOCAL_STATIC_LIBRARIES += \
+        libstagefright_chromium_http \
+        libchromium_net         \
+        libwebcore              \
+
+ifneq ($(TARGET_SIMULATOR),true)
+LOCAL_SHARED_LIBRARIES += libstlport
+include external/stlport/libstlport.mk
+endif
+
+LOCAL_CPPFLAGS += -DCHROMIUM_AVAILABLE=1
+
+endif  # ifeq ($(HTTP_STACK),chrome)
+
+################################################################################
+
 LOCAL_SHARED_LIBRARIES += \
         libstagefright_amrnb_common \
         libstagefright_enc_common \
diff --git a/media/libstagefright/AudioPlayer.cpp b/media/libstagefright/AudioPlayer.cpp
index e7c0299..07f250a 100644
--- a/media/libstagefright/AudioPlayer.cpp
+++ b/media/libstagefright/AudioPlayer.cpp
@@ -280,6 +280,26 @@
     buffer->size = numBytesWritten;
 }
 
+uint32_t AudioPlayer::getNumFramesPendingPlayout() const {
+    uint32_t numFramesPlayedOut;
+    status_t err;
+
+    if (mAudioSink != NULL) {
+        err = mAudioSink->getPosition(&numFramesPlayedOut);
+    } else {
+        err = mAudioTrack->getPosition(&numFramesPlayedOut);
+    }
+
+    if (err != OK || mNumFramesPlayed < numFramesPlayedOut) {
+        return 0;
+    }
+
+    // mNumFramesPlayed is the number of frames submitted
+    // to the audio sink for playback, but not all of them
+    // may have played out by now.
+    return mNumFramesPlayed - numFramesPlayedOut;
+}
+
 size_t AudioPlayer::fillBuffer(void *data, size_t size) {
     if (mNumFramesPlayed == 0) {
         LOGV("AudioCallback");
@@ -342,7 +362,34 @@
 
             if (err != OK) {
                 if (mObserver && !mReachedEOS) {
-                    mObserver->postAudioEOS();
+                    // We don't want to post EOS right away but only
+                    // after all frames have actually been played out.
+
+                    // These are the number of frames submitted to the
+                    // AudioTrack that you haven't heard yet.
+                    uint32_t numFramesPendingPlayout =
+                        getNumFramesPendingPlayout();
+
+                    // These are the number of frames we're going to
+                    // submit to the AudioTrack by returning from this
+                    // callback.
+                    uint32_t numAdditionalFrames = size_done / mFrameSize;
+
+                    numFramesPendingPlayout += numAdditionalFrames;
+
+                    int64_t timeToCompletionUs =
+                        (1000000ll * numFramesPendingPlayout) / mSampleRate;
+
+                    LOGV("total number of frames played: %lld (%lld us)",
+                            (mNumFramesPlayed + numAdditionalFrames),
+                            1000000ll * (mNumFramesPlayed + numAdditionalFrames)
+                                / mSampleRate);
+
+                    LOGV("%d frames left to play, %lld us (%.2f secs)",
+                         numFramesPendingPlayout,
+                         timeToCompletionUs, timeToCompletionUs / 1E6);
+
+                    mObserver->postAudioEOS(timeToCompletionUs + mLatencyUs);
                 }
 
                 mReachedEOS = true;
diff --git a/media/libstagefright/AwesomePlayer.cpp b/media/libstagefright/AwesomePlayer.cpp
index 4c744bd..7fdb1a1 100644
--- a/media/libstagefright/AwesomePlayer.cpp
+++ b/media/libstagefright/AwesomePlayer.cpp
@@ -45,6 +45,7 @@
 #include <surfaceflinger/Surface.h>
 #include <gui/ISurfaceTexture.h>
 #include <gui/SurfaceTextureClient.h>
+#include <surfaceflinger/ISurfaceComposer.h>
 
 #include <media/stagefright/foundation/ALooper.h>
 #include <media/stagefright/foundation/AMessage.h>
@@ -303,7 +304,7 @@
         return UNKNOWN_ERROR;
     }
 
-    dataSource->getDrmInfo(&mDecryptHandle, &mDrmManagerClient);
+    dataSource->getDrmInfo(mDecryptHandle, &mDrmManagerClient);
     if (mDecryptHandle != NULL) {
         CHECK(mDrmManagerClient);
         if (RightsStatus::RIGHTS_VALID != mDecryptHandle->status) {
@@ -749,8 +750,6 @@
     mFlags |= PLAYING;
     mFlags |= FIRST_FRAME;
 
-    bool deferredAudioSeek = false;
-
     if (mDecryptHandle != NULL) {
         int64_t position;
         getPosition(&position);
@@ -766,10 +765,11 @@
 
                 mTimeSource = mAudioPlayer;
 
-                deferredAudioSeek = true;
-
-                mWatchForAudioSeekComplete = false;
-                mWatchForAudioEOS = true;
+                // If there was a seek request before we ever started,
+                // honor the request now.
+                // Make sure to do this before starting the audio player
+                // to avoid a race condition.
+                seekAudioIfNecessary_l();
             }
         }
 
@@ -807,12 +807,6 @@
         }
     }
 
-    if (deferredAudioSeek) {
-        // If there was a seek request while we were paused
-        // and we're just starting up again, honor the request now.
-        seekAudioIfNecessary_l();
-    }
-
     if (mFlags & AT_EOS) {
         // Legacy behaviour, if a stream finishes playing and then
         // is started again, we play from the start...
@@ -882,6 +876,17 @@
              cropLeft, cropTop, cropRight, cropBottom);
     }
 
+    int32_t displayWidth;
+    if (meta->findInt32(kKeyDisplayWidth, &displayWidth)) {
+        LOGV("Display width changed (%d=>%d)", mDisplayWidth, displayWidth);
+        mDisplayWidth = displayWidth;
+    }
+    int32_t displayHeight;
+    if (meta->findInt32(kKeyDisplayHeight, &displayHeight)) {
+        LOGV("Display height changed (%d=>%d)", mDisplayHeight, displayHeight);
+        mDisplayHeight = displayHeight;
+    }
+
     int32_t usableWidth = cropRight - cropLeft + 1;
     int32_t usableHeight = cropBottom - cropTop + 1;
     if (mDisplayWidth != 0) {
@@ -1125,7 +1130,6 @@
 
         mWatchForAudioSeekComplete = true;
         mWatchForAudioEOS = true;
-        mSeekNotificationSent = false;
 
         if (mDecryptHandle != NULL) {
             mDrmManagerClient->setPlaybackStatus(mDecryptHandle,
@@ -1189,6 +1193,19 @@
 }
 
 status_t AwesomePlayer::initVideoDecoder(uint32_t flags) {
+
+    // Either the application or the DRM system can independently say
+    // that there must be a hardware-protected path to an external video sink.
+    // For now we always require a hardware-protected path to external video sink
+    // if content is DRMed, but eventually this could be optional per DRM agent.
+    // When the application wants protection, then
+    //   (USE_SURFACE_ALLOC && (mSurface != 0) &&
+    //   (mSurface->getFlags() & ISurfaceComposer::eProtectedByApp))
+    // will be true, but that part is already handled by SurfaceFlinger.
+    if (mDecryptHandle != NULL) {
+        flags |= OMXCodec::kEnableGrallocUsageProtected;
+    }
+    LOGV("initVideoDecoder flags=0x%x", flags);
     mVideoSource = OMXCodec::Create(
             mClient.interface(), mVideoTrack->getFormat(),
             false, // createEncoder
@@ -1237,11 +1254,11 @@
         // If we're playing video only, report seek complete now,
         // otherwise audio player will notify us later.
         notifyListener_l(MEDIA_SEEK_COMPLETE);
+        mSeekNotificationSent = true;
     }
 
     mFlags |= FIRST_FRAME;
     mSeeking = NO_SEEK;
-    mSeekNotificationSent = false;
 
     if (mDecryptHandle != NULL) {
         mDrmManagerClient->setPlaybackStatus(mDecryptHandle,
@@ -1496,12 +1513,12 @@
     mQueue.postEventWithDelay(mVideoLagEvent, 1000000ll);
 }
 
-void AwesomePlayer::postCheckAudioStatusEvent_l() {
+void AwesomePlayer::postCheckAudioStatusEvent_l(int64_t delayUs) {
     if (mAudioStatusEventPending) {
         return;
     }
     mAudioStatusEventPending = true;
-    mQueue.postEvent(mCheckAudioStatusEvent);
+    mQueue.postEventWithDelay(mCheckAudioStatusEvent, delayUs);
 }
 
 void AwesomePlayer::onCheckAudioStatus() {
@@ -1597,8 +1614,10 @@
 
     if (!strncasecmp("http://", mUri.string(), 7)
             || !strncasecmp("https://", mUri.string(), 8)) {
-        mConnectingDataSource = new NuHTTPDataSource(
-                (mFlags & INCOGNITO) ? NuHTTPDataSource::kFlagIncognito : 0);
+        mConnectingDataSource = HTTPBase::Create(
+                (mFlags & INCOGNITO)
+                    ? HTTPBase::kFlagIncognito
+                    : 0);
 
         mLock.unlock();
         status_t err = mConnectingDataSource->connect(mUri, &mUriHeaders);
@@ -1687,7 +1706,8 @@
         return UNKNOWN_ERROR;
     }
 
-    dataSource->getDrmInfo(&mDecryptHandle, &mDrmManagerClient);
+    dataSource->getDrmInfo(mDecryptHandle, &mDrmManagerClient);
+
     if (mDecryptHandle != NULL) {
         CHECK(mDrmManagerClient);
         if (RightsStatus::RIGHTS_VALID == mDecryptHandle->status) {
@@ -1790,12 +1810,12 @@
     return mExtractorFlags;
 }
 
-void AwesomePlayer::postAudioEOS() {
-    postCheckAudioStatusEvent_l();
+void AwesomePlayer::postAudioEOS(int64_t delayUs) {
+    postCheckAudioStatusEvent_l(delayUs);
 }
 
 void AwesomePlayer::postAudioSeekComplete() {
-    postCheckAudioStatusEvent_l();
+    postCheckAudioStatusEvent_l(0 /* delayUs */);
 }
 
 }  // namespace android
diff --git a/media/libstagefright/DRMExtractor.cpp b/media/libstagefright/DRMExtractor.cpp
index 2809df5..c4ed516 100644
--- a/media/libstagefright/DRMExtractor.cpp
+++ b/media/libstagefright/DRMExtractor.cpp
@@ -41,7 +41,7 @@
 class DRMSource : public MediaSource {
 public:
     DRMSource(const sp<MediaSource> &mediaSource,
-            DecryptHandle *decryptHandle,
+            const sp<DecryptHandle> &decryptHandle,
             DrmManagerClient *managerClient,
             int32_t trackId, DrmBuffer *ipmpBox);
 
@@ -56,7 +56,7 @@
 
 private:
     sp<MediaSource> mOriginalMediaSource;
-    DecryptHandle* mDecryptHandle;
+    sp<DecryptHandle> mDecryptHandle;
     DrmManagerClient* mDrmManagerClient;
     size_t mTrackId;
     mutable Mutex mDRMLock;
@@ -70,7 +70,7 @@
 ////////////////////////////////////////////////////////////////////////////////
 
 DRMSource::DRMSource(const sp<MediaSource> &mediaSource,
-        DecryptHandle *decryptHandle,
+        const sp<DecryptHandle> &decryptHandle,
         DrmManagerClient *managerClient,
         int32_t trackId, DrmBuffer *ipmpBox)
     : mOriginalMediaSource(mediaSource),
@@ -245,7 +245,7 @@
     mOriginalExtractor->setDrmFlag(true);
     mOriginalExtractor->getMetaData()->setInt32(kKeyIsDRM, 1);
 
-    source->getDrmInfo(&mDecryptHandle, &mDrmManagerClient);
+    source->getDrmInfo(mDecryptHandle, &mDrmManagerClient);
 }
 
 DRMExtractor::~DRMExtractor() {
@@ -281,7 +281,7 @@
 bool SniffDRM(
     const sp<DataSource> &source, String8 *mimeType, float *confidence,
         sp<AMessage> *) {
-    DecryptHandle *decryptHandle = source->DrmInitialization();
+    sp<DecryptHandle> decryptHandle = source->DrmInitialization();
 
     if (decryptHandle != NULL) {
         if (decryptHandle->decryptApiType == DecryptApiType::CONTAINER_BASED) {
diff --git a/media/libstagefright/DataSource.cpp b/media/libstagefright/DataSource.cpp
index 3b38208..b5c51f4 100644
--- a/media/libstagefright/DataSource.cpp
+++ b/media/libstagefright/DataSource.cpp
@@ -21,7 +21,7 @@
 #include "include/OggExtractor.h"
 #include "include/MPEG2TSExtractor.h"
 #include "include/NuCachedSource2.h"
-#include "include/NuHTTPDataSource.h"
+#include "include/HTTPBase.h"
 #include "include/DRMExtractor.h"
 #include "include/FLACExtractor.h"
 #include "include/AACExtractor.h"
@@ -127,7 +127,7 @@
         source = new FileSource(uri + 7);
     } else if (!strncasecmp("http://", uri, 7)
             || !strncasecmp("https://", uri, 8)) {
-        sp<NuHTTPDataSource> httpSource = new NuHTTPDataSource;
+        sp<HTTPBase> httpSource = HTTPBase::Create();
         if (httpSource->connect(uri, headers) != OK) {
             return NULL;
         }
diff --git a/media/libstagefright/FileSource.cpp b/media/libstagefright/FileSource.cpp
index 02a78c9..f2f3500 100644
--- a/media/libstagefright/FileSource.cpp
+++ b/media/libstagefright/FileSource.cpp
@@ -125,7 +125,7 @@
     return OK;
 }
 
-DecryptHandle* FileSource::DrmInitialization() {
+sp<DecryptHandle> FileSource::DrmInitialization() {
     if (mDrmManagerClient == NULL) {
         mDrmManagerClient = new DrmManagerClient();
     }
@@ -147,8 +147,8 @@
     return mDecryptHandle;
 }
 
-void FileSource::getDrmInfo(DecryptHandle **handle, DrmManagerClient **client) {
-    *handle = mDecryptHandle;
+void FileSource::getDrmInfo(sp<DecryptHandle> &handle, DrmManagerClient **client) {
+    handle = mDecryptHandle;
 
     *client = mDrmManagerClient;
 }
diff --git a/media/libstagefright/HTTPBase.cpp b/media/libstagefright/HTTPBase.cpp
new file mode 100644
index 0000000..58b17a7
--- /dev/null
+++ b/media/libstagefright/HTTPBase.cpp
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "include/HTTPBase.h"
+
+#if CHROMIUM_AVAILABLE
+#include "include/ChromiumHTTPDataSource.h"
+#endif
+
+#include "include/NuHTTPDataSource.h"
+
+#include <cutils/properties.h>
+
+namespace android {
+
+HTTPBase::HTTPBase() {}
+
+// static
+sp<HTTPBase> HTTPBase::Create(uint32_t flags) {
+#if CHROMIUM_AVAILABLE
+    char value[PROPERTY_VALUE_MAX];
+    if (!property_get("media.stagefright.use-chromium", value, NULL)
+            || (strcasecmp("false", value) && strcmp("0", value))) {
+        return new ChromiumHTTPDataSource(flags);
+    } else
+#endif
+    {
+        return new NuHTTPDataSource(flags);
+    }
+}
+
+}  // namespace android
diff --git a/media/libstagefright/HTTPStream.cpp b/media/libstagefright/HTTPStream.cpp
index 498c7b8..2caf211 100644
--- a/media/libstagefright/HTTPStream.cpp
+++ b/media/libstagefright/HTTPStream.cpp
@@ -220,40 +220,58 @@
         return ERROR_ALREADY_CONNECTED;
     }
 
-    struct hostent *ent = gethostbyname(server);
-    if (ent == NULL) {
+    if (port < 0 || port > (int) USHRT_MAX) {
+        return UNKNOWN_ERROR;
+    }
+
+    char service[sizeof("65536")];
+    sprintf(service, "%d", port);
+    struct addrinfo hints, *ai;
+    memset(&hints, 0, sizeof(hints));
+    hints.ai_flags = AI_ADDRCONFIG | AI_NUMERICSERV;
+    hints.ai_socktype = SOCK_STREAM;
+
+    int ret = getaddrinfo(server, service, &hints, &ai);
+    if (ret) {
         return ERROR_UNKNOWN_HOST;
     }
 
     CHECK_EQ(mSocket, -1);
-    mSocket = socket(AF_INET, SOCK_STREAM, 0);
-
-    if (mSocket < 0) {
-        return UNKNOWN_ERROR;
-    }
-
-    setReceiveTimeout(30);  // Time out reads after 30 secs by default
 
     mState = CONNECTING;
+    status_t res = -1;
+    struct addrinfo *tmp;
+    for (tmp = ai; tmp; tmp = tmp->ai_next) {
+        mSocket = socket(tmp->ai_family, tmp->ai_socktype, tmp->ai_protocol);
+        if (mSocket < 0) {
+            continue;
+        }
 
-    int s = mSocket;
+        setReceiveTimeout(30);  // Time out reads after 30 secs by default.
 
-    mLock.unlock();
+        int s = mSocket;
 
-    struct sockaddr_in addr;
-    addr.sin_family = AF_INET;
-    addr.sin_port = htons(port);
-    addr.sin_addr.s_addr = *(in_addr_t *)ent->h_addr;
-    memset(addr.sin_zero, 0, sizeof(addr.sin_zero));
+        mLock.unlock();
 
-    status_t res = MyConnect(s, (const struct sockaddr *)&addr, sizeof(addr));
+        res = MyConnect(s, tmp->ai_addr, tmp->ai_addrlen);
 
-    mLock.lock();
+        mLock.lock();
 
-    if (mState != CONNECTING) {
-        return UNKNOWN_ERROR;
+        if (mState != CONNECTING) {
+            close(s);
+            freeaddrinfo(ai);
+            return UNKNOWN_ERROR;
+        }
+
+        if (res == OK) {
+            break;
+        }
+
+        close(s);
     }
 
+    freeaddrinfo(ai);
+
     if (res != OK) {
         close(mSocket);
         mSocket = -1;
diff --git a/media/libstagefright/MP3Extractor.cpp b/media/libstagefright/MP3Extractor.cpp
index eb4c68d..03ce202 100644
--- a/media/libstagefright/MP3Extractor.cpp
+++ b/media/libstagefright/MP3Extractor.cpp
@@ -39,10 +39,10 @@
 namespace android {
 
 // Everything must match except for
-// protection, bitrate, padding, private bits, mode extension,
+// protection, bitrate, padding, private bits, mode, mode extension,
 // copyright bit, original bit and emphasis.
 // Yes ... there are things that must indeed match...
-static const uint32_t kMask = 0xfffe0cc0;
+static const uint32_t kMask = 0xfffe0c00;
 
 // static
 bool MP3Extractor::get_mp3_frame_size(
diff --git a/media/libstagefright/MPEG4Writer.cpp b/media/libstagefright/MPEG4Writer.cpp
index 5d6ea7c..e13b67e 100644
--- a/media/libstagefright/MPEG4Writer.cpp
+++ b/media/libstagefright/MPEG4Writer.cpp
@@ -52,7 +52,7 @@
 
 class MPEG4Writer::Track {
 public:
-    Track(MPEG4Writer *owner, const sp<MediaSource> &source);
+    Track(MPEG4Writer *owner, const sp<MediaSource> &source, size_t trackId);
 
     ~Track();
 
@@ -82,6 +82,7 @@
     bool mIsAvc;
     bool mIsAudio;
     bool mIsMPEG4;
+    int32_t mTrackId;
     int64_t mTrackDurationUs;
 
     // For realtime applications, we need to adjust the media clock
@@ -231,7 +232,7 @@
       mEstimatedMoovBoxSize(0),
       mInterleaveDurationUs(1000000) {
 
-    mFd = open(filename, O_CREAT | O_LARGEFILE | O_TRUNC);
+    mFd = open(filename, O_CREAT | O_LARGEFILE | O_TRUNC | O_RDWR);
     if (mFd >= 0) {
         mInitCheck = OK;
     }
@@ -295,7 +296,12 @@
 }
 
 status_t MPEG4Writer::addSource(const sp<MediaSource> &source) {
-    Track *track = new Track(this, source);
+    Mutex::Autolock l(mLock);
+    if (mStarted) {
+        LOGE("Attempt to add source AFTER recording is started");
+        return UNKNOWN_ERROR;
+    }
+    Track *track = new Track(this, source, mTracks.size());
     mTracks.push_back(track);
 
     return OK;
@@ -945,7 +951,7 @@
 ////////////////////////////////////////////////////////////////////////////////
 
 MPEG4Writer::Track::Track(
-        MPEG4Writer *owner, const sp<MediaSource> &source)
+        MPEG4Writer *owner, const sp<MediaSource> &source, size_t trackId)
     : mOwner(owner),
       mMeta(source->getFormat()),
       mSource(source),
@@ -953,6 +959,7 @@
       mPaused(false),
       mResumed(false),
       mStarted(false),
+      mTrackId(trackId),
       mTrackDurationUs(0),
       mEstimatedTrackSizeBytes(0),
       mSamplesHaveSameSize(true),
@@ -2030,7 +2037,7 @@
         (OK != checkCodecSpecificData())) {          // no codec specific data
         err = ERROR_MALFORMED;
     }
-    mOwner->trackProgressStatus(this, -1, err);
+    mOwner->trackProgressStatus(mTrackId, -1, err);
 
     // Last chunk
     if (mOwner->numTracks() == 1) {
@@ -2077,41 +2084,34 @@
     if (mTrackEveryTimeDurationUs > 0 &&
         timeUs - mPreviousTrackTimeUs >= mTrackEveryTimeDurationUs) {
         LOGV("Fire time tracking progress status at %lld us", timeUs);
-        mOwner->trackProgressStatus(this, timeUs - mPreviousTrackTimeUs, err);
+        mOwner->trackProgressStatus(mTrackId, timeUs - mPreviousTrackTimeUs, err);
         mPreviousTrackTimeUs = timeUs;
     }
 }
 
 void MPEG4Writer::trackProgressStatus(
-        const MPEG4Writer::Track* track, int64_t timeUs, status_t err) {
+        size_t trackId, int64_t timeUs, status_t err) {
     Mutex::Autolock lock(mLock);
-    int32_t nTracks = mTracks.size();
-    CHECK(nTracks >= 1);
-    CHECK(nTracks < 64);  // Arbitrary number
-
-    int32_t trackNum = 0;
-    CHECK(trackNum < nTracks);
-    trackNum <<= 16;
+    int32_t trackNum = (trackId << 28);
 
     // Error notification
     // Do not consider ERROR_END_OF_STREAM an error
     if (err != OK && err != ERROR_END_OF_STREAM) {
-        notify(MEDIA_RECORDER_EVENT_ERROR,
-               trackNum | MEDIA_RECORDER_ERROR_UNKNOWN,
+        notify(MEDIA_RECORDER_TRACK_EVENT_ERROR,
+               trackNum | MEDIA_RECORDER_TRACK_ERROR_GENERAL,
                err);
         return;
     }
 
     if (timeUs == -1) {
         // Send completion notification
-        notify(MEDIA_RECORDER_EVENT_INFO,
-               trackNum | MEDIA_RECORDER_INFO_COMPLETION_STATUS,
+        notify(MEDIA_RECORDER_TRACK_EVENT_INFO,
+               trackNum | MEDIA_RECORDER_TRACK_INFO_COMPLETION_STATUS,
                err);
-        return;
     } else {
         // Send progress status
-        notify(MEDIA_RECORDER_EVENT_INFO,
-               trackNum | MEDIA_RECORDER_INFO_PROGRESS_TIME_STATUS,
+        notify(MEDIA_RECORDER_TRACK_EVENT_INFO,
+               trackNum | MEDIA_RECORDER_TRACK_INFO_PROGRESS_IN_TIME,
                timeUs / 1000);
     }
 }
diff --git a/media/libstagefright/NuCachedSource2.cpp b/media/libstagefright/NuCachedSource2.cpp
index c7b99b9..3c99d1c 100644
--- a/media/libstagefright/NuCachedSource2.cpp
+++ b/media/libstagefright/NuCachedSource2.cpp
@@ -135,6 +135,10 @@
 void PageCache::copy(size_t from, void *data, size_t size) {
     LOGV("copy from %d size %d", from, size);
 
+    if (size == 0) {
+        return;
+    }
+
     CHECK_LE(from + size, mTotalSize);
 
     size_t offset = 0;
@@ -477,11 +481,11 @@
     restartPrefetcherIfNecessary_l(true /* ignore low water threshold */);
 }
 
-DecryptHandle* NuCachedSource2::DrmInitialization() {
+sp<DecryptHandle> NuCachedSource2::DrmInitialization() {
     return mSource->DrmInitialization();
 }
 
-void NuCachedSource2::getDrmInfo(DecryptHandle **handle, DrmManagerClient **client) {
+void NuCachedSource2::getDrmInfo(sp<DecryptHandle> &handle, DrmManagerClient **client) {
     mSource->getDrmInfo(handle, client);
 }
 
diff --git a/media/libstagefright/NuHTTPDataSource.cpp b/media/libstagefright/NuHTTPDataSource.cpp
index dbbf3b4..73daf12 100644
--- a/media/libstagefright/NuHTTPDataSource.cpp
+++ b/media/libstagefright/NuHTTPDataSource.cpp
@@ -1,3 +1,19 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
 //#define LOG_NDEBUG 0
 #define LOG_TAG "NuHTTPDataSource"
 #include <utils/Log.h>
@@ -514,7 +530,7 @@
     }
 }
 
-DecryptHandle* NuHTTPDataSource::DrmInitialization() {
+sp<DecryptHandle> NuHTTPDataSource::DrmInitialization() {
     if (mDrmManagerClient == NULL) {
         mDrmManagerClient = new DrmManagerClient();
     }
@@ -538,8 +554,8 @@
     return mDecryptHandle;
 }
 
-void NuHTTPDataSource::getDrmInfo(DecryptHandle **handle, DrmManagerClient **client) {
-    *handle = mDecryptHandle;
+void NuHTTPDataSource::getDrmInfo(sp<DecryptHandle> &handle, DrmManagerClient **client) {
+    handle = mDecryptHandle;
 
     *client = mDrmManagerClient;
 }
diff --git a/media/libstagefright/OMXCodec.cpp b/media/libstagefright/OMXCodec.cpp
index 4a94e0d..a6a34b3 100644
--- a/media/libstagefright/OMXCodec.cpp
+++ b/media/libstagefright/OMXCodec.cpp
@@ -528,6 +528,12 @@
         mOnlySubmitOneBufferAtOneTime = true;
     }
 
+    mEnableGrallocUsageProtected = false;
+    if (flags & kEnableGrallocUsageProtected) {
+        mEnableGrallocUsageProtected = true;
+    }
+    LOGV("configureCodec protected=%d", mEnableGrallocUsageProtected);
+
     if (!(flags & kIgnoreCodecSpecificData)) {
         uint32_t type;
         const void *data;
@@ -1751,7 +1757,11 @@
         // XXX: Currently this error is logged, but not fatal.
         usage = 0;
     }
+    if (mEnableGrallocUsageProtected) {
+        usage |= GRALLOC_USAGE_PROTECTED;
+    }
 
+    LOGV("native_window_set_usage usage=0x%x", usage);
     err = native_window_set_usage(
             mNativeWindow.get(), usage | GRALLOC_USAGE_HW_TEXTURE | GRALLOC_USAGE_EXTERNAL_DISP);
     if (err != 0) {
@@ -2205,13 +2215,15 @@
 
             if (data2 == 0 || data2 == OMX_IndexParamPortDefinition) {
                 onPortSettingsChanged(data1);
-            } else if (data1 == kPortIndexOutput
-                    && data2 == OMX_IndexConfigCommonOutputCrop) {
+            } else if (data1 == kPortIndexOutput &&
+                        (data2 == OMX_IndexConfigCommonOutputCrop ||
+                         data2 == OMX_IndexConfigCommonScale)) {
 
                 sp<MetaData> oldOutputFormat = mOutputFormat;
                 initOutputFormat(mSource->getFormat());
 
-                if (formatHasNotablyChanged(oldOutputFormat, mOutputFormat)) {
+                if (data2 == OMX_IndexConfigCommonOutputCrop &&
+                    formatHasNotablyChanged(oldOutputFormat, mOutputFormat)) {
                     mOutputPortSettingsHaveChanged = true;
 
                     if (mNativeWindow != NULL) {
@@ -2230,6 +2242,39 @@
                         // already invalid, we'll know soon enough.
                         native_window_set_crop(mNativeWindow.get(), &crop);
                     }
+                } else if (data2 == OMX_IndexConfigCommonScale) {
+                    OMX_CONFIG_SCALEFACTORTYPE scale;
+                    InitOMXParams(&scale);
+                    scale.nPortIndex = kPortIndexOutput;
+
+                    // Change display dimension only when necessary.
+                    if (OK == mOMX->getConfig(
+                                        mNode,
+                                        OMX_IndexConfigCommonScale,
+                                        &scale, sizeof(scale))) {
+                        int32_t left, top, right, bottom;
+                        CHECK(mOutputFormat->findRect(kKeyCropRect,
+                                                      &left, &top,
+                                                      &right, &bottom));
+
+                        // The scale is in 16.16 format.
+                        // scale 1.0 = 0x010000. When there is no
+                        // need to change the display, skip it.
+                        LOGV("Get OMX_IndexConfigScale: 0x%lx/0x%lx",
+                                scale.xWidth, scale.xHeight);
+
+                        if (scale.xWidth != 0x010000) {
+                            mOutputFormat->setInt32(kKeyDisplayWidth,
+                                    ((right - left +  1) * scale.xWidth)  >> 16);
+                            mOutputPortSettingsHaveChanged = true;
+                        }
+
+                        if (scale.xHeight != 0x010000) {
+                            mOutputFormat->setInt32(kKeyDisplayHeight,
+                                    ((bottom  - top + 1) * scale.xHeight) >> 16);
+                            mOutputPortSettingsHaveChanged = true;
+                        }
+                    }
                 }
             }
             break;
diff --git a/media/libstagefright/StagefrightMetadataRetriever.cpp b/media/libstagefright/StagefrightMetadataRetriever.cpp
index ea3b801..4095fbf 100644
--- a/media/libstagefright/StagefrightMetadataRetriever.cpp
+++ b/media/libstagefright/StagefrightMetadataRetriever.cpp
@@ -48,7 +48,8 @@
     mClient.disconnect();
 }
 
-status_t StagefrightMetadataRetriever::setDataSource(const char *uri) {
+status_t StagefrightMetadataRetriever::setDataSource(
+        const char *uri, const KeyedVector<String8, String8> *headers) {
     LOGV("setDataSource(%s)", uri);
 
     mParsedMetaData = false;
@@ -56,7 +57,7 @@
     delete mAlbumArt;
     mAlbumArt = NULL;
 
-    mSource = DataSource::CreateFromURI(uri);
+    mSource = DataSource::CreateFromURI(uri, headers);
 
     if (mSource == NULL) {
         return UNKNOWN_ERROR;
@@ -231,6 +232,14 @@
     frame->mData = new uint8_t[frame->mSize];
     frame->mRotationAngle = rotationAngle;
 
+    int32_t displayWidth, displayHeight;
+    if (meta->findInt32(kKeyDisplayWidth, &displayWidth)) {
+        frame->mDisplayWidth = displayWidth;
+    }
+    if (meta->findInt32(kKeyDisplayHeight, &displayHeight)) {
+        frame->mDisplayHeight = displayHeight;
+    }
+
     int32_t srcFormat;
     CHECK(meta->findInt32(kKeyColorFormat, &srcFormat));
 
@@ -411,6 +420,12 @@
 
     mMetaData.add(METADATA_KEY_NUM_TRACKS, String8(tmp));
 
+    bool hasAudio = false;
+    bool hasVideo = false;
+    int32_t videoWidth = -1;
+    int32_t videoHeight = -1;
+    int32_t audioBitrate = -1;
+
     // The overall duration is the duration of the longest track.
     int64_t maxDurationUs = 0;
     for (size_t i = 0; i < numTracks; ++i) {
@@ -422,12 +437,55 @@
                 maxDurationUs = durationUs;
             }
         }
+
+        const char *mime;
+        if (trackMeta->findCString(kKeyMIMEType, &mime)) {
+            if (!hasAudio && !strncasecmp("audio/", mime, 6)) {
+                hasAudio = true;
+
+                if (!trackMeta->findInt32(kKeyBitRate, &audioBitrate)) {
+                    audioBitrate = -1;
+                }
+            } else if (!hasVideo && !strncasecmp("video/", mime, 6)) {
+                hasVideo = true;
+
+                CHECK(trackMeta->findInt32(kKeyWidth, &videoWidth));
+                CHECK(trackMeta->findInt32(kKeyHeight, &videoHeight));
+            }
+        }
     }
 
     // The duration value is a string representing the duration in ms.
     sprintf(tmp, "%lld", (maxDurationUs + 500) / 1000);
     mMetaData.add(METADATA_KEY_DURATION, String8(tmp));
 
+    if (hasAudio) {
+        mMetaData.add(METADATA_KEY_HAS_AUDIO, String8("yes"));
+    }
+
+    if (hasVideo) {
+        mMetaData.add(METADATA_KEY_HAS_VIDEO, String8("yes"));
+
+        sprintf(tmp, "%d", videoWidth);
+        mMetaData.add(METADATA_KEY_VIDEO_WIDTH, String8(tmp));
+
+        sprintf(tmp, "%d", videoHeight);
+        mMetaData.add(METADATA_KEY_VIDEO_HEIGHT, String8(tmp));
+    }
+
+    if (numTracks == 1 && hasAudio && audioBitrate >= 0) {
+        sprintf(tmp, "%d", audioBitrate);
+        mMetaData.add(METADATA_KEY_BITRATE, String8(tmp));
+    } else {
+        off64_t sourceSize;
+        if (mSource->getSize(&sourceSize) == OK) {
+            int64_t avgBitRate = (int64_t)(sourceSize * 8E6 / maxDurationUs);
+
+            sprintf(tmp, "%lld", avgBitRate);
+            mMetaData.add(METADATA_KEY_BITRATE, String8(tmp));
+        }
+    }
+
     if (numTracks == 1) {
         const char *fileMIME;
         CHECK(meta->findCString(kKeyMIMEType, &fileMIME));
diff --git a/media/libstagefright/WAVExtractor.cpp b/media/libstagefright/WAVExtractor.cpp
index 9332120..e9e5ef9 100644
--- a/media/libstagefright/WAVExtractor.cpp
+++ b/media/libstagefright/WAVExtractor.cpp
@@ -353,8 +353,6 @@
         return ERROR_END_OF_STREAM;
     }
 
-    mCurrentPos += n;
-
     buffer->set_range(0, n);
 
     if (mWaveFormat == WAVE_FORMAT_PCM) {
@@ -406,6 +404,7 @@
                 / (mNumChannels * bytesPerSample) / mSampleRate);
 
     buffer->meta_data()->setInt32(kKeyIsSyncFrame, 1);
+    mCurrentPos += n;
 
     *out = buffer;
 
diff --git a/media/libstagefright/chromium_http/Android.mk b/media/libstagefright/chromium_http/Android.mk
new file mode 100644
index 0000000..80b2478
--- /dev/null
+++ b/media/libstagefright/chromium_http/Android.mk
@@ -0,0 +1,25 @@
+LOCAL_PATH:= $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES:=       \
+        ChromiumHTTPDataSource.cpp        \
+        support.cpp                     \
+
+LOCAL_C_INCLUDES:= \
+        $(JNI_H_INCLUDE) \
+        frameworks/base/media/libstagefright \
+        $(TOP)/frameworks/base/include/media/stagefright/openmax \
+        external/chromium \
+        external/chromium/android
+
+LOCAL_CFLAGS += -Wno-multichar
+
+ifneq ($(TARGET_SIMULATOR),true)
+LOCAL_SHARED_LIBRARIES += libstlport
+include external/stlport/libstlport.mk
+endif
+
+LOCAL_MODULE:= libstagefright_chromium_http
+
+include $(BUILD_STATIC_LIBRARY)
diff --git a/media/libstagefright/chromium_http/ChromiumHTTPDataSource.cpp b/media/libstagefright/chromium_http/ChromiumHTTPDataSource.cpp
new file mode 100644
index 0000000..949a5e4
--- /dev/null
+++ b/media/libstagefright/chromium_http/ChromiumHTTPDataSource.cpp
@@ -0,0 +1,327 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "ChromiumHTTPDataSource"
+#include <media/stagefright/foundation/ADebug.h>
+
+#include "include/ChromiumHTTPDataSource.h"
+
+#include <media/stagefright/foundation/ALooper.h>
+#include <media/stagefright/MediaErrors.h>
+
+#include "support.h"
+
+namespace android {
+
+ChromiumHTTPDataSource::ChromiumHTTPDataSource(uint32_t flags)
+    : mFlags(flags),
+      mState(DISCONNECTED),
+      mDelegate(new SfDelegate),
+      mCurrentOffset(0),
+      mIOResult(OK),
+      mContentSize(-1),
+      mNumBandwidthHistoryItems(0),
+      mTotalTransferTimeUs(0),
+      mTotalTransferBytes(0),
+      mDecryptHandle(NULL),
+      mDrmManagerClient(NULL) {
+    mDelegate->setOwner(this);
+}
+
+ChromiumHTTPDataSource::~ChromiumHTTPDataSource() {
+    disconnect();
+
+    delete mDelegate;
+    mDelegate = NULL;
+
+    if (mDrmManagerClient != NULL) {
+        delete mDrmManagerClient;
+        mDrmManagerClient = NULL;
+    }
+}
+
+status_t ChromiumHTTPDataSource::connect(
+        const char *uri,
+        const KeyedVector<String8, String8> *headers,
+        off64_t offset) {
+    Mutex::Autolock autoLock(mLock);
+
+    return connect_l(uri, headers, offset);
+}
+
+status_t ChromiumHTTPDataSource::connect_l(
+        const char *uri,
+        const KeyedVector<String8, String8> *headers,
+        off64_t offset) {
+    if (mState != DISCONNECTED) {
+        disconnect_l();
+    }
+
+    if (!(mFlags & kFlagIncognito)) {
+        LOG_PRI(ANDROID_LOG_INFO, LOG_TAG, "connect to %s @%lld", uri, offset);
+    } else {
+        LOG_PRI(ANDROID_LOG_INFO, LOG_TAG,
+                "connect to <URL suppressed> @%lld", offset);
+    }
+
+    mURI = uri;
+
+    if (headers != NULL) {
+        mHeaders = *headers;
+    } else {
+        mHeaders.clear();
+    }
+
+    mState = CONNECTING;
+    mContentSize = -1;
+    mCurrentOffset = offset;
+
+    mDelegate->initiateConnection(mURI.c_str(), &mHeaders, offset);
+
+    while (mState == CONNECTING) {
+        mCondition.wait(mLock);
+    }
+
+    return mState == CONNECTED ? OK : mIOResult;
+}
+
+void ChromiumHTTPDataSource::onConnectionEstablished(int64_t contentSize) {
+    Mutex::Autolock autoLock(mLock);
+    mState = CONNECTED;
+    mContentSize = (contentSize < 0) ? -1 : contentSize + mCurrentOffset;
+    mCondition.broadcast();
+}
+
+void ChromiumHTTPDataSource::onConnectionFailed(status_t err) {
+    Mutex::Autolock autoLock(mLock);
+    mState = DISCONNECTED;
+    mCondition.broadcast();
+
+    mURI.clear();
+
+    mIOResult = err;
+
+    clearDRMState_l();
+}
+
+void ChromiumHTTPDataSource::disconnect() {
+    Mutex::Autolock autoLock(mLock);
+    disconnect_l();
+}
+
+void ChromiumHTTPDataSource::disconnect_l() {
+    if (mState == DISCONNECTED) {
+        return;
+    }
+
+    mState = DISCONNECTING;
+    mIOResult = -EINTR;
+
+    mDelegate->initiateDisconnect();
+
+    while (mState == DISCONNECTING) {
+        mCondition.wait(mLock);
+    }
+
+    CHECK_EQ((int)mState, (int)DISCONNECTED);
+}
+
+status_t ChromiumHTTPDataSource::initCheck() const {
+    Mutex::Autolock autoLock(mLock);
+
+    return mState == CONNECTED ? OK : NO_INIT;
+}
+
+ssize_t ChromiumHTTPDataSource::readAt(off64_t offset, void *data, size_t size) {
+    Mutex::Autolock autoLock(mLock);
+
+    if (mState != CONNECTED) {
+        return ERROR_NOT_CONNECTED;
+    }
+
+    if (offset != mCurrentOffset) {
+        AString tmp = mURI;
+        KeyedVector<String8, String8> tmpHeaders = mHeaders;
+
+        disconnect_l();
+
+        status_t err = connect_l(tmp.c_str(), &tmpHeaders, offset);
+
+        if (err != OK) {
+            return err;
+        }
+    }
+
+    mState = READING;
+
+    int64_t startTimeUs = ALooper::GetNowUs();
+
+    mDelegate->initiateRead(data, size);
+
+    while (mState == READING) {
+        mCondition.wait(mLock);
+    }
+
+    if (mIOResult < OK) {
+        return mIOResult;
+    }
+
+    if (mState == CONNECTED) {
+        int64_t delayUs = ALooper::GetNowUs() - startTimeUs;
+
+        // The read operation was successful, mIOResult contains
+        // the number of bytes read.
+        addBandwidthMeasurement_l(mIOResult, delayUs);
+
+        mCurrentOffset += mIOResult;
+        return mIOResult;
+    }
+
+    return ERROR_IO;
+}
+
+void ChromiumHTTPDataSource::onReadCompleted(ssize_t size) {
+    Mutex::Autolock autoLock(mLock);
+
+    mIOResult = size;
+
+    if (mState == READING) {
+        mState = CONNECTED;
+        mCondition.broadcast();
+    }
+}
+
+status_t ChromiumHTTPDataSource::getSize(off64_t *size) {
+    Mutex::Autolock autoLock(mLock);
+
+    if (mContentSize < 0) {
+        return ERROR_UNSUPPORTED;
+    }
+
+    *size = mContentSize;
+
+    return OK;
+}
+
+uint32_t ChromiumHTTPDataSource::flags() {
+    return kWantsPrefetching;
+}
+
+// static
+void ChromiumHTTPDataSource::InitiateRead(
+        ChromiumHTTPDataSource *me, void *data, size_t size) {
+    me->initiateRead(data, size);
+}
+
+void ChromiumHTTPDataSource::initiateRead(void *data, size_t size) {
+    mDelegate->initiateRead(data, size);
+}
+
+void ChromiumHTTPDataSource::onDisconnectComplete() {
+    Mutex::Autolock autoLock(mLock);
+    CHECK_EQ((int)mState, (int)DISCONNECTING);
+
+    mState = DISCONNECTED;
+    mURI.clear();
+
+    mCondition.broadcast();
+
+    clearDRMState_l();
+}
+
+void ChromiumHTTPDataSource::addBandwidthMeasurement_l(
+        size_t numBytes, int64_t delayUs) {
+    BandwidthEntry entry;
+    entry.mDelayUs = delayUs;
+    entry.mNumBytes = numBytes;
+    mTotalTransferTimeUs += delayUs;
+    mTotalTransferBytes += numBytes;
+
+    mBandwidthHistory.push_back(entry);
+    if (++mNumBandwidthHistoryItems > 100) {
+        BandwidthEntry *entry = &*mBandwidthHistory.begin();
+        mTotalTransferTimeUs -= entry->mDelayUs;
+        mTotalTransferBytes -= entry->mNumBytes;
+        mBandwidthHistory.erase(mBandwidthHistory.begin());
+        --mNumBandwidthHistoryItems;
+    }
+}
+
+bool ChromiumHTTPDataSource::estimateBandwidth(int32_t *bandwidth_bps) {
+    Mutex::Autolock autoLock(mLock);
+
+    if (mNumBandwidthHistoryItems < 2) {
+        return false;
+    }
+
+    *bandwidth_bps = ((double)mTotalTransferBytes * 8E6 / mTotalTransferTimeUs);
+
+    return true;
+}
+
+sp<DecryptHandle> ChromiumHTTPDataSource::DrmInitialization() {
+    Mutex::Autolock autoLock(mLock);
+
+    if (mDrmManagerClient == NULL) {
+        mDrmManagerClient = new DrmManagerClient();
+    }
+
+    if (mDrmManagerClient == NULL) {
+        return NULL;
+    }
+
+    if (mDecryptHandle == NULL) {
+        /* Note if redirect occurs, mUri is the redirect uri instead of the
+         * original one
+         */
+        mDecryptHandle = mDrmManagerClient->openDecryptSession(
+                String8(mURI.c_str()));
+    }
+
+    if (mDecryptHandle == NULL) {
+        delete mDrmManagerClient;
+        mDrmManagerClient = NULL;
+    }
+
+    return mDecryptHandle;
+}
+
+void ChromiumHTTPDataSource::getDrmInfo(
+        sp<DecryptHandle> &handle, DrmManagerClient **client) {
+    Mutex::Autolock autoLock(mLock);
+
+    handle = mDecryptHandle;
+    *client = mDrmManagerClient;
+}
+
+String8 ChromiumHTTPDataSource::getUri() {
+    Mutex::Autolock autoLock(mLock);
+
+    return String8(mURI.c_str());
+}
+
+void ChromiumHTTPDataSource::clearDRMState_l() {
+    if (mDecryptHandle != NULL) {
+        // To release mDecryptHandle
+        CHECK(mDrmManagerClient);
+        mDrmManagerClient->closeDecryptSession(mDecryptHandle);
+        mDecryptHandle = NULL;
+    }
+}
+
+}  // namespace android
+
diff --git a/media/libstagefright/chromium_http/support.cpp b/media/libstagefright/chromium_http/support.cpp
new file mode 100644
index 0000000..7ac56e8
--- /dev/null
+++ b/media/libstagefright/chromium_http/support.cpp
@@ -0,0 +1,457 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "ChromiumHTTPDataSourceSupport"
+#include <utils/Log.h>
+
+#include <media/stagefright/foundation/AString.h>
+
+#include "support.h"
+
+#include "android/net/android_network_library_impl.h"
+#include "base/thread.h"
+#include "net/base/host_resolver.h"
+#include "net/base/ssl_config_service.h"
+#include "net/http/http_auth_handler_factory.h"
+#include "net/http/http_cache.h"
+#include "net/proxy/proxy_config_service_android.h"
+
+#include "include/ChromiumHTTPDataSource.h"
+
+#include <cutils/properties.h>
+#include <media/stagefright/MediaErrors.h>
+
+namespace android {
+
+static Mutex gNetworkThreadLock;
+static base::Thread *gNetworkThread = NULL;
+static scoped_refptr<URLRequestContext> gReqContext;
+
+static void InitializeNetworkThreadIfNecessary() {
+    Mutex::Autolock autoLock(gNetworkThreadLock);
+    if (gNetworkThread == NULL) {
+        gNetworkThread = new base::Thread("network");
+        base::Thread::Options options;
+        options.message_loop_type = MessageLoop::TYPE_IO;
+        CHECK(gNetworkThread->StartWithOptions(options));
+
+        gReqContext = new SfRequestContext;
+
+        net::AndroidNetworkLibrary::RegisterSharedInstance(
+                new SfNetworkLibrary);
+    }
+}
+
+static void MY_LOGI(const char *s) {
+    LOG_PRI(ANDROID_LOG_INFO, LOG_TAG, "%s", s);
+}
+
+static void MY_LOGV(const char *s) {
+#if !defined(LOG_NDEBUG) || LOG_NDEBUG == 0
+    LOG_PRI(ANDROID_LOG_VERBOSE, LOG_TAG, "%s", s);
+#endif
+}
+
+SfNetLog::SfNetLog()
+    : mNextID(1) {
+}
+
+void SfNetLog::AddEntry(
+        EventType type,
+        const base::TimeTicks &time,
+        const Source &source,
+        EventPhase phase,
+        EventParameters *params) {
+#if 0
+    MY_LOGI(StringPrintf(
+                "AddEntry time=%s type=%s source=%s phase=%s\n",
+                TickCountToString(time).c_str(),
+                EventTypeToString(type),
+                SourceTypeToString(source.type),
+                EventPhaseToString(phase)).c_str());
+#endif
+}
+
+uint32 SfNetLog::NextID() {
+    return mNextID++;
+}
+
+net::NetLog::LogLevel SfNetLog::GetLogLevel() const {
+    return LOG_ALL;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+SfRequestContext::SfRequestContext() {
+    AString ua;
+    ua.append("stagefright/1.2 (Linux;Android ");
+
+#if (PROPERTY_VALUE_MAX < 8)
+#error "PROPERTY_VALUE_MAX must be at least 8"
+#endif
+
+    char value[PROPERTY_VALUE_MAX];
+    property_get("ro.build.version.release", value, "Unknown");
+    ua.append(value);
+    ua.append(")");
+
+    mUserAgent = ua.c_str();
+
+    net_log_ = new SfNetLog;
+
+    host_resolver_ =
+        net::CreateSystemHostResolver(
+                net::HostResolver::kDefaultParallelism,
+                NULL /* resolver_proc */,
+                net_log_);
+
+    ssl_config_service_ =
+        net::SSLConfigService::CreateSystemSSLConfigService();
+
+    proxy_service_ = net::ProxyService::CreateWithoutProxyResolver(
+            new net::ProxyConfigServiceAndroid, net_log_);
+
+    http_transaction_factory_ = new net::HttpCache(
+            host_resolver_,
+            dnsrr_resolver_,
+            dns_cert_checker_.get(),
+            proxy_service_.get(),
+            ssl_config_service_.get(),
+            net::HttpAuthHandlerFactory::CreateDefault(host_resolver_),
+            network_delegate_,
+            net_log_,
+            NULL);  // backend_factory
+}
+
+const std::string &SfRequestContext::GetUserAgent(const GURL &url) const {
+    return mUserAgent;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+SfNetworkLibrary::SfNetworkLibrary() {}
+
+SfNetworkLibrary::VerifyResult SfNetworkLibrary::VerifyX509CertChain(
+        const std::vector<std::string>& cert_chain,
+        const std::string& hostname,
+        const std::string& auth_type) {
+    return VERIFY_OK;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+SfDelegate::SfDelegate()
+    : mOwner(NULL),
+      mURLRequest(NULL),
+      mReadBuffer(new net::IOBufferWithSize(8192)),
+      mNumBytesRead(0),
+      mNumBytesTotal(0),
+      mDataDestination(NULL),
+      mAtEOS(false) {
+    InitializeNetworkThreadIfNecessary();
+}
+
+SfDelegate::~SfDelegate() {
+    CHECK(mURLRequest == NULL);
+}
+
+void SfDelegate::setOwner(ChromiumHTTPDataSource *owner) {
+    mOwner = owner;
+}
+
+void SfDelegate::OnReceivedRedirect(
+            URLRequest *request, const GURL &new_url, bool *defer_redirect) {
+    MY_LOGI("OnReceivedRedirect");
+}
+
+void SfDelegate::OnAuthRequired(
+            URLRequest *request, net::AuthChallengeInfo *auth_info) {
+    MY_LOGI("OnAuthRequired");
+
+    inherited::OnAuthRequired(request, auth_info);
+}
+
+void SfDelegate::OnCertificateRequested(
+            URLRequest *request, net::SSLCertRequestInfo *cert_request_info) {
+    MY_LOGI("OnCertificateRequested");
+
+    inherited::OnCertificateRequested(request, cert_request_info);
+}
+
+void SfDelegate::OnSSLCertificateError(
+            URLRequest *request, int cert_error, net::X509Certificate *cert) {
+    fprintf(stderr, "OnSSLCertificateError cert_error=%d\n", cert_error);
+
+    inherited::OnSSLCertificateError(request, cert_error, cert);
+}
+
+void SfDelegate::OnGetCookies(URLRequest *request, bool blocked_by_policy) {
+    MY_LOGI("OnGetCookies");
+}
+
+void SfDelegate::OnSetCookie(
+        URLRequest *request,
+        const std::string &cookie_line,
+        const net::CookieOptions &options,
+        bool blocked_by_policy) {
+    MY_LOGI("OnSetCookie");
+}
+
+void SfDelegate::OnResponseStarted(URLRequest *request) {
+    if (request->status().status() != URLRequestStatus::SUCCESS) {
+        MY_LOGI(StringPrintf(
+                    "Request failed with status %d and os_error %d",
+                    request->status().status(),
+                    request->status().os_error()).c_str());
+
+        delete mURLRequest;
+        mURLRequest = NULL;
+
+        mOwner->onConnectionFailed(ERROR_IO);
+        return;
+    } else if (mRangeRequested && request->GetResponseCode() != 206) {
+        MY_LOGI(StringPrintf(
+                    "We requested a content range, but server didn't "
+                    "support that. (responded with %d)",
+                    request->GetResponseCode()).c_str());
+
+        delete mURLRequest;
+        mURLRequest = NULL;
+
+        mOwner->onConnectionFailed(-EPIPE);
+        return;
+    } else if ((request->GetResponseCode() / 100) != 2) {
+        MY_LOGI(StringPrintf(
+                    "Server responded with http status %d",
+                    request->GetResponseCode()).c_str());
+
+        delete mURLRequest;
+        mURLRequest = NULL;
+
+        mOwner->onConnectionFailed(ERROR_IO);
+        return;
+    }
+
+    MY_LOGV("OnResponseStarted");
+
+    std::string headers;
+    request->GetAllResponseHeaders(&headers);
+
+    MY_LOGV(StringPrintf("response headers: %s", headers.c_str()).c_str());
+
+    mOwner->onConnectionEstablished(request->GetExpectedContentSize());
+}
+
+void SfDelegate::OnReadCompleted(URLRequest *request, int bytes_read) {
+    if (bytes_read == -1) {
+        MY_LOGI(StringPrintf(
+                    "OnReadCompleted, read failed, status %d",
+                    request->status().status()).c_str());
+
+        mOwner->onReadCompleted(ERROR_IO);
+        return;
+    }
+
+    MY_LOGV(StringPrintf("OnReadCompleted, read %d bytes", bytes_read).c_str());
+
+    if (bytes_read < 0) {
+        MY_LOGI(StringPrintf(
+                    "Read failed w/ status %d\n",
+                    request->status().status()).c_str());
+
+        mOwner->onReadCompleted(ERROR_IO);
+        return;
+    } else if (bytes_read == 0) {
+        mAtEOS = true;
+        mOwner->onReadCompleted(mNumBytesRead);
+        return;
+    }
+
+    CHECK_GT(bytes_read, 0);
+    CHECK_LE(mNumBytesRead + bytes_read, mNumBytesTotal);
+
+    memcpy((uint8_t *)mDataDestination + mNumBytesRead,
+           mReadBuffer->data(),
+           bytes_read);
+
+    mNumBytesRead += bytes_read;
+
+    readMore(request);
+}
+
+void SfDelegate::readMore(URLRequest *request) {
+    while (mNumBytesRead < mNumBytesTotal) {
+        size_t copy = mNumBytesTotal - mNumBytesRead;
+        if (copy > mReadBuffer->size()) {
+            copy = mReadBuffer->size();
+        }
+
+        int n;
+        if (request->Read(mReadBuffer, copy, &n)) {
+            MY_LOGV(StringPrintf("Read %d bytes directly.", n).c_str());
+
+            CHECK_LE((size_t)n, copy);
+
+            memcpy((uint8_t *)mDataDestination + mNumBytesRead,
+                   mReadBuffer->data(),
+                   n);
+
+            mNumBytesRead += n;
+
+            if (n == 0) {
+                mAtEOS = true;
+                break;
+            }
+        } else {
+            MY_LOGV("readMore pending read");
+
+            if (request->status().status() != URLRequestStatus::IO_PENDING) {
+                MY_LOGI(StringPrintf(
+                            "Direct read failed w/ status %d\n",
+                            request->status().status()).c_str());
+
+                mOwner->onReadCompleted(ERROR_IO);
+                return;
+            }
+
+            return;
+        }
+    }
+
+    mOwner->onReadCompleted(mNumBytesRead);
+}
+
+void SfDelegate::initiateConnection(
+        const char *uri,
+        const KeyedVector<String8, String8> *headers,
+        off64_t offset) {
+    GURL url(uri);
+
+    MessageLoop *loop = gNetworkThread->message_loop();
+    loop->PostTask(
+            FROM_HERE,
+            NewRunnableFunction(
+                &SfDelegate::OnInitiateConnectionWrapper,
+                this,
+                url,
+                headers,
+                offset));
+
+}
+
+// static
+void SfDelegate::OnInitiateConnectionWrapper(
+        SfDelegate *me, GURL url,
+        const KeyedVector<String8, String8> *headers,
+        off64_t offset) {
+    me->onInitiateConnection(url, headers, offset);
+}
+
+void SfDelegate::onInitiateConnection(
+        const GURL &url,
+        const KeyedVector<String8, String8> *extra,
+        off64_t offset) {
+    CHECK(mURLRequest == NULL);
+
+    mURLRequest = new URLRequest(url, this);
+    mAtEOS = false;
+
+    mRangeRequested = false;
+
+    if (offset != 0 || extra != NULL) {
+        net::HttpRequestHeaders headers =
+            mURLRequest->extra_request_headers();
+
+        if (offset != 0) {
+            headers.AddHeaderFromString(
+                    StringPrintf("Range: bytes=%lld-", offset).c_str());
+
+            mRangeRequested = true;
+        }
+
+        if (extra != NULL) {
+            for (size_t i = 0; i < extra->size(); ++i) {
+                AString s;
+                s.append(extra->keyAt(i).string());
+                s.append(": ");
+                s.append(extra->valueAt(i).string());
+
+                headers.AddHeaderFromString(s.c_str());
+            }
+        }
+
+        mURLRequest->SetExtraRequestHeaders(headers);
+    }
+
+    mURLRequest->set_context(gReqContext);
+
+    mURLRequest->Start();
+}
+
+void SfDelegate::initiateDisconnect() {
+    MessageLoop *loop = gNetworkThread->message_loop();
+    loop->PostTask(
+            FROM_HERE,
+            NewRunnableFunction(
+                &SfDelegate::OnInitiateDisconnectWrapper, this));
+}
+
+// static
+void SfDelegate::OnInitiateDisconnectWrapper(SfDelegate *me) {
+    me->onInitiateDisconnect();
+}
+
+void SfDelegate::onInitiateDisconnect() {
+    mURLRequest->Cancel();
+
+    delete mURLRequest;
+    mURLRequest = NULL;
+
+    mOwner->onDisconnectComplete();
+}
+
+void SfDelegate::initiateRead(void *data, size_t size) {
+    MessageLoop *loop = gNetworkThread->message_loop();
+    loop->PostTask(
+            FROM_HERE,
+            NewRunnableFunction(
+                &SfDelegate::OnInitiateReadWrapper, this, data, size));
+}
+
+// static
+void SfDelegate::OnInitiateReadWrapper(
+        SfDelegate *me, void *data, size_t size) {
+    me->onInitiateRead(data, size);
+}
+
+void SfDelegate::onInitiateRead(void *data, size_t size) {
+    CHECK(mURLRequest != NULL);
+
+    mNumBytesRead = 0;
+    mNumBytesTotal = size;
+    mDataDestination = data;
+
+    if (mAtEOS) {
+        mOwner->onReadCompleted(0);
+        return;
+    }
+
+    readMore(mURLRequest);
+}
+
+}  // namespace android
+
diff --git a/media/libstagefright/chromium_http/support.h b/media/libstagefright/chromium_http/support.h
new file mode 100644
index 0000000..634ac93
--- /dev/null
+++ b/media/libstagefright/chromium_http/support.h
@@ -0,0 +1,159 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef SUPPORT_H_
+
+#define SUPPORT_H_
+
+#include <assert.h>
+
+#include "net/base/net_log.h"
+#include "net/url_request/url_request.h"
+#include "net/url_request/url_request_context.h"
+#include "net/base/android_network_library.h"
+#include "net/base/io_buffer.h"
+
+#include <utils/KeyedVector.h>
+#include <utils/String8.h>
+
+namespace android {
+
+struct SfNetLog : public net::NetLog {
+    SfNetLog();
+
+    virtual void AddEntry(
+            EventType type,
+            const base::TimeTicks &time,
+            const Source &source,
+            EventPhase phase,
+            EventParameters *params);
+
+    virtual uint32 NextID();
+    virtual LogLevel GetLogLevel() const;
+
+private:
+    uint32 mNextID;
+
+    DISALLOW_EVIL_CONSTRUCTORS(SfNetLog);
+};
+
+struct SfRequestContext : public URLRequestContext {
+    SfRequestContext();
+
+    virtual const std::string &GetUserAgent(const GURL &url) const;
+
+private:
+    std::string mUserAgent;
+
+    DISALLOW_EVIL_CONSTRUCTORS(SfRequestContext);
+};
+
+// This is required for https support, we don't really verify certificates,
+// we accept anything...
+struct SfNetworkLibrary : public net::AndroidNetworkLibrary {
+    SfNetworkLibrary();
+
+    virtual VerifyResult VerifyX509CertChain(
+            const std::vector<std::string>& cert_chain,
+            const std::string& hostname,
+            const std::string& auth_type);
+
+private:
+    DISALLOW_EVIL_CONSTRUCTORS(SfNetworkLibrary);
+};
+
+struct ChromiumHTTPDataSource;
+
+struct SfDelegate : public URLRequest::Delegate {
+    SfDelegate();
+    virtual ~SfDelegate();
+
+    void initiateConnection(
+            const char *uri,
+            const KeyedVector<String8, String8> *headers,
+            off64_t offset);
+
+    void initiateDisconnect();
+    void initiateRead(void *data, size_t size);
+
+    void setOwner(ChromiumHTTPDataSource *mOwner);
+
+    virtual void OnReceivedRedirect(
+            URLRequest *request, const GURL &new_url, bool *defer_redirect);
+
+    virtual void OnAuthRequired(
+            URLRequest *request, net::AuthChallengeInfo *auth_info);
+
+    virtual void OnCertificateRequested(
+            URLRequest *request, net::SSLCertRequestInfo *cert_request_info);
+
+    virtual void OnSSLCertificateError(
+            URLRequest *request, int cert_error, net::X509Certificate *cert);
+
+    virtual void OnGetCookies(URLRequest *request, bool blocked_by_policy);
+
+    virtual void OnSetCookie(
+            URLRequest *request,
+            const std::string &cookie_line,
+            const net::CookieOptions &options,
+            bool blocked_by_policy);
+
+    virtual void OnResponseStarted(URLRequest *request);
+
+    virtual void OnReadCompleted(URLRequest *request, int bytes_read);
+
+private:
+    typedef Delegate inherited;
+
+    ChromiumHTTPDataSource *mOwner;
+
+    URLRequest *mURLRequest;
+    scoped_refptr<net::IOBufferWithSize> mReadBuffer;
+
+    size_t mNumBytesRead;
+    size_t mNumBytesTotal;
+    void *mDataDestination;
+
+    bool mRangeRequested;
+    bool mAtEOS;
+
+    void readMore(URLRequest *request);
+
+    static void OnInitiateConnectionWrapper(
+            SfDelegate *me,
+            GURL url,
+            const KeyedVector<String8, String8> *headers,
+            off64_t offset);
+
+    static void OnInitiateDisconnectWrapper(SfDelegate *me);
+
+    static void OnInitiateReadWrapper(
+            SfDelegate *me, void *data, size_t size);
+
+    void onInitiateConnection(
+            const GURL &url,
+            const KeyedVector<String8, String8> *headers,
+            off64_t offset);
+
+    void onInitiateDisconnect();
+    void onInitiateRead(void *data, size_t size);
+
+    DISALLOW_EVIL_CONSTRUCTORS(SfDelegate);
+};
+
+}  // namespace android
+
+#endif  // SUPPORT_H_
diff --git a/media/libstagefright/codecs/aacdec/sbr_dec.cpp b/media/libstagefright/codecs/aacdec/sbr_dec.cpp
index 8fcc3ce..8519b17 100644
--- a/media/libstagefright/codecs/aacdec/sbr_dec.cpp
+++ b/media/libstagefright/codecs/aacdec/sbr_dec.cpp
@@ -1,5 +1,5 @@
 /* ------------------------------------------------------------------
- * Copyright (C) 1998-2009 PacketVideo
+ * Copyright (C) 1998-2010 PacketVideo
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -447,7 +447,12 @@
 
             if (xoverBand > sbrDec->highSubband)
             {
-                xoverBand = 32; /* error condition, default to upsampling mode */
+                /*
+                 * error condition, default to upsampling mode
+                 * and make sure that the number of bands for xover does
+                 * not exceed the number of high freq bands.
+                 */
+                xoverBand = (sbrDec->highSubband > 32)? 32: sbrDec->highSubband;
             }
 
             m = sbrDec->bufReadOffs + i;    /*  2 + i */
@@ -558,18 +563,22 @@
         /*
          *  Set Circular buffer for PS hybrid analysis
          */
+
+        int32_t *pt_temp = &scratch_mem[2][32];
+
         for (i = 0, j = 0; i < 3; i++)
         {
 
-            pv_memmove(&scratch_mem[2][32 + j     ],
+            pv_memmove(&pt_temp[ j],
                        hParametricStereoDec->hHybrid->mQmfBufferReal[i],
                        HYBRID_FILTER_LENGTH_m_1*sizeof(*hParametricStereoDec->hHybrid->mQmfBufferReal));
-            pv_memmove(&scratch_mem[2][32 + j + 44],
+            pv_memmove(&pt_temp[ j + 44],
                        hParametricStereoDec->hHybrid->mQmfBufferImag[i],
                        HYBRID_FILTER_LENGTH_m_1*sizeof(*hParametricStereoDec->hHybrid->mQmfBufferImag));
             j += 88;
         }
 
+
         pv_memset((void *)&qmf_PS_generated_Real[hParametricStereoDec->usb],
                   0,
                   (64 - hParametricStereoDec->usb)*sizeof(*qmf_PS_generated_Real));
@@ -626,19 +635,23 @@
          *  Save Circular buffer history used on PS hybrid analysis
          */
 
+
+        pt_temp = &scratch_mem[2][64];
+
         for (i = 0, j = 0; i < 3; i++)
         {
             pv_memmove(hParametricStereoDec->hHybrid->mQmfBufferReal[i],
-                       &scratch_mem[2][ 64 + j     ],
+                       &pt_temp[ j],
                        HYBRID_FILTER_LENGTH_m_1*sizeof(*hParametricStereoDec->hHybrid->mQmfBufferReal));
 
             pv_memmove(hParametricStereoDec->hHybrid->mQmfBufferImag[i],
-                       &scratch_mem[2][ 64 + j + 44],
+                       &pt_temp[ j + 44],
                        HYBRID_FILTER_LENGTH_m_1*sizeof(*hParametricStereoDec->hHybrid->mQmfBufferImag));
 
             j += 88;
         }
 
+
         pv_memmove(hFrameData->V, &circular_buffer_s[0], 1152*sizeof(*circular_buffer_s));
 
         /*
@@ -746,7 +759,12 @@
 
                 if (xoverBand > sbrDec->highSubband)
                 {
-                    xoverBand = 32; /* error condition, default to upsampling mode */
+                    /*
+                     * error condition, default to upsampling mode
+                     * and make sure that the number of bands for xover does
+                     * not exceed the number of high freq bands.
+                     */
+                    xoverBand = (sbrDec->highSubband > 32)? 32: sbrDec->highSubband;
                 }
             }
             else
diff --git a/media/libstagefright/codecs/aacenc/AACEncoder.cpp b/media/libstagefright/codecs/aacenc/AACEncoder.cpp
index a8b1292..e4ff128 100644
--- a/media/libstagefright/codecs/aacenc/AACEncoder.cpp
+++ b/media/libstagefright/codecs/aacenc/AACEncoder.cpp
@@ -189,6 +189,9 @@
     delete mApiHandle;
     mApiHandle = NULL;
 
+    delete mMemOperator;
+    mMemOperator = NULL;
+
     mStarted = false;
 
     return OK;
diff --git a/media/libstagefright/codecs/aacenc/Android.mk b/media/libstagefright/codecs/aacenc/Android.mk
index cda4f9d..f9cc6a3 100644
--- a/media/libstagefright/codecs/aacenc/Android.mk
+++ b/media/libstagefright/codecs/aacenc/Android.mk
@@ -2,7 +2,7 @@
 include $(CLEAR_VARS)
 include frameworks/base/media/libstagefright/codecs/common/Config.mk
 
-LOCAL_PRELINK_MODULE := false
+
 
 LOCAL_SRC_FILES := basic_op/basicop2.c basic_op/oper_32b.c
 
diff --git a/media/libstagefright/codecs/aacenc/SampleCode/AAC_E_SAMPLES.c b/media/libstagefright/codecs/aacenc/SampleCode/AAC_E_SAMPLES.c
index 64d012d..774da7b 100644
--- a/media/libstagefright/codecs/aacenc/SampleCode/AAC_E_SAMPLES.c
+++ b/media/libstagefright/codecs/aacenc/SampleCode/AAC_E_SAMPLES.c
@@ -188,7 +188,7 @@
 	useData.memflag = VO_IMF_USERMEMOPERATOR;

 	useData.memData = (VO_PTR)(&moper);

 	// open encoder dll;

-	handle = dlopen("/data/local/tmp/libvoAACEncv7.so", RTLD_NOW);

+	handle = dlopen("libstagefright.so", RTLD_NOW);

 	if(handle == 0)

 	{

 		printf("open dll error......");

diff --git a/media/libstagefright/codecs/aacenc/SampleCode/Android.mk b/media/libstagefright/codecs/aacenc/SampleCode/Android.mk
index 52c9c07..ba3f4d2 100644
--- a/media/libstagefright/codecs/aacenc/SampleCode/Android.mk
+++ b/media/libstagefright/codecs/aacenc/SampleCode/Android.mk
@@ -1,24 +1,25 @@
 LOCAL_PATH := $(call my-dir)
 include $(CLEAR_VARS)
 
-LOCAL_SRC_FILES := 	AAC_E_SAMPLES.c
-	
-LOCAL_SRC_FILES += 	\
-	../../../Common/cmnMemory.c 
+LOCAL_SRC_FILES := \
+    AAC_E_SAMPLES.c \
+    ../../common/cmnMemory.c
 
-LOCAL_MODULE := TestvoAACEnc
+LOCAL_CFLAGS += $(VO_CFLAGS)
+
+LOCAL_MODULE_TAGS := debug
+
+LOCAL_MODULE := AACEncTest
 
 LOCAL_ARM_MODE := arm
 
-LOCAL_STATIC_LIBRARIES := 
-
-LOCAL_SHARED_LIBRARIES := libvoAACEnc
+LOCAL_SHARED_LIBRARIES := \
+    libstagefright \
+    libdl
 
 LOCAL_C_INCLUDES := \
-	$(LOCAL_PATH)/ \
-	$(LOCAL_PATH)/../../../Common \
-	$(LOCAL_PATH)/../../../Include \
+    $(LOCAL_PATH)/ \
+    $(LOCAL_PATH)/../../common \
+    $(LOCAL_PATH)/../../common/include \
 
-LOCAL_CFLAGS := $(VO_CFLAGS)
-	
 include $(BUILD_EXECUTABLE)
diff --git a/media/libstagefright/codecs/aacenc/SampleCode/eclair/Makefile b/media/libstagefright/codecs/aacenc/SampleCode/eclair/Makefile
deleted file mode 100644
index 22c5dc1..0000000
--- a/media/libstagefright/codecs/aacenc/SampleCode/eclair/Makefile
+++ /dev/null
@@ -1,55 +0,0 @@
-#/*

-#** Copyright 2003-2010, VisualOn, Inc.

-#**

-#** 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.

-#*/

-

-# target6

-# available: pc, v4(armv4), v5(armv5), v5x(armv5 xscale), v6(armv6), v7(cortex-a8 neon)

-VOTT:= v7

-

-

-# module type

-# please specify the type of your module: lib or exe

-VOMT:= exe

-

-

-# module macros

-# please append the additional macro definitions here for your module if necessary. 

-# e.g. -DVISUALON, macro VISUALON defined for your module 

-VOMM:= #ARMV5E

-

-

-

-# please specify the name of your module

-VOTARGET:= voAACEncTestv7

-

-

-# please modify here to be sure to see the g1.mk

-include ../../../../Tools/eclair.mk 

-

-# dependent libraries.

-VODEPLIBS:=-ldl

-

-# module source

-# please modify here to be sure to see the ms.mk which specifies all source info of your module

-include ../ms.mk

-

-

-# please specify where is the voRelease on your PC, relative path is suggested

-VORELDIR:=../../../../../Release/

-

-

-# please modify here to be sure to see the doit.mk

-include ../../../../Tools/doit.mk 

-

diff --git a/media/libstagefright/codecs/aacenc/SampleCode/ms.mk b/media/libstagefright/codecs/aacenc/SampleCode/ms.mk
deleted file mode 100644
index 771a569..0000000
--- a/media/libstagefright/codecs/aacenc/SampleCode/ms.mk
+++ /dev/null
@@ -1,23 +0,0 @@
-#/*

-#** Copyright 2003-2010, VisualOn, Inc.

-#**

-#** 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.

-#*/

-

-# please list all objects needed by your target here

-OBJS:=AAC_E_SAMPLES.o	cmnMemory.o

-			

-# please list all directories that all source files relative with your module(.h .c .cpp) locate 

-VOSRCDIR:=../ ../../../../include  ../../../../Common

-					

-				

diff --git a/media/libstagefright/codecs/aacenc/Tools/doit.mk b/media/libstagefright/codecs/aacenc/Tools/doit.mk
deleted file mode 100644
index dea0b0a..0000000
--- a/media/libstagefright/codecs/aacenc/Tools/doit.mk
+++ /dev/null
@@ -1,133 +0,0 @@
-#/*
-# ** Copyright 2003-2010, VisualOn, Inc.
-# **
-# ** 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.
-# */
-
-VERBOSE:=@
-
-
-VOMT ?= lib
-
-ifeq ($(VOMT), lib)
-LIB_STATIC=$(VOTARGET).a
-LIB_DYNAMIC=$(VOTARGET).so
-endif
-
-ifeq ($(VOMT), exe)
-TARGET=$(VOTARGET)
-endif
-
-CFLAGS=$(VOCFLAGS) $(addprefix -I, $(VOSRCDIR)) 
-CPPFLAGS=$(VOCPPFLAGS) $(addprefix -I, $(VOSRCDIR)) 
-ifneq ($(VOTT), pc)
-ASFLAGS=$(VOASFLAGS) $(addprefix -I, $(VOSRCDIR)) 
-endif
-
-LDFLAGS:=$(VOLDFLAGS)
-VOTEDEPS+=$(VODEPLIBS)
-VOTLDEPS+=$(VODEPLIBS)
-VOSTCLIBS ?=
-
-vpath %.c $(VOSRCDIR)
-vpath %.cpp $(VOSRCDIR)
-ifneq ($(VOTT), pc)
-vpath %.s $(VOSRCDIR)
-endif
-
-ifeq ($(VOTT), pc)
-BLTDIRS=$(VORELDIR)/Linux/static
-BLTDIRD=$(VORELDIR)/Linux/shared
-else
-BLTDIRS=$(VORELDIR)/Google/$(VONJ)/lib/$(VOTT)
-BLTDIRD=$(VORELDIR)/Google/$(VONJ)/so/$(VOTT)
-endif
-
-
-.PRECIOUS: $(OBJDIR)/%.o
-
-ifeq ($(VOMT), lib)
-all: mkdirs $(LIB_STATIC) $(LIB_DYNAMIC)
-mkdirs: $(OBJDIR) $(BLTDIRS) $(BLTDIRD)
-else
-all: mkdirs $(TARGET)
-mkdirs: $(OBJDIR)
-endif
-
-$(OBJDIR):
-	@if test ! -d $@; then \
-		mkdir -p $@; \
-	fi;
-
-ifeq ($(VOMT), lib)
-$(BLTDIRS):
-	@if test ! -d $@; then \
-		mkdir -p $@; \
-	fi;
-$(BLTDIRD):
-	@if test ! -d $@; then \
-		mkdir -p $@; \
-	fi;
-endif
-
-
-ifeq ($(VOMT), lib)
-$(LIB_STATIC):$(OBJS)
-	$(AR) cr $@ $(OBJDIR)/*.o $(VOSTCLIBS)
-	$(RANLIB) $@
-ifneq ($(VODBG), yes)
-	#$(STRIP) $@
-endif
-
-$(LIB_DYNAMIC):$(OBJS)
-	$(GG) $(LDFLAGS) -o $@ $(OBJDIR)/*.o -Wl,--whole-archive $(VOSTCLIBS) -Wl,--no-whole-archive $(VOTLDEPS) 
-ifneq ($(VODBG), yes)
-		$(STRIP) $@
-endif
-
-else
-
-$(TARGET):$(OBJS)
-	$(GG) $(LDFLAGS) -o $@ $(OBJDIR)/*.o -Wl,--whole-archive $(VOSTCLIBS) -Wl,--no-whole-archive $(VOTEDEPS)
-ifneq ($(VODBG), yes)
-	$(STRIP) $@
-endif
-
-endif
-
-
-.SUFFIXES: .c .cpp .s .o
-.c.o:
-	$(VERBOSE) $(CC) $(CFLAGS) -o $(OBJDIR)/$@ -c $<
-#%.c:$(OBJDIR)/%.o
-#	$(VERBOSE) $(CC) $(CFLAGS) -o $@ -c $<
-.cpp.o:
-	$(VERBOSE) $(GG) $(CPPFLAGS) -o $(OBJDIR)/$@ -c $<
-ifneq ($(VOTT), pc)
-.s.o:
-	$(VERBOSE) $(AS) $(ASFLAGS) -o $(OBJDIR)/$@ $<
-endif
-
-
-.PHONY: clean devel
-clean:
-ifeq ($(VOMT), lib)
-	-rm -fr $(OBJDIR) .*.sw* $(VOTARGET).*
-else
-	-rm -fr $(OBJDIR) .*.sw* $(VOTARGET)
-endif
-
-devel:
-	cp -a $(LIB_STATIC) $(BLTDIRS)
-	cp -a $(LIB_DYNAMIC) $(BLTDIRD)
-
diff --git a/media/libstagefright/codecs/aacenc/Tools/eclair.mk b/media/libstagefright/codecs/aacenc/Tools/eclair.mk
deleted file mode 100644
index 1688361..0000000
--- a/media/libstagefright/codecs/aacenc/Tools/eclair.mk
+++ /dev/null
@@ -1,172 +0,0 @@
-#/*
-# ** Copyright 2003-2010, VisualOn, Inc.
-# **
-# ** 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.
-# */
-
-# special macro definitions for building 
-VOPREDEF=-DLINUX -D_LINUX 
-
-VOPRJ ?= 
-VONJ ?= eclair
-VOTT ?= v6
-# control the version to release out
-# available: eva(evaluation), rel(release)
-VOVER=
-ifeq ($(VOVER), eva)
-VOPREDEF+=-D__VOVER_EVA__
-endif
-
-# for debug or not: yes for debug, any other for release
-VODBG?=ye
-
-# for detecting memory leak
-VODML=
-ifeq ($(VODML), yes)
-VOPREDEF+=-DDMEMLEAK
-endif
-
-VOPREDEF+=-D__VOTT_ARM__ -D__VONJ_ECLAIR__
-TCROOTPATH:=/opt/eclair
-GCCVER:=4.4.0
-TCPATH:=$(TCROOTPATH)/prebuilt/linux-x86/toolchain/arm-eabi-$(GCCVER)
-CCTPRE:=$(TCPATH)/bin/arm-eabi-
-AS:=$(CCTPRE)as
-AR:=$(CCTPRE)ar
-NM:=$(CCTPRE)nm
-CC:=$(CCTPRE)gcc
-GG:=$(CCTPRE)g++
-LD:=$(CCTPRE)ld
-SIZE:=$(CCTPRE)size
-STRIP:=$(CCTPRE)strip
-RANLIB:=$(CCTPRE)ranlib
-OBJCOPY:=$(CCTPRE)objcopy
-OBJDUMP:=$(CCTPRE)objdump
-READELF:=$(CCTPRE)readelf
-STRINGS:=$(CCTPRE)strings
-
-# target product dependcy
-# available: dream, generic
-VOTP:=sapphire-open
-CCTLIB:=$(TCROOTPATH)/out/target/product/$(VOTP)/obj/lib
-CCTINC:=-I$(TCROOTPATH)/system/core/include \
-	-I$(TCROOTPATH)/hardware/libhardware/include \
-	-I$(TCROOTPATH)/hardware/ril/include \
-	-I$(TCROOTPATH)/hardware/libhardware_legacy/include \
-	-I$(TCROOTPATH)/dalvik/libnativehelper/include \
-	-I$(TCROOTPATH)/dalvik/libnativehelper/include/nativehelper \
-	-I$(TCROOTPATH)/frameworks/base/include \
-	-I$(TCROOTPATH)/frameworks/base/core/jni \
-	-I$(TCROOTPATH)/frameworks/base/libs/audioflinger \
-	-I$(TCROOTPATH)/external/skia/include \
-	-I$(TCROOTPATH)/out/target/product/$(VOTP)/obj/include \
-	-I$(TCROOTPATH)/bionic/libc/arch-arm/include \
-	-I$(TCROOTPATH)/bionic/libc/include \
-	-I$(TCROOTPATH)/bionic/libstdc++/include \
-	-I$(TCROOTPATH)/bionic/libc/kernel/common \
-	-I$(TCROOTPATH)/bionic/libc/kernel/arch-arm \
-	-I$(TCROOTPATH)/bionic/libm/include \
-	-I$(TCROOTPATH)/bionic/libm/include/arm \
-	-I$(TCROOTPATH)/bionic/libthread_db/include \
-	-I$(TCROOTPATH)/bionic/libm/arm \
-	-I$(TCROOTPATH)/bionic/libm \
-	-I$(TCROOTPATH)/frameworks/base/include/android_runtime 
-	#-I$(TCROOTPATH)/out/target/product/$(VOTP)/obj/SHARED_LIBRARIES/libm_intermediates
-
-CCTCFLAGS:=-msoft-float -mthumb-interwork -fno-exceptions -ffunction-sections -funwind-tables -fstack-protector -fno-short-enums -fmessage-length=0 -finline-functions -finline-limit=600 -fno-inline-functions-called-once -fgcse-after-reload -frerun-cse-after-loop -frename-registers -fstrict-aliasing -funswitch-loops
-#-fwide-exec-charset=charset=UTF-32 
-
-# for target exe
-TELDFLAGS:=-nostdlib -Bdynamic -Wl,-T,$(TCROOTPATH)/build/core/armelf.x -Wl,-dynamic-linker,/system/bin/linker -Wl,--gc-sections -Wl,-z,nocopyreloc -Wl,--no-undefined -Wl,-rpath-link=$(CCTLIB) -L$(CCTLIB) 
-
-VOTEDEPS:=$(CCTLIB)/crtbegin_dynamic.o $(CCTLIB)/crtend_android.o $(TCPATH)/lib/gcc/arm-eabi/$(GCCVER)/interwork/libgcc.a -lc -lm
-
-# for target lib
-TLLDFLAGS:=-nostdlib -Wl,-T,$(TCROOTPATH)/build/core/armelf.xsc -Wl,--gc-sections -Wl,-shared,-Bsymbolic -L$(CCTLIB) -Wl,--no-whole-archive -Wl,--no-undefined $(TCPATH)/lib/gcc/arm-eabi/$(GCCVER)/interwork/libgcc.a 
-
-VOTLDEPS:=-lm -lc
-
-
-ifeq ($(VOTT), v4)
-VOCFLAGS:=-mtune=arm9tdmi -march=armv4t
-VOASFLAGS:=-march=armv4t -mfpu=softfpa
-endif
-
-ifeq ($(VOTT), v5)
-VOCFLAGS:=-march=armv5te
-VOASFLAGS:=-march=armv5te -mfpu=vfp
-endif
-
-ifeq ($(VOTT), v5x)
-VOCFLAGS:=-march=armv5te -mtune=xscale
-VOASFLAGS:=-march=armv5te -mfpu=vfp
-endif
-
-ifeq ($(VOTT), v6)
-#VOCFLAGS:=-march=armv6 -mtune=arm1136jf-s 
-#VOASFLAGS:=-march=armv6
-VOCFLAGS:=-march=armv6j -mtune=arm1136jf-s -mfpu=vfp -mfloat-abi=softfp -mapcs -mtpcs-leaf-frame -mlong-calls
-VOASFLAGS:=-march=armv6j -mcpu=arm1136jf-s -mfpu=arm1136jf-s -mfloat-abi=softfp -mapcs-float -mapcs-reentrant
-endif
-
-#
-# global link options
-VOLDFLAGS:=-Wl,-x,-X,--as-needed
-
-
-ifeq ($(VOTT), v7)
-VOCFLAGS+=-march=armv7-a -mtune=cortex-a8 -mfpu=neon -mfloat-abi=softfp
-VOASFLAGS+=-march=armv7-a -mcpu=cortex-a8 -mfpu=neon -mfloat-abi=softfp
-VOLDFLAGS+=-Wl,--fix-cortex-a8
-endif
-
-#global compiling options for ARM target
-ifneq ($(VOTT), pc)
-VOASFLAGS+=--strip-local-absolute -R
-endif 
-
-
-ifeq ($(VODBG), yes)
-VOCFLAGS+=-D_DEBUG -g
-else
-VOCFLAGS+=-DNDEBUG -O3
-endif
-
-VOCFLAGS+=$(VOPREDEF) $(VOMM) -Wall -fsigned-char -fomit-frame-pointer -fno-leading-underscore -fpic -fPIC -pipe -ftracer -fforce-addr -fno-bounds-check #-fvisibility=hidden #-fvisibility-inlines-hidden ##-ftree-loop-linear  -mthumb -nostdinc  -dD -fprefetch-loop-arrays
-
-
-ifneq ($(VOTT), pc)
-VOCFLAGS+=$(CCTCFLAGS) $(CCTINC)
-VOCPPFLAGS:=-fno-rtti $(VOCFLAGS)
-
-ifeq ($(VOMT), exe)
-VOLDFLAGS+=$(TELDFLAGS)
-endif
-
-ifeq ($(VOMT), lib)
-VOLDFLAGS+=$(TLLDFLAGS)
-endif
-else
-VOCPPFLAGS:=$(VOCFLAGS)
-ifeq ($(VOMT), lib)
-VOLDFLAGS+=-shared
-endif
-endif
-
-ifeq ($(VODBG), yes)
-#VOLDFLAGS:=
-endif
-
-# where to place object files 
-OBJDIR=obj
-
diff --git a/media/libstagefright/codecs/aacenc/build/eclair/ARMV5E/Makefile b/media/libstagefright/codecs/aacenc/build/eclair/ARMV5E/Makefile
deleted file mode 100644
index b4f63af..0000000
--- a/media/libstagefright/codecs/aacenc/build/eclair/ARMV5E/Makefile
+++ /dev/null
@@ -1,55 +0,0 @@
-#/*

-#** Copyright 2003-2010, VisualOn, Inc.

-#**

-#** 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.

-#*/

-

-# target6

-# available: pc, v4(armv4), v5(armv5), v5x(armv5 xscale), v6(armv6), v7(cortex-a8 neon)

-VOTT:= v5

-

-

-# module type

-# please specify the type of your module: lib or exe

-VOMT:= lib

-

-

-# module macros

-# please append the additional macro definitions here for your module if necessary. 

-# e.g. -DVISUALON, macro VISUALON defined for your module 

-VOMM:= -DARMV5E -DARM_INASM -DARMV5_INASM 

-

-

-

-# please specify the name of your module

-VOTARGET:=libvoAACEncv5

-

-

-# please modify here to be sure to see the g1.mk

-include ../../../../../Tools/eclair.mk 

-

-# dependent libraries.

-VODEPLIBS:=#-ldl -lstdc++ 

-

-# module source

-# please modify here to be sure to see the ms.mk which specifies all source info of your module

-include ../../ms.mk

-

-

-# please specify where is the voRelease on your PC, relative path is suggested

-VORELDIR:=../../../../../../Release

-

-

-# please modify here to be sure to see the doit.mk

-include ../../../../../Tools/doit.mk 

-

diff --git a/media/libstagefright/codecs/aacenc/build/eclair/ARMV7/Makefile b/media/libstagefright/codecs/aacenc/build/eclair/ARMV7/Makefile
deleted file mode 100644
index cdce2c1..0000000
--- a/media/libstagefright/codecs/aacenc/build/eclair/ARMV7/Makefile
+++ /dev/null
@@ -1,55 +0,0 @@
-#/*

-#** Copyright 2003-2010, VisualOn, Inc.

-#**

-#** 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.

-#*/

-

-# target6

-# available: pc, v4(armv4), v5(armv5), v5x(armv5 xscale), v6(armv6), v7(cortex-a8 neon)

-VOTT:= v7

-

-

-# module type

-# please specify the type of your module: lib or exe

-VOMT:= lib

-

-

-# module macros

-# please append the additional macro definitions here for your module if necessary. 

-# e.g. -DVISUALON, macro VISUALON defined for your module 

-VOMM:= -DARMV5E -DARMV7Neon -DARM_INASM -DARMV5_INASM 

-

-

-

-# please specify the name of your module

-VOTARGET:=libvoAACEncv7

-

-

-# please modify here to be sure to see the g1.mk

-include ../../../../../Tools/eclair.mk 

-

-# dependent libraries.

-VODEPLIBS:=#-ldl -lstdc++ 

-

-# module source

-# please modify here to be sure to see the ms.mk which specifies all source info of your module

-include ../../ms.mk

-

-

-# please specify where is the voRelease on your PC, relative path is suggested

-VORELDIR:=../../../../../../Release

-

-

-# please modify here to be sure to see the doit.mk

-include ../../../../../Tools/doit.mk  

-

diff --git a/media/libstagefright/codecs/aacenc/build/eclair/makefile b/media/libstagefright/codecs/aacenc/build/eclair/makefile
deleted file mode 100644
index 6bb3c13..0000000
--- a/media/libstagefright/codecs/aacenc/build/eclair/makefile
+++ /dev/null
@@ -1,40 +0,0 @@
-#/*
-#** Copyright 2003-2010, VisualOn, Inc.
-#**
-#** 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.
-#*/
-
-# Just acting as Father Makefile of Modules
-# please keep the name 'makefile' unchanged
- 
-# Module Subdirs
-VOMSD:=$(dir $(shell find . -name 'Makefile'))
-
-all:
-	for dir in $(VOMSD); \
-		do \
-			$(MAKE) -C $$dir; \
-		done
-
-.PHONY:clean devel
-clean:
-	for dir in $(VOMSD); \
-		do \
-			$(MAKE) -C $$dir clean; \
-		done
-
-devel:
-	for dir in $(VOMSD); \
-		do \
-			$(MAKE) -C $$dir devel; \
-		done
diff --git a/media/libstagefright/codecs/aacenc/build/ms.mk b/media/libstagefright/codecs/aacenc/build/ms.mk
deleted file mode 100644
index b67efbc..0000000
--- a/media/libstagefright/codecs/aacenc/build/ms.mk
+++ /dev/null
@@ -1,42 +0,0 @@
-#/*

-#** Copyright 2003-2010, VisualOn, Inc.

-#**

-#** 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.

-#*/

-

-

-# please list all objects needed by your target here

-OBJS:=basicop2.o oper_32b.o aac_rom.o aacenc.o aacenc_core.o adj_thr.o \

-			band_nrg.o bit_cnt.o bitbuffer.o bitenc.o block_switch.o channel_map.o \

-			dyn_bits.o grp_data.o interface.o line_pe.o memalign.o ms_stereo.o \

-			pre_echo_control.o psy_configuration.o psy_main.o qc_main.o quantize.o sf_estim.o \

-			spreading.o stat_bits.o tns.o transform.o

-			

-# please list all directories that all source files relative with your module(.h .c .cpp) locate 

-VOSRCDIR:=../../../src \

-					../../../inc \

-					../../../basic_op\

-					../../../../../Include 

-					

-ifeq ($(VOTT), v5)

-OBJS+= AutoCorrelation_v5.o band_nrg_v5.o CalcWindowEnergy_v5.o \

-				PrePostMDCT_v5.o R4R8First_v5.o Radix4FFT_v5.o

-VOSRCDIR+= ../../../src/asm/ARMV5E/

-endif	

-

-ifeq ($(VOTT), v7)

-OBJS+= AutoCorrelation_v5.o band_nrg_v5.o CalcWindowEnergy_v5.o \

-			 PrePostMDCT_v7.o R4R8First_v7.o Radix4FFT_v7.o

-VOSRCDIR+= ../../../src/asm/ARMV5E/

-VOSRCDIR+= ../../../src/asm/ARMV7/

-endif		
\ No newline at end of file
diff --git a/media/libstagefright/codecs/amrnb/dec/AMRNBDecoder.cpp b/media/libstagefright/codecs/amrnb/dec/AMRNBDecoder.cpp
index fb300da..a11d46b 100644
--- a/media/libstagefright/codecs/amrnb/dec/AMRNBDecoder.cpp
+++ b/media/libstagefright/codecs/amrnb/dec/AMRNBDecoder.cpp
@@ -14,6 +14,10 @@
  * limitations under the License.
  */
 
+//#define LOG_NDEBUG 0
+#define LOG_TAG "AMRNBDecoder"
+#include <utils/Log.h>
+
 #include "AMRNBDecoder.h"
 
 #include "gsmamr_dec.h"
@@ -154,18 +158,24 @@
     const uint8_t *inputPtr =
         (const uint8_t *)mInputBuffer->data() + mInputBuffer->range_offset();
 
-    size_t numBytesRead =
+    int32_t numBytesRead =
         AMRDecode(mState,
           (Frame_Type_3GPP)((inputPtr[0] >> 3) & 0x0f),
           (UWord8 *)&inputPtr[1],
           static_cast<int16_t *>(buffer->data()),
           MIME_IETF);
 
+    if (numBytesRead == -1 ) {
+        LOGE("PV AMR decoder AMRDecode() call failed");
+        buffer->release();
+        buffer = NULL;
+        return ERROR_MALFORMED;
+    }
     ++numBytesRead;  // Include the frame type header byte.
 
     buffer->set_range(0, kNumSamplesPerFrame * sizeof(int16_t));
 
-    if (numBytesRead > mInputBuffer->range_length()) {
+    if (static_cast<size_t>(numBytesRead) > mInputBuffer->range_length()) {
         // This is bad, should never have happened, but did. Abort now.
 
         buffer->release();
diff --git a/media/libstagefright/codecs/amrwbenc/Android.mk b/media/libstagefright/codecs/amrwbenc/Android.mk
index 4293287..5179380 100644
--- a/media/libstagefright/codecs/amrwbenc/Android.mk
+++ b/media/libstagefright/codecs/amrwbenc/Android.mk
@@ -2,7 +2,7 @@
 include $(CLEAR_VARS)
 include frameworks/base/media/libstagefright/codecs/common/Config.mk
 
-LOCAL_PRELINK_MODULE := false
+
  	
 LOCAL_SRC_FILES := \
 	AMRWBEncoder.cpp \
diff --git a/media/libstagefright/codecs/amrwbenc/SampleCode/AMRWB_E_SAMPLE.c b/media/libstagefright/codecs/amrwbenc/SampleCode/AMRWB_E_SAMPLE.c
index 792d3cc..5e71a5b 100644
--- a/media/libstagefright/codecs/amrwbenc/SampleCode/AMRWB_E_SAMPLE.c
+++ b/media/libstagefright/codecs/amrwbenc/SampleCode/AMRWB_E_SAMPLE.c
@@ -129,7 +129,7 @@
 	useData.memData = (VO_PTR)(&moper);

 

 #ifdef LINUX

-	handle = dlopen("/data/local/tmp/voAMRWBEnc.so", RTLD_NOW);

+	handle = dlopen("libstagefright.so", RTLD_NOW);

 	if(handle == 0)

 	{

 		printf("open dll error......");

diff --git a/media/libstagefright/codecs/amrwbenc/SampleCode/Android.mk b/media/libstagefright/codecs/amrwbenc/SampleCode/Android.mk
index 7edb166..85ddceb 100644
--- a/media/libstagefright/codecs/amrwbenc/SampleCode/Android.mk
+++ b/media/libstagefright/codecs/amrwbenc/SampleCode/Android.mk
@@ -1,26 +1,26 @@
 LOCAL_PATH := $(call my-dir)
 include $(CLEAR_VARS)
 
-LOCAL_SRC_FILES := 	AMRWB_E_SAMPLE.c
-	
-LOCAL_SRC_FILES += 	\
-	../../../Common/cmnMemory.c 
+LOCAL_SRC_FILES := \
+    AMRWB_E_SAMPLE.c \
+    ../../common/cmnMemory.c
 
-LOCAL_MODULE := TestvoAMRWBEnc
+LOCAL_MODULE_TAGS := debug
+LOCAL_MODULE := AMRWBEncTest
 
 LOCAL_ARM_MODE := arm
 
-LOCAL_STATIC_LIBRARIES := 
+LOCAL_CFLAGS := $(VO_CFLAGS)
 
-LOCAL_SHARED_LIBRARIES := libvoAMRWBEnc
+LOCAL_SHARED_LIBRARIES := \
+    libstagefright \
+    libdl
 
 LOCAL_C_INCLUDES := \
-	$(LOCAL_PATH)/ \
-	$(LOCAL_PATH)/../../../Common \
-	$(LOCAL_PATH)/../../../Include \
+    $(LOCAL_PATH)/ \
+    $(LOCAL_PATH)/../../common \
+    $(LOCAL_PATH)/../../common/include
 
-LOCAL_CFLAGS := $(VO_CFLAGS)
-	
 include $(BUILD_EXECUTABLE)
 
 
diff --git a/media/libstagefright/codecs/amrwbenc/SampleCode/eclair/Makefile b/media/libstagefright/codecs/amrwbenc/SampleCode/eclair/Makefile
deleted file mode 100644
index 55b876a..0000000
--- a/media/libstagefright/codecs/amrwbenc/SampleCode/eclair/Makefile
+++ /dev/null
@@ -1,56 +0,0 @@
-#/*

-# ** Copyright 2003-2010, VisualOn, Inc.

-# **

-# ** 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.

-# */

-

-# target6

-# available: pc, v4(armv4), v5(armv5), v5x(armv5 xscale), v6(armv6), v7(cortex-a8 neon)

-VOTT:= v6

-

-

-# module type

-# please specify the type of your module: lib or exe

-VOMT:= exe

-

-

-# module macros

-# please append the additional macro definitions here for your module if necessary. 

-# e.g. -DVISUALON, macro VISUALON defined for your module 

-VOMM:= #ARMV5E

-

-

-

-# please specify the name of your module

-VOTARGET:= voAMRWBEnc_Test

-

-

-# please modify here to be sure to see the g1.mk

-include ../../../../Tools/eclair.mk 

-

-# dependent libraries.

-VODEPLIBS:=-ldl

-

-

-# module source

-# please modify here to be sure to see the ms.mk which specifies all source info of your module

-include ../ms.mk

-

-

-# please specify where is the voRelease on your PC, relative path is suggested

-VORELDIR:=../

-

-

-# please modify here to be sure to see the doit.mk

-include ../../../../Tools/doit.mk 

-

diff --git a/media/libstagefright/codecs/amrwbenc/SampleCode/ms.mk b/media/libstagefright/codecs/amrwbenc/SampleCode/ms.mk
deleted file mode 100644
index 74e8913..0000000
--- a/media/libstagefright/codecs/amrwbenc/SampleCode/ms.mk
+++ /dev/null
@@ -1,24 +0,0 @@
-#/*

-# ** Copyright 2003-2010, VisualOn, Inc.

-# **

-# ** 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.

-# */

-# please list all objects needed by your target here

-OBJS:=AMRWB_E_SAMPLE.o cmnMemory.o

-			

-# please list all directories that all source files relative with your module(.h .c .cpp) locate 

-VOSRCDIR:=../ \

-          ../../../../Common \

-	  ../../../../Include

-					

-				

diff --git a/media/libstagefright/codecs/amrwbenc/build/eclair/ARMV5E/Makefile b/media/libstagefright/codecs/amrwbenc/build/eclair/ARMV5E/Makefile
deleted file mode 100644
index 58fda29..0000000
--- a/media/libstagefright/codecs/amrwbenc/build/eclair/ARMV5E/Makefile
+++ /dev/null
@@ -1,53 +0,0 @@
-#/*

-# ** Copyright 2003-2010, VisualOn, Inc.

-# **

-# ** 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.

-# */

-

-# target type

-# available: pc, v4(armv4), v5(armv5), v5x(armv5 xscale), v6(armv6), v7(cortex-a8 neon)

-VOTT:= v5

-

-

-# module type

-# please specify the type of your module: lib or exe

-VOMT:= lib

-

-

-# module macros

-# please append the additional macro definitions here for your module if necessary. 

-ifeq ($(VOTT), v5)

-VOMM:=-DARM -DASM_OPT

-endif

-

-# please specify the name of your module

-VOTARGET:= libvoAMRWBEncv5

-

-

-# please modify here to be sure to see the g1.mk

-include ../../../../../Tools/eclair.mk 

-

-# dependent libraries.

-VODEPLIBS:=-ldl -lstdc++ -lcutils

-

-# module source

-# please modify here to be sure to see the ms.mk which specifies all source info of your module

-include ../ms.mk

-

-

-# please specify where is the voRelease on your PC, relative path is suggested

-VORELDIR:=../../../../../../Release

-

-# please modify here to be sure to see the doit.mk

-include ../../../../../Tools/doit.mk 

-

diff --git a/media/libstagefright/codecs/amrwbenc/build/eclair/ARMV7/Makefile b/media/libstagefright/codecs/amrwbenc/build/eclair/ARMV7/Makefile
deleted file mode 100644
index 5686411..0000000
--- a/media/libstagefright/codecs/amrwbenc/build/eclair/ARMV7/Makefile
+++ /dev/null
@@ -1,53 +0,0 @@
-#/*

-# ** Copyright 2003-2010, VisualOn, Inc.

-# **

-# ** 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.

-# */

-

-# target type

-# available: pc, v4(armv4), v5(armv5), v5x(armv5 xscale), v6(armv6), v7(cortex-a8 neon)

-VOTT:= v7

-

-

-# module type

-# please specify the type of your module: lib or exe

-VOMT:= lib

-

-

-# module macros

-# please append the additional macro definitions here for your module if necessary. 

-ifeq ($(VOTT), v7)

-VOMM:=-DARM -DARMV7 -DASM_OPT

-endif

-

-# please specify the name of your module

-VOTARGET:= libvoAMRWBEncv7

-

-

-# please modify here to be sure to see the g1.mk

-include ../../../../../Tools/eclair.mk 

-

-# dependent libraries.

-VODEPLIBS:=-ldl -lstdc++ -lcutils

-

-# module source

-# please modify here to be sure to see the ms.mk which specifies all source info of your module

-include ../ms.mk

-

-

-# please specify where is the voRelease on your PC, relative path is suggested

-VORELDIR:=../../../../../../Release

-

-# please modify here to be sure to see the doit.mk

-include ../../../../../Tools/doit.mk 

-

diff --git a/media/libstagefright/codecs/amrwbenc/build/eclair/makefile b/media/libstagefright/codecs/amrwbenc/build/eclair/makefile
deleted file mode 100644
index 3473a1a..0000000
--- a/media/libstagefright/codecs/amrwbenc/build/eclair/makefile
+++ /dev/null
@@ -1,39 +0,0 @@
-#/*
-# ** Copyright 2003-2010, VisualOn, Inc.
-# **
-# ** 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.
-# */
-# Just acting as Father Makefile of Modules
-# please keep the name 'makefile' unchanged
- 
-# Module Subdirs
-VOMSD:=$(dir $(shell find . -name 'Makefile'))
-
-all:
-	for dir in $(VOMSD); \
-		do \
-			$(MAKE) -C $$dir; \
-		done
-
-.PHONY:clean devel
-clean:
-	for dir in $(VOMSD); \
-		do \
-			$(MAKE) -C $$dir clean; \
-		done
-
-devel:
-	for dir in $(VOMSD); \
-		do \
-			$(MAKE) -C $$dir devel; \
-		done
diff --git a/media/libstagefright/codecs/amrwbenc/build/eclair/ms.mk b/media/libstagefright/codecs/amrwbenc/build/eclair/ms.mk
deleted file mode 100644
index bd6620c..0000000
--- a/media/libstagefright/codecs/amrwbenc/build/eclair/ms.mk
+++ /dev/null
@@ -1,43 +0,0 @@
-#/*

-# ** Copyright 2003-2010, VisualOn, Inc.

-# **

-# ** 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.

-# */

-# please list all directories that all source files relative with your module(.h .c .cpp) locate 

-VOSRCDIR:=../../../inc \

-          ../../../src \

-	  ../../../../../Include 

-

-# please list all objects needed by your target here

-OBJS:= autocorr.o az_isp.o bits.o c2t64fx.o c4t64fx.o convolve.o cor_h_x.o decim54.o \

-       deemph.o dtx.o g_pitch.o gpclip.o homing.o hp400.o hp50.o hp6k.o hp_wsp.o \

-       int_lpc.o isp_az.o isp_isf.o lag_wind.o levinson.o log2.o lp_dec2.o math_op.o mem_align.o \

-       oper_32b.o p_med_ol.o pit_shrp.o pitch_f4.o pred_lt4.o preemph.o q_gain2.o q_pulse.o \

-       qisf_ns.o qpisf_2s.o random.o residu.o scale.o stream.o syn_filt.o updt_tar.o util.o \

-       voAMRWBEnc.o voicefac.o wb_vad.o weight_a.o

-			

-

-ifeq ($(VOTT), v5)

-OBJS += cor_h_vec_opt.o Deemph_32_opt.o Dot_p_opt.o Filt_6k_7k_opt.o residu_asm_opt.o \

-       scale_sig_opt.o Syn_filt_32_opt.o syn_filt_opt.o pred_lt4_1_opt.o convolve_opt.o \

-       Norm_Corr_opt.o

-VOSRCDIR+= ../../../src/asm/ARMV5E

-endif

-

-ifeq ($(VOTT), v7)

-OBJS+= cor_h_vec_neon.o Deemph_32_neon.o Dot_p_neon.o Filt_6k_7k_neon.o residu_asm_neon.o \

-       scale_sig_neon.o Syn_filt_32_neon.o syn_filt_neon.o pred_lt4_1_neon.o convolve_neon.o \

-       Norm_Corr_neon.o

-VOSRCDIR+= ../../../src/asm/ARMV7

-endif

-

diff --git a/media/libstagefright/codecs/avc/common/include/avc_types.h b/media/libstagefright/codecs/avc/common/include/avc_types.h
index 73cad89..ec8b6de 100644
--- a/media/libstagefright/codecs/avc/common/include/avc_types.h
+++ b/media/libstagefright/codecs/avc/common/include/avc_types.h
@@ -1,3 +1,18 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 #ifndef AVC_TYPES_H_
 
 #define AVC_TYPES_H_
diff --git a/media/libstagefright/codecs/avc/dec/AVCDecoder.cpp b/media/libstagefright/codecs/avc/dec/AVCDecoder.cpp
index 5bbba35..490129f 100644
--- a/media/libstagefright/codecs/avc/dec/AVCDecoder.cpp
+++ b/media/libstagefright/codecs/avc/dec/AVCDecoder.cpp
@@ -534,7 +534,8 @@
             default:
             {
                 LOGE("Should not be here, unknown nalType %d", nalType);
-                CHECK(!"Should not be here");
+
+                err = ERROR_MALFORMED;
                 break;
             }
         }
diff --git a/media/libstagefright/codecs/common/Android.mk b/media/libstagefright/codecs/common/Android.mk
index fffb2ad..af8795a 100644
--- a/media/libstagefright/codecs/common/Android.mk
+++ b/media/libstagefright/codecs/common/Android.mk
@@ -1,7 +1,7 @@
 LOCAL_PATH := $(call my-dir)
 include $(CLEAR_VARS)
 
-LOCAL_PRELINK_MODULE := false
+
 
 LOCAL_SRC_FILES := cmnMemory.c
 
diff --git a/media/libstagefright/codecs/mp3dec/MP3Decoder.cpp b/media/libstagefright/codecs/mp3dec/MP3Decoder.cpp
index 59dd740..0ba42ff 100644
--- a/media/libstagefright/codecs/mp3dec/MP3Decoder.cpp
+++ b/media/libstagefright/codecs/mp3dec/MP3Decoder.cpp
@@ -14,6 +14,9 @@
  * limitations under the License.
  */
 
+//#define LOG_NDEBUG 0
+#define LOG_TAG "MP3Decoder"
+
 #include "MP3Decoder.h"
 
 #include "include/pvmp3decoder_api.h"
@@ -175,7 +178,12 @@
             != NO_DECODING_ERROR) {
         LOGV("mp3 decoder returned error %d", decoderErr);
 
-        if (decoderErr != NO_ENOUGH_MAIN_DATA_ERROR) {
+        if (decoderErr != NO_ENOUGH_MAIN_DATA_ERROR ||
+                mConfig->outputFrameSize == 0) {
+
+            if (mConfig->outputFrameSize == 0) {
+                LOGE("Output frame size is 0");
+            }
             buffer->release();
             buffer = NULL;
 
diff --git a/media/libstagefright/foundation/AHierarchicalStateMachine.cpp b/media/libstagefright/foundation/AHierarchicalStateMachine.cpp
index 30286d8..3b3f786 100644
--- a/media/libstagefright/foundation/AHierarchicalStateMachine.cpp
+++ b/media/libstagefright/foundation/AHierarchicalStateMachine.cpp
@@ -1,3 +1,19 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
 #include <media/stagefright/foundation/AHierarchicalStateMachine.h>
 
 #include <media/stagefright/foundation/ADebug.h>
diff --git a/media/libstagefright/foundation/Android.mk b/media/libstagefright/foundation/Android.mk
index 4e07f6f..d5025a1 100644
--- a/media/libstagefright/foundation/Android.mk
+++ b/media/libstagefright/foundation/Android.mk
@@ -25,6 +25,6 @@
 
 LOCAL_MODULE:= libstagefright_foundation
 
-LOCAL_PRELINK_MODULE:= false
+
 
 include $(BUILD_SHARED_LIBRARY)
diff --git a/media/libstagefright/httplive/LiveSession.cpp b/media/libstagefright/httplive/LiveSession.cpp
index f0cd6a0..8e1bdf3 100644
--- a/media/libstagefright/httplive/LiveSession.cpp
+++ b/media/libstagefright/httplive/LiveSession.cpp
@@ -23,7 +23,7 @@
 #include "LiveDataSource.h"
 
 #include "include/M3UParser.h"
-#include "include/NuHTTPDataSource.h"
+#include "include/HTTPBase.h"
 
 #include <cutils/properties.h>
 #include <media/stagefright/foundation/hexdump.h>
@@ -45,9 +45,9 @@
     : mFlags(flags),
       mDataSource(new LiveDataSource),
       mHTTPDataSource(
-              new NuHTTPDataSource(
+              HTTPBase::Create(
                   (mFlags & kFlagIncognito)
-                    ? NuHTTPDataSource::kFlagIncognito
+                    ? HTTPBase::kFlagIncognito
                     : 0)),
       mPrevBandwidthIndex(-1),
       mLastPlaylistFetchTimeUs(-1),
@@ -625,7 +625,12 @@
     } else {
         key = new ABuffer(16);
 
-        sp<NuHTTPDataSource> keySource = new NuHTTPDataSource;
+        sp<HTTPBase> keySource =
+              HTTPBase::Create(
+                  (mFlags & kFlagIncognito)
+                    ? HTTPBase::kFlagIncognito
+                    : 0);
+
         status_t err = keySource->connect(keyURI.c_str());
 
         if (err == OK) {
diff --git a/media/libstagefright/httplive/M3UParser.cpp b/media/libstagefright/httplive/M3UParser.cpp
index 95f6741..2eb180a 100644
--- a/media/libstagefright/httplive/M3UParser.cpp
+++ b/media/libstagefright/httplive/M3UParser.cpp
@@ -20,8 +20,8 @@
 
 #include "include/M3UParser.h"
 
+#include <media/stagefright/foundation/ADebug.h>
 #include <media/stagefright/foundation/AMessage.h>
-#include <media/stagefright/MediaDebug.h>
 #include <media/stagefright/MediaErrors.h>
 
 namespace android {
@@ -306,6 +306,29 @@
     return OK;
 }
 
+// Find the next occurence of the character "what" at or after "offset",
+// but ignore occurences between quotation marks.
+// Return the index of the occurrence or -1 if not found.
+static ssize_t FindNextUnquoted(
+        const AString &line, char what, size_t offset) {
+    CHECK_NE((int)what, (int)'"');
+
+    bool quoted = false;
+    while (offset < line.size()) {
+        char c = line.c_str()[offset];
+
+        if (c == '"') {
+            quoted = !quoted;
+        } else if (c == what && !quoted) {
+            return offset;
+        }
+
+        ++offset;
+    }
+
+    return -1;
+}
+
 // static
 status_t M3UParser::parseCipherInfo(
         const AString &line, sp<AMessage> *meta, const AString &baseURI) {
@@ -318,7 +341,7 @@
     size_t offset = colonPos + 1;
 
     while (offset < line.size()) {
-        ssize_t end = line.find(",", offset);
+        ssize_t end = FindNextUnquoted(line, ',', offset);
         if (end < 0) {
             end = line.size();
         }
diff --git a/media/libstagefright/include/AwesomePlayer.h b/media/libstagefright/include/AwesomePlayer.h
index 4e6f75c..a9b7ae8 100644
--- a/media/libstagefright/include/AwesomePlayer.h
+++ b/media/libstagefright/include/AwesomePlayer.h
@@ -18,7 +18,7 @@
 
 #define AWESOME_PLAYER_H_
 
-#include "NuHTTPDataSource.h"
+#include "HTTPBase.h"
 #include "TimedEventQueue.h"
 
 #include <media/MediaPlayerInterface.h>
@@ -93,7 +93,7 @@
     // This is a mask of MediaExtractor::Flags.
     uint32_t flags() const;
 
-    void postAudioEOS();
+    void postAudioEOS(int64_t delayUs = 0ll);
     void postAudioSeekComplete();
 
 private:
@@ -203,13 +203,13 @@
     void postVideoEvent_l(int64_t delayUs = -1);
     void postBufferingEvent_l();
     void postStreamDoneEvent_l(status_t status);
-    void postCheckAudioStatusEvent_l();
+    void postCheckAudioStatusEvent_l(int64_t delayUs);
     void postVideoLagEvent_l();
     status_t play_l();
 
     MediaBuffer *mVideoBuffer;
 
-    sp<NuHTTPDataSource> mConnectingDataSource;
+    sp<HTTPBase> mConnectingDataSource;
     sp<NuCachedSource2> mCachedSource;
 
     sp<ALooper> mLooper;
@@ -217,7 +217,7 @@
     sp<ARTSPController> mConnectingRTSPController;
 
     DrmManagerClient *mDrmManagerClient;
-    DecryptHandle *mDecryptHandle;
+    sp<DecryptHandle> mDecryptHandle;
 
     status_t setDataSource_l(
             const char *uri,
diff --git a/media/libstagefright/include/ChromiumHTTPDataSource.h b/media/libstagefright/include/ChromiumHTTPDataSource.h
new file mode 100644
index 0000000..af49059
--- /dev/null
+++ b/media/libstagefright/include/ChromiumHTTPDataSource.h
@@ -0,0 +1,127 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef CHROME_HTTP_DATA_SOURCE_H_
+
+#define CHROME_HTTP_DATA_SOURCE_H_
+
+#include <media/stagefright/foundation/AString.h>
+#include <utils/threads.h>
+
+#include "HTTPBase.h"
+
+namespace android {
+
+struct SfDelegate;
+
+struct ChromiumHTTPDataSource : public HTTPBase {
+    ChromiumHTTPDataSource(uint32_t flags = 0);
+
+    virtual status_t connect(
+            const char *uri,
+            const KeyedVector<String8, String8> *headers = NULL,
+            off64_t offset = 0);
+
+    virtual void disconnect();
+
+    virtual status_t initCheck() const;
+
+    virtual ssize_t readAt(off64_t offset, void *data, size_t size);
+    virtual status_t getSize(off64_t *size);
+    virtual uint32_t flags();
+
+    virtual bool estimateBandwidth(int32_t *bandwidth_bps);
+
+    virtual sp<DecryptHandle> DrmInitialization();
+
+    virtual void getDrmInfo(sp<DecryptHandle> &handle, DrmManagerClient **client);
+
+    virtual String8 getUri();
+
+protected:
+    virtual ~ChromiumHTTPDataSource();
+
+private:
+    friend struct SfDelegate;
+
+    enum State {
+        DISCONNECTED,
+        CONNECTING,
+        CONNECTED,
+        READING,
+        DISCONNECTING
+    };
+
+    struct BandwidthEntry {
+        int64_t mDelayUs;
+        size_t mNumBytes;
+    };
+
+    const uint32_t mFlags;
+
+    mutable Mutex mLock;
+    Condition mCondition;
+
+    State mState;
+
+    SfDelegate *mDelegate;
+
+    AString mURI;
+    KeyedVector<String8, String8> mHeaders;
+
+    off64_t mCurrentOffset;
+
+    // Any connection error or the result of a read operation
+    // (for the lattter this is the number of bytes read, if successful).
+    ssize_t mIOResult;
+
+    int64_t mContentSize;
+
+    List<BandwidthEntry> mBandwidthHistory;
+    size_t mNumBandwidthHistoryItems;
+    int64_t mTotalTransferTimeUs;
+    size_t mTotalTransferBytes;
+
+    sp<DecryptHandle> mDecryptHandle;
+    DrmManagerClient *mDrmManagerClient;
+
+    void disconnect_l();
+
+    status_t connect_l(
+            const char *uri,
+            const KeyedVector<String8, String8> *headers,
+            off64_t offset);
+
+    static void InitiateRead(
+            ChromiumHTTPDataSource *me, void *data, size_t size);
+
+    void initiateRead(void *data, size_t size);
+
+    void onConnectionEstablished(int64_t contentSize);
+    void onConnectionFailed(status_t err);
+    void onReadCompleted(ssize_t size);
+    void onDisconnectComplete();
+
+    void addBandwidthMeasurement_l(size_t numBytes, int64_t delayUs);
+
+    void clearDRMState_l();
+
+    DISALLOW_EVIL_CONSTRUCTORS(ChromiumHTTPDataSource);
+};
+
+}  // namespace android
+
+#endif  // CHROME_HTTP_DATA_SOURCE_H_
diff --git a/media/libstagefright/include/DRMExtractor.h b/media/libstagefright/include/DRMExtractor.h
index 9881cc1..b4e4afb 100644
--- a/media/libstagefright/include/DRMExtractor.h
+++ b/media/libstagefright/include/DRMExtractor.h
@@ -45,7 +45,7 @@
     sp<DataSource> mDataSource;
 
     sp<MediaExtractor> mOriginalExtractor;
-    DecryptHandle* mDecryptHandle;
+    sp<DecryptHandle> mDecryptHandle;
     DrmManagerClient* mDrmManagerClient;
 
     DRMExtractor(const DRMExtractor &);
diff --git a/media/libstagefright/include/HTTPBase.h b/media/libstagefright/include/HTTPBase.h
new file mode 100644
index 0000000..6cec390
--- /dev/null
+++ b/media/libstagefright/include/HTTPBase.h
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef HTTP_BASE_H_
+
+#define HTTP_BASE_H_
+
+#include <media/stagefright/foundation/ABase.h>
+#include <media/stagefright/DataSource.h>
+
+namespace android {
+
+struct HTTPBase : public DataSource {
+    enum Flags {
+        // Don't log any URLs.
+        kFlagIncognito = 1
+    };
+
+    HTTPBase();
+
+    virtual status_t connect(
+            const char *uri,
+            const KeyedVector<String8, String8> *headers = NULL,
+            off64_t offset = 0) = 0;
+
+    virtual void disconnect() = 0;
+
+    // Returns true if bandwidth could successfully be estimated,
+    // false otherwise.
+    virtual bool estimateBandwidth(int32_t *bandwidth_bps) = 0;
+
+    static sp<HTTPBase> Create(uint32_t flags = 0);
+
+private:
+    DISALLOW_EVIL_CONSTRUCTORS(HTTPBase);
+};
+
+}  // namespace android
+
+#endif  // HTTP_BASE_H_
diff --git a/media/libstagefright/include/LiveSession.h b/media/libstagefright/include/LiveSession.h
index 3fe5d4e..2b5ea0e 100644
--- a/media/libstagefright/include/LiveSession.h
+++ b/media/libstagefright/include/LiveSession.h
@@ -26,7 +26,7 @@
 struct DataSource;
 struct LiveDataSource;
 struct M3UParser;
-struct NuHTTPDataSource;
+struct HTTPBase;
 
 struct LiveSession : public AHandler {
     enum Flags {
@@ -75,7 +75,7 @@
 
     sp<LiveDataSource> mDataSource;
 
-    sp<NuHTTPDataSource> mHTTPDataSource;
+    sp<HTTPBase> mHTTPDataSource;
 
     AString mMasterURL;
     Vector<BandwidthItem> mBandwidthItems;
diff --git a/media/libstagefright/include/MPEG2TSExtractor.h b/media/libstagefright/include/MPEG2TSExtractor.h
index efe7496..fe74a42 100644
--- a/media/libstagefright/include/MPEG2TSExtractor.h
+++ b/media/libstagefright/include/MPEG2TSExtractor.h
@@ -1,3 +1,19 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
 #ifndef MPEG2_TS_EXTRACTOR_H_
 
 #define MPEG2_TS_EXTRACTOR_H_
diff --git a/media/libstagefright/include/NuCachedSource2.h b/media/libstagefright/include/NuCachedSource2.h
index 022804c..02d5817 100644
--- a/media/libstagefright/include/NuCachedSource2.h
+++ b/media/libstagefright/include/NuCachedSource2.h
@@ -37,8 +37,8 @@
     virtual status_t getSize(off64_t *size);
     virtual uint32_t flags();
 
-    virtual DecryptHandle* DrmInitialization();
-    virtual void getDrmInfo(DecryptHandle **handle, DrmManagerClient **client);
+    virtual sp<DecryptHandle> DrmInitialization();
+    virtual void getDrmInfo(sp<DecryptHandle> &handle, DrmManagerClient **client);
     virtual String8 getUri();
     ////////////////////////////////////////////////////////////////////////////
 
diff --git a/media/libstagefright/include/NuHTTPDataSource.h b/media/libstagefright/include/NuHTTPDataSource.h
index 082b589..7dd5d59 100644
--- a/media/libstagefright/include/NuHTTPDataSource.h
+++ b/media/libstagefright/include/NuHTTPDataSource.h
@@ -1,29 +1,41 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
 #ifndef NU_HTTP_DATA_SOURCE_H_
 
 #define NU_HTTP_DATA_SOURCE_H_
 
-#include <media/stagefright/DataSource.h>
 #include <utils/List.h>
 #include <utils/String8.h>
 #include <utils/threads.h>
 
 #include "HTTPStream.h"
+#include "include/HTTPBase.h"
 
 namespace android {
 
-struct NuHTTPDataSource : public DataSource {
-    enum Flags {
-        // Don't log any URLs.
-        kFlagIncognito = 1
-    };
+struct NuHTTPDataSource : public HTTPBase {
     NuHTTPDataSource(uint32_t flags = 0);
 
-    status_t connect(
+    virtual status_t connect(
             const char *uri,
             const KeyedVector<String8, String8> *headers = NULL,
             off64_t offset = 0);
 
-    void disconnect();
+    virtual void disconnect();
 
     virtual status_t initCheck() const;
 
@@ -33,10 +45,10 @@
 
     // Returns true if bandwidth could successfully be estimated,
     // false otherwise.
-    bool estimateBandwidth(int32_t *bandwidth_bps);
+    virtual bool estimateBandwidth(int32_t *bandwidth_bps);
 
-    virtual DecryptHandle* DrmInitialization();
-    virtual void getDrmInfo(DecryptHandle **handle, DrmManagerClient **client);
+    virtual sp<DecryptHandle> DrmInitialization();
+    virtual void getDrmInfo(sp<DecryptHandle> &handle, DrmManagerClient **client);
     virtual String8 getUri();
 
 protected:
@@ -82,7 +94,7 @@
     int64_t mTotalTransferTimeUs;
     size_t mTotalTransferBytes;
 
-    DecryptHandle *mDecryptHandle;
+    sp<DecryptHandle> mDecryptHandle;
     DrmManagerClient *mDrmManagerClient;
 
     status_t connect(
diff --git a/media/libstagefright/include/StagefrightMetadataRetriever.h b/media/libstagefright/include/StagefrightMetadataRetriever.h
index 07b1ec8..b02ed0e 100644
--- a/media/libstagefright/include/StagefrightMetadataRetriever.h
+++ b/media/libstagefright/include/StagefrightMetadataRetriever.h
@@ -32,7 +32,10 @@
     StagefrightMetadataRetriever();
     virtual ~StagefrightMetadataRetriever();
 
-    virtual status_t setDataSource(const char *url);
+    virtual status_t setDataSource(
+            const char *url,
+            const KeyedVector<String8, String8> *headers);
+
     virtual status_t setDataSource(int fd, int64_t offset, int64_t length);
 
     virtual VideoFrame *getFrameAtTime(int64_t timeUs, int option);
diff --git a/media/libstagefright/matroska/MatroskaExtractor.cpp b/media/libstagefright/matroska/MatroskaExtractor.cpp
index 733de92..b3e29b9 100644
--- a/media/libstagefright/matroska/MatroskaExtractor.cpp
+++ b/media/libstagefright/matroska/MatroskaExtractor.cpp
@@ -60,7 +60,10 @@
     virtual int Length(long long* total, long long* available) {
         off64_t size;
         if (mSource->getSize(&size) != OK) {
-            return -1;
+            *total = -1;
+            *available = (long long)((1ull << 63) - 1);
+
+            return 0;
         }
 
         if (total) {
@@ -84,7 +87,7 @@
 ////////////////////////////////////////////////////////////////////////////////
 
 struct BlockIterator {
-    BlockIterator(mkvparser::Segment *segment, unsigned long trackNum);
+    BlockIterator(MatroskaExtractor *extractor, unsigned long trackNum);
 
     bool eos() const;
 
@@ -96,11 +99,14 @@
     int64_t blockTimeUs() const;
 
 private:
-    mkvparser::Segment *mSegment;
+    MatroskaExtractor *mExtractor;
     unsigned long mTrackNum;
 
-    mkvparser::Cluster *mCluster;
+    const mkvparser::Cluster *mCluster;
     const mkvparser::BlockEntry *mBlockEntry;
+    long mBlockEntryIndex;
+
+    void advance_l();
 
     BlockIterator(const BlockIterator &);
     BlockIterator &operator=(const BlockIterator &);
@@ -150,7 +156,7 @@
     : mExtractor(extractor),
       mTrackIndex(index),
       mType(OTHER),
-      mBlockIter(mExtractor->mSegment,
+      mBlockIter(mExtractor.get(),
                  mExtractor->mTracks.itemAt(index).mTrackNum),
       mNALSizeLen(0) {
     sp<MetaData> meta = mExtractor->mTracks.itemAt(index).mMeta;
@@ -199,11 +205,12 @@
 ////////////////////////////////////////////////////////////////////////////////
 
 BlockIterator::BlockIterator(
-        mkvparser::Segment *segment, unsigned long trackNum)
-    : mSegment(segment),
+        MatroskaExtractor *extractor, unsigned long trackNum)
+    : mExtractor(extractor),
       mTrackNum(trackNum),
       mCluster(NULL),
-      mBlockEntry(NULL) {
+      mBlockEntry(NULL),
+      mBlockEntryIndex(0) {
     reset();
 }
 
@@ -212,45 +219,97 @@
 }
 
 void BlockIterator::advance() {
-    while (!eos()) {
-        if (mBlockEntry != NULL) {
-            mBlockEntry = mCluster->GetNext(mBlockEntry);
-        } else if (mCluster != NULL) {
-            mCluster = mSegment->GetNext(mCluster);
+    Mutex::Autolock autoLock(mExtractor->mLock);
+    advance_l();
+}
 
-            if (eos()) {
+void BlockIterator::advance_l() {
+    for (;;) {
+        long res = mCluster->GetEntry(mBlockEntryIndex, mBlockEntry);
+        LOGV("GetEntry returned %ld", res);
+
+        long long pos;
+        long len;
+        if (res < 0) {
+            // Need to parse this cluster some more
+
+            CHECK_EQ(res, mkvparser::E_BUFFER_NOT_FULL);
+
+            res = mCluster->Parse(pos, len);
+            LOGV("Parse returned %ld", res);
+
+            if (res < 0) {
+                // I/O error
+
+                LOGE("Cluster::Parse returned result %ld", res);
+
+                mCluster = NULL;
                 break;
             }
 
-            mBlockEntry = mCluster->GetFirst();
+            continue;
+        } else if (res == 0) {
+            // We're done with this cluster
+
+            const mkvparser::Cluster *nextCluster;
+            res = mExtractor->mSegment->ParseNext(
+                    mCluster, nextCluster, pos, len);
+            LOGV("ParseNext returned %ld", res);
+
+            if (res > 0) {
+                // EOF
+
+                mCluster = NULL;
+                break;
+            }
+
+            CHECK_EQ(res, 0);
+            CHECK(nextCluster != NULL);
+            CHECK(!nextCluster->EOS());
+
+            mCluster = nextCluster;
+
+            res = mCluster->Parse(pos, len);
+            LOGV("Parse (2) returned %ld", res);
+            CHECK_GE(res, 0);
+
+            mBlockEntryIndex = 0;
+            continue;
         }
 
-        if (mBlockEntry != NULL
-                && mBlockEntry->GetBlock()->GetTrackNumber() == mTrackNum) {
+        CHECK(mBlockEntry != NULL);
+        CHECK(mBlockEntry->GetBlock() != NULL);
+        ++mBlockEntryIndex;
+
+        if (mBlockEntry->GetBlock()->GetTrackNumber() == mTrackNum) {
             break;
         }
     }
 }
 
 void BlockIterator::reset() {
-    mCluster = mSegment->GetFirst();
-    mBlockEntry = mCluster->GetFirst();
+    Mutex::Autolock autoLock(mExtractor->mLock);
 
-    while (!eos() && block()->GetTrackNumber() != mTrackNum) {
-        advance();
-    }
+    mCluster = mExtractor->mSegment->GetFirst();
+    mBlockEntryIndex = 0;
+
+    do {
+        advance_l();
+    } while (!eos() && block()->GetTrackNumber() != mTrackNum);
 }
 
 void BlockIterator::seek(int64_t seekTimeUs) {
-    mCluster = mSegment->FindCluster(seekTimeUs * 1000ll);
-    mBlockEntry = mCluster != NULL ? mCluster->GetFirst() : NULL;
+    Mutex::Autolock autoLock(mExtractor->mLock);
+
+    mCluster = mExtractor->mSegment->FindCluster(seekTimeUs * 1000ll);
+    mBlockEntryIndex = 0;
 
     while (!eos() && block()->GetTrackNumber() != mTrackNum) {
-        advance();
+        advance_l();
     }
 
     while (!eos() && !mBlockEntry->GetBlock()->IsKey()) {
-        advance();
+        advance_l();
     }
 }
 
@@ -291,16 +350,6 @@
     }
 }
 
-#define BAIL(err) \
-    do {                        \
-        if (bigbuf) {           \
-            bigbuf->release();  \
-            bigbuf = NULL;      \
-        }                       \
-                                \
-        return err;             \
-    } while (0)
-
 status_t MatroskaSource::readBlock() {
     CHECK(mPendingFrames.empty());
 
@@ -310,181 +359,39 @@
 
     const mkvparser::Block *block = mBlockIter.block();
 
-    size_t size = block->GetSize();
     int64_t timeUs = mBlockIter.blockTimeUs();
-    int32_t isSync = block->IsKey();
 
-    MediaBuffer *bigbuf = new MediaBuffer(size);
+    for (int i = 0; i < block->GetFrameCount(); ++i) {
+        const mkvparser::Block::Frame &frame = block->GetFrame(i);
 
-    long res = block->Read(
-            mExtractor->mReader, (unsigned char *)bigbuf->data());
+        MediaBuffer *mbuf = new MediaBuffer(frame.len);
+        mbuf->meta_data()->setInt64(kKeyTime, timeUs);
+        mbuf->meta_data()->setInt32(kKeyIsSyncFrame, block->IsKey());
 
-    if (res != 0) {
-        bigbuf->release();
-        bigbuf = NULL;
+        long n = frame.Read(mExtractor->mReader, (unsigned char *)mbuf->data());
+        if (n != 0) {
+            mPendingFrames.clear();
 
-        return ERROR_END_OF_STREAM;
+            mBlockIter.advance();
+            return ERROR_IO;
+        }
+
+        mPendingFrames.push_back(mbuf);
     }
 
     mBlockIter.advance();
 
-    bigbuf->meta_data()->setInt64(kKeyTime, timeUs);
-    bigbuf->meta_data()->setInt32(kKeyIsSyncFrame, isSync);
-
-    unsigned lacing = (block->Flags() >> 1) & 3;
-
-    if (lacing == 0) {
-        mPendingFrames.push_back(bigbuf);
-        return OK;
-    }
-
-    LOGV("lacing = %u, size = %d", lacing, size);
-
-    const uint8_t *data = (const uint8_t *)bigbuf->data();
-    // hexdump(data, size);
-
-    if (size == 0) {
-        BAIL(ERROR_MALFORMED);
-    }
-
-    unsigned numFrames = (unsigned)data[0] + 1;
-    ++data;
-    --size;
-
-    Vector<uint64_t> frameSizes;
-
-    switch (lacing) {
-        case 1:  // Xiph
-        {
-            for (size_t i = 0; i < numFrames - 1; ++i) {
-                size_t frameSize = 0;
-                uint8_t byte;
-                do {
-                    if (size == 0) {
-                        BAIL(ERROR_MALFORMED);
-                    }
-                    byte = data[0];
-                    ++data;
-                    --size;
-
-                    frameSize += byte;
-                } while (byte == 0xff);
-
-                frameSizes.push(frameSize);
-            }
-
-            break;
-        }
-
-        case 2:  // fixed-size
-        {
-            if ((size % numFrames) != 0) {
-                BAIL(ERROR_MALFORMED);
-            }
-
-            size_t frameSize = size / numFrames;
-            for (size_t i = 0; i < numFrames - 1; ++i) {
-                frameSizes.push(frameSize);
-            }
-
-            break;
-        }
-
-        case 3:  // EBML
-        {
-            uint64_t lastFrameSize = 0;
-            for (size_t i = 0; i < numFrames - 1; ++i) {
-                uint8_t byte;
-
-                if (size == 0) {
-                    BAIL(ERROR_MALFORMED);
-                }
-                byte = data[0];
-                ++data;
-                --size;
-
-                size_t numLeadingZeroes = clz(byte);
-
-                uint64_t frameSize = byte & ~(0x80 >> numLeadingZeroes);
-                for (size_t j = 0; j < numLeadingZeroes; ++j) {
-                    if (size == 0) {
-                        BAIL(ERROR_MALFORMED);
-                    }
-
-                    frameSize = frameSize << 8;
-                    frameSize |= data[0];
-                    ++data;
-                    --size;
-                }
-
-                if (i == 0) {
-                    frameSizes.push(frameSize);
-                } else {
-                    size_t shift =
-                        7 - numLeadingZeroes + 8 * numLeadingZeroes;
-
-                    int64_t delta =
-                        (int64_t)frameSize - (1ll << (shift - 1)) + 1;
-
-                    frameSize = lastFrameSize + delta;
-
-                    frameSizes.push(frameSize);
-                }
-
-                lastFrameSize = frameSize;
-            }
-            break;
-        }
-
-        default:
-            TRESPASS();
-    }
-
-#if 0
-    AString out;
-    for (size_t i = 0; i < frameSizes.size(); ++i) {
-        if (i > 0) {
-            out.append(", ");
-        }
-        out.append(StringPrintf("%llu", frameSizes.itemAt(i)));
-    }
-    LOGV("sizes = [%s]", out.c_str());
-#endif
-
-    for (size_t i = 0; i < frameSizes.size(); ++i) {
-        uint64_t frameSize = frameSizes.itemAt(i);
-
-        if (size < frameSize) {
-            BAIL(ERROR_MALFORMED);
-        }
-
-        MediaBuffer *mbuf = new MediaBuffer(frameSize);
-        mbuf->meta_data()->setInt64(kKeyTime, timeUs);
-        mbuf->meta_data()->setInt32(kKeyIsSyncFrame, isSync);
-        memcpy(mbuf->data(), data, frameSize);
-        mPendingFrames.push_back(mbuf);
-
-        data += frameSize;
-        size -= frameSize;
-    }
-
-    size_t offset = bigbuf->range_length() - size;
-    bigbuf->set_range(offset, size);
-
-    mPendingFrames.push_back(bigbuf);
-
     return OK;
 }
 
-#undef BAIL
-
 status_t MatroskaSource::read(
         MediaBuffer **out, const ReadOptions *options) {
     *out = NULL;
 
     int64_t seekTimeUs;
     ReadOptions::SeekMode mode;
-    if (options && options->getSeekTo(&seekTimeUs, &mode)) {
+    if (options && options->getSeekTo(&seekTimeUs, &mode)
+            && !mExtractor->isLiveStreaming()) {
         clearPendingFrames();
         mBlockIter.seek(seekTimeUs);
     }
@@ -584,6 +491,13 @@
       mReader(new DataSourceReader(mDataSource)),
       mSegment(NULL),
       mExtractedThumbnails(false) {
+    off64_t size;
+    mIsLiveStreaming =
+        (mDataSource->flags()
+            & (DataSource::kWantsPrefetching
+                | DataSource::kIsCachingDataSource))
+        && mDataSource->getSize(&size) != OK;
+
     mkvparser::EBMLHeader ebmlHeader;
     long long pos;
     if (ebmlHeader.Parse(mReader, pos) < 0) {
@@ -598,7 +512,16 @@
         return;
     }
 
-    ret = mSegment->Load();
+    if (isLiveStreaming()) {
+        ret = mSegment->ParseHeaders();
+        CHECK_EQ(ret, 0);
+
+        long len;
+        ret = mSegment->LoadCluster(pos, len);
+        CHECK_EQ(ret, 0);
+    } else {
+        ret = mSegment->Load();
+    }
 
     if (ret < 0) {
         delete mSegment;
@@ -635,7 +558,8 @@
         return NULL;
     }
 
-    if ((flags & kIncludeExtensiveMetaData) && !mExtractedThumbnails) {
+    if ((flags & kIncludeExtensiveMetaData) && !mExtractedThumbnails
+            && !isLiveStreaming()) {
         findThumbnails();
         mExtractedThumbnails = true;
     }
@@ -643,6 +567,10 @@
     return mTracks.itemAt(index).mMeta;
 }
 
+bool MatroskaExtractor::isLiveStreaming() const {
+    return mIsLiveStreaming;
+}
+
 static void addESDSFromAudioSpecificInfo(
         const sp<MetaData> &meta, const void *asi, size_t asiSize) {
     static const uint8_t kStaticESDS[] = {
@@ -794,7 +722,7 @@
             continue;
         }
 
-        BlockIterator iter(mSegment, info->mTrackNum);
+        BlockIterator iter(this, info->mTrackNum);
         int32_t i = 0;
         int64_t thumbnailTimeUs = 0;
         size_t maxBlockSize = 0;
@@ -802,7 +730,11 @@
             if (iter.block()->IsKey()) {
                 ++i;
 
-                size_t blockSize = iter.block()->GetSize();
+                size_t blockSize = 0;
+                for (int i = 0; i < iter.block()->GetFrameCount(); ++i) {
+                    blockSize += iter.block()->GetFrame(i).len;
+                }
+
                 if (blockSize > maxBlockSize) {
                     maxBlockSize = blockSize;
                     thumbnailTimeUs = iter.blockTimeUs();
@@ -821,6 +753,15 @@
     return meta;
 }
 
+uint32_t MatroskaExtractor::flags() const {
+    uint32_t x = CAN_PAUSE;
+    if (!isLiveStreaming()) {
+        x |= CAN_SEEK_BACKWARD | CAN_SEEK_FORWARD | CAN_SEEK;
+    }
+
+    return x;
+}
+
 bool SniffMatroska(
         const sp<DataSource> &source, String8 *mimeType, float *confidence,
         sp<AMessage> *) {
diff --git a/media/libstagefright/matroska/MatroskaExtractor.h b/media/libstagefright/matroska/MatroskaExtractor.h
index fa20b84..38ebd61 100644
--- a/media/libstagefright/matroska/MatroskaExtractor.h
+++ b/media/libstagefright/matroska/MatroskaExtractor.h
@@ -20,6 +20,7 @@
 
 #include <media/stagefright/MediaExtractor.h>
 #include <utils/Vector.h>
+#include <utils/threads.h>
 
 namespace mkvparser {
 struct Segment;
@@ -45,26 +46,34 @@
 
     virtual sp<MetaData> getMetaData();
 
+    virtual uint32_t flags() const;
+
 protected:
     virtual ~MatroskaExtractor();
 
 private:
     friend struct MatroskaSource;
+    friend struct BlockIterator;
 
     struct TrackInfo {
         unsigned long mTrackNum;
         sp<MetaData> mMeta;
     };
+
+    Mutex mLock;
     Vector<TrackInfo> mTracks;
 
     sp<DataSource> mDataSource;
     DataSourceReader *mReader;
     mkvparser::Segment *mSegment;
     bool mExtractedThumbnails;
+    bool mIsLiveStreaming;
 
     void addTracks();
     void findThumbnails();
 
+    bool isLiveStreaming() const;
+
     MatroskaExtractor(const MatroskaExtractor &);
     MatroskaExtractor &operator=(const MatroskaExtractor &);
 };
diff --git a/media/libstagefright/yuv/Android.mk b/media/libstagefright/yuv/Android.mk
index 7697e3c..a4253f6 100644
--- a/media/libstagefright/yuv/Android.mk
+++ b/media/libstagefright/yuv/Android.mk
@@ -10,6 +10,6 @@
 
 LOCAL_MODULE:= libstagefright_yuv
 
-LOCAL_PRELINK_MODULE := false
+
 
 include $(BUILD_SHARED_LIBRARY)
diff --git a/media/mtp/MtpDataPacket.cpp b/media/mtp/MtpDataPacket.cpp
index 801edb0..0b0c80d 100644
--- a/media/mtp/MtpDataPacket.cpp
+++ b/media/mtp/MtpDataPacket.cpp
@@ -28,7 +28,7 @@
 namespace android {
 
 MtpDataPacket::MtpDataPacket()
-    :   MtpPacket(512),
+    :   MtpPacket(16384),   // MAX_USBFS_BUFFER_SIZE
         mOffset(MTP_CONTAINER_HEADER_SIZE)
 {
 }
@@ -399,10 +399,10 @@
     if (length >= MTP_CONTAINER_HEADER_SIZE) {
         // look at the length field to see if the data spans multiple packets
         uint32_t totalLength = MtpPacket::getUInt32(MTP_CONTAINER_LENGTH_OFFSET);
+        allocate(totalLength);
         while (totalLength > length) {
-            allocate(length + mAllocationIncrement);
             request->buffer = mBuffer + length;
-            request->buffer_length = mAllocationIncrement;
+            request->buffer_length = totalLength - length;
             int ret = transfer(request);
             if (ret >= 0)
                 length += ret;
diff --git a/media/mtp/MtpDevice.cpp b/media/mtp/MtpDevice.cpp
index 4ea8849..2e86159 100644
--- a/media/mtp/MtpDevice.cpp
+++ b/media/mtp/MtpDevice.cpp
@@ -819,6 +819,10 @@
         return mResponse.getResponseCode();
     }
     int ret = mResponse.read(mRequestIn1);
+    // handle zero length packets, which might occur if the data transfer
+    // ends on a packet boundary
+    if (ret == 0)
+        ret = mResponse.read(mRequestIn1);
     if (ret >= MTP_CONTAINER_HEADER_SIZE) {
         mResponse.dump();
         return mResponse.getResponseCode();
diff --git a/media/tests/CameraBrowser/Android.mk b/media/tests/CameraBrowser/Android.mk
index 1d81129..46596a7 100644
--- a/media/tests/CameraBrowser/Android.mk
+++ b/media/tests/CameraBrowser/Android.mk
@@ -7,4 +7,6 @@
 
 LOCAL_PACKAGE_NAME := CameraBrowser
 
+LOCAL_SDK_VERSION := current
+
 include $(BUILD_PACKAGE)
diff --git a/media/tests/CameraBrowser/src/com/android/camerabrowser/CameraBrowser.java b/media/tests/CameraBrowser/src/com/android/camerabrowser/CameraBrowser.java
index f642d93..af17ded 100644
--- a/media/tests/CameraBrowser/src/com/android/camerabrowser/CameraBrowser.java
+++ b/media/tests/CameraBrowser/src/com/android/camerabrowser/CameraBrowser.java
@@ -20,7 +20,6 @@
 import android.content.ContentResolver;
 import android.content.Context;
 import android.content.Intent;
-import android.mtp.MtpClient;
 import android.mtp.MtpDevice;
 import android.mtp.MtpDeviceInfo;
 import android.os.Bundle;
@@ -79,8 +78,8 @@
                 view = (TwoLineListItem)convertView;
             }
 
-            TextView textView1 = (TextView)view.findViewById(com.android.internal.R.id.text1);
-            TextView textView2 = (TextView)view.findViewById(com.android.internal.R.id.text2);
+            TextView textView1 = (TextView)view.findViewById(android.R.id.text1);
+            TextView textView2 = (TextView)view.findViewById(android.R.id.text2);
             MtpDevice device = mDeviceList.get(position);
             MtpDeviceInfo info = device.getDeviceInfo();
             if (info != null) {
diff --git a/media/tests/CameraBrowser/src/com/android/camerabrowser/CameraBrowserApplication.java b/media/tests/CameraBrowser/src/com/android/camerabrowser/CameraBrowserApplication.java
index 6f1edfea..8075862 100644
--- a/media/tests/CameraBrowser/src/com/android/camerabrowser/CameraBrowserApplication.java
+++ b/media/tests/CameraBrowser/src/com/android/camerabrowser/CameraBrowserApplication.java
@@ -17,8 +17,6 @@
 package com.android.camerabrowser;
 
 import android.app.Application;
-import android.mtp.MtpClient;
-
 
 public class CameraBrowserApplication extends Application {
 
diff --git a/media/java/android/mtp/MtpClient.java b/media/tests/CameraBrowser/src/com/android/camerabrowser/MtpClient.java
similarity index 77%
rename from media/java/android/mtp/MtpClient.java
rename to media/tests/CameraBrowser/src/com/android/camerabrowser/MtpClient.java
index c4ee19e..edb5e37 100644
--- a/media/java/android/mtp/MtpClient.java
+++ b/media/tests/CameraBrowser/src/com/android/camerabrowser/MtpClient.java
@@ -14,21 +14,28 @@
  * limitations under the License.
  */
 
-package android.mtp;
+package com.android.camerabrowser;
 
+import android.app.PendingIntent;
 import android.content.BroadcastReceiver;
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
 import android.hardware.usb.UsbConstants;
 import android.hardware.usb.UsbDevice;
+import android.hardware.usb.UsbDeviceConnection;
 import android.hardware.usb.UsbInterface;
 import android.hardware.usb.UsbManager;
+import android.mtp.MtpDevice;
+import android.mtp.MtpDeviceInfo;
+import android.mtp.MtpObjectInfo;
+import android.mtp.MtpStorageInfo;
 import android.os.ParcelFileDescriptor;
 import android.util.Log;
 
 import java.io.IOException;
 import java.util.ArrayList;
+import java.util.HashMap;
 import java.util.List;
 
 /**
@@ -40,34 +47,58 @@
 
     private static final String TAG = "MtpClient";
 
+    private static final String ACTION_USB_PERMISSION =
+            "android.mtp.MtpClient.action.USB_PERMISSION";
+
     private final Context mContext;
     private final UsbManager mUsbManager;
     private final ArrayList<Listener> mListeners = new ArrayList<Listener>();
-    private final ArrayList<MtpDevice> mDeviceList = new ArrayList<MtpDevice>();
+    // mDevices contains all MtpDevices that have been seen by our client,
+    // so we can inform when the device has been detached.
+    // mDevices is also used for synchronization in this class.
+    private final HashMap<String, MtpDevice> mDevices = new HashMap<String, MtpDevice>();
+
+    private final PendingIntent mPermissionIntent;
 
     private final BroadcastReceiver mUsbReceiver = new BroadcastReceiver() {
         @Override
         public void onReceive(Context context, Intent intent) {
+            String action = intent.getAction();
             UsbDevice usbDevice = (UsbDevice)intent.getParcelableExtra(UsbManager.EXTRA_DEVICE);
             String deviceName = usbDevice.getDeviceName();
 
-            synchronized (mDeviceList) {
-                MtpDevice mtpDevice = getDeviceLocked(deviceName);
+            synchronized (mDevices) {
+                MtpDevice mtpDevice = mDevices.get(deviceName);
 
-                if (UsbManager.ACTION_USB_DEVICE_ATTACHED.equals(intent.getAction())) {
+                if (UsbManager.ACTION_USB_DEVICE_ATTACHED.equals(action)) {
                     if (mtpDevice == null) {
-                        mtpDevice = openDevice(usbDevice);
+                        mtpDevice = openDeviceLocked(usbDevice);
                     }
                     if (mtpDevice != null) {
-                        mDeviceList.add(mtpDevice);
                         for (Listener listener : mListeners) {
                             listener.deviceAdded(mtpDevice);
                         }
                     }
-                } else if (mtpDevice != null) {
-                    mDeviceList.remove(mtpDevice);
-                    for (Listener listener : mListeners) {
-                        listener.deviceRemoved(mtpDevice);
+                } else if (UsbManager.ACTION_USB_DEVICE_DETACHED.equals(action)) {
+                    if (mtpDevice != null) {
+                        mDevices.remove(deviceName);
+                        for (Listener listener : mListeners) {
+                            listener.deviceRemoved(mtpDevice);
+                        }
+                    }
+                } else if (ACTION_USB_PERMISSION.equals(action)) {
+                    boolean permission = intent.getBooleanExtra(UsbManager.EXTRA_PERMISSION_GRANTED,
+                            false);
+                    Log.d(TAG, "ACTION_USB_PERMISSION: " + permission);
+                    if (permission) {
+                        if (mtpDevice == null) {
+                            mtpDevice = openDeviceLocked(usbDevice);
+                        }
+                        if (mtpDevice != null) {
+                            for (Listener listener : mListeners) {
+                                listener.deviceAdded(mtpDevice);
+                            }
+                        }
                     }
                 }
             }
@@ -122,21 +153,12 @@
     public MtpClient(Context context) {
         mContext = context;
         mUsbManager = (UsbManager)context.getSystemService(Context.USB_SERVICE);
-
+        mPermissionIntent = PendingIntent.getBroadcast(mContext, 0, new Intent(ACTION_USB_PERMISSION), 0);
         IntentFilter filter = new IntentFilter();
         filter.addAction(UsbManager.ACTION_USB_DEVICE_ATTACHED);
         filter.addAction(UsbManager.ACTION_USB_DEVICE_DETACHED);
+        filter.addAction(ACTION_USB_PERMISSION);
         context.registerReceiver(mUsbReceiver, filter);
-
-        for (UsbDevice usbDevice : mUsbManager.getDeviceList().values()) {
-            MtpDevice mtpDevice = getDeviceLocked(usbDevice.getDeviceName());
-            if (mtpDevice == null) {
-                mtpDevice = openDevice(usbDevice);
-            }
-            if (mtpDevice != null) {
-                mDeviceList.add(mtpDevice);
-            }
-        }
     }
 
     /**
@@ -146,11 +168,19 @@
      * @param device the device to open
      * @return an MtpDevice for the device.
      */
-    private MtpDevice openDevice(UsbDevice usbDevice) {
+    private MtpDevice openDeviceLocked(UsbDevice usbDevice) {
         if (isCamera(usbDevice)) {
-            MtpDevice mtpDevice = new MtpDevice(usbDevice);
-            if (mtpDevice.open(mUsbManager)) {
-                return mtpDevice;
+            if (!mUsbManager.hasPermission(usbDevice)) {
+                mUsbManager.requestPermission(usbDevice, mPermissionIntent);
+            } else {
+                UsbDeviceConnection connection = mUsbManager.openDevice(usbDevice);
+                if (connection != null) {
+                    MtpDevice mtpDevice = new MtpDevice(usbDevice);
+                    if (mtpDevice.open(connection)) {
+                        mDevices.put(usbDevice.getDeviceName(), mtpDevice);
+                        return mtpDevice;
+                    }
+                }
             }
         }
         return null;
@@ -170,7 +200,7 @@
      * @param listener the listener to register
      */
     public void addListener(Listener listener) {
-        synchronized (mDeviceList) {
+        synchronized (mDevices) {
             if (!mListeners.contains(listener)) {
                 mListeners.add(listener);
             }
@@ -183,7 +213,7 @@
      * @param listener the listener to unregister
      */
     public void removeListener(Listener listener) {
-        synchronized (mDeviceList) {
+        synchronized (mDevices) {
             mListeners.remove(listener);
         }
     }
@@ -196,8 +226,8 @@
      * @return the MtpDevice, or null if it does not exist
      */
     public MtpDevice getDevice(String deviceName) {
-        synchronized (mDeviceList) {
-            return getDeviceLocked(deviceName);
+        synchronized (mDevices) {
+            return mDevices.get(deviceName);
         }
     }
 
@@ -209,28 +239,27 @@
      * @return the MtpDevice, or null if it does not exist
      */
     public MtpDevice getDevice(int id) {
-        synchronized (mDeviceList) {
-            return getDeviceLocked(UsbDevice.getDeviceName(id));
+        synchronized (mDevices) {
+            return mDevices.get(UsbDevice.getDeviceName(id));
         }
     }
 
-    private MtpDevice getDeviceLocked(String deviceName) {
-        for (MtpDevice device : mDeviceList) {
-            if (device.getDeviceName().equals(deviceName)) {
-                return device;
-            }
-        }
-        return null;
-    }
-
     /**
      * Retrieves a list of all currently connected {@link android.mtp.MtpDevice}.
      *
      * @return the list of MtpDevices
      */
     public List<MtpDevice> getDeviceList() {
-        synchronized (mDeviceList) {
-            return new ArrayList<MtpDevice>(mDeviceList);
+        synchronized (mDevices) {
+            // Query the USB manager since devices might have attached
+            // before we added our listener.
+            for (UsbDevice usbDevice : mUsbManager.getDeviceList().values()) {
+                if (mDevices.get(usbDevice.getDeviceName()) == null) {
+                    openDeviceLocked(usbDevice);
+                }
+            }
+
+            return new ArrayList<MtpDevice>(mDevices.values());
         }
     }
 
diff --git a/media/tests/CameraBrowser/src/com/android/camerabrowser/ObjectBrowser.java b/media/tests/CameraBrowser/src/com/android/camerabrowser/ObjectBrowser.java
index 82251d9..68fed7b 100644
--- a/media/tests/CameraBrowser/src/com/android/camerabrowser/ObjectBrowser.java
+++ b/media/tests/CameraBrowser/src/com/android/camerabrowser/ObjectBrowser.java
@@ -22,7 +22,6 @@
 import android.database.Cursor;
 import android.graphics.Bitmap;
 import android.graphics.BitmapFactory;
-import android.mtp.MtpClient;
 import android.mtp.MtpConstants;
 import android.mtp.MtpDevice;
 import android.mtp.MtpObjectInfo;
diff --git a/media/tests/CameraBrowser/src/com/android/camerabrowser/ObjectViewer.java b/media/tests/CameraBrowser/src/com/android/camerabrowser/ObjectViewer.java
index e9ea9f3..ef69c44 100644
--- a/media/tests/CameraBrowser/src/com/android/camerabrowser/ObjectViewer.java
+++ b/media/tests/CameraBrowser/src/com/android/camerabrowser/ObjectViewer.java
@@ -23,7 +23,6 @@
 import android.graphics.BitmapFactory;
 import android.media.MediaScannerConnection;
 import android.media.MediaScannerConnection.MediaScannerConnectionClient;
-import android.mtp.MtpClient;
 import android.mtp.MtpConstants;
 import android.mtp.MtpObjectInfo;
 import android.net.Uri;
diff --git a/media/tests/CameraBrowser/src/com/android/camerabrowser/StorageBrowser.java b/media/tests/CameraBrowser/src/com/android/camerabrowser/StorageBrowser.java
index 7d5a5da..64320fe 100644
--- a/media/tests/CameraBrowser/src/com/android/camerabrowser/StorageBrowser.java
+++ b/media/tests/CameraBrowser/src/com/android/camerabrowser/StorageBrowser.java
@@ -19,7 +19,6 @@
 import android.app.ListActivity;
 import android.content.Context;
 import android.content.Intent;
-import android.mtp.MtpClient;
 import android.mtp.MtpDevice;
 import android.mtp.MtpStorageInfo;
 import android.os.Bundle;
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/MediaTestUtil.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/MediaTestUtil.java
index 0183b5d..a80fc13 100755
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/MediaTestUtil.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/MediaTestUtil.java
@@ -16,10 +16,17 @@
 
 package com.android.mediaframeworktest;
 
+import java.io.BufferedWriter;
+import java.io.File;
 import java.io.FileOutputStream;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.Writer;
 
 import android.os.Debug;
 import android.os.Environment;
+import android.util.Log;
 
 /**
  *
@@ -27,19 +34,119 @@
  *
  */
 public class MediaTestUtil {
-    private MediaTestUtil(){
+
+    private static String TAG = "MediaTestUtil";
+    private static final String STORAGE_PATH = Environment.getExternalStorageDirectory().toString();
+    private int mStartMemory = 0;
+    private int mStartPid = 0;
+    private Writer mOutput = null;
+    private String mTestName = null;
+    private String mProcessName = null;
+
+    public MediaTestUtil(String memoryOutFileName, String testName, String processName)
+            throws Exception {
+        File memoryOut = new File(memoryOutFileName);
+        mOutput = new BufferedWriter(new FileWriter(memoryOut, true));
+        mProcessName = processName;
+        mTestName = testName;
+        mStartPid = getPid();
+        mStartMemory = getVsize();
     }
 
-    private static final String STORAGE_PATH =
-        Environment.getExternalStorageDirectory().toString();
-
-    //Catpure the heapdump for memory leaksage analysis\
-    public static void getNativeHeapDump (String name) throws Exception {
+    // Catpure the heapdump for memory leaksage analysis
+    public static void getNativeHeapDump(String name) throws Exception {
         System.gc();
         System.runFinalization();
         Thread.sleep(1000);
-        FileOutputStream o = new FileOutputStream(STORAGE_PATH + '/' +name + ".dump");
+        FileOutputStream o = new FileOutputStream(STORAGE_PATH + '/' + name + ".dump");
         Debug.dumpNativeHeap(o.getFD());
         o.close();
     }
-}
\ No newline at end of file
+
+    private void validateProcessStatus() throws Exception {
+        int currentPid = getPid();
+        //Process crash
+        if (mStartPid != currentPid) {
+            mOutput.write(mProcessName + " died. Test failed\n");
+        }
+    }
+
+    private int getPid() {
+        String memoryUsage = null;
+        int pidvalue = 0;
+        memoryUsage = captureMemInfo();
+        String[] poList2 = memoryUsage.split("\t|\\s+");
+        String pid = poList2[1];
+        pidvalue = Integer.parseInt(pid);
+        Log.v(TAG, "PID = " + pidvalue);
+        return pidvalue;
+    }
+
+    private String captureMemInfo() {
+        String cm = "ps ";
+        cm += mProcessName;
+        Log.v(TAG, cm);
+        String memoryUsage = null;
+
+        int ch;
+        try {
+            Process p = Runtime.getRuntime().exec(cm);
+            InputStream in = p.getInputStream();
+            StringBuffer sb = new StringBuffer(512);
+            while ((ch = in.read()) != -1) {
+                sb.append((char) ch);
+            }
+            memoryUsage = sb.toString();
+        } catch (IOException e) {
+            Log.v(TAG, e.toString());
+        }
+        String[] poList = memoryUsage.split("\r|\n|\r\n");
+        String memusage = poList[1].concat("\n");
+        return memusage;
+    }
+
+    private int getVsize() {
+        String memoryUsage = captureMemInfo();
+        String[] poList2 = memoryUsage.split("\t|\\s+");
+        String vsize = poList2[3];
+        int vsizevalue = Integer.parseInt(vsize);
+        Log.v(TAG, "VSIZE = " + vsizevalue);
+        return vsizevalue;
+    }
+
+    // Write the startup media memory mOutput to the file
+    public void getStartMemoryLog() throws Exception {
+        String memusage = null;
+        mStartMemory = getVsize();
+        mOutput.write(mTestName + '\n');
+        mOutput.write("Start memory : " + mStartMemory + "\n");
+        memusage = captureMemInfo();
+        mOutput.write(memusage);
+    }
+
+    // Write the ps mediaserver mOutput to the file
+    public void getMemoryLog() throws Exception {
+        String memusage = null;
+        memusage = captureMemInfo();
+        mOutput.write(memusage);
+        mOutput.flush();
+    }
+
+    public void getMemorySummary() throws Exception {
+        int endMemory = 0;
+        int memDiff = 0;
+
+        endMemory = getVsize();
+        memDiff = endMemory - mStartMemory;
+
+        mOutput.write("End Memory :" + endMemory + "\n");
+        if (memDiff < 0) {
+            memDiff = 0;
+        }
+        mOutput.write(mTestName + " total diff = " + memDiff);
+        mOutput.write("\n\n");
+        validateProcessStatus();
+        mOutput.flush();
+        mOutput.close();
+    }
+}
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/MediaAudioEffectTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/MediaAudioEffectTest.java
index 34025f69e..90be041 100644
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/MediaAudioEffectTest.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/MediaAudioEffectTest.java
@@ -744,7 +744,7 @@
             assertNotNull(msg + ": could not create AudioEffect", effect);
             byte[] param = intToByteArray(Equalizer.PARAM_CURRENT_PRESET);
             byte[] value = new byte[2];
-            if (effect.getParameter(param, value) == AudioEffect.SUCCESS) {
+            if (!AudioEffect.isError(effect.getParameter(param, value))) {
                 result = true;
             }
         } catch (IllegalArgumentException e) {
@@ -777,8 +777,8 @@
                                     0);
             assertNotNull(msg + ": could not create AudioEffect", effect);
             int[] value = new int[1];
-            if (effect.getParameter(EnvironmentalReverb.PARAM_DECAY_TIME, value)
-                    == AudioEffect.SUCCESS) {
+            if (!AudioEffect.isError(
+                    effect.getParameter(EnvironmentalReverb.PARAM_DECAY_TIME, value))) {
                 result = true;
             }
         } catch (IllegalArgumentException e) {
@@ -811,8 +811,7 @@
                                     0);
             assertNotNull(msg + ": could not create AudioEffect", effect);
             short[] value = new short[1];
-            if (effect.getParameter(Equalizer.PARAM_CURRENT_PRESET, value)
-                    == AudioEffect.SUCCESS) {
+            if (!AudioEffect.isError(effect.getParameter(Equalizer.PARAM_CURRENT_PRESET, value))) {
                 result = true;
             }
         } catch (IllegalArgumentException e) {
@@ -845,8 +844,7 @@
                                     0);
             assertNotNull(msg + ": could not create AudioEffect", effect);
             byte[] value = new byte[2];
-            if (effect.getParameter(Equalizer.PARAM_CURRENT_PRESET, value)
-                    == AudioEffect.SUCCESS) {
+            if (!AudioEffect.isError(effect.getParameter(Equalizer.PARAM_CURRENT_PRESET, value))) {
                 result = true;
             }
         } catch (IllegalArgumentException e) {
@@ -881,8 +879,7 @@
             int[] param = new int[1];
             int[] value = new int[1];
             param[0] = EnvironmentalReverb.PARAM_DECAY_TIME;
-            if (effect.getParameter(param, value)
-                    == AudioEffect.SUCCESS) {
+            if (!AudioEffect.isError(effect.getParameter(param, value))) {
                 result = true;
             }
         } catch (IllegalArgumentException e) {
@@ -917,8 +914,7 @@
             int[] param = new int[1];
             short[] value = new short[1];
             param[0] = Equalizer.PARAM_CURRENT_PRESET;
-            if (effect.getParameter(param, value)
-                    == AudioEffect.SUCCESS) {
+            if (!AudioEffect.isError(effect.getParameter(param, value))) {
                 result = true;
             }
         } catch (IllegalArgumentException e) {
@@ -953,8 +949,7 @@
             int[] param = new int[1];
             byte[] value = new byte[2];
             param[0] = Equalizer.PARAM_CURRENT_PRESET;
-            if (effect.getParameter(param, value)
-                    == AudioEffect.SUCCESS) {
+            if (!AudioEffect.isError(effect.getParameter(param, value))) {
                 result = true;
             }
         } catch (IllegalArgumentException e) {
@@ -1082,8 +1077,8 @@
 
             short[] value = new short[1];
             status = effect2.getParameter(Equalizer.PARAM_CURRENT_PRESET, value);
-            assertEquals(msg + ": Effect2 getParameter failed",
-                    AudioEffect.SUCCESS, status);
+            assertFalse(msg + ": Effect2 getParameter failed",
+                    AudioEffect.isError(status));
             assertEquals(msg + ": Effect1 changed parameter",
                     (short)0, value[0]);
 
@@ -1278,7 +1273,7 @@
                 byte[] cmd = new byte[0];
                 byte[] reply = new byte[4];
                 int status = effect.command(3, cmd, reply);
-                assertEquals(msg + ": command failed", AudioEffect.SUCCESS, status);
+                assertFalse(msg + ": command failed", AudioEffect.isError(status));
                 assertTrue(msg + ": effect not enabled", effect.getEnabled());
                 result = true;
             } catch (IllegalStateException e) {
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/MediaItemThumbnailTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/MediaItemThumbnailTest.java
index 895ca25..154f691 100755
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/MediaItemThumbnailTest.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/MediaItemThumbnailTest.java
@@ -585,7 +585,9 @@
         try{
         final MediaImageItem mii = new MediaImageItem(mVideoEditor, "m1",
             imageItemFileName, 3000, renderingMode);
-        }catch (IllegalArgumentException e){
+        } catch (IllegalArgumentException e) {
+            flagForException = true;
+        } catch (IOException e) {
             flagForException = true;
         }
         assertTrue(" Invalid File Path", flagForException);
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/MediaPropertiesTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/MediaPropertiesTest.java
index 3efa5b2..59783e5 100755
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/MediaPropertiesTest.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/MediaPropertiesTest.java
@@ -30,6 +30,7 @@
 import android.test.suitebuilder.annotation.LargeTest;
 import com.android.mediaframeworktest.MediaFrameworkTest;
 import com.android.mediaframeworktest.VideoEditorHelper;
+import com.android.mediaframeworktest.MediaProfileReader;
 
 public class MediaPropertiesTest extends
     ActivityInstrumentationTestCase<MediaFrameworkTest> {
@@ -465,11 +466,17 @@
         final String videoItemFilename = INPUT_FILE_PATH +
             "WMV_V7_640x480_15fps_512Kbps_wma_V9_44khz_48Kbps_s_1_30.wmv";
         boolean flagForException = false;
-        try {
-            new MediaVideoItem(mVideoEditor, "m1", videoItemFilename,
-                MediaItem.RENDERING_MODE_BLACK_BORDER);
-        } catch (IllegalArgumentException e) {
+        if (MediaProfileReader.getWMVEnable() == false) {
             flagForException = true;
+        } else {
+            try {
+                new MediaVideoItem(mVideoEditor, "m1", videoItemFilename,
+                    MediaItem.RENDERING_MODE_BLACK_BORDER);
+            } catch (IllegalArgumentException e) {
+                flagForException = true;
+            } catch (IOException e) {
+                flagForException = true;
+            }
         }
         assertTrue("Media Properties for a WMV File -- Unsupported file type",
             flagForException);
@@ -513,6 +520,8 @@
                 MediaItem.RENDERING_MODE_BLACK_BORDER);
         } catch (IllegalArgumentException e) {
             flagForException = true;
+        } catch (IOException e) {
+            flagForException = true;
         }
         assertTrue("Media Properties for non exsisting file", flagForException);
      }
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/VideoEditorExportTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/VideoEditorExportTest.java
index 37b1f54..74d4766 100755
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/VideoEditorExportTest.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/VideoEditorExportTest.java
@@ -44,6 +44,7 @@
 
 import com.android.mediaframeworktest.MediaFrameworkTest;
 import android.test.suitebuilder.annotation.LargeTest;
+import android.test.suitebuilder.annotation.Suppress;
 import com.android.mediaframeworktest.VideoEditorHelper;
 
 public class VideoEditorExportTest extends
@@ -701,6 +702,7 @@
      *
      * @throws Exception
      */
+    @Suppress
     @LargeTest
     public void testExportDuration1Hour() throws Exception {
         final String videoItemFilename1 = INPUT_FILE_PATH +
diff --git a/media/tests/omxjpegdecoder/Android.mk b/media/tests/omxjpegdecoder/Android.mk
index 7802efd..81c6167 100644
--- a/media/tests/omxjpegdecoder/Android.mk
+++ b/media/tests/omxjpegdecoder/Android.mk
@@ -22,11 +22,6 @@
         SkOmxPixelRef.cpp \
         StreamSource.cpp
 
-
-# add external/skia/src/images/SkImageDecoder_libjpeg.cpp
-LOCAL_SRC_FILES += \
-        ../../../../../external/skia/src/images/SkImageDecoder_libjpeg.cpp
-
 LOCAL_SHARED_LIBRARIES := \
     libcutils \
     libskia \
diff --git a/media/tests/players/Android.mk b/media/tests/players/Android.mk
index 10367cf..c655ae6 100644
--- a/media/tests/players/Android.mk
+++ b/media/tests/players/Android.mk
@@ -24,6 +24,6 @@
 
 LOCAL_MODULE:= invoke_mock_media_player
 LOCAL_MODULE_TAGS := tests eng
-LOCAL_PRELINK_MODULE:= false
+
 
 include $(BUILD_SHARED_LIBRARY)
diff --git a/native/android/native_window.cpp b/native/android/native_window.cpp
index 7f92eec..ae1993d 100644
--- a/native/android/native_window.cpp
+++ b/native/android/native_window.cpp
@@ -20,6 +20,7 @@
 #include <android/native_window_jni.h>
 #include <surfaceflinger/Surface.h>
 #include <android_runtime/android_view_Surface.h>
+#include <android_runtime/android_graphics_SurfaceTexture.h>
 
 using namespace android;
 
@@ -31,6 +32,14 @@
     return win.get();
 }
 
+ANativeWindow* ANativeWindow_fromSurfaceTexture(JNIEnv* env, jobject surfaceTexture) {
+    sp<ANativeWindow> win = android_SurfaceTexture_getNativeWindow(env, surfaceTexture);
+    if (win != NULL) {
+        win->incStrong((void*)ANativeWindow_acquire);
+    }
+    return win.get();
+}
+
 void ANativeWindow_acquire(ANativeWindow* window) {
     window->incStrong((void*)ANativeWindow_acquire);
 }
@@ -65,6 +74,12 @@
 
 int32_t ANativeWindow_lock(ANativeWindow* window, ANativeWindow_Buffer* outBuffer,
         ARect* inOutDirtyBounds) {
+    int type = -1;
+    if (window->query(window, NATIVE_WINDOW_CONCRETE_TYPE, &type) != 0 ||
+            type != NATIVE_WINDOW_SURFACE) {
+        return BAD_VALUE;
+    }
+
     Region dirtyRegion;
     Region* dirtyParam = NULL;
     if (inOutDirtyBounds != NULL) {
diff --git a/native/include/android/input.h b/native/include/android/input.h
index f19e8be..953ee10 100644
--- a/native/include/android/input.h
+++ b/native/include/android/input.h
@@ -359,6 +359,11 @@
     AMOTION_EVENT_AXIS_HAT_Y = 16,
     AMOTION_EVENT_AXIS_LTRIGGER = 17,
     AMOTION_EVENT_AXIS_RTRIGGER = 18,
+    AMOTION_EVENT_AXIS_THROTTLE = 19,
+    AMOTION_EVENT_AXIS_RUDDER = 20,
+    AMOTION_EVENT_AXIS_WHEEL = 21,
+    AMOTION_EVENT_AXIS_GAS = 22,
+    AMOTION_EVENT_AXIS_BRAKE = 23,
     AMOTION_EVENT_AXIS_GENERIC_1 = 32,
     AMOTION_EVENT_AXIS_GENERIC_2 = 33,
     AMOTION_EVENT_AXIS_GENERIC_3 = 34,
@@ -652,7 +657,8 @@
  * and views.
  * Whole numbers are pixels; the value may have a fraction for input devices
  * that are sub-pixel precise. */
-float AMotionEvent_getHistoricalRawX(const AInputEvent* motion_event, size_t pointer_index);
+float AMotionEvent_getHistoricalRawX(const AInputEvent* motion_event, size_t pointer_index,
+        size_t history_index);
 
 /* Get the historical raw Y coordinate of this event for the given pointer index that
  * occurred between this event and the previous motion event.
@@ -661,7 +667,8 @@
  * and views.
  * Whole numbers are pixels; the value may have a fraction for input devices
  * that are sub-pixel precise. */
-float AMotionEvent_getHistoricalRawY(const AInputEvent* motion_event, size_t pointer_index);
+float AMotionEvent_getHistoricalRawY(const AInputEvent* motion_event, size_t pointer_index,
+        size_t history_index);
 
 /* Get the historical X coordinate of this event for the given pointer index that
  * occurred between this event and the previous motion event.
diff --git a/native/include/android/keycodes.h b/native/include/android/keycodes.h
index c4a7eff..5d49775 100644
--- a/native/include/android/keycodes.h
+++ b/native/include/android/keycodes.h
@@ -247,6 +247,9 @@
     AKEYCODE_BUTTON_14       = 201,
     AKEYCODE_BUTTON_15       = 202,
     AKEYCODE_BUTTON_16       = 203,
+    AKEYCODE_LANGUAGE_SWITCH = 204,
+    AKEYCODE_MANNER_MODE     = 205,
+    AKEYCODE_3D_MODE         = 206,
 
     // NOTE: If you add a new keycode here you must also add it to several other files.
     //       Refer to frameworks/base/core/java/android/view/KeyEvent.java for the full list.
diff --git a/native/include/android/native_window_jni.h b/native/include/android/native_window_jni.h
index b9e72ef..408c263 100644
--- a/native/include/android/native_window_jni.h
+++ b/native/include/android/native_window_jni.h
@@ -33,6 +33,14 @@
  */
 ANativeWindow* ANativeWindow_fromSurface(JNIEnv* env, jobject surface);
 
+/**
+ * Return the ANativeWindow associated with a Java SurfaceTexture object,
+ * for interacting with it through native code.  This acquires a reference
+ * on the ANativeWindow that is returned; be sure to use ANativeWindow_release()
+ * when done with it so that it doesn't leak.
+ */
+ANativeWindow* ANativeWindow_fromSurfaceTexture(JNIEnv* env, jobject surfaceTexture);
+
 #ifdef __cplusplus
 };
 #endif
diff --git a/nfc-extras/Android.mk b/nfc-extras/Android.mk
new file mode 100644
index 0000000..131d898
--- /dev/null
+++ b/nfc-extras/Android.mk
@@ -0,0 +1,14 @@
+LOCAL_PATH:= $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_TAGS := optional
+
+LOCAL_SRC_FILES := $(call all-subdir-java-files)
+
+LOCAL_MODULE:= com.android.nfc_extras
+
+include $(BUILD_JAVA_LIBRARY)
+
+# put the classes.jar, with full class files instead of classes.dex inside, into the dist directory
+$(call dist-for-goals, droidcore, $(full_classes_jar):com.android.nfc_extras.jar)
diff --git a/nfc-extras/com.android.nfc_extras.xml b/nfc-extras/com.android.nfc_extras.xml
new file mode 100644
index 0000000..370145d
--- /dev/null
+++ b/nfc-extras/com.android.nfc_extras.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2011 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<permissions>
+    <library name="com.android.nfc_extras"
+            file="/system/framework/com.android.nfc_extras.jar" />
+</permissions>
diff --git a/nfc-extras/java/com/android/nfc_extras/NfcAdapterExtras.java b/nfc-extras/java/com/android/nfc_extras/NfcAdapterExtras.java
new file mode 100644
index 0000000..cf38bd1
--- /dev/null
+++ b/nfc-extras/java/com/android/nfc_extras/NfcAdapterExtras.java
@@ -0,0 +1,180 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.nfc_extras;
+
+import android.annotation.SdkConstant;
+import android.annotation.SdkConstant.SdkConstantType;
+import android.nfc.INfcAdapterExtras;
+import android.nfc.NfcAdapter;
+import android.os.RemoteException;
+import android.util.Log;
+
+/**
+ * Provides additional methods on an {@link NfcAdapter} for Card Emulation
+ * and management of {@link NfcExecutionEnvironment}'s.
+ *
+ * There is a 1-1 relationship between an {@link NfcAdapterExtras} object and
+ * a {@link NfcAdapter} object.
+ */
+public final class NfcAdapterExtras {
+    private static final String TAG = "NfcAdapterExtras";
+
+    /**
+     * Broadcast Action: an RF field ON has been detected.
+     *
+     * <p class="note">This is an unreliable signal, and will be removed.
+     * <p class="note">
+     * Requires the {@link android.Manifest.permission#WRITE_SECURE_SETTINGS} permission
+     * to receive.
+     */
+    public static final String ACTION_RF_FIELD_ON_DETECTED =
+            "com.android.nfc_extras.action.RF_FIELD_ON_DETECTED";
+
+    /**
+     * Broadcast Action: an RF field OFF has been detected.
+     *
+     * <p class="note">This is an unreliable signal, and will be removed.
+     * <p class="note">
+     * Requires the {@link android.Manifest.permission#WRITE_SECURE_SETTINGS} permission
+     * to receive.
+     */
+    public static final String ACTION_RF_FIELD_OFF_DETECTED =
+            "com.android.nfc_extras.action.RF_FIELD_OFF_DETECTED";
+
+    // protected by NfcAdapterExtras.class, and final after first construction
+    private static INfcAdapterExtras sService;
+    private static boolean sIsInitialized = false;
+    private static NfcAdapterExtras sSingleton;
+    private static NfcExecutionEnvironment sEmbeddedEe;
+    private static CardEmulationRoute sRouteOff;
+    private static CardEmulationRoute sRouteOnWhenScreenOn;
+
+    /**
+     * Get the {@link NfcAdapterExtras} for the given {@link NfcAdapter}.
+     *
+     * <p class="note">
+     * Requires the {@link android.Manifest.permission#WRITE_SECURE_SETTINGS} permission.
+     *
+     * @param adapter a {@link NfcAdapter}, must not be null
+     * @return the {@link NfcAdapterExtras} object for the given {@link NfcAdapter}
+     */
+    public static NfcAdapterExtras get(NfcAdapter adapter) {
+        synchronized(NfcAdapterExtras.class) {
+            if (!sIsInitialized) {
+               sIsInitialized = true;
+               sService = adapter.getNfcAdapterExtrasInterface();
+               sEmbeddedEe = new NfcExecutionEnvironment(sService);
+               sRouteOff = new CardEmulationRoute(CardEmulationRoute.ROUTE_OFF, null);
+               sRouteOnWhenScreenOn = new CardEmulationRoute(
+                       CardEmulationRoute.ROUTE_ON_WHEN_SCREEN_ON, sEmbeddedEe);
+               sSingleton = new NfcAdapterExtras();
+            }
+            return sSingleton;
+        }
+    }
+
+    private NfcAdapterExtras() {}
+
+    /**
+     * Immutable data class that describes a card emulation route.
+     */
+    public final static class CardEmulationRoute {
+        /**
+         * Card Emulation is turned off on this NfcAdapter.
+         * <p>This is the default routing state after boot.
+         */
+        public static final int ROUTE_OFF = 1;
+
+        /**
+         * Card Emulation is routed to {@link #nfcEe} only when the screen is on,
+         * otherwise it is turned off.
+         */
+        public static final int ROUTE_ON_WHEN_SCREEN_ON = 2;
+
+        /**
+         * A route such as {@link #ROUTE_OFF} or {@link #ROUTE_ON_WHEN_SCREEN_ON}.
+         */
+        public final int route;
+
+        /**
+         * The {@link NFcExecutionEnvironment} that is Card Emulation is routed to.
+         * <p>null if {@link #route} is {@link #ROUTE_OFF}, otherwise not null.
+         */
+        public final NfcExecutionEnvironment nfcEe;
+
+        public CardEmulationRoute(int route, NfcExecutionEnvironment nfcEe) {
+            if (route == ROUTE_OFF && nfcEe != null) {
+                throw new IllegalArgumentException("must not specifiy a NFC-EE with ROUTE_OFF");
+            } else if (route != ROUTE_OFF && nfcEe == null) {
+                throw new IllegalArgumentException("must specifiy a NFC-EE for this route");
+            }
+            this.route = route;
+            this.nfcEe = nfcEe;
+        }
+    }
+
+    /**
+     * Get the routing state of this NFC EE.
+     *
+     * <p class="note">
+     * Requires the {@link android.Manifest.permission#WRITE_SECURE_SETTINGS} permission.
+     *
+     * @return
+     */
+    public CardEmulationRoute getCardEmulationRoute() {
+        try {
+            int route = sService.getCardEmulationRoute();
+            return route == CardEmulationRoute.ROUTE_OFF ?
+                    sRouteOff :
+                    sRouteOnWhenScreenOn;
+        } catch (RemoteException e) {
+            Log.e(TAG, "", e);
+            return sRouteOff;
+        }
+    }
+
+    /**
+     * Set the routing state of this NFC EE.
+     *
+     * <p>This routing state is not persisted across reboot.
+     *
+     * <p class="note">
+     * Requires the {@link android.Manifest.permission#WRITE_SECURE_SETTINGS} permission.
+     *
+     * @param route a {@link #CardEmulationRoute}
+     */
+    public void setCardEmulationRoute(CardEmulationRoute route) {
+        try {
+            sService.setCardEmulationRoute(route.route);
+        } catch (RemoteException e) {
+            Log.e(TAG, "", e);
+        }
+    }
+
+    /**
+     * Get the {@link NfcExecutionEnvironment} that is embedded with the
+     * {@link NFcAdapter}.
+     *
+     * <p class="note">
+     * Requires the {@link android.Manifest.permission#WRITE_SECURE_SETTINGS} permission.
+     *
+     * @return a {@link NfcExecutionEnvironment}, or null if there is no embedded NFC-EE
+     */
+    public NfcExecutionEnvironment getEmbeddedExecutionEnvironment() {
+        return sEmbeddedEe;
+    }
+}
diff --git a/nfc-extras/java/com/android/nfc_extras/NfcExecutionEnvironment.java b/nfc-extras/java/com/android/nfc_extras/NfcExecutionEnvironment.java
new file mode 100644
index 0000000..3efe492
--- /dev/null
+++ b/nfc-extras/java/com/android/nfc_extras/NfcExecutionEnvironment.java
@@ -0,0 +1,125 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.nfc_extras;
+
+import java.io.IOException;
+
+import android.annotation.SdkConstant;
+import android.annotation.SdkConstant.SdkConstantType;
+import android.content.Context;
+import android.nfc.INfcAdapterExtras;
+import android.nfc.NfcAdapter;
+import android.os.Binder;
+import android.os.Bundle;
+import android.os.IBinder;
+import android.os.RemoteException;
+
+public class NfcExecutionEnvironment {
+    private final INfcAdapterExtras mService;
+
+    /**
+     * Broadcast Action: An ISO-DEP AID was selected.
+     *
+     * <p>This happens as the result of a 'SELECT AID' command from an
+     * external NFC reader/writer.
+     *
+     * <p>Always contains the extra field {@link #EXTRA_AID}
+     *
+     * <p class="note">
+     * Requires the {@link android.Manifest.permission#WRITE_SECURE_SETTINGS} permission
+     * to receive.
+     */
+    @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+    public static final String ACTION_AID_SELECTED =
+        "com.android.nfc_extras.action.AID_SELECTED";
+
+    /**
+     * Mandatory byte array extra field in {@link #ACTION_AID_SELECTED}.
+     *
+     * <p>Contains the AID selected.
+     * @hide
+     */
+    public static final String EXTRA_AID = "com.android.nfc_extras.extra.AID";
+
+    NfcExecutionEnvironment(INfcAdapterExtras service) {
+        mService = service;
+    }
+
+    /**
+     * Open the NFC Execution Environment on its contact interface.
+     *
+     * <p>Only one process may open the secure element at a time. If it is
+     * already open, an {@link IOException} is thrown.
+     *
+     * <p>All other NFC functionality is disabled while the NFC-EE is open
+     * on its contact interface, so make sure to call {@link #close} once complete.
+     *
+     * <p class="note">
+     * Requires the {@link android.Manifest.permission#WRITE_SECURE_SETTINGS} permission.
+     *
+     * @throws IOException if the NFC-EE is already open, or some other error occurs
+     */
+    public void open() throws IOException {
+        try {
+            Bundle b = mService.open(new Binder());
+            throwBundle(b);
+        } catch (RemoteException e) {
+            return;
+        }
+    }
+
+    /**
+     * Close the NFC Execution Environment on its contact interface.
+     *
+     * <p class="note">
+     * Requires the {@link android.Manifest.permission#WRITE_SECURE_SETTINGS} permission.
+     *
+     * @throws IOException if the NFC-EE is already open, or some other error occurs
+     */
+    public void close() throws IOException {
+        try {
+            throwBundle(mService.close());
+        } catch (RemoteException e) {
+            return;
+        }
+    }
+
+    /**
+     * Send raw commands to the NFC-EE and receive the response.
+     *
+     * <p class="note">
+     * Requires the {@link android.Manifest.permission#WRITE_SECURE_SETTINGS} permission.
+     *
+     * @throws IOException if the NFC-EE is not open, or some other error occurs
+     */
+    public byte[] transceive(byte[] in) throws IOException {
+        Bundle b;
+        try {
+            b = mService.transceive(in);
+        } catch (RemoteException e) {
+            throw new IOException(e.getMessage());
+        }
+        throwBundle(b);
+        return b.getByteArray("out");
+    }
+
+    private static void throwBundle(Bundle b) throws IOException {
+        if (b.getInt("e") == -1) {
+            throw new IOException(b.getString("m"));
+        }
+    }
+}
diff --git a/opengl/java/com/google/android/gles_jni/EGLContextImpl.java b/opengl/java/com/google/android/gles_jni/EGLContextImpl.java
index 9cf5de7..cd36099 100644
--- a/opengl/java/com/google/android/gles_jni/EGLContextImpl.java
+++ b/opengl/java/com/google/android/gles_jni/EGLContextImpl.java
@@ -32,4 +32,19 @@
     public GL getGL() {
         return mGLContext;
     }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) return true;
+        if (o == null || getClass() != o.getClass()) return false;
+
+        EGLContextImpl that = (EGLContextImpl) o;
+
+        return mEGLContext == that.mEGLContext;
+    }
+
+    @Override
+    public int hashCode() {
+        return mEGLContext;
+    }
 }
diff --git a/opengl/java/com/google/android/gles_jni/EGLDisplayImpl.java b/opengl/java/com/google/android/gles_jni/EGLDisplayImpl.java
index cb94888..e6c9817 100644
--- a/opengl/java/com/google/android/gles_jni/EGLDisplayImpl.java
+++ b/opengl/java/com/google/android/gles_jni/EGLDisplayImpl.java
@@ -24,4 +24,20 @@
     public EGLDisplayImpl(int dpy) {
         mEGLDisplay = dpy;
     }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) return true;
+        if (o == null || getClass() != o.getClass()) return false;
+
+        EGLDisplayImpl that = (EGLDisplayImpl) o;
+
+        return mEGLDisplay == that.mEGLDisplay;
+
+    }
+
+    @Override
+    public int hashCode() {
+        return mEGLDisplay;
+    }
 }
diff --git a/opengl/java/com/google/android/gles_jni/EGLSurfaceImpl.java b/opengl/java/com/google/android/gles_jni/EGLSurfaceImpl.java
index f6b90ab..e7f15dc 100644
--- a/opengl/java/com/google/android/gles_jni/EGLSurfaceImpl.java
+++ b/opengl/java/com/google/android/gles_jni/EGLSurfaceImpl.java
@@ -29,4 +29,20 @@
         mEGLSurface = surface;
         mNativePixelRef = 0;
     }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) return true;
+        if (o == null || getClass() != o.getClass()) return false;
+
+        EGLSurfaceImpl that = (EGLSurfaceImpl) o;
+
+        return mEGLSurface == that.mEGLSurface;
+
+    }
+
+    @Override
+    public int hashCode() {
+        return mEGLSurface;
+    }
 }
diff --git a/opengl/libagl2/Android.mk b/opengl/libagl2/Android.mk
new file mode 100644
index 0000000..564932f
--- /dev/null
+++ b/opengl/libagl2/Android.mk
@@ -0,0 +1,58 @@
+LOCAL_PATH:= $(call my-dir)
+
+#
+# Build the software OpenGL ES library
+#
+
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES:= \
+	src/api.cpp \
+	src/egl.cpp \
+    src/get.cpp \
+	src/shader.cpp \
+	src/state.cpp \
+	src/texture.cpp \
+	src/vertex.cpp
+
+LOCAL_C_INCLUDES :=	\
+    $(LOCAL_PATH) \
+    external/mesa3d/include \
+    external/mesa3d/src \
+    external/stlport/stlport \
+    bionic
+    
+#LOCAL_CFLAGS += -DLOG_TAG=\"libagl2\"
+#LOCAL_CFLAGS += -DGL_GLEXT_PROTOTYPES -DEGL_EGLEXT_PROTOTYPES
+#LOCAL_CFLAGS += -fvisibility=hidden
+#LOCAL_CFLAGS += -O0 -g -DDEBUG -UNDEBUG
+LOCAL_CFLAGS += -O3
+LOCAL_STATIC_LIBRARIES := libMesa
+LOCAL_SHARED_LIBRARIES := libstlport libcutils libhardware libutils libbcc libdl
+LOCAL_LDLIBS := -lpthread
+
+ifeq ($(TARGET_ARCH),arm)
+	LOCAL_CFLAGS += -fstrict-aliasing
+endif
+
+ifeq ($(ARCH_ARM_HAVE_TLS_REGISTER),true)
+    LOCAL_CFLAGS += -DHAVE_ARM_TLS_REGISTER
+endif
+
+ifneq ($(TARGET_SIMULATOR),true)
+    # we need to access the private Bionic header <bionic_tls.h>
+    # on ARM platforms, we need to mirror the ARCH_ARM_HAVE_TLS_REGISTER
+    # behavior from the bionic Android.mk file
+    ifeq ($(TARGET_ARCH)-$(ARCH_ARM_HAVE_TLS_REGISTER),arm-true)
+        LOCAL_CFLAGS += -DHAVE_ARM_TLS_REGISTER
+    endif
+    LOCAL_C_INCLUDES += bionic/libc/private
+endif
+
+LOCAL_MODULE_PATH := $(TARGET_OUT_SHARED_LIBRARIES)/egl
+#replace libagl for now
+LOCAL_MODULE:= libGLES_android
+LOCAL_MODULE_TAGS := eng
+
+## Disable this makefile for now
+## include $(BUILD_SHARED_LIBRARY)
diff --git a/opengl/libagl2/README b/opengl/libagl2/README
new file mode 100644
index 0000000..34746d3
--- /dev/null
+++ b/opengl/libagl2/README
@@ -0,0 +1,26 @@
+libAgl2 provides software GL ES 2.0 implementation using Pixelflinger2 in external/mesa3d
+
+To build, enable Android.mk, which builds libGLES_android.so, then replace the one built from libAgl in system/lib/egl.
+ES 1.0 functions are not implemented and will cause exit, so do not setprop debug.egl.hw 0 until launcher is loaded.
+
+All functions have little to none error checking.
+Not thread safe, Pixelflinger2 uses some static data.
+
+Most shader functions are implemented, however, most Get* functions for shaders/programs/uniforms/attribs are not.
+No name system for shaders/programs, just using the pointers as names.
+
+Basic glTexImage2D, glTexSubImage2D, glCopyImage2D and glCopySubImage2D are implemented, with a range of 8/16/24/32bpp formats.
+Cube map support is minimal. No mipmapping.
+TexParameter is mostly implemented, supports texcoord wrap modes, and only linear for both min and mag, or nearest for both min and mag filtering.
+Texture names are implemented, but bad.
+
+Frame buffer and render buffers are not implemented.
+
+Depth and stencil are implemented, but not tested.
+Blending seems to work.
+Colorbuffer supports RGBA_8888 and RGB_565.
+
+Vertex buffer objects are implemented.
+Some GL_TRIANGLES and GL_TRIANGLE_STRIPS modes for glDrawArrays and glDrawElements are implemented, but vertex order is probably wrong so culling is disabled.
+
+Basic apps should work, and some libhwui should work, except for frame buffer operations, which will cause exit.
diff --git a/opengl/libagl2/libagl2.project b/opengl/libagl2/libagl2.project
new file mode 100644
index 0000000..f234421
--- /dev/null
+++ b/opengl/libagl2/libagl2.project
@@ -0,0 +1,108 @@
+<?xml version="1.0" encoding="utf-8"?>
+<CodeLite_Project Name="libagl2" InternalType="Console">
+  <Plugins>
+    <Plugin Name="qmake">
+      <![CDATA[00010001N0005Debug000000000000]]>
+    </Plugin>
+  </Plugins>
+  <Description/>
+  <Dependencies/>
+  <Dependencies Name="Release"/>
+  <VirtualDirectory Name="src">
+    <File Name="src/egl.cpp"/>
+    <File Name="src/api.cpp"/>
+    <File Name="src/gles2context.h"/>
+    <File Name="src/shader.cpp"/>
+    <File Name="src/vertex.cpp"/>
+    <File Name="src/state.cpp"/>
+    <File Name="src/texture.cpp"/>
+    <File Name="src/get.cpp"/>
+  </VirtualDirectory>
+  <VirtualDirectory Name="include"/>
+  <Settings Type="Executable">
+    <Configuration Name="Debug" CompilerType="gnu gcc" DebuggerType="GNU gdb debugger" Type="Executable" BuildCmpWithGlobalSettings="append" BuildLnkWithGlobalSettings="append" BuildResWithGlobalSettings="append">
+      <Compiler Options="-g;-m32" Required="yes" PreCompiledHeader="">
+        <IncludePath Value="/usr/include/c++/4.4"/>
+        <IncludePath Value="/usr/include/c++/4.4/ext"/>
+        <IncludePath Value="."/>
+        <IncludePath Value="include"/>
+        <IncludePath Value="../../../../external/mesa3d/include"/>
+        <IncludePath Value="../../../../external/mesa3d/src"/>
+        <IncludePath Value="../../../../hardware/libhardware/include"/>
+        <IncludePath Value="../../../../system/core/include"/>
+        <IncludePath Value="../include"/>
+        <IncludePath Value="../../include"/>
+        <IncludePath Value="../../../../development/ndk/platforms/android-9/include"/>
+        <IncludePath Value="../../../../bionic/libc/include/"/>
+        <IncludePath Value="/../../../../development/ndk/platforms/android-5/arch-x86/include"/>
+        <IncludePath Value="../../../../bionic/libc/arch-x86/include"/>
+        <IncludePath Value="../../../../bionic/libc/kernel/arch-x86"/>
+        <IncludePath Value="/../../../../external/kernel-headers/original"/>
+        <IncludePath Value="../../../../prebuilt/ndk/android-ndk-r4/platforms/android-8/arch-x86/usr/include"/>
+      </Compiler>
+      <Linker Options="-m32;-lstdc++" Required="yes"/>
+      <ResourceCompiler Options="" Required="no"/>
+      <General OutputFile="$(IntermediateDirectory)/$(ProjectName)" IntermediateDirectory="./Debug" Command="./$(ProjectName)" CommandArguments="" WorkingDirectory="$(IntermediateDirectory)" PauseExecWhenProcTerminates="yes"/>
+      <Debugger IsRemote="no" RemoteHostName="" RemoteHostPort="" DebuggerPath="">
+        <PostConnectCommands/>
+        <StartupCommands/>
+      </Debugger>
+      <PreBuild/>
+      <PostBuild/>
+      <CustomBuild Enabled="no">
+        <RebuildCommand/>
+        <CleanCommand/>
+        <BuildCommand/>
+        <PreprocessFileCommand/>
+        <SingleFileCommand/>
+        <MakefileGenerationCommand/>
+        <ThirdPartyToolName>None</ThirdPartyToolName>
+        <WorkingDirectory/>
+      </CustomBuild>
+      <AdditionalRules>
+        <CustomPostBuild/>
+        <CustomPreBuild/>
+      </AdditionalRules>
+    </Configuration>
+    <Configuration Name="Release" CompilerType="gnu gcc" DebuggerType="GNU gdb debugger" Type="" BuildCmpWithGlobalSettings="append" BuildLnkWithGlobalSettings="append" BuildResWithGlobalSettings="append">
+      <Compiler Options="" Required="yes" PreCompiledHeader="">
+        <IncludePath Value="."/>
+      </Compiler>
+      <Linker Options="-O2" Required="yes"/>
+      <ResourceCompiler Options="" Required="no"/>
+      <General OutputFile="$(IntermediateDirectory)/$(ProjectName)" IntermediateDirectory="./Release" Command="./$(ProjectName)" CommandArguments="" WorkingDirectory="$(IntermediateDirectory)" PauseExecWhenProcTerminates="yes"/>
+      <Debugger IsRemote="no" RemoteHostName="" RemoteHostPort="" DebuggerPath="">
+        <PostConnectCommands/>
+        <StartupCommands/>
+      </Debugger>
+      <PreBuild/>
+      <PostBuild/>
+      <CustomBuild Enabled="no">
+        <RebuildCommand/>
+        <CleanCommand/>
+        <BuildCommand/>
+        <PreprocessFileCommand/>
+        <SingleFileCommand/>
+        <MakefileGenerationCommand/>
+        <ThirdPartyToolName>None</ThirdPartyToolName>
+        <WorkingDirectory/>
+      </CustomBuild>
+      <AdditionalRules>
+        <CustomPostBuild/>
+        <CustomPreBuild/>
+      </AdditionalRules>
+    </Configuration>
+    <GlobalSettings>
+      <Compiler Options="">
+        <IncludePath Value="."/>
+      </Compiler>
+      <Linker Options="">
+        <LibraryPath Value="."/>
+      </Linker>
+      <ResourceCompiler Options=""/>
+    </GlobalSettings>
+  </Settings>
+  <Dependencies Name="Debug">
+    <Project Name="libMesa"/>
+  </Dependencies>
+</CodeLite_Project>
diff --git a/opengl/libagl2/src/api.cpp b/opengl/libagl2/src/api.cpp
new file mode 100644
index 0000000..bb8d62b
--- /dev/null
+++ b/opengl/libagl2/src/api.cpp
@@ -0,0 +1,266 @@
+#include "gles2context.h"
+
+#define API_ENTRY
+#define CALL_GL_API(NAME,...) LOGD("?"#NAME); assert(0);
+#define CALL_GL_API_RETURN(NAME,...) LOGD("?"#NAME); assert(0); return 0;
+
+
+void API_ENTRY(glBindFramebuffer)(GLenum target, GLuint framebuffer)
+{
+   CALL_GL_API(glBindFramebuffer, target, framebuffer);
+}
+void API_ENTRY(glBindRenderbuffer)(GLenum target, GLuint renderbuffer)
+{
+   CALL_GL_API(glBindRenderbuffer, target, renderbuffer);
+}
+GLenum API_ENTRY(glCheckFramebufferStatus)(GLenum target)
+{
+   CALL_GL_API_RETURN(glCheckFramebufferStatus, target);
+}
+void API_ENTRY(glColorMask)(GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha)
+{
+   CALL_GL_API(glColorMask, red, green, blue, alpha);
+}
+void API_ENTRY(glDeleteFramebuffers)(GLsizei n, const GLuint* framebuffers)
+{
+   CALL_GL_API(glDeleteFramebuffers, n, framebuffers);
+}
+void API_ENTRY(glDeleteRenderbuffers)(GLsizei n, const GLuint* renderbuffers)
+{
+   CALL_GL_API(glDeleteRenderbuffers, n, renderbuffers);
+}
+void API_ENTRY(glDepthFunc)(GLenum func)
+{
+   CALL_GL_API(glDepthFunc, func);
+}
+void API_ENTRY(glDepthMask)(GLboolean flag)
+{
+   CALL_GL_API(glDepthMask, flag);
+}
+void API_ENTRY(glDepthRangef)(GLclampf zNear, GLclampf zFar)
+{
+   CALL_GL_API(glDepthRangef, zNear, zFar);
+}
+void API_ENTRY(glFramebufferRenderbuffer)(GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer)
+{
+   CALL_GL_API(glFramebufferRenderbuffer, target, attachment, renderbuffertarget, renderbuffer);
+}
+void API_ENTRY(glFramebufferTexture2D)(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level)
+{
+   CALL_GL_API(glFramebufferTexture2D, target, attachment, textarget, texture, level);
+}
+void glGenerateMipmap(GLenum target)
+{
+   //CALL_GL_API(glGenerateMipmap, target);
+   LOGD("agl2: glGenerateMipmap not implemented");
+}
+void API_ENTRY(glGenFramebuffers)(GLsizei n, GLuint* framebuffers)
+{
+   CALL_GL_API(glGenFramebuffers, n, framebuffers);
+}
+void API_ENTRY(glGenRenderbuffers)(GLsizei n, GLuint* renderbuffers)
+{
+   CALL_GL_API(glGenRenderbuffers, n, renderbuffers);
+}
+void API_ENTRY(glGetActiveAttrib)(GLuint program, GLuint index, GLsizei bufsize, GLsizei* length, GLint* size, GLenum* type, GLchar* name)
+{
+   CALL_GL_API(glGetActiveAttrib, program, index, bufsize, length, size, type, name);
+}
+void API_ENTRY(glGetActiveUniform)(GLuint program, GLuint index, GLsizei bufsize, GLsizei* length, GLint* size, GLenum* type, GLchar* name)
+{
+   CALL_GL_API(glGetActiveUniform, program, index, bufsize, length, size, type, name);
+}
+void API_ENTRY(glGetAttachedShaders)(GLuint program, GLsizei maxcount, GLsizei* count, GLuint* shaders)
+{
+   CALL_GL_API(glGetAttachedShaders, program, maxcount, count, shaders);
+}
+void API_ENTRY(glGetBooleanv)(GLenum pname, GLboolean* params)
+{
+   CALL_GL_API(glGetBooleanv, pname, params);
+}
+void API_ENTRY(glGetBufferParameteriv)(GLenum target, GLenum pname, GLint* params)
+{
+   CALL_GL_API(glGetBufferParameteriv, target, pname, params);
+}
+GLenum glGetError(void)
+{
+   puts("agl2: glGetError");
+   return GL_NO_ERROR;
+   //CALL_GL_API_RETURN(glGetError);
+}
+void API_ENTRY(glGetFloatv)(GLenum pname, GLfloat* params)
+{
+   CALL_GL_API(glGetFloatv, pname, params);
+}
+void API_ENTRY(glGetFramebufferAttachmentParameteriv)(GLenum target, GLenum attachment, GLenum pname, GLint* params)
+{
+   CALL_GL_API(glGetFramebufferAttachmentParameteriv, target, attachment, pname, params);
+}
+void API_ENTRY(glGetRenderbufferParameteriv)(GLenum target, GLenum pname, GLint* params)
+{
+   CALL_GL_API(glGetRenderbufferParameteriv, target, pname, params);
+}
+void API_ENTRY(glGetShaderPrecisionFormat)(GLenum shadertype, GLenum precisiontype, GLint* range, GLint* precision)
+{
+   CALL_GL_API(glGetShaderPrecisionFormat, shadertype, precisiontype, range, precision);
+}
+void API_ENTRY(glGetShaderSource)(GLuint shader, GLsizei bufsize, GLsizei* length, GLchar* source)
+{
+   CALL_GL_API(glGetShaderSource, shader, bufsize, length, source);
+}
+void API_ENTRY(glGetUniformfv)(GLuint program, GLint location, GLfloat* params)
+{
+   CALL_GL_API(glGetUniformfv, program, location, params);
+}
+void API_ENTRY(glGetUniformiv)(GLuint program, GLint location, GLint* params)
+{
+   CALL_GL_API(glGetUniformiv, program, location, params);
+}
+void API_ENTRY(glGetVertexAttribfv)(GLuint index, GLenum pname, GLfloat* params)
+{
+   CALL_GL_API(glGetVertexAttribfv, index, pname, params);
+}
+void API_ENTRY(glGetVertexAttribiv)(GLuint index, GLenum pname, GLint* params)
+{
+   CALL_GL_API(glGetVertexAttribiv, index, pname, params);
+}
+void API_ENTRY(glGetVertexAttribPointerv)(GLuint index, GLenum pname, GLvoid** pointer)
+{
+   CALL_GL_API(glGetVertexAttribPointerv, index, pname, pointer);
+}
+GLboolean API_ENTRY(glIsBuffer)(GLuint buffer)
+{
+   CALL_GL_API_RETURN(glIsBuffer, buffer);
+}
+GLboolean API_ENTRY(glIsEnabled)(GLenum cap)
+{
+   CALL_GL_API_RETURN(glIsEnabled, cap);
+}
+GLboolean API_ENTRY(glIsFramebuffer)(GLuint framebuffer)
+{
+   CALL_GL_API_RETURN(glIsFramebuffer, framebuffer);
+}
+GLboolean API_ENTRY(glIsProgram)(GLuint program)
+{
+   CALL_GL_API_RETURN(glIsProgram, program);
+}
+GLboolean API_ENTRY(glIsRenderbuffer)(GLuint renderbuffer)
+{
+   CALL_GL_API_RETURN(glIsRenderbuffer, renderbuffer);
+}
+GLboolean API_ENTRY(glIsShader)(GLuint shader)
+{
+   CALL_GL_API_RETURN(glIsShader, shader);
+}
+void API_ENTRY(glLineWidth)(GLfloat width)
+{
+   CALL_GL_API(glLineWidth, width);
+}
+void API_ENTRY(glPolygonOffset)(GLfloat factor, GLfloat units)
+{
+   CALL_GL_API(glPolygonOffset, factor, units);
+}
+void API_ENTRY(glReadPixels)(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLvoid* pixels)
+{
+   CALL_GL_API(glReadPixels, x, y, width, height, format, type, pixels);
+}
+void API_ENTRY(glReleaseShaderCompiler)(void)
+{
+   CALL_GL_API(glReleaseShaderCompiler);
+}
+void API_ENTRY(glRenderbufferStorage)(GLenum target, GLenum internalformat, GLsizei width, GLsizei height)
+{
+   CALL_GL_API(glRenderbufferStorage, target, internalformat, width, height);
+}
+void API_ENTRY(glSampleCoverage)(GLclampf value, GLboolean invert)
+{
+   CALL_GL_API(glSampleCoverage, value, invert);
+}
+void API_ENTRY(glShaderBinary)(GLsizei n, const GLuint* shaders, GLenum binaryformat, const GLvoid* binary, GLsizei length)
+{
+   CALL_GL_API(glShaderBinary, n, shaders, binaryformat, binary, length);
+}
+void API_ENTRY(glStencilFunc)(GLenum func, GLint ref, GLuint mask)
+{
+   CALL_GL_API(glStencilFunc, func, ref, mask);
+}
+void API_ENTRY(glStencilFuncSeparate)(GLenum face, GLenum func, GLint ref, GLuint mask)
+{
+   CALL_GL_API(glStencilFuncSeparate, face, func, ref, mask);
+}
+void API_ENTRY(glStencilMask)(GLuint mask)
+{
+   CALL_GL_API(glStencilMask, mask);
+}
+void API_ENTRY(glStencilMaskSeparate)(GLenum face, GLuint mask)
+{
+   CALL_GL_API(glStencilMaskSeparate, face, mask);
+}
+void API_ENTRY(glStencilOp)(GLenum fail, GLenum zfail, GLenum zpass)
+{
+   CALL_GL_API(glStencilOp, fail, zfail, zpass);
+}
+void API_ENTRY(glStencilOpSeparate)(GLenum face, GLenum fail, GLenum zfail, GLenum zpass)
+{
+   CALL_GL_API(glStencilOpSeparate, face, fail, zfail, zpass);
+}
+void API_ENTRY(glUniform1fv)(GLint location, GLsizei count, const GLfloat* v)
+{
+   CALL_GL_API(glUniform1fv, location, count, v);
+}
+void API_ENTRY(glUniform1iv)(GLint location, GLsizei count, const GLint* v)
+{
+   CALL_GL_API(glUniform1iv, location, count, v);
+}
+void API_ENTRY(glUniform2fv)(GLint location, GLsizei count, const GLfloat* v)
+{
+   CALL_GL_API(glUniform2fv, location, count, v);
+}
+void API_ENTRY(glUniform2i)(GLint location, GLint x, GLint y)
+{
+   CALL_GL_API(glUniform2i, location, x, y);
+}
+void API_ENTRY(glUniform2iv)(GLint location, GLsizei count, const GLint* v)
+{
+   CALL_GL_API(glUniform2iv, location, count, v);
+}
+void API_ENTRY(glUniform3f)(GLint location, GLfloat x, GLfloat y, GLfloat z)
+{
+   CALL_GL_API(glUniform3f, location, x, y, z);
+}
+void API_ENTRY(glUniform3fv)(GLint location, GLsizei count, const GLfloat* v)
+{
+   CALL_GL_API(glUniform3fv, location, count, v);
+}
+void API_ENTRY(glUniform3i)(GLint location, GLint x, GLint y, GLint z)
+{
+   CALL_GL_API(glUniform3i, location, x, y, z);
+}
+void API_ENTRY(glUniform3iv)(GLint location, GLsizei count, const GLint* v)
+{
+   CALL_GL_API(glUniform3iv, location, count, v);
+}
+void API_ENTRY(glUniform4fv)(GLint location, GLsizei count, const GLfloat* v)
+{
+   CALL_GL_API(glUniform4fv, location, count, v);
+}
+void API_ENTRY(glUniform4i)(GLint location, GLint x, GLint y, GLint z, GLint w)
+{
+   CALL_GL_API(glUniform4i, location, x, y, z, w);
+}
+void API_ENTRY(glUniform4iv)(GLint location, GLsizei count, const GLint* v)
+{
+   CALL_GL_API(glUniform4iv, location, count, v);
+}
+void API_ENTRY(glUniformMatrix2fv)(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value)
+{
+   CALL_GL_API(glUniformMatrix2fv, location, count, transpose, value);
+}
+void API_ENTRY(glUniformMatrix3fv)(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value)
+{
+   CALL_GL_API(glUniformMatrix3fv, location, count, transpose, value);
+}
+void API_ENTRY(glValidateProgram)(GLuint program)
+{
+   CALL_GL_API(glValidateProgram, program);
+}
diff --git a/opengl/libagl2/src/egl.cpp b/opengl/libagl2/src/egl.cpp
new file mode 100644
index 0000000..6184644
--- /dev/null
+++ b/opengl/libagl2/src/egl.cpp
@@ -0,0 +1,2232 @@
+/*
+**
+** Copyright 2007 The Android Open Source Project
+**
+** Licensed under the Apache License Version 2.0(the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing software
+** distributed under the License is distributed on an "AS IS" BASIS
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+
+#include <errno.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/ioctl.h>
+#include <sys/types.h>
+#include <sys/mman.h>
+
+#include <cutils/atomic.h>
+
+
+#include <private/ui/android_natives_priv.h>
+
+#include <hardware/copybit.h>
+
+#include "gles2context.h"
+
+// ----------------------------------------------------------------------------
+namespace android
+{
+// ----------------------------------------------------------------------------
+
+const unsigned int NUM_DISPLAYS = 1;
+
+static pthread_mutex_t gInitMutex = PTHREAD_MUTEX_INITIALIZER;
+static pthread_mutex_t gErrorKeyMutex = PTHREAD_MUTEX_INITIALIZER;
+static pthread_key_t gEGLErrorKey = -1;
+#ifndef HAVE_ANDROID_OS
+namespace gl {
+pthread_key_t gGLKey = -1;
+}; // namespace gl
+#endif
+
+template<typename T>
+static T setError(GLint error, T returnValue)
+{
+   if (ggl_unlikely(gEGLErrorKey == -1)) {
+      pthread_mutex_lock(&gErrorKeyMutex);
+      if (gEGLErrorKey == -1)
+         pthread_key_create(&gEGLErrorKey, NULL);
+      pthread_mutex_unlock(&gErrorKeyMutex);
+   }
+   pthread_setspecific(gEGLErrorKey, (void*)error);
+   return returnValue;
+}
+
+static GLint getError()
+{
+   if (ggl_unlikely(gEGLErrorKey == -1))
+      return EGL_SUCCESS;
+   GLint error = (GLint)pthread_getspecific(gEGLErrorKey);
+   if (error == 0) {
+      // The TLS key has been created by another thread, but the value for
+      // this thread has not been initialized.
+      return EGL_SUCCESS;
+   }
+   pthread_setspecific(gEGLErrorKey, (void*)EGL_SUCCESS);
+   return error;
+}
+
+// ----------------------------------------------------------------------------
+
+struct egl_display_t {
+   egl_display_t() : type(0), initialized(0) { }
+
+   static egl_display_t& get_display(EGLDisplay dpy);
+
+   static EGLBoolean is_valid(EGLDisplay dpy) {
+      return ((uintptr_t(dpy)-1U) >= NUM_DISPLAYS) ? EGL_FALSE : EGL_TRUE;
+   }
+
+   NativeDisplayType   type;
+   volatile int32_t    initialized;
+};
+
+static egl_display_t gDisplays[NUM_DISPLAYS];
+
+egl_display_t& egl_display_t::get_display(EGLDisplay dpy)
+{
+   return gDisplays[uintptr_t(dpy)-1U];
+}
+
+// ----------------------------------------------------------------------------
+
+struct egl_surface_t {
+   enum {
+      PAGE_FLIP = 0x00000001,
+      MAGIC     = 0x31415265
+   };
+
+   uint32_t            magic;
+   EGLDisplay          dpy;
+   EGLConfig           config;
+   EGLContext          ctx;
+
+   egl_surface_t(EGLDisplay dpy, EGLConfig config, int32_t depthFormat);
+   virtual     ~egl_surface_t();
+   bool    isValid() const;
+   virtual     bool    initCheck() const = 0;
+
+   virtual     EGLBoolean  bindDrawSurface(GLES2Context* gl) = 0;
+   virtual     EGLBoolean  bindReadSurface(GLES2Context* gl) = 0;
+   virtual     EGLBoolean  connect() {
+      return EGL_TRUE;
+   }
+   virtual     void        disconnect() {}
+   virtual     EGLint      getWidth() const = 0;
+   virtual     EGLint      getHeight() const = 0;
+
+   virtual     EGLint      getHorizontalResolution() const;
+   virtual     EGLint      getVerticalResolution() const;
+   virtual     EGLint      getRefreshRate() const;
+   virtual     EGLint      getSwapBehavior() const;
+   virtual     EGLBoolean  swapBuffers();
+   virtual     EGLBoolean  setSwapRectangle(EGLint l, EGLint t, EGLint w, EGLint h);
+protected:
+   GGLSurface              depth;
+};
+
+egl_surface_t::egl_surface_t(EGLDisplay dpy,
+                             EGLConfig config,
+                             int32_t depthFormat)
+      : magic(MAGIC), dpy(dpy), config(config), ctx(0)
+{
+   depth.version = sizeof(GGLSurface);
+   depth.data = 0;
+   depth.format = (GGLPixelFormat)depthFormat;
+}
+egl_surface_t::~egl_surface_t()
+{
+   magic = 0;
+   free(depth.data);
+}
+bool egl_surface_t::isValid() const
+{
+   LOGE_IF(magic != MAGIC, "invalid EGLSurface (%p)", this);
+   return magic == MAGIC;
+}
+
+EGLBoolean egl_surface_t::swapBuffers()
+{
+   return EGL_FALSE;
+}
+EGLint egl_surface_t::getHorizontalResolution() const
+{
+   return (0 * EGL_DISPLAY_SCALING) * (1.0f / 25.4f);
+}
+EGLint egl_surface_t::getVerticalResolution() const
+{
+   return (0 * EGL_DISPLAY_SCALING) * (1.0f / 25.4f);
+}
+EGLint egl_surface_t::getRefreshRate() const
+{
+   return (60 * EGL_DISPLAY_SCALING);
+}
+EGLint egl_surface_t::getSwapBehavior() const
+{
+   return EGL_BUFFER_PRESERVED;
+}
+EGLBoolean egl_surface_t::setSwapRectangle(
+   EGLint l, EGLint t, EGLint w, EGLint h)
+{
+   return EGL_FALSE;
+}
+
+// ----------------------------------------------------------------------------
+
+struct egl_window_surface_v2_t : public egl_surface_t {
+   egl_window_surface_v2_t(
+      EGLDisplay dpy, EGLConfig config,
+      int32_t depthFormat,
+      ANativeWindow* window);
+
+   ~egl_window_surface_v2_t();
+
+   virtual     bool        initCheck() const {
+      return true;   // TODO: report failure if ctor fails
+   }
+   virtual     EGLBoolean  swapBuffers();
+   virtual     EGLBoolean  bindDrawSurface(GLES2Context* gl);
+   virtual     EGLBoolean  bindReadSurface(GLES2Context* gl);
+   virtual     EGLBoolean  connect();
+   virtual     void        disconnect();
+   virtual     EGLint      getWidth() const    {
+      return width;
+   }
+   virtual     EGLint      getHeight() const   {
+      return height;
+   }
+   virtual     EGLint      getHorizontalResolution() const;
+   virtual     EGLint      getVerticalResolution() const;
+   virtual     EGLint      getRefreshRate() const;
+   virtual     EGLint      getSwapBehavior() const;
+   virtual     EGLBoolean  setSwapRectangle(EGLint l, EGLint t, EGLint w, EGLint h);
+
+private:
+   status_t lock(android_native_buffer_t* buf, int usage, void** vaddr);
+   status_t unlock(android_native_buffer_t* buf);
+   ANativeWindow*   nativeWindow;
+   android_native_buffer_t*   buffer;
+   android_native_buffer_t*   previousBuffer;
+   gralloc_module_t const*    module;
+   copybit_device_t*          blitengine;
+   int width;
+   int height;
+   void* bits;
+   GGLFormat const* pixelFormatTable;
+
+   struct Rect {
+      inline Rect() { };
+      inline Rect(int32_t w, int32_t h)
+            : left(0), top(0), right(w), bottom(h) { }
+      inline Rect(int32_t l, int32_t t, int32_t r, int32_t b)
+            : left(l), top(t), right(r), bottom(b) { }
+      Rect& andSelf(const Rect& r) {
+         left   = max(left, r.left);
+         top    = max(top, r.top);
+         right  = min(right, r.right);
+         bottom = min(bottom, r.bottom);
+         return *this;
+      }
+      bool isEmpty() const {
+         return (left>=right || top>=bottom);
+      }
+      void dump(char const* what) {
+         LOGD("%s { %5d, %5d, w=%5d, h=%5d }",
+              what, left, top, right-left, bottom-top);
+      }
+
+      int32_t left;
+      int32_t top;
+      int32_t right;
+      int32_t bottom;
+   };
+
+   struct Region {
+      inline Region() : count(0) { }
+      typedef Rect const* const_iterator;
+      const_iterator begin() const {
+         return storage;
+      }
+      const_iterator end() const {
+         return storage+count;
+      }
+      static Region subtract(const Rect& lhs, const Rect& rhs) {
+         Region reg;
+         Rect* storage = reg.storage;
+         if (!lhs.isEmpty()) {
+            if (lhs.top < rhs.top) { // top rect
+               storage->left   = lhs.left;
+               storage->top    = lhs.top;
+               storage->right  = lhs.right;
+               storage->bottom = rhs.top;
+               storage++;
+            }
+            const int32_t top = max(lhs.top, rhs.top);
+            const int32_t bot = min(lhs.bottom, rhs.bottom);
+            if (top < bot) {
+               if (lhs.left < rhs.left) { // left-side rect
+                  storage->left   = lhs.left;
+                  storage->top    = top;
+                  storage->right  = rhs.left;
+                  storage->bottom = bot;
+                  storage++;
+               }
+               if (lhs.right > rhs.right) { // right-side rect
+                  storage->left   = rhs.right;
+                  storage->top    = top;
+                  storage->right  = lhs.right;
+                  storage->bottom = bot;
+                  storage++;
+               }
+            }
+            if (lhs.bottom > rhs.bottom) { // bottom rect
+               storage->left   = lhs.left;
+               storage->top    = rhs.bottom;
+               storage->right  = lhs.right;
+               storage->bottom = lhs.bottom;
+               storage++;
+            }
+            reg.count = storage - reg.storage;
+         }
+         return reg;
+      }
+      bool isEmpty() const {
+         return count<=0;
+      }
+private:
+      Rect storage[4];
+      ssize_t count;
+   };
+
+   struct region_iterator : public copybit_region_t {
+      region_iterator(const Region& region)
+            : b(region.begin()), e(region.end()) {
+         this->next = iterate;
+      }
+private:
+      static int iterate(copybit_region_t const * self, copybit_rect_t* rect) {
+         region_iterator const* me = static_cast<region_iterator const*>(self);
+         if (me->b != me->e) {
+            *reinterpret_cast<Rect*>(rect) = *me->b++;
+            return 1;
+         }
+         return 0;
+      }
+      mutable Region::const_iterator b;
+      Region::const_iterator const e;
+   };
+
+   void copyBlt(
+      android_native_buffer_t* dst, void* dst_vaddr,
+      android_native_buffer_t* src, void const* src_vaddr,
+      const Region& clip);
+
+   Rect dirtyRegion;
+   Rect oldDirtyRegion;
+};
+
+egl_window_surface_v2_t::egl_window_surface_v2_t(EGLDisplay dpy,
+      EGLConfig config,
+      int32_t depthFormat,
+      ANativeWindow* window)
+      : egl_surface_t(dpy, config, depthFormat),
+      nativeWindow(window), buffer(0), previousBuffer(0), module(0),
+      blitengine(0), bits(NULL)
+{
+   hw_module_t const* pModule;
+   hw_get_module(GRALLOC_HARDWARE_MODULE_ID, &pModule);
+   module = reinterpret_cast<gralloc_module_t const*>(pModule);
+
+   if (hw_get_module(COPYBIT_HARDWARE_MODULE_ID, &pModule) == 0) {
+      copybit_open(pModule, &blitengine);
+   }
+
+   pixelFormatTable = gglGetPixelFormatTable();
+
+   // keep a reference on the window
+   nativeWindow->common.incRef(&nativeWindow->common);
+   nativeWindow->query(nativeWindow, NATIVE_WINDOW_WIDTH, &width);
+   nativeWindow->query(nativeWindow, NATIVE_WINDOW_HEIGHT, &height);
+   int format = 0;
+   nativeWindow->query(nativeWindow, NATIVE_WINDOW_FORMAT, &format);
+   LOGD("agl2: egl_window_surface_v2_t format=0x%.4X", format);
+//   assert(0);
+}
+
+egl_window_surface_v2_t::~egl_window_surface_v2_t()
+{
+   if (buffer) {
+      buffer->common.decRef(&buffer->common);
+   }
+   if (previousBuffer) {
+      previousBuffer->common.decRef(&previousBuffer->common);
+   }
+   nativeWindow->common.decRef(&nativeWindow->common);
+   if (blitengine) {
+      copybit_close(blitengine);
+   }
+}
+
+EGLBoolean egl_window_surface_v2_t::connect()
+{
+   // we're intending to do software rendering
+   native_window_set_usage(nativeWindow,
+                           GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN);
+
+   // dequeue a buffer
+   if (nativeWindow->dequeueBuffer(nativeWindow, &buffer) != NO_ERROR) {
+      return setError(EGL_BAD_ALLOC, EGL_FALSE);
+   }
+
+   // allocate a corresponding depth-buffer
+   width = buffer->width;
+   height = buffer->height;
+   if (depth.format) {
+      depth.width   = width;
+      depth.height  = height;
+      depth.stride  = depth.width; // use the width here
+      assert(GGL_PIXEL_FORMAT_Z_32 == depth.format);
+      depth.data    = (GGLubyte*)malloc(depth.stride*depth.height*4);
+      if (depth.data == 0) {
+         return setError(EGL_BAD_ALLOC, EGL_FALSE);
+      }
+   }
+
+   // keep a reference on the buffer
+   buffer->common.incRef(&buffer->common);
+
+   // Lock the buffer
+   nativeWindow->lockBuffer(nativeWindow, buffer);
+   // pin the buffer down
+   if (lock(buffer, GRALLOC_USAGE_SW_READ_OFTEN |
+            GRALLOC_USAGE_SW_WRITE_OFTEN, &bits) != NO_ERROR) {
+      LOGE("connect() failed to lock buffer %p (%ux%u)",
+           buffer, buffer->width, buffer->height);
+      return setError(EGL_BAD_ACCESS, EGL_FALSE);
+      // FIXME: we should make sure we're not accessing the buffer anymore
+   }
+   return EGL_TRUE;
+}
+
+void egl_window_surface_v2_t::disconnect()
+{
+   if (buffer && bits) {
+      bits = NULL;
+      unlock(buffer);
+   }
+   // enqueue the last frame
+   if (buffer)
+      nativeWindow->queueBuffer(nativeWindow, buffer);
+   if (buffer) {
+      buffer->common.decRef(&buffer->common);
+      buffer = 0;
+   }
+   if (previousBuffer) {
+      previousBuffer->common.decRef(&previousBuffer->common);
+      previousBuffer = 0;
+   }
+}
+
+status_t egl_window_surface_v2_t::lock(
+   android_native_buffer_t* buf, int usage, void** vaddr)
+{
+   int err;
+
+   err = module->lock(module, buf->handle,
+                      usage, 0, 0, buf->width, buf->height, vaddr);
+
+   return err;
+}
+
+status_t egl_window_surface_v2_t::unlock(android_native_buffer_t* buf)
+{
+   if (!buf) return BAD_VALUE;
+   int err = NO_ERROR;
+
+   err = module->unlock(module, buf->handle);
+
+   return err;
+}
+
+void egl_window_surface_v2_t::copyBlt(
+   android_native_buffer_t* dst, void* dst_vaddr,
+   android_native_buffer_t* src, void const* src_vaddr,
+   const Region& clip)
+{
+   // FIXME: use copybit if possible
+   // NOTE: dst and src must be the same format
+
+   status_t err = NO_ERROR;
+   copybit_device_t* const copybit = blitengine;
+   if (copybit)  {
+      copybit_image_t simg;
+      simg.w = src->stride;
+      simg.h = src->height;
+      simg.format = src->format;
+      simg.handle = const_cast<native_handle_t*>(src->handle);
+
+      copybit_image_t dimg;
+      dimg.w = dst->stride;
+      dimg.h = dst->height;
+      dimg.format = dst->format;
+      dimg.handle = const_cast<native_handle_t*>(dst->handle);
+
+      copybit->set_parameter(copybit, COPYBIT_TRANSFORM, 0);
+      copybit->set_parameter(copybit, COPYBIT_PLANE_ALPHA, 255);
+      copybit->set_parameter(copybit, COPYBIT_DITHER, COPYBIT_DISABLE);
+      region_iterator it(clip);
+      err = copybit->blit(copybit, &dimg, &simg, &it);
+      if (err != NO_ERROR) {
+         LOGE("copybit failed (%s)", strerror(err));
+      }
+   }
+
+   if (!copybit || err) {
+      Region::const_iterator cur = clip.begin();
+      Region::const_iterator end = clip.end();
+
+      const size_t bpp = pixelFormatTable[src->format].size;
+      const size_t dbpr = dst->stride * bpp;
+      const size_t sbpr = src->stride * bpp;
+
+      uint8_t const * const src_bits = (uint8_t const *)src_vaddr;
+      uint8_t       * const dst_bits = (uint8_t       *)dst_vaddr;
+
+      while (cur != end) {
+         const Rect& r(*cur++);
+         ssize_t w = r.right - r.left;
+         ssize_t h = r.bottom - r.top;
+         if (w <= 0 || h<=0) continue;
+         size_t size = w * bpp;
+         uint8_t const * s = src_bits + (r.left + src->stride * r.top) * bpp;
+         uint8_t       * d = dst_bits + (r.left + dst->stride * r.top) * bpp;
+         if (dbpr==sbpr && size==sbpr) {
+            size *= h;
+            h = 1;
+         }
+         do {
+            memcpy(d, s, size);
+            d += dbpr;
+            s += sbpr;
+         } while (--h > 0);
+      }
+   }
+}
+
+EGLBoolean egl_window_surface_v2_t::swapBuffers()
+{
+   if (!buffer) {
+      return setError(EGL_BAD_ACCESS, EGL_FALSE);
+   }
+
+   /*
+    * Handle eglSetSwapRectangleANDROID()
+    * We copyback from the front buffer
+    */
+   if (!dirtyRegion.isEmpty()) {
+      dirtyRegion.andSelf(Rect(buffer->width, buffer->height));
+      if (previousBuffer) {
+         // This was const Region copyBack, but that causes an
+         // internal compile error on simulator builds
+         /*const*/
+         Region copyBack(Region::subtract(oldDirtyRegion, dirtyRegion));
+         if (!copyBack.isEmpty()) {
+            void* prevBits;
+            if (lock(previousBuffer,
+                     GRALLOC_USAGE_SW_READ_OFTEN, &prevBits) == NO_ERROR) {
+               // copy from previousBuffer to buffer
+               copyBlt(buffer, bits, previousBuffer, prevBits, copyBack);
+               unlock(previousBuffer);
+            }
+         }
+      }
+      oldDirtyRegion = dirtyRegion;
+   }
+
+   if (previousBuffer) {
+      previousBuffer->common.decRef(&previousBuffer->common);
+      previousBuffer = 0;
+   }
+
+   unlock(buffer);
+   previousBuffer = buffer;
+   nativeWindow->queueBuffer(nativeWindow, buffer);
+   buffer = 0;
+
+   // dequeue a new buffer
+   if (nativeWindow->dequeueBuffer(nativeWindow, &buffer) == NO_ERROR) {
+
+      // TODO: lockBuffer should rather be executed when the very first
+      // direct rendering occurs.
+      nativeWindow->lockBuffer(nativeWindow, buffer);
+
+      // reallocate the depth-buffer if needed
+      if ((width != buffer->width) || (height != buffer->height)) {
+         // TODO: we probably should reset the swap rect here
+         // if the window size has changed
+         width = buffer->width;
+         height = buffer->height;
+         if (depth.data) {
+            free(depth.data);
+            depth.width   = width;
+            depth.height  = height;
+            depth.stride  = buffer->stride;
+            depth.data    = (GGLubyte*)malloc(depth.stride*depth.height*2);
+            if (depth.data == 0) {
+               setError(EGL_BAD_ALLOC, EGL_FALSE);
+               return EGL_FALSE;
+            }
+         }
+      }
+
+      // keep a reference on the buffer
+      buffer->common.incRef(&buffer->common);
+
+      // finally pin the buffer down
+      if (lock(buffer, GRALLOC_USAGE_SW_READ_OFTEN |
+               GRALLOC_USAGE_SW_WRITE_OFTEN, &bits) != NO_ERROR) {
+         LOGE("eglSwapBuffers() failed to lock buffer %p (%ux%u)",
+              buffer, buffer->width, buffer->height);
+         return setError(EGL_BAD_ACCESS, EGL_FALSE);
+         // FIXME: we should make sure we're not accessing the buffer anymore
+      }
+   } else {
+      return setError(EGL_BAD_CURRENT_SURFACE, EGL_FALSE);
+   }
+
+   return EGL_TRUE;
+}
+
+EGLBoolean egl_window_surface_v2_t::setSwapRectangle(
+   EGLint l, EGLint t, EGLint w, EGLint h)
+{
+   dirtyRegion = Rect(l, t, l+w, t+h);
+   return EGL_TRUE;
+}
+
+EGLBoolean egl_window_surface_v2_t::bindDrawSurface(GLES2Context* gl)
+{
+   GGLSurface buffer;
+   buffer.version = sizeof(GGLSurface);
+   buffer.width   = this->buffer->width;
+   buffer.height  = this->buffer->height;
+   buffer.stride  = this->buffer->stride;
+   buffer.data    = (GGLubyte*)bits;
+   buffer.format  = (GGLPixelFormat)this->buffer->format;
+   gl->rasterizer.interface.SetBuffer(&gl->rasterizer.interface, GL_COLOR_BUFFER_BIT, &buffer);
+   if (depth.data != gl->rasterizer.depthSurface.data)
+      gl->rasterizer.interface.SetBuffer(&gl->rasterizer.interface, GL_DEPTH_BUFFER_BIT, &depth);
+
+   return EGL_TRUE;
+}
+EGLBoolean egl_window_surface_v2_t::bindReadSurface(GLES2Context* gl)
+{
+   GGLSurface buffer;
+   buffer.version = sizeof(GGLSurface);
+   buffer.width   = this->buffer->width;
+   buffer.height  = this->buffer->height;
+   buffer.stride  = this->buffer->stride;
+   buffer.data    = (GGLubyte*)bits; // FIXME: hopefully is is LOCKED!!!
+   buffer.format  = (GGLPixelFormat)this->buffer->format;
+   puts("agl2: readBuffer not implemented");
+   //gl->rasterizer.interface.readBuffer(gl, &buffer);
+   return EGL_TRUE;
+}
+EGLint egl_window_surface_v2_t::getHorizontalResolution() const
+{
+   return (nativeWindow->xdpi * EGL_DISPLAY_SCALING) * (1.0f / 25.4f);
+}
+EGLint egl_window_surface_v2_t::getVerticalResolution() const
+{
+   return (nativeWindow->ydpi * EGL_DISPLAY_SCALING) * (1.0f / 25.4f);
+}
+EGLint egl_window_surface_v2_t::getRefreshRate() const
+{
+   return (60 * EGL_DISPLAY_SCALING); // FIXME
+}
+EGLint egl_window_surface_v2_t::getSwapBehavior() const
+{
+   /*
+    * EGL_BUFFER_PRESERVED means that eglSwapBuffers() completely preserves
+    * the content of the swapped buffer.
+    *
+    * EGL_BUFFER_DESTROYED means that the content of the buffer is lost.
+    *
+    * However when ANDROID_swap_retcangle is supported, EGL_BUFFER_DESTROYED
+    * only applies to the area specified by eglSetSwapRectangleANDROID(), that
+    * is, everything outside of this area is preserved.
+    *
+    * This implementation of EGL assumes the later case.
+    *
+    */
+
+   return EGL_BUFFER_DESTROYED;
+}
+
+// ----------------------------------------------------------------------------
+
+struct egl_pixmap_surface_t : public egl_surface_t {
+   egl_pixmap_surface_t(
+      EGLDisplay dpy, EGLConfig config,
+      int32_t depthFormat,
+      egl_native_pixmap_t const * pixmap);
+
+   virtual ~egl_pixmap_surface_t() { }
+
+   virtual     bool        initCheck() const {
+      return !depth.format || depth.data!=0;
+   }
+   virtual     EGLBoolean  bindDrawSurface(GLES2Context* gl);
+   virtual     EGLBoolean  bindReadSurface(GLES2Context* gl);
+   virtual     EGLint      getWidth() const    {
+      return nativePixmap.width;
+   }
+   virtual     EGLint      getHeight() const   {
+      return nativePixmap.height;
+   }
+private:
+   egl_native_pixmap_t     nativePixmap;
+};
+
+egl_pixmap_surface_t::egl_pixmap_surface_t(EGLDisplay dpy,
+      EGLConfig config,
+      int32_t depthFormat,
+      egl_native_pixmap_t const * pixmap)
+      : egl_surface_t(dpy, config, depthFormat), nativePixmap(*pixmap)
+{
+   if (depthFormat) {
+      depth.width   = pixmap->width;
+      depth.height  = pixmap->height;
+      depth.stride  = depth.width; // use the width here
+      depth.data    = (GGLubyte*)malloc(depth.stride*depth.height*2);
+      if (depth.data == 0) {
+         setError(EGL_BAD_ALLOC, EGL_NO_SURFACE);
+      }
+   }
+}
+EGLBoolean egl_pixmap_surface_t::bindDrawSurface(GLES2Context* gl)
+{
+   GGLSurface buffer;
+   buffer.version = sizeof(GGLSurface);
+   buffer.width   = nativePixmap.width;
+   buffer.height  = nativePixmap.height;
+   buffer.stride  = nativePixmap.stride;
+   buffer.data    = nativePixmap.data;
+   buffer.format  = (GGLPixelFormat)nativePixmap.format;
+
+   gl->rasterizer.interface.SetBuffer(&gl->rasterizer.interface, GL_COLOR_BUFFER_BIT, &buffer);
+   if (depth.data != gl->rasterizer.depthSurface.data)
+      gl->rasterizer.interface.SetBuffer(&gl->rasterizer.interface, GL_DEPTH_BUFFER_BIT, &depth);
+   return EGL_TRUE;
+}
+EGLBoolean egl_pixmap_surface_t::bindReadSurface(GLES2Context* gl)
+{
+   GGLSurface buffer;
+   buffer.version = sizeof(GGLSurface);
+   buffer.width   = nativePixmap.width;
+   buffer.height  = nativePixmap.height;
+   buffer.stride  = nativePixmap.stride;
+   buffer.data    = nativePixmap.data;
+   buffer.format  = (GGLPixelFormat)nativePixmap.format;
+   puts("agl2: readBuffer not implemented");
+   //gl->rasterizer.interface.readBuffer(gl, &buffer);
+   return EGL_TRUE;
+}
+
+// ----------------------------------------------------------------------------
+
+struct egl_pbuffer_surface_t : public egl_surface_t {
+   egl_pbuffer_surface_t(
+      EGLDisplay dpy, EGLConfig config, int32_t depthFormat,
+      int32_t w, int32_t h, int32_t f);
+
+   virtual ~egl_pbuffer_surface_t();
+
+   virtual     bool        initCheck() const   {
+      return pbuffer.data != 0;
+   }
+   virtual     EGLBoolean  bindDrawSurface(GLES2Context* gl);
+   virtual     EGLBoolean  bindReadSurface(GLES2Context* gl);
+   virtual     EGLint      getWidth() const    {
+      return pbuffer.width;
+   }
+   virtual     EGLint      getHeight() const   {
+      return pbuffer.height;
+   }
+private:
+   GGLSurface  pbuffer;
+};
+
+egl_pbuffer_surface_t::egl_pbuffer_surface_t(EGLDisplay dpy,
+      EGLConfig config, int32_t depthFormat,
+      int32_t w, int32_t h, int32_t f)
+      : egl_surface_t(dpy, config, depthFormat)
+{
+   size_t size = w*h;
+   switch (f) {
+   case GGL_PIXEL_FORMAT_A_8:
+      size *= 1;
+      break;
+   case GGL_PIXEL_FORMAT_RGB_565:
+      size *= 2;
+      break;
+   case GGL_PIXEL_FORMAT_RGBA_8888:
+      size *= 4;
+      break;
+   case GGL_PIXEL_FORMAT_RGBX_8888:
+      size *= 4;
+      break;
+   default:
+      LOGE("incompatible pixel format for pbuffer (format=%d)", f);
+      pbuffer.data = 0;
+      break;
+   }
+   pbuffer.version = sizeof(GGLSurface);
+   pbuffer.width   = w;
+   pbuffer.height  = h;
+   pbuffer.stride  = w;
+   pbuffer.data    = (GGLubyte*)malloc(size);
+   pbuffer.format  = (GGLPixelFormat)f;
+
+   if (depthFormat) {
+      depth.width   = pbuffer.width;
+      depth.height  = pbuffer.height;
+      depth.stride  = depth.width; // use the width here
+      depth.data    = (GGLubyte*)malloc(depth.stride*depth.height*2);
+      if (depth.data == 0) {
+         setError(EGL_BAD_ALLOC, EGL_NO_SURFACE);
+         return;
+      }
+   }
+}
+egl_pbuffer_surface_t::~egl_pbuffer_surface_t()
+{
+   free(pbuffer.data);
+}
+EGLBoolean egl_pbuffer_surface_t::bindDrawSurface(GLES2Context* gl)
+{
+   gl->rasterizer.interface.SetBuffer(&gl->rasterizer.interface, GL_COLOR_BUFFER_BIT, &pbuffer);
+   if (depth.data != gl->rasterizer.depthSurface.data)
+      gl->rasterizer.interface.SetBuffer(&gl->rasterizer.interface, GL_DEPTH_BUFFER_BIT, &depth);
+   return EGL_TRUE;
+}
+EGLBoolean egl_pbuffer_surface_t::bindReadSurface(GLES2Context* gl)
+{
+   puts("agl2: readBuffer not implemented");
+   //gl->rasterizer.interface.readBuffer(gl, &pbuffer);
+   return EGL_TRUE;
+}
+
+// ----------------------------------------------------------------------------
+
+struct config_pair_t {
+   GLint key;
+   GLint value;
+};
+
+struct configs_t {
+   const config_pair_t* array;
+   int                  size;
+};
+
+struct config_management_t {
+   GLint key;
+   bool (*match)(GLint reqValue, GLint confValue);
+   static bool atLeast(GLint reqValue, GLint confValue) {
+      return (reqValue == EGL_DONT_CARE) || (confValue >= reqValue);
+   }
+   static bool exact(GLint reqValue, GLint confValue) {
+      return (reqValue == EGL_DONT_CARE) || (confValue == reqValue);
+   }
+   static bool mask(GLint reqValue, GLint confValue) {
+      return (confValue & reqValue) == reqValue;
+   }
+   static bool ignore(GLint reqValue, GLint confValue) {
+      return true;
+   }
+};
+
+// ----------------------------------------------------------------------------
+
+#define VERSION_MAJOR 1
+#define VERSION_MINOR 2
+static char const * const gVendorString     = "Google Inc.";
+static char const * const gVersionString    = "0.0 Android Driver 0.0.0";
+static char const * const gClientApiString  = "OpenGL ES2";
+static char const * const gExtensionsString =
+   //"EGL_KHR_image_base "
+   // "KHR_image_pixmap "
+   //"EGL_ANDROID_image_native_buffer "
+   //"EGL_ANDROID_swap_rectangle "
+   "";
+
+// ----------------------------------------------------------------------------
+
+struct extention_map_t {
+   const char * const name;
+   __eglMustCastToProperFunctionPointerType address;
+};
+
+static const extention_map_t gExtentionMap[] = {
+//    { "glDrawTexsOES",
+//            (__eglMustCastToProperFunctionPointerType)&glDrawTexsOES },
+//    { "glDrawTexiOES",
+//            (__eglMustCastToProperFunctionPointerType)&glDrawTexiOES },
+//    { "glDrawTexfOES",
+//            (__eglMustCastToProperFunctionPointerType)&glDrawTexfOES },
+//    { "glDrawTexxOES",
+//            (__eglMustCastToProperFunctionPointerType)&glDrawTexxOES },
+//    { "glDrawTexsvOES",
+//            (__eglMustCastToProperFunctionPointerType)&glDrawTexsvOES },
+//    { "glDrawTexivOES",
+//            (__eglMustCastToProperFunctionPointerType)&glDrawTexivOES },
+//    { "glDrawTexfvOES",
+//            (__eglMustCastToProperFunctionPointerType)&glDrawTexfvOES },
+//    { "glDrawTexxvOES",
+//            (__eglMustCastToProperFunctionPointerType)&glDrawTexxvOES },
+//    { "glQueryMatrixxOES",
+//            (__eglMustCastToProperFunctionPointerType)&glQueryMatrixxOES },
+//    { "glEGLImageTargetTexture2DOES",
+//            (__eglMustCastToProperFunctionPointerType)&glEGLImageTargetTexture2DOES },
+//    { "glEGLImageTargetRenderbufferStorageOES",
+//            (__eglMustCastToProperFunctionPointerType)&glEGLImageTargetRenderbufferStorageOES },
+//    { "glClipPlanef",
+//            (__eglMustCastToProperFunctionPointerType)&glClipPlanef },
+//    { "glClipPlanex",
+//            (__eglMustCastToProperFunctionPointerType)&glClipPlanex },
+//    { "glBindBuffer",
+//            (__eglMustCastToProperFunctionPointerType)&glBindBuffer },
+//    { "glBufferData",
+//            (__eglMustCastToProperFunctionPointerType)&glBufferData },
+//    { "glBufferSubData",
+//            (__eglMustCastToProperFunctionPointerType)&glBufferSubData },
+//    { "glDeleteBuffers",
+//            (__eglMustCastToProperFunctionPointerType)&glDeleteBuffers },
+//    { "glGenBuffers",
+//            (__eglMustCastToProperFunctionPointerType)&glGenBuffers },
+//    { "eglCreateImageKHR",
+//            (__eglMustCastToProperFunctionPointerType)&eglCreateImageKHR },
+//    { "eglDestroyImageKHR",
+//            (__eglMustCastToProperFunctionPointerType)&eglDestroyImageKHR },
+//    { "eglSetSwapRectangleANDROID",
+//            (__eglMustCastToProperFunctionPointerType)&eglSetSwapRectangleANDROID },
+};
+
+/*
+ * In the lists below, attributes names MUST be sorted.
+ * Additionally, all configs must be sorted according to
+ * the EGL specification.
+ */
+
+static config_pair_t const config_base_attribute_list[] = {
+   { EGL_STENCIL_SIZE,               0                                 },
+   { EGL_CONFIG_CAVEAT,              EGL_SLOW_CONFIG                   },
+   { EGL_LEVEL,                      0                                 },
+   { EGL_MAX_PBUFFER_HEIGHT,         GGL_MAX_VIEWPORT_DIMS             },
+   { EGL_MAX_PBUFFER_PIXELS,
+     GGL_MAX_VIEWPORT_DIMS*GGL_MAX_VIEWPORT_DIMS                 },
+   { EGL_MAX_PBUFFER_WIDTH,          GGL_MAX_VIEWPORT_DIMS             },
+   { EGL_NATIVE_RENDERABLE,          EGL_TRUE                          },
+   { EGL_NATIVE_VISUAL_ID,           0                                 },
+   { EGL_NATIVE_VISUAL_TYPE,         GGL_PIXEL_FORMAT_RGBA_8888        },
+   { EGL_SAMPLES,                    0                                 },
+   { EGL_SAMPLE_BUFFERS,             0                                 },
+   { EGL_TRANSPARENT_TYPE,           EGL_NONE                          },
+   { EGL_TRANSPARENT_BLUE_VALUE,     0                                 },
+   { EGL_TRANSPARENT_GREEN_VALUE,    0                                 },
+   { EGL_TRANSPARENT_RED_VALUE,      0                                 },
+   { EGL_BIND_TO_TEXTURE_RGBA,       EGL_FALSE                         },
+   { EGL_BIND_TO_TEXTURE_RGB,        EGL_FALSE                         },
+   { EGL_MIN_SWAP_INTERVAL,          1                                 },
+   { EGL_MAX_SWAP_INTERVAL,          1                                 },
+   { EGL_LUMINANCE_SIZE,             0                                 },
+   { EGL_ALPHA_MASK_SIZE,            0                                 },
+   { EGL_COLOR_BUFFER_TYPE,          EGL_RGB_BUFFER                    },
+   { EGL_RENDERABLE_TYPE,            EGL_OPENGL_ES2_BIT                },
+   { EGL_CONFORMANT,                 0                                 }
+};
+
+// These configs can override the base attribute list
+// NOTE: when adding a config here, don't forget to update eglCreate*Surface()
+
+// 565 configs
+static config_pair_t const config_0_attribute_list[] = {
+   { EGL_BUFFER_SIZE,     16 },
+   { EGL_ALPHA_SIZE,       0 },
+   { EGL_BLUE_SIZE,        5 },
+   { EGL_GREEN_SIZE,       6 },
+   { EGL_RED_SIZE,         5 },
+   { EGL_DEPTH_SIZE,       0 },
+   { EGL_CONFIG_ID,        0 },
+   { EGL_NATIVE_VISUAL_ID, GGL_PIXEL_FORMAT_RGB_565 },
+   { EGL_SURFACE_TYPE,     EGL_SWAP_BEHAVIOR_PRESERVED_BIT|EGL_WINDOW_BIT|EGL_PBUFFER_BIT|EGL_PIXMAP_BIT },
+};
+
+static config_pair_t const config_1_attribute_list[] = {
+   { EGL_BUFFER_SIZE,     16 },
+   { EGL_ALPHA_SIZE,       0 },
+   { EGL_BLUE_SIZE,        5 },
+   { EGL_GREEN_SIZE,       6 },
+   { EGL_RED_SIZE,         5 },
+   { EGL_DEPTH_SIZE,      16 },
+   { EGL_CONFIG_ID,        1 },
+   { EGL_NATIVE_VISUAL_ID, GGL_PIXEL_FORMAT_RGB_565 },
+   { EGL_SURFACE_TYPE,     EGL_SWAP_BEHAVIOR_PRESERVED_BIT|EGL_WINDOW_BIT|EGL_PBUFFER_BIT|EGL_PIXMAP_BIT },
+};
+
+// RGB 888 configs
+static config_pair_t const config_2_attribute_list[] = {
+   { EGL_BUFFER_SIZE,     32 },
+   { EGL_ALPHA_SIZE,       0 },
+   { EGL_BLUE_SIZE,        8 },
+   { EGL_GREEN_SIZE,       8 },
+   { EGL_RED_SIZE,         8 },
+   { EGL_DEPTH_SIZE,       0 },
+   { EGL_CONFIG_ID,        6 },
+   { EGL_NATIVE_VISUAL_ID, GGL_PIXEL_FORMAT_RGBX_8888 },
+   { EGL_SURFACE_TYPE,     EGL_SWAP_BEHAVIOR_PRESERVED_BIT|EGL_WINDOW_BIT|EGL_PBUFFER_BIT|EGL_PIXMAP_BIT },
+};
+
+static config_pair_t const config_3_attribute_list[] = {
+   { EGL_BUFFER_SIZE,     32 },
+   { EGL_ALPHA_SIZE,       0 },
+   { EGL_BLUE_SIZE,        8 },
+   { EGL_GREEN_SIZE,       8 },
+   { EGL_RED_SIZE,         8 },
+   { EGL_DEPTH_SIZE,      16 },
+   { EGL_CONFIG_ID,        7 },
+   { EGL_NATIVE_VISUAL_ID, GGL_PIXEL_FORMAT_RGBX_8888 },
+   { EGL_SURFACE_TYPE,     EGL_SWAP_BEHAVIOR_PRESERVED_BIT|EGL_WINDOW_BIT|EGL_PBUFFER_BIT|EGL_PIXMAP_BIT },
+};
+
+// 8888 configs
+static config_pair_t const config_4_attribute_list[] = {
+   { EGL_BUFFER_SIZE,     32 },
+   { EGL_ALPHA_SIZE,       8 },
+   { EGL_BLUE_SIZE,        8 },
+   { EGL_GREEN_SIZE,       8 },
+   { EGL_RED_SIZE,         8 },
+   { EGL_DEPTH_SIZE,       0 },
+   { EGL_CONFIG_ID,        2 },
+   { EGL_NATIVE_VISUAL_ID, GGL_PIXEL_FORMAT_RGBA_8888 },
+   { EGL_SURFACE_TYPE,     EGL_SWAP_BEHAVIOR_PRESERVED_BIT|EGL_WINDOW_BIT|EGL_PBUFFER_BIT|EGL_PIXMAP_BIT },
+};
+
+static config_pair_t const config_5_attribute_list[] = {
+   { EGL_BUFFER_SIZE,     32 },
+   { EGL_ALPHA_SIZE,       8 },
+   { EGL_BLUE_SIZE,        8 },
+   { EGL_GREEN_SIZE,       8 },
+   { EGL_RED_SIZE,         8 },
+   { EGL_DEPTH_SIZE,      16 },
+   { EGL_CONFIG_ID,        3 },
+   { EGL_NATIVE_VISUAL_ID, GGL_PIXEL_FORMAT_RGBA_8888 },
+   { EGL_SURFACE_TYPE,     EGL_SWAP_BEHAVIOR_PRESERVED_BIT|EGL_WINDOW_BIT|EGL_PBUFFER_BIT|EGL_PIXMAP_BIT },
+};
+
+// A8 configs
+static config_pair_t const config_6_attribute_list[] = {
+   { EGL_BUFFER_SIZE,      8 },
+   { EGL_ALPHA_SIZE,       8 },
+   { EGL_BLUE_SIZE,        0 },
+   { EGL_GREEN_SIZE,       0 },
+   { EGL_RED_SIZE,         0 },
+   { EGL_DEPTH_SIZE,       0 },
+   { EGL_CONFIG_ID,        4 },
+   { EGL_NATIVE_VISUAL_ID, GGL_PIXEL_FORMAT_A_8 },
+   { EGL_SURFACE_TYPE,     EGL_SWAP_BEHAVIOR_PRESERVED_BIT|EGL_WINDOW_BIT|EGL_PBUFFER_BIT|EGL_PIXMAP_BIT },
+};
+
+static config_pair_t const config_7_attribute_list[] = {
+   { EGL_BUFFER_SIZE,      8 },
+   { EGL_ALPHA_SIZE,       8 },
+   { EGL_BLUE_SIZE,        0 },
+   { EGL_GREEN_SIZE,       0 },
+   { EGL_RED_SIZE,         0 },
+   { EGL_DEPTH_SIZE,      16 },
+   { EGL_CONFIG_ID,        5 },
+   { EGL_NATIVE_VISUAL_ID, GGL_PIXEL_FORMAT_A_8 },
+   { EGL_SURFACE_TYPE,     EGL_SWAP_BEHAVIOR_PRESERVED_BIT|EGL_WINDOW_BIT|EGL_PBUFFER_BIT|EGL_PIXMAP_BIT },
+};
+
+static configs_t const gConfigs[] = {
+   { config_0_attribute_list, NELEM(config_0_attribute_list) },
+   { config_1_attribute_list, NELEM(config_1_attribute_list) },
+   { config_2_attribute_list, NELEM(config_2_attribute_list) },
+   { config_3_attribute_list, NELEM(config_3_attribute_list) },
+   { config_4_attribute_list, NELEM(config_4_attribute_list) },
+   { config_5_attribute_list, NELEM(config_5_attribute_list) },
+//   { config_6_attribute_list, NELEM(config_6_attribute_list) },
+//   { config_7_attribute_list, NELEM(config_7_attribute_list) },
+};
+
+static config_management_t const gConfigManagement[] = {
+   { EGL_BUFFER_SIZE,                config_management_t::atLeast },
+   { EGL_ALPHA_SIZE,                 config_management_t::atLeast },
+   { EGL_BLUE_SIZE,                  config_management_t::atLeast },
+   { EGL_GREEN_SIZE,                 config_management_t::atLeast },
+   { EGL_RED_SIZE,                   config_management_t::atLeast },
+   { EGL_DEPTH_SIZE,                 config_management_t::atLeast },
+   { EGL_STENCIL_SIZE,               config_management_t::atLeast },
+   { EGL_CONFIG_CAVEAT,              config_management_t::exact   },
+   { EGL_CONFIG_ID,                  config_management_t::exact   },
+   { EGL_LEVEL,                      config_management_t::exact   },
+   { EGL_MAX_PBUFFER_HEIGHT,         config_management_t::ignore   },
+   { EGL_MAX_PBUFFER_PIXELS,         config_management_t::ignore   },
+   { EGL_MAX_PBUFFER_WIDTH,          config_management_t::ignore   },
+   { EGL_NATIVE_RENDERABLE,          config_management_t::exact   },
+   { EGL_NATIVE_VISUAL_ID,           config_management_t::ignore   },
+   { EGL_NATIVE_VISUAL_TYPE,         config_management_t::exact   },
+   { EGL_SAMPLES,                    config_management_t::exact   },
+   { EGL_SAMPLE_BUFFERS,             config_management_t::exact   },
+   { EGL_SURFACE_TYPE,               config_management_t::mask    },
+   { EGL_TRANSPARENT_TYPE,           config_management_t::exact   },
+   { EGL_TRANSPARENT_BLUE_VALUE,     config_management_t::exact   },
+   { EGL_TRANSPARENT_GREEN_VALUE,    config_management_t::exact   },
+   { EGL_TRANSPARENT_RED_VALUE,      config_management_t::exact   },
+   { EGL_BIND_TO_TEXTURE_RGBA,       config_management_t::exact   },
+   { EGL_BIND_TO_TEXTURE_RGB,        config_management_t::exact   },
+   { EGL_MIN_SWAP_INTERVAL,          config_management_t::exact   },
+   { EGL_MAX_SWAP_INTERVAL,          config_management_t::exact   },
+   { EGL_LUMINANCE_SIZE,             config_management_t::atLeast },
+   { EGL_ALPHA_MASK_SIZE,            config_management_t::atLeast },
+   { EGL_COLOR_BUFFER_TYPE,          config_management_t::exact   },
+   { EGL_RENDERABLE_TYPE,            config_management_t::mask    },
+   { EGL_CONFORMANT,                 config_management_t::mask    }
+};
+
+
+static config_pair_t const config_defaults[] = {
+   // attributes that are not specified are simply ignored, if a particular
+   // one needs not be ignored, it must be specified here, eg:
+   // { EGL_SURFACE_TYPE, EGL_WINDOW_BIT },
+};
+
+// ----------------------------------------------------------------------------
+
+static status_t getConfigFormatInfo(EGLint configID,
+                                    int32_t& pixelFormat, int32_t& depthFormat)
+{
+   switch (configID) {
+   case 0:
+      pixelFormat = GGL_PIXEL_FORMAT_RGB_565;
+      depthFormat = 0;
+      break;
+   case 1:
+      pixelFormat = GGL_PIXEL_FORMAT_RGB_565;
+      depthFormat = GGL_PIXEL_FORMAT_Z_32;
+      break;
+   case 2:
+      pixelFormat = GGL_PIXEL_FORMAT_RGBA_8888;
+      depthFormat = 0;
+      break;
+   case 3:
+      pixelFormat = GGL_PIXEL_FORMAT_RGBA_8888;
+      depthFormat = GGL_PIXEL_FORMAT_Z_32;
+      break;
+   case 4:
+      pixelFormat = GGL_PIXEL_FORMAT_RGBA_8888;
+      depthFormat = 0;
+      break;
+   case 5:
+      pixelFormat = GGL_PIXEL_FORMAT_RGBA_8888;
+      depthFormat = GGL_PIXEL_FORMAT_Z_32;
+      break;
+   case 6:
+      pixelFormat = GGL_PIXEL_FORMAT_A_8;
+      depthFormat = 0;
+      break;
+   case 7:
+      pixelFormat = GGL_PIXEL_FORMAT_A_8;
+      depthFormat = GGL_PIXEL_FORMAT_Z_32;
+      break;
+   default:
+      return NAME_NOT_FOUND;
+   }
+   return NO_ERROR;
+}
+
+// ----------------------------------------------------------------------------
+
+template<typename T>
+static int binarySearch(T const sortedArray[], int first, int last, EGLint key)
+{
+   while (first <= last) {
+      int mid = (first + last) / 2;
+      if (key > sortedArray[mid].key) {
+         first = mid + 1;
+      } else if (key < sortedArray[mid].key) {
+         last = mid - 1;
+      } else {
+         return mid;
+      }
+   }
+   return -1;
+}
+
+static int isAttributeMatching(int i, EGLint attr, EGLint val)
+{
+   // look for the attribute in all of our configs
+   config_pair_t const* configFound = gConfigs[i].array;
+   int index = binarySearch<config_pair_t>(
+                  gConfigs[i].array,
+                  0, gConfigs[i].size-1,
+                  attr);
+   if (index < 0) {
+      configFound = config_base_attribute_list;
+      index = binarySearch<config_pair_t>(
+                 config_base_attribute_list,
+                 0, NELEM(config_base_attribute_list)-1,
+                 attr);
+   }
+   if (index >= 0) {
+      // attribute found, check if this config could match
+      int cfgMgtIndex = binarySearch<config_management_t>(
+                           gConfigManagement,
+                           0, NELEM(gConfigManagement)-1,
+                           attr);
+      if (cfgMgtIndex >= 0) {
+         bool match = gConfigManagement[cfgMgtIndex].match(
+                         val, configFound[index].value);
+         if (match) {
+            // this config matches
+            return 1;
+         }
+      } else {
+         // attribute not found. this should NEVER happen.
+      }
+   } else {
+      // error, this attribute doesn't exist
+   }
+   return 0;
+}
+
+static int makeCurrent(GLES2Context* gl)
+{
+   GLES2Context* current = (GLES2Context*)getGlThreadSpecific();
+   if (gl) {
+      egl_context_t* c = egl_context_t::context(gl);
+      if (c->flags & egl_context_t::IS_CURRENT) {
+         if (current != gl) {
+            // it is an error to set a context current, if it's already
+            // current to another thread
+            return -1;
+         }
+      } else {
+         if (current) {
+            // mark the current context as not current, and flush
+            glFlush();
+            egl_context_t::context(current)->flags &= ~egl_context_t::IS_CURRENT;
+         }
+      }
+      if (!(c->flags & egl_context_t::IS_CURRENT)) {
+         // The context is not current, make it current!
+         setGlThreadSpecific(gl);
+         c->flags |= egl_context_t::IS_CURRENT;
+      }
+   } else {
+      if (current) {
+         // mark the current context as not current, and flush
+         glFlush();
+         egl_context_t::context(current)->flags &= ~egl_context_t::IS_CURRENT;
+      }
+      // this thread has no context attached to it
+      setGlThreadSpecific(0);
+   }
+   return 0;
+}
+
+static EGLBoolean getConfigAttrib(EGLDisplay dpy, EGLConfig config,
+                                  EGLint attribute, EGLint *value)
+{
+   size_t numConfigs =  NELEM(gConfigs);
+   int index = (int)config;
+   if (uint32_t(index) >= numConfigs)
+      return setError(EGL_BAD_CONFIG, EGL_FALSE);
+
+   int attrIndex;
+   attrIndex = binarySearch<config_pair_t>(
+                  gConfigs[index].array,
+                  0, gConfigs[index].size-1,
+                  attribute);
+   if (attrIndex>=0) {
+      *value = gConfigs[index].array[attrIndex].value;
+      return EGL_TRUE;
+   }
+
+   attrIndex = binarySearch<config_pair_t>(
+                  config_base_attribute_list,
+                  0, NELEM(config_base_attribute_list)-1,
+                  attribute);
+   if (attrIndex>=0) {
+      *value = config_base_attribute_list[attrIndex].value;
+      return EGL_TRUE;
+   }
+   return setError(EGL_BAD_ATTRIBUTE, EGL_FALSE);
+}
+
+static EGLSurface createWindowSurface(EGLDisplay dpy, EGLConfig config,
+                                      NativeWindowType window, const EGLint *attrib_list)
+{
+   if (egl_display_t::is_valid(dpy) == EGL_FALSE)
+      return setError(EGL_BAD_DISPLAY, EGL_NO_SURFACE);
+   if (window == 0)
+      return setError(EGL_BAD_MATCH, EGL_NO_SURFACE);
+
+   EGLint surfaceType;
+   if (getConfigAttrib(dpy, config, EGL_SURFACE_TYPE, &surfaceType) == EGL_FALSE)
+      return EGL_FALSE;
+
+   if (!(surfaceType & EGL_WINDOW_BIT))
+      return setError(EGL_BAD_MATCH, EGL_NO_SURFACE);
+
+   if (reinterpret_cast<ANativeWindow*>(window)->common.magic !=
+         ANDROID_NATIVE_WINDOW_MAGIC) {
+      return setError(EGL_BAD_NATIVE_WINDOW, EGL_NO_SURFACE);
+   }
+
+   EGLint configID;
+   if (getConfigAttrib(dpy, config, EGL_CONFIG_ID, &configID) == EGL_FALSE)
+      return EGL_FALSE;
+
+   int32_t depthFormat;
+   int32_t pixelFormat;
+   if (getConfigFormatInfo(configID, pixelFormat, depthFormat) != NO_ERROR) {
+      return setError(EGL_BAD_MATCH, EGL_NO_SURFACE);
+   }
+
+   // FIXME: we don't have access to the pixelFormat here just yet.
+   // (it's possible that the surface is not fully initialized)
+   // maybe this should be done after the page-flip
+   //if (EGLint(info.format) != pixelFormat)
+   //    return setError(EGL_BAD_MATCH, EGL_NO_SURFACE);
+
+   egl_surface_t* surface;
+   surface = new egl_window_surface_v2_t(dpy, config, depthFormat,
+                                         reinterpret_cast<ANativeWindow*>(window));
+
+   if (!surface->initCheck()) {
+      // there was a problem in the ctor, the error
+      // flag has been set.
+      delete surface;
+      surface = 0;
+   }
+   return surface;
+}
+
+static EGLSurface createPixmapSurface(EGLDisplay dpy, EGLConfig config,
+                                      NativePixmapType pixmap, const EGLint *attrib_list)
+{
+   if (egl_display_t::is_valid(dpy) == EGL_FALSE)
+      return setError(EGL_BAD_DISPLAY, EGL_NO_SURFACE);
+   if (pixmap == 0)
+      return setError(EGL_BAD_MATCH, EGL_NO_SURFACE);
+
+   EGLint surfaceType;
+   if (getConfigAttrib(dpy, config, EGL_SURFACE_TYPE, &surfaceType) == EGL_FALSE)
+      return EGL_FALSE;
+
+   if (!(surfaceType & EGL_PIXMAP_BIT))
+      return setError(EGL_BAD_MATCH, EGL_NO_SURFACE);
+
+   if (reinterpret_cast<egl_native_pixmap_t*>(pixmap)->version !=
+         sizeof(egl_native_pixmap_t)) {
+      return setError(EGL_BAD_NATIVE_PIXMAP, EGL_NO_SURFACE);
+   }
+
+   EGLint configID;
+   if (getConfigAttrib(dpy, config, EGL_CONFIG_ID, &configID) == EGL_FALSE)
+      return EGL_FALSE;
+
+   int32_t depthFormat;
+   int32_t pixelFormat;
+   if (getConfigFormatInfo(configID, pixelFormat, depthFormat) != NO_ERROR) {
+      return setError(EGL_BAD_MATCH, EGL_NO_SURFACE);
+   }
+
+   if (reinterpret_cast<egl_native_pixmap_t *>(pixmap)->format != pixelFormat)
+      return setError(EGL_BAD_MATCH, EGL_NO_SURFACE);
+
+   egl_surface_t* surface =
+      new egl_pixmap_surface_t(dpy, config, depthFormat,
+                               reinterpret_cast<egl_native_pixmap_t*>(pixmap));
+
+   if (!surface->initCheck()) {
+      // there was a problem in the ctor, the error
+      // flag has been set.
+      delete surface;
+      surface = 0;
+   }
+   return surface;
+}
+
+static EGLSurface createPbufferSurface(EGLDisplay dpy, EGLConfig config,
+                                       const EGLint *attrib_list)
+{
+   if (egl_display_t::is_valid(dpy) == EGL_FALSE)
+      return setError(EGL_BAD_DISPLAY, EGL_NO_SURFACE);
+
+   EGLint surfaceType;
+   if (getConfigAttrib(dpy, config, EGL_SURFACE_TYPE, &surfaceType) == EGL_FALSE)
+      return EGL_FALSE;
+
+   if (!(surfaceType & EGL_PBUFFER_BIT))
+      return setError(EGL_BAD_MATCH, EGL_NO_SURFACE);
+
+   EGLint configID;
+   if (getConfigAttrib(dpy, config, EGL_CONFIG_ID, &configID) == EGL_FALSE)
+      return EGL_FALSE;
+
+   int32_t depthFormat;
+   int32_t pixelFormat;
+   if (getConfigFormatInfo(configID, pixelFormat, depthFormat) != NO_ERROR) {
+      return setError(EGL_BAD_MATCH, EGL_NO_SURFACE);
+   }
+
+   int32_t w = 0;
+   int32_t h = 0;
+   while (attrib_list[0]) {
+      if (attrib_list[0] == EGL_WIDTH)  w = attrib_list[1];
+      if (attrib_list[0] == EGL_HEIGHT) h = attrib_list[1];
+      attrib_list+=2;
+   }
+
+   egl_surface_t* surface =
+      new egl_pbuffer_surface_t(dpy, config, depthFormat, w, h, pixelFormat);
+
+   if (!surface->initCheck()) {
+      // there was a problem in the ctor, the error
+      // flag has been set.
+      delete surface;
+      surface = 0;
+   }
+   return surface;
+}
+
+// ----------------------------------------------------------------------------
+}; // namespace android
+// ----------------------------------------------------------------------------
+
+using namespace android;
+
+// ----------------------------------------------------------------------------
+// Initialization
+// ----------------------------------------------------------------------------
+
+EGLDisplay eglGetDisplay(NativeDisplayType display)
+{
+   puts("agl2:eglGetDisplay");
+#ifndef HAVE_ANDROID_OS
+   // this just needs to be done once
+   if (gGLKey == -1) {
+      pthread_mutex_lock(&gInitMutex);
+      if (gGLKey == -1)
+         pthread_key_create(&gGLKey, NULL);
+      pthread_mutex_unlock(&gInitMutex);
+   }
+#endif
+   if (display == EGL_DEFAULT_DISPLAY) {
+      EGLDisplay dpy = (EGLDisplay)1;
+      egl_display_t& d = egl_display_t::get_display(dpy);
+      d.type = display;
+      return dpy;
+   }
+   return EGL_NO_DISPLAY;
+}
+
+EGLBoolean eglInitialize(EGLDisplay dpy, EGLint *major, EGLint *minor)
+{
+   puts("agl2:eglInitialize");
+   if (egl_display_t::is_valid(dpy) == EGL_FALSE)
+      return setError(EGL_BAD_DISPLAY, EGL_FALSE);
+
+   EGLBoolean res = EGL_TRUE;
+   egl_display_t& d = egl_display_t::get_display(dpy);
+
+   if (android_atomic_inc(&d.initialized) == 0) {
+      // initialize stuff here if needed
+      //pthread_mutex_lock(&gInitMutex);
+      //pthread_mutex_unlock(&gInitMutex);
+   }
+
+   if (res == EGL_TRUE) {
+      if (major != NULL) *major = VERSION_MAJOR;
+      if (minor != NULL) *minor = VERSION_MINOR;
+   }
+   return res;
+}
+
+EGLBoolean eglTerminate(EGLDisplay dpy)
+{
+   puts("agl2:eglTerminate");
+   if (egl_display_t::is_valid(dpy) == EGL_FALSE)
+      return setError(EGL_BAD_DISPLAY, EGL_FALSE);
+
+   EGLBoolean res = EGL_TRUE;
+   egl_display_t& d = egl_display_t::get_display(dpy);
+   if (android_atomic_dec(&d.initialized) == 1) {
+      // TODO: destroy all resources (surfaces, contexts, etc...)
+      //pthread_mutex_lock(&gInitMutex);
+      //pthread_mutex_unlock(&gInitMutex);
+   }
+   return res;
+}
+
+// ----------------------------------------------------------------------------
+// configuration
+// ----------------------------------------------------------------------------
+
+EGLBoolean eglGetConfigs(   EGLDisplay dpy,
+                            EGLConfig *configs,
+                            EGLint config_size, EGLint *num_config)
+{
+   puts("agl2:eglGetConfigs");
+   if (egl_display_t::is_valid(dpy) == EGL_FALSE)
+      return setError(EGL_BAD_DISPLAY, EGL_FALSE);
+
+   GLint numConfigs = NELEM(gConfigs);
+   if (!configs) {
+      *num_config = numConfigs;
+      return EGL_TRUE;
+   }
+   GLint i;
+   for (i=0 ; i<numConfigs && i<config_size ; i++) {
+      *configs++ = (EGLConfig)i;
+   }
+   *num_config = i;
+   return EGL_TRUE;
+}
+
+static const char * ATTRIBUTE_NAMES [] = {
+   "EGL_BUFFER_SIZE",
+   "EGL_ALPHA_SIZE",
+   "EGL_BLUE_SIZE",
+   "EGL_GREEN_SIZE",
+   "EGL_RED_SIZE",
+   "EGL_DEPTH_SIZE",
+   "EGL_STENCIL_SIZE",
+   "EGL_CONFIG_CAVEAT",
+   "EGL_CONFIG_ID",
+   "EGL_LEVEL",
+   "EGL_MAX_PBUFFER_HEIGHT",
+   "EGL_MAX_PBUFFER_PIXELS",
+   "EGL_MAX_PBUFFER_WIDTH",
+   "EGL_NATIVE_RENDERABLE",
+   "EGL_NATIVE_VISUAL_ID",
+   "EGL_NATIVE_VISUAL_TYPE",
+   "EGL_PRESERVED_RESOURCES",
+   "EGL_SAMPLES",
+   "EGL_SAMPLE_BUFFERS",
+   "EGL_SURFACE_TYPE",
+   "EGL_TRANSPARENT_TYPE",
+   "EGL_TRANSPARENT_BLUE_VALUE",
+   "EGL_TRANSPARENT_GREEN_VALUE",
+   "EGL_TRANSPARENT_RED_VALUE",
+   "EGL_NONE",   /* Attrib list terminator */
+   "EGL_BIND_TO_TEXTURE_RGB",
+   "EGL_BIND_TO_TEXTURE_RGBA",
+   "EGL_MIN_SWAP_INTERVAL",
+   "EGL_MAX_SWAP_INTERVAL",
+   "EGL_LUMINANCE_SIZE",
+   "EGL_ALPHA_MASK_SIZE",
+   "EGL_COLOR_BUFFER_TYPE",
+   "EGL_RENDERABLE_TYPE",
+   "EGL_MATCH_NATIVE_PIXMAP",   /* Pseudo-attribute (not queryable) */
+   "EGL_CONFORMANT",
+};
+
+EGLBoolean eglChooseConfig( EGLDisplay dpy, const EGLint *attrib_list,
+                            EGLConfig *configs, EGLint config_size,
+                            EGLint *num_config)
+{
+   puts("agl2:eglChooseConfig");
+   LOGD("\n***\n***\n agl2:LOGD eglChooseConfig \n***\n***\n");
+   if (egl_display_t::is_valid(dpy) == EGL_FALSE)
+      return setError(EGL_BAD_DISPLAY, EGL_FALSE);
+
+   if (ggl_unlikely(num_config==0)) {
+      LOGD("\n***\n***\n num_config==0 \n***\n***\n");
+      return setError(EGL_BAD_PARAMETER, EGL_FALSE);
+   }
+
+   if (ggl_unlikely(attrib_list==0)) {
+      /*
+       * A NULL attrib_list should be treated as though it was an empty
+       * one (terminated with EGL_NONE) as defined in
+       * section 3.4.1 "Querying Configurations" in the EGL specification.
+       */
+      LOGD("\n***\n***\n attrib_list==0 \n***\n***\n");
+      static const EGLint dummy = EGL_NONE;
+      attrib_list = &dummy;
+   }
+
+   for (const EGLint * attrib = attrib_list; *attrib != EGL_NONE; attrib += 2) {
+      LOGD("eglChooseConfig %s(%.4X): %d \n", ATTRIBUTE_NAMES[attrib[0] - EGL_BUFFER_SIZE], attrib[0], attrib[1]);
+      if (EGL_BUFFER_SIZE > attrib[0] || EGL_CONFORMANT < attrib[0])
+         LOGD("eglChooseConfig invalid config attrib: 0x%.4X=%d \n", attrib[0], attrib[1]);
+   }
+
+   int numAttributes = 0;
+   int numConfigs =  NELEM(gConfigs);
+   uint32_t possibleMatch = (1<<numConfigs)-1;
+   while (possibleMatch && *attrib_list != EGL_NONE) {
+      numAttributes++;
+      EGLint attr = *attrib_list++;
+      EGLint val  = *attrib_list++;
+      for (int i=0 ; possibleMatch && i<numConfigs ; i++) {
+         if (!(possibleMatch & (1<<i)))
+            continue;
+         if (isAttributeMatching(i, attr, val) == 0) {
+            LOGD("!isAttributeMatching config(%d) %s=%d \n", i, ATTRIBUTE_NAMES[attr - EGL_BUFFER_SIZE], val);
+            possibleMatch &= ~(1<<i);
+         }
+      }
+   }
+
+   LOGD("eglChooseConfig possibleMatch=%.4X \n", possibleMatch);
+
+   // now, handle the attributes which have a useful default value
+   for (size_t j=0 ; possibleMatch && j<NELEM(config_defaults) ; j++) {
+      // see if this attribute was specified, if not, apply its
+      // default value
+      if (binarySearch<config_pair_t>(
+               (config_pair_t const*)attrib_list,
+               0, numAttributes-1,
+               config_defaults[j].key) < 0) {
+         for (int i=0 ; possibleMatch && i<numConfigs ; i++) {
+            if (!(possibleMatch & (1<<i)))
+               continue;
+            if (isAttributeMatching(i,
+                                    config_defaults[j].key,
+                                    config_defaults[j].value) == 0) {
+               possibleMatch &= ~(1<<i);
+            }
+         }
+      }
+   }
+
+   // return the configurations found
+   int n=0;
+   if (possibleMatch) {
+      if (configs) {
+         for (int i=0 ; config_size && i<numConfigs ; i++) {
+            if (possibleMatch & (1<<i)) {
+               *configs++ = (EGLConfig)i;
+               config_size--;
+               n++;
+            }
+         }
+      } else {
+         for (int i=0 ; i<numConfigs ; i++) {
+            if (possibleMatch & (1<<i)) {
+               n++;
+            }
+         }
+      }
+   }
+   *num_config = n;
+   LOGD("\n***\n***\n num_config==%d \n***\n***\n", *num_config);
+   return EGL_TRUE;
+}
+
+EGLBoolean eglGetConfigAttrib(EGLDisplay dpy, EGLConfig config,
+                              EGLint attribute, EGLint *value)
+{
+   puts("agl2:eglGetConfigAttrib");
+   if (egl_display_t::is_valid(dpy) == EGL_FALSE)
+      return setError(EGL_BAD_DISPLAY, EGL_FALSE);
+
+   return getConfigAttrib(dpy, config, attribute, value);
+}
+
+// ----------------------------------------------------------------------------
+// surfaces
+// ----------------------------------------------------------------------------
+
+EGLSurface eglCreateWindowSurface(  EGLDisplay dpy, EGLConfig config,
+                                    NativeWindowType window,
+                                    const EGLint *attrib_list)
+{
+   puts("agl2:eglCreateWindowSurface");
+   return createWindowSurface(dpy, config, window, attrib_list);
+}
+
+EGLSurface eglCreatePixmapSurface(  EGLDisplay dpy, EGLConfig config,
+                                    NativePixmapType pixmap,
+                                    const EGLint *attrib_list)
+{
+   puts("agl2:eglCreatePixmapSurface");
+   return createPixmapSurface(dpy, config, pixmap, attrib_list);
+}
+
+EGLSurface eglCreatePbufferSurface( EGLDisplay dpy, EGLConfig config,
+                                    const EGLint *attrib_list)
+{
+   puts("agl2:eglCreatePbufferSurface");
+   return createPbufferSurface(dpy, config, attrib_list);
+}
+
+EGLBoolean eglDestroySurface(EGLDisplay dpy, EGLSurface eglSurface)
+{
+   puts("agl2:eglDestroySurface");
+   if (egl_display_t::is_valid(dpy) == EGL_FALSE)
+      return setError(EGL_BAD_DISPLAY, EGL_FALSE);
+   if (eglSurface != EGL_NO_SURFACE) {
+      egl_surface_t* surface( static_cast<egl_surface_t*>(eglSurface) );
+      if (!surface->isValid())
+         return setError(EGL_BAD_SURFACE, EGL_FALSE);
+      if (surface->dpy != dpy)
+         return setError(EGL_BAD_DISPLAY, EGL_FALSE);
+      if (surface->ctx) {
+         // FIXME: this surface is current check what the spec says
+         surface->disconnect();
+         surface->ctx = 0;
+      }
+      delete surface;
+   }
+   return EGL_TRUE;
+}
+
+EGLBoolean eglQuerySurface( EGLDisplay dpy, EGLSurface eglSurface,
+                            EGLint attribute, EGLint *value)
+{
+   puts("agl2:eglQuerySurface");
+   if (egl_display_t::is_valid(dpy) == EGL_FALSE)
+      return setError(EGL_BAD_DISPLAY, EGL_FALSE);
+   egl_surface_t* surface = static_cast<egl_surface_t*>(eglSurface);
+   if (!surface->isValid())
+      return setError(EGL_BAD_SURFACE, EGL_FALSE);
+   if (surface->dpy != dpy)
+      return setError(EGL_BAD_DISPLAY, EGL_FALSE);
+
+   EGLBoolean ret = EGL_TRUE;
+   switch (attribute) {
+   case EGL_CONFIG_ID:
+      ret = getConfigAttrib(dpy, surface->config, EGL_CONFIG_ID, value);
+      break;
+   case EGL_WIDTH:
+      *value = surface->getWidth();
+      break;
+   case EGL_HEIGHT:
+      *value = surface->getHeight();
+      break;
+   case EGL_LARGEST_PBUFFER:
+      // not modified for a window or pixmap surface
+      break;
+   case EGL_TEXTURE_FORMAT:
+      *value = EGL_NO_TEXTURE;
+      break;
+   case EGL_TEXTURE_TARGET:
+      *value = EGL_NO_TEXTURE;
+      break;
+   case EGL_MIPMAP_TEXTURE:
+      *value = EGL_FALSE;
+      break;
+   case EGL_MIPMAP_LEVEL:
+      *value = 0;
+      break;
+   case EGL_RENDER_BUFFER:
+      // TODO: return the real RENDER_BUFFER here
+      *value = EGL_BACK_BUFFER;
+      break;
+   case EGL_HORIZONTAL_RESOLUTION:
+      // pixel/mm * EGL_DISPLAY_SCALING
+      *value = surface->getHorizontalResolution();
+      break;
+   case EGL_VERTICAL_RESOLUTION:
+      // pixel/mm * EGL_DISPLAY_SCALING
+      *value = surface->getVerticalResolution();
+      break;
+   case EGL_PIXEL_ASPECT_RATIO: {
+      // w/h * EGL_DISPLAY_SCALING
+      int wr = surface->getHorizontalResolution();
+      int hr = surface->getVerticalResolution();
+      *value = (wr * EGL_DISPLAY_SCALING) / hr;
+   }
+   break;
+   case EGL_SWAP_BEHAVIOR:
+      *value = surface->getSwapBehavior();
+      break;
+   default:
+      ret = setError(EGL_BAD_ATTRIBUTE, EGL_FALSE);
+   }
+   return ret;
+}
+
+EGLContext eglCreateContext(EGLDisplay dpy, EGLConfig config,
+                            EGLContext share_list, const EGLint *attrib_list)
+{
+   puts("agl2:eglCreateContext");
+   if (egl_display_t::is_valid(dpy) == EGL_FALSE)
+      return setError(EGL_BAD_DISPLAY, EGL_NO_SURFACE);
+
+   GLES2Context* gl = new GLES2Context();//ogles_init(sizeof(egl_context_t));
+   if (!gl) return setError(EGL_BAD_ALLOC, EGL_NO_CONTEXT);
+
+   //egl_context_t* c = static_cast<egl_context_t*>(gl->rasterizer.base);
+   egl_context_t * c = &gl->egl;
+   c->flags = egl_context_t::NEVER_CURRENT;
+   c->dpy = dpy;
+   c->config = config;
+   c->read = 0;
+   c->draw = 0;
+   
+   c->frame = 0;
+   c->lastSwapTime = clock();
+   c->accumulateSeconds = 0;
+   return (EGLContext)gl;
+}
+
+EGLBoolean eglDestroyContext(EGLDisplay dpy, EGLContext ctx)
+{
+   puts("agl2:eglDestroyContext");
+   if (egl_display_t::is_valid(dpy) == EGL_FALSE)
+      return setError(EGL_BAD_DISPLAY, EGL_FALSE);
+   egl_context_t* c = egl_context_t::context(ctx);
+   if (c->flags & egl_context_t::IS_CURRENT)
+      setGlThreadSpecific(0);
+   //ogles_uninit((GLES2Context*)ctx);
+   delete (GLES2Context*)ctx;
+   return EGL_TRUE;
+}
+
+EGLBoolean eglMakeCurrent(  EGLDisplay dpy, EGLSurface draw,
+                            EGLSurface read, EGLContext ctx)
+{
+   puts("agl2:eglMakeCurrent");
+   if (egl_display_t::is_valid(dpy) == EGL_FALSE)
+      return setError(EGL_BAD_DISPLAY, EGL_FALSE);
+   if (draw) {
+      egl_surface_t* s = (egl_surface_t*)draw;
+      if (!s->isValid())
+         return setError(EGL_BAD_SURFACE, EGL_FALSE);
+      if (s->dpy != dpy)
+         return setError(EGL_BAD_DISPLAY, EGL_FALSE);
+      // TODO: check that draw is compatible with the context
+   }
+   if (read && read!=draw) {
+      egl_surface_t* s = (egl_surface_t*)read;
+      if (!s->isValid())
+         return setError(EGL_BAD_SURFACE, EGL_FALSE);
+      if (s->dpy != dpy)
+         return setError(EGL_BAD_DISPLAY, EGL_FALSE);
+      // TODO: check that read is compatible with the context
+   }
+
+   EGLContext current_ctx = EGL_NO_CONTEXT;
+
+   if ((read == EGL_NO_SURFACE && draw == EGL_NO_SURFACE) && (ctx != EGL_NO_CONTEXT))
+      return setError(EGL_BAD_MATCH, EGL_FALSE);
+
+   if ((read != EGL_NO_SURFACE || draw != EGL_NO_SURFACE) && (ctx == EGL_NO_CONTEXT))
+      return setError(EGL_BAD_MATCH, EGL_FALSE);
+
+   if (ctx == EGL_NO_CONTEXT) {
+      // if we're detaching, we need the current context
+      current_ctx = (EGLContext)getGlThreadSpecific();
+   } else {
+      egl_context_t* c = egl_context_t::context(ctx);
+      egl_surface_t* d = (egl_surface_t*)draw;
+      egl_surface_t* r = (egl_surface_t*)read;
+      if ((d && d->ctx && d->ctx != ctx) ||
+            (r && r->ctx && r->ctx != ctx)) {
+         // one of the surface is bound to a context in another thread
+         return setError(EGL_BAD_ACCESS, EGL_FALSE);
+      }
+   }
+
+   GLES2Context* gl = (GLES2Context*)ctx;
+   if (makeCurrent(gl) == 0) {
+      if (ctx) {
+         egl_context_t* c = egl_context_t::context(ctx);
+         egl_surface_t* d = (egl_surface_t*)draw;
+         egl_surface_t* r = (egl_surface_t*)read;
+
+         if (c->draw) {
+            egl_surface_t* s = reinterpret_cast<egl_surface_t*>(c->draw);
+            s->disconnect();
+         }
+         if (c->read) {
+            // FIXME: unlock/disconnect the read surface too
+         }
+
+         c->draw = draw;
+         c->read = read;
+
+         if (c->flags & egl_context_t::NEVER_CURRENT) {
+            c->flags &= ~egl_context_t::NEVER_CURRENT;
+            GLint w = 0;
+            GLint h = 0;
+            if (draw) {
+               w = d->getWidth();
+               h = d->getHeight();
+            }
+            gl->rasterizer.interface.Viewport(&gl->rasterizer.interface, 0, 0, w, h);
+            //ogles_surfaceport(gl, 0, 0);
+            //ogles_viewport(gl, 0, 0, w, h);
+            //ogles_scissor(gl, 0, 0, w, h);
+         }
+         if (d) {
+            if (d->connect() == EGL_FALSE) {
+               return EGL_FALSE;
+            }
+            d->ctx = ctx;
+            d->bindDrawSurface(gl);
+         }
+         if (r) {
+            // FIXME: lock/connect the read surface too
+            r->ctx = ctx;
+            r->bindReadSurface(gl);
+         }
+      } else {
+         // if surfaces were bound to the context bound to this thread
+         // mark then as unbound.
+         if (current_ctx) {
+            egl_context_t* c = egl_context_t::context(current_ctx);
+            egl_surface_t* d = (egl_surface_t*)c->draw;
+            egl_surface_t* r = (egl_surface_t*)c->read;
+            if (d) {
+               c->draw = 0;
+               d->ctx = EGL_NO_CONTEXT;
+               d->disconnect();
+            }
+            if (r) {
+               c->read = 0;
+               r->ctx = EGL_NO_CONTEXT;
+               // FIXME: unlock/disconnect the read surface too
+            }
+         }
+      }
+      return EGL_TRUE;
+   }
+   return setError(EGL_BAD_ACCESS, EGL_FALSE);
+}
+
+EGLContext eglGetCurrentContext(void)
+{
+   // eglGetCurrentContext returns the current EGL rendering context,
+   // as specified by eglMakeCurrent. If no context is current,
+   // EGL_NO_CONTEXT is returned.
+   return (EGLContext)getGlThreadSpecific();
+}
+
+EGLSurface eglGetCurrentSurface(EGLint readdraw)
+{
+   // eglGetCurrentSurface returns the read or draw surface attached
+   // to the current EGL rendering context, as specified by eglMakeCurrent.
+   // If no context is current, EGL_NO_SURFACE is returned.
+   EGLContext ctx = (EGLContext)getGlThreadSpecific();
+   if (ctx == EGL_NO_CONTEXT) return EGL_NO_SURFACE;
+   egl_context_t* c = egl_context_t::context(ctx);
+   if (readdraw == EGL_READ) {
+      return c->read;
+   } else if (readdraw == EGL_DRAW) {
+      return c->draw;
+   }
+   return setError(EGL_BAD_ATTRIBUTE, EGL_NO_SURFACE);
+}
+
+EGLDisplay eglGetCurrentDisplay(void)
+{
+   // eglGetCurrentDisplay returns the current EGL display connection
+   // for the current EGL rendering context, as specified by eglMakeCurrent.
+   // If no context is current, EGL_NO_DISPLAY is returned.
+   EGLContext ctx = (EGLContext)getGlThreadSpecific();
+   if (ctx == EGL_NO_CONTEXT) return EGL_NO_DISPLAY;
+   egl_context_t* c = egl_context_t::context(ctx);
+   return c->dpy;
+}
+
+EGLBoolean eglQueryContext( EGLDisplay dpy, EGLContext ctx,
+                            EGLint attribute, EGLint *value)
+{
+   if (egl_display_t::is_valid(dpy) == EGL_FALSE)
+      return setError(EGL_BAD_DISPLAY, EGL_FALSE);
+   egl_context_t* c = egl_context_t::context(ctx);
+   switch (attribute) {
+   case EGL_CONFIG_ID:
+      // Returns the ID of the EGL frame buffer configuration with
+      // respect to which the context was created
+      return getConfigAttrib(dpy, c->config, EGL_CONFIG_ID, value);
+   }
+   return setError(EGL_BAD_ATTRIBUTE, EGL_FALSE);
+}
+
+EGLBoolean eglWaitGL(void)
+{
+   return EGL_TRUE;
+}
+
+EGLBoolean eglWaitNative(EGLint engine)
+{
+   return EGL_TRUE;
+}
+
+EGLBoolean eglSwapBuffers(EGLDisplay dpy, EGLSurface draw)
+{
+   if (egl_display_t::is_valid(dpy) == EGL_FALSE)
+      return setError(EGL_BAD_DISPLAY, EGL_FALSE);
+
+   egl_surface_t* d = static_cast<egl_surface_t*>(draw);
+   if (!d->isValid())
+      return setError(EGL_BAD_SURFACE, EGL_FALSE);
+   if (d->dpy != dpy)
+      return setError(EGL_BAD_DISPLAY, EGL_FALSE);
+
+   // post the surface
+   d->swapBuffers();
+
+   // if it's bound to a context, update the buffer
+   if (d->ctx != EGL_NO_CONTEXT) {
+      d->bindDrawSurface((GLES2Context*)d->ctx);
+      // if this surface is also the read surface of the context
+      // it is bound to, make sure to update the read buffer as well.
+      // The EGL spec is a little unclear about this.
+      egl_context_t* c = egl_context_t::context(d->ctx);
+      if (c->read == draw) {
+         d->bindReadSurface((GLES2Context*)d->ctx);
+      }
+      clock_t time = clock();
+      float elapsed = (float)(time - c->lastSwapTime) / CLOCKS_PER_SEC;
+      c->accumulateSeconds += elapsed;
+      c->frame++;
+//      LOGD("agl2: eglSwapBuffers elapsed=%.2fms \n*", elapsed * 1000);
+      if (20 == c->frame) {
+         float avg = c->accumulateSeconds / c->frame;
+         LOGD("\n*\n* agl2: eglSwapBuffers %u frame avg fps=%.1f elapsed=%.2fms \n*",
+              c->frame, 1 / avg, avg * 1000);
+         c->frame = 0;
+         c->accumulateSeconds = 0;
+      }
+      c->lastSwapTime = time;
+   }
+
+   return EGL_TRUE;
+}
+
+EGLBoolean eglCopyBuffers(  EGLDisplay dpy, EGLSurface surface,
+                            NativePixmapType target)
+{
+   if (egl_display_t::is_valid(dpy) == EGL_FALSE)
+      return setError(EGL_BAD_DISPLAY, EGL_FALSE);
+   // TODO: eglCopyBuffers()
+   return EGL_FALSE;
+}
+
+EGLint eglGetError(void)
+{
+   return getError();
+}
+
+const char* eglQueryString(EGLDisplay dpy, EGLint name)
+{
+   if (egl_display_t::is_valid(dpy) == EGL_FALSE)
+      return setError(EGL_BAD_DISPLAY, (const char*)0);
+
+   switch (name) {
+   case EGL_VENDOR:
+      return gVendorString;
+   case EGL_VERSION:
+      return gVersionString;
+   case EGL_EXTENSIONS:
+      return gExtensionsString;
+   case EGL_CLIENT_APIS:
+      return gClientApiString;
+   }
+   return setError(EGL_BAD_PARAMETER, (const char *)0);
+}
+
+// ----------------------------------------------------------------------------
+// EGL 1.1
+// ----------------------------------------------------------------------------
+
+EGLBoolean eglSurfaceAttrib(
+   EGLDisplay dpy, EGLSurface surface, EGLint attribute, EGLint value)
+{
+   if (egl_display_t::is_valid(dpy) == EGL_FALSE)
+      return setError(EGL_BAD_DISPLAY, EGL_FALSE);
+   // TODO: eglSurfaceAttrib()
+   return setError(EGL_BAD_PARAMETER, EGL_FALSE);
+}
+
+EGLBoolean eglBindTexImage(
+   EGLDisplay dpy, EGLSurface surface, EGLint buffer)
+{
+   if (egl_display_t::is_valid(dpy) == EGL_FALSE)
+      return setError(EGL_BAD_DISPLAY, EGL_FALSE);
+   // TODO: eglBindTexImage()
+   return setError(EGL_BAD_PARAMETER, EGL_FALSE);
+}
+
+EGLBoolean eglReleaseTexImage(
+   EGLDisplay dpy, EGLSurface surface, EGLint buffer)
+{
+   if (egl_display_t::is_valid(dpy) == EGL_FALSE)
+      return setError(EGL_BAD_DISPLAY, EGL_FALSE);
+   // TODO: eglReleaseTexImage()
+   return setError(EGL_BAD_PARAMETER, EGL_FALSE);
+}
+
+EGLBoolean eglSwapInterval(EGLDisplay dpy, EGLint interval)
+{
+   if (egl_display_t::is_valid(dpy) == EGL_FALSE)
+      return setError(EGL_BAD_DISPLAY, EGL_FALSE);
+   // TODO: eglSwapInterval()
+   return EGL_TRUE;
+}
+
+// ----------------------------------------------------------------------------
+// EGL 1.2
+// ----------------------------------------------------------------------------
+
+EGLBoolean eglBindAPI(EGLenum api)
+{
+   if (api != EGL_OPENGL_ES_API)
+      return setError(EGL_BAD_PARAMETER, EGL_FALSE);
+   return EGL_TRUE;
+}
+
+EGLenum eglQueryAPI(void)
+{
+   return EGL_OPENGL_ES_API;
+}
+
+EGLBoolean eglWaitClient(void)
+{
+   glFinish();
+   return EGL_TRUE;
+}
+
+EGLBoolean eglReleaseThread(void)
+{
+   // TODO: eglReleaseThread()
+   return EGL_TRUE;
+}
+
+EGLSurface eglCreatePbufferFromClientBuffer(
+   EGLDisplay dpy, EGLenum buftype, EGLClientBuffer buffer,
+   EGLConfig config, const EGLint *attrib_list)
+{
+   if (egl_display_t::is_valid(dpy) == EGL_FALSE)
+      return setError(EGL_BAD_DISPLAY, EGL_NO_SURFACE);
+   // TODO: eglCreatePbufferFromClientBuffer()
+   return setError(EGL_BAD_PARAMETER, EGL_NO_SURFACE);
+}
+
+// ----------------------------------------------------------------------------
+// EGL_EGLEXT_VERSION 3
+// ----------------------------------------------------------------------------
+
+void (*eglGetProcAddress (const char *procname))()
+{
+   extention_map_t const * const map = gExtentionMap;
+   for (uint32_t i=0 ; i<NELEM(gExtentionMap) ; i++) {
+      if (!strcmp(procname, map[i].name)) {
+         return map[i].address;
+      }
+   }
+   return NULL;
+}
+
+EGLBoolean eglLockSurfaceKHR(EGLDisplay dpy, EGLSurface surface,
+                             const EGLint *attrib_list)
+{
+   EGLBoolean result = EGL_FALSE;
+   return result;
+}
+
+EGLBoolean eglUnlockSurfaceKHR(EGLDisplay dpy, EGLSurface surface)
+{
+   EGLBoolean result = EGL_FALSE;
+   return result;
+}
+
+EGLImageKHR eglCreateImageKHR(EGLDisplay dpy, EGLContext ctx, EGLenum target,
+                              EGLClientBuffer buffer, const EGLint *attrib_list)
+{
+   if (egl_display_t::is_valid(dpy) == EGL_FALSE) {
+      return setError(EGL_BAD_DISPLAY, EGL_NO_IMAGE_KHR);
+   }
+   if (ctx != EGL_NO_CONTEXT) {
+      return setError(EGL_BAD_CONTEXT, EGL_NO_IMAGE_KHR);
+   }
+   if (target != EGL_NATIVE_BUFFER_ANDROID) {
+      return setError(EGL_BAD_PARAMETER, EGL_NO_IMAGE_KHR);
+   }
+
+   android_native_buffer_t* native_buffer = (android_native_buffer_t*)buffer;
+
+   if (native_buffer->common.magic != ANDROID_NATIVE_BUFFER_MAGIC)
+      return setError(EGL_BAD_PARAMETER, EGL_NO_IMAGE_KHR);
+
+   if (native_buffer->common.version != sizeof(android_native_buffer_t))
+      return setError(EGL_BAD_PARAMETER, EGL_NO_IMAGE_KHR);
+
+   switch (native_buffer->format) {
+   case HAL_PIXEL_FORMAT_RGBA_8888:
+   case HAL_PIXEL_FORMAT_RGBX_8888:
+   case HAL_PIXEL_FORMAT_RGB_888:
+   case HAL_PIXEL_FORMAT_RGB_565:
+   case HAL_PIXEL_FORMAT_BGRA_8888:
+   case HAL_PIXEL_FORMAT_RGBA_5551:
+   case HAL_PIXEL_FORMAT_RGBA_4444:
+      break;
+   default:
+      return setError(EGL_BAD_PARAMETER, EGL_NO_IMAGE_KHR);
+   }
+
+   native_buffer->common.incRef(&native_buffer->common);
+   return (EGLImageKHR)native_buffer;
+}
+
+EGLBoolean eglDestroyImageKHR(EGLDisplay dpy, EGLImageKHR img)
+{
+   if (egl_display_t::is_valid(dpy) == EGL_FALSE) {
+      return setError(EGL_BAD_DISPLAY, EGL_FALSE);
+   }
+
+   android_native_buffer_t* native_buffer = (android_native_buffer_t*)img;
+
+   if (native_buffer->common.magic != ANDROID_NATIVE_BUFFER_MAGIC)
+      return setError(EGL_BAD_PARAMETER, EGL_FALSE);
+
+   if (native_buffer->common.version != sizeof(android_native_buffer_t))
+      return setError(EGL_BAD_PARAMETER, EGL_FALSE);
+
+   native_buffer->common.decRef(&native_buffer->common);
+
+   return EGL_TRUE;
+}
+
+// ----------------------------------------------------------------------------
+// ANDROID extensions
+// ----------------------------------------------------------------------------
+
+EGLBoolean eglSetSwapRectangleANDROID(EGLDisplay dpy, EGLSurface draw,
+                                      EGLint left, EGLint top, EGLint width, EGLint height)
+{
+   if (egl_display_t::is_valid(dpy) == EGL_FALSE)
+      return setError(EGL_BAD_DISPLAY, EGL_FALSE);
+
+   egl_surface_t* d = static_cast<egl_surface_t*>(draw);
+   if (!d->isValid())
+      return setError(EGL_BAD_SURFACE, EGL_FALSE);
+   if (d->dpy != dpy)
+      return setError(EGL_BAD_DISPLAY, EGL_FALSE);
+
+   // post the surface
+   d->setSwapRectangle(left, top, width, height);
+
+   return EGL_TRUE;
+}
diff --git a/opengl/libagl2/src/get.cpp b/opengl/libagl2/src/get.cpp
new file mode 100644
index 0000000..13c28ce
--- /dev/null
+++ b/opengl/libagl2/src/get.cpp
@@ -0,0 +1,79 @@
+#include "gles2context.h"
+
+static char const * const gVendorString     = "Android";
+static char const * const gRendererString   = "Android PixelFlinger2 0.0";
+static char const * const gVersionString    = "OpenGL ES 2.0";
+static char const * const gExtensionsString =
+//   "GL_OES_byte_coordinates "              // OK
+//   "GL_OES_fixed_point "                   // OK
+//   "GL_OES_single_precision "              // OK
+//   "GL_OES_read_format "                   // OK
+//   "GL_OES_compressed_paletted_texture "   // OK
+//   "GL_OES_draw_texture "                  // OK
+//   "GL_OES_matrix_get "                    // OK
+//   "GL_OES_query_matrix "                  // OK
+//   //        "GL_OES_point_size_array "              // TODO
+//   //        "GL_OES_point_sprite "                  // TODO
+//   "GL_OES_EGL_image "                     // OK
+//#ifdef GL_OES_compressed_ETC1_RGB8_texture
+//   "GL_OES_compressed_ETC1_RGB8_texture "  // OK
+//#endif
+//   "GL_ARB_texture_compression "           // OK
+//   "GL_ARB_texture_non_power_of_two "      // OK
+//   "GL_ANDROID_user_clip_plane "           // OK
+//   "GL_ANDROID_vertex_buffer_object "      // OK
+//   "GL_ANDROID_generate_mipmap "           // OK
+   ""
+   ;
+
+void glGetIntegerv(GLenum pname, GLint* params)
+{
+   switch (pname) {
+   case GL_MAX_TEXTURE_SIZE :
+      *params = 4096; // limit is in precision of texcoord calculation, which uses 16.16
+      break;
+   case GL_MAX_VERTEX_ATTRIBS:
+      *params = GGL_MAXVERTEXATTRIBS;
+      break;
+   case GL_MAX_VERTEX_UNIFORM_VECTORS:
+      *params = GGL_MAXVERTEXUNIFORMVECTORS;
+      break;
+   case GL_MAX_VARYING_VECTORS:
+      *params = GGL_MAXVARYINGVECTORS;
+      break;
+   case GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS:
+      *params = GGL_MAXCOMBINEDTEXTUREIMAGEUNITS;
+      break;
+   case GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS:
+      *params = GGL_MAXVERTEXTEXTUREIMAGEUNITS;
+      break;
+   case GL_MAX_TEXTURE_IMAGE_UNITS:
+      *params = GGL_MAXTEXTUREIMAGEUNITS;
+      break;
+   case GL_MAX_FRAGMENT_UNIFORM_VECTORS:
+      *params = GGL_MAXFRAGMENTUNIFORMVECTORS;
+      break;
+   case GL_ALIASED_LINE_WIDTH_RANGE:
+      *params = 1; // TODO: not implemented
+      break;
+   default:
+      LOGD("agl2: glGetIntegerv 0x%.4X", pname);
+      assert(0);
+   }
+}
+
+const GLubyte* glGetString(GLenum name)
+{
+   switch (name) {
+   case GL_VENDOR:
+      return (const GLubyte*)gVendorString;
+   case GL_RENDERER:
+      return (const GLubyte*)gRendererString;
+   case GL_VERSION:
+      return (const GLubyte*)gVersionString;
+   case GL_EXTENSIONS:
+      return (const GLubyte*)gExtensionsString;
+   }
+   assert(0); //(c, GL_INVALID_ENUM);
+   return 0;
+}
diff --git a/opengl/libagl2/src/gles2context.h b/opengl/libagl2/src/gles2context.h
new file mode 100644
index 0000000..cec0340
--- /dev/null
+++ b/opengl/libagl2/src/gles2context.h
@@ -0,0 +1,166 @@
+#define _SIZE_T_DEFINED_
+typedef unsigned int size_t;
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <EGL/egl.h>
+#include <EGL/eglext.h>
+#include <GLES/gl.h>
+#include <GLES/glext.h>
+
+#include <utils/threads.h>
+#include <pthread.h>
+
+#include <cutils/log.h>
+
+#include <assert.h>
+
+#ifdef __arm__
+#ifndef __location__
+#define __HIERALLOC_STRING_0__(s)   #s
+#define __HIERALLOC_STRING_1__(s)   __HIERALLOC_STRING_0__(s)
+#define __HIERALLOC_STRING_2__      __HIERALLOC_STRING_1__(__LINE__)
+#define __location__                __FILE__ ":" __HIERALLOC_STRING_2__
+#endif
+#undef assert
+#define assert(EXPR) { do { if (!(EXPR)) {LOGD("\n*\n*\n*\n* assert fail: '"#EXPR"' at "__location__"\n*\n*\n*\n*"); exit(EXIT_FAILURE); } } while (false); }
+//#define printf LOGD
+#else // #ifdef __arm__
+//#define LOGD printf
+#endif // #ifdef __arm__
+
+
+#include <pixelflinger2/pixelflinger2_format.h>
+#include <pixelflinger2/pixelflinger2.h>
+
+#include <map>
+
+typedef uint8_t                 GGLubyte;               // ub
+
+#define ggl_likely(x)   __builtin_expect(!!(x), 1)
+#define ggl_unlikely(x) __builtin_expect(!!(x), 0)
+
+#undef NELEM
+#define NELEM(x) (sizeof(x)/sizeof(*(x)))
+
+template<typename T>
+inline T max(T a, T b)
+{
+   return a<b ? b : a;
+}
+
+template<typename T>
+inline T min(T a, T b)
+{
+   return a<b ? a : b;
+}
+
+struct egl_context_t {
+   enum {
+      IS_CURRENT      =   0x00010000,
+      NEVER_CURRENT   =   0x00020000
+   };
+   uint32_t            flags;
+   EGLDisplay          dpy;
+   EGLConfig           config;
+   EGLSurface          read;
+   EGLSurface          draw;
+
+   unsigned frame;
+   clock_t lastSwapTime;
+   float accumulateSeconds;
+   
+   static inline egl_context_t* context(EGLContext ctx);
+};
+
+struct GLES2Context;
+
+#ifdef HAVE_ANDROID_OS
+#include <bionic_tls.h>
+// We have a dedicated TLS slot in bionic
+inline void setGlThreadSpecific(GLES2Context *value)
+{
+   ((uint32_t *)__get_tls())[TLS_SLOT_OPENGL] = (uint32_t)value;
+}
+inline GLES2Context* getGlThreadSpecific()
+{
+   return (GLES2Context *)(((unsigned *)__get_tls())[TLS_SLOT_OPENGL]);
+}
+#else
+extern pthread_key_t gGLKey;
+inline void setGlThreadSpecific(GLES2Context *value)
+{
+   pthread_setspecific(gGLKey, value);
+}
+inline GLES2Context* getGlThreadSpecific()
+{
+   return static_cast<GLES2Context*>(pthread_getspecific(gGLKey));
+}
+#endif
+
+struct VBO {
+   unsigned size;
+   GLenum usage;
+   void * data;
+};
+
+struct GLES2Context {
+   GGLContext rasterizer;
+   egl_context_t egl;
+   GGLInterface * iface; // shortcut to &rasterizer.interface
+
+   struct VertexState {
+      struct VertAttribPointer {
+         unsigned size; // number of values per vertex
+         GLenum type;  // data type
+         unsigned stride; // bytes
+         const void * ptr;
+bool normalized :
+         1;
+bool enabled :
+         1;
+      } attribs [GGL_MAXVERTEXATTRIBS];
+
+      VBO * vbo, * indices;
+      std::map<GLuint, VBO *> vbos;
+      GLuint free;
+
+      Vector4 defaultAttribs [GGL_MAXVERTEXATTRIBS];
+   } vert;
+
+   struct TextureState {
+      GGLTexture * tmus[GGL_MAXCOMBINEDTEXTUREIMAGEUNITS];
+      int sampler2tmu[GGL_MAXCOMBINEDTEXTUREIMAGEUNITS]; // sampler2tmu[sampler] is index of tmu, -1 means not used
+      unsigned active;
+      std::map<GLuint, GGLTexture *> textures;
+      GLuint free; // first possible free name
+      GGLTexture * tex2D, * texCube; // default textures
+      unsigned unpack;
+      
+      void UpdateSampler(GGLInterface * iface, unsigned tmu);
+   } tex;
+
+   GLES2Context();
+   void InitializeTextures();
+   void InitializeVertices();
+
+   ~GLES2Context();
+   void UninitializeTextures();
+   void UninitializeVertices();
+
+   static inline GLES2Context* get() {
+      return getGlThreadSpecific();
+   }
+};
+
+inline egl_context_t* egl_context_t::context(EGLContext ctx)
+{
+   GLES2Context* const gl = static_cast<GLES2Context*>(ctx);
+   return static_cast<egl_context_t*>(&gl->egl);
+}
+
+#define GLES2_GET_CONTEXT(ctx) GLES2Context * ctx = GLES2Context::get(); \
+                                 /*puts(__FUNCTION__);*/
+#define GLES2_GET_CONST_CONTEXT(ctx) GLES2Context * ctx = GLES2Context::get(); \
+                                       /*puts(__FUNCTION__);*/
diff --git a/opengl/libagl2/src/shader.cpp b/opengl/libagl2/src/shader.cpp
new file mode 100644
index 0000000..076e388
--- /dev/null
+++ b/opengl/libagl2/src/shader.cpp
@@ -0,0 +1,191 @@
+#include "gles2context.h"
+
+//#undef LOGD
+//#define LOGD(...)
+
+static inline GLuint s2n(gl_shader * s)
+{
+   return (GLuint)s ^ 0xaf3c532d;
+}
+
+static inline gl_shader * n2s(GLuint n)
+{
+   return (gl_shader *)(n ^ 0xaf3c532d);
+}
+
+static inline GLuint p2n(gl_shader_program * p)
+{
+   return (GLuint)p ^ 0x04dc18f9;
+}
+
+static inline gl_shader_program * n2p(GLuint n)
+{
+   return (gl_shader_program *)(n ^ 0x04dc18f9);
+}
+
+void glAttachShader(GLuint program, GLuint shader)
+{
+   GLES2_GET_CONST_CONTEXT(ctx);
+   ctx->iface->ShaderAttach(ctx->iface, n2p(program), n2s(shader));
+}
+
+void glBindAttribLocation(GLuint program, GLuint index, const GLchar* name)
+{
+   GLES2_GET_CONST_CONTEXT(ctx);
+   ctx->iface->ShaderAttributeBind(n2p(program), index, name);
+//   assert(0);
+}
+
+GLuint glCreateShader(GLenum type)
+{
+   GLES2_GET_CONST_CONTEXT(ctx);
+   return s2n(ctx->iface->ShaderCreate(ctx->iface, type));
+}
+
+GLuint glCreateProgram(void)
+{
+   GLES2_GET_CONST_CONTEXT(ctx);
+   return  p2n(ctx->iface->ShaderProgramCreate(ctx->iface));
+}
+
+void glCompileShader(GLuint shader)
+{
+   GLES2_GET_CONST_CONTEXT(ctx);
+   ctx->iface->ShaderCompile(ctx->iface, n2s(shader), NULL, NULL);
+}
+
+void glDeleteProgram(GLuint program)
+{
+   GLES2_GET_CONST_CONTEXT(ctx);
+   ctx->iface->ShaderProgramDelete(ctx->iface, n2p(program));
+}
+
+void glDeleteShader(GLuint shader)
+{
+   GLES2_GET_CONST_CONTEXT(ctx);
+   ctx->iface->ShaderDelete(ctx->iface, n2s(shader));
+}
+
+void glDetachShader(GLuint program, GLuint shader)
+{
+   GLES2_GET_CONST_CONTEXT(ctx);
+   ctx->iface->ShaderDetach(ctx->iface, n2p(program), n2s(shader));
+}
+
+GLint glGetAttribLocation(GLuint program, const GLchar* name)
+{
+   GLES2_GET_CONST_CONTEXT(ctx);
+   GLint location = ctx->iface->ShaderAttributeLocation(n2p(program), name);
+//   LOGD("\n*\n*\n* agl2: glGetAttribLocation program=%u name=%s location=%d \n*\n*",
+//        program, name, location);
+   return location;
+}
+
+void glGetProgramiv(GLuint program, GLenum pname, GLint* params)
+{
+   GLES2_GET_CONST_CONTEXT(ctx);
+   ctx->iface->ShaderProgramGetiv(n2p(program), pname, params);
+   LOGD("agl2: glGetProgramiv 0x%.4X=%d \n", pname, *params);
+}
+
+void glGetProgramInfoLog(GLuint program, GLsizei bufsize, GLsizei* length, GLchar* infolog)
+{
+   GLES2_GET_CONST_CONTEXT(ctx);
+   ctx->iface->ShaderProgramGetInfoLog(n2p(program), bufsize, length, infolog);
+}
+
+void glGetShaderiv(GLuint shader, GLenum pname, GLint* params)
+{
+   GLES2_GET_CONST_CONTEXT(ctx);
+   ctx->iface->ShaderGetiv(n2s(shader), pname, params);
+   LOGD("agl2: glGetShaderiv 0x%.4X=%d \n", pname, *params);
+}
+
+void glGetShaderInfoLog(GLuint shader, GLsizei bufsize, GLsizei* length, GLchar* infolog)
+{
+   GLES2_GET_CONST_CONTEXT(ctx);
+   ctx->iface->ShaderGetInfoLog(n2s(shader), bufsize, length, infolog);
+}
+
+int glGetUniformLocation(GLuint program, const GLchar* name)
+{
+   GLES2_GET_CONST_CONTEXT(ctx);
+   return ctx->iface->ShaderUniformLocation(n2p(program), name);
+}
+
+void glLinkProgram(GLuint program)
+{
+   GLES2_GET_CONST_CONTEXT(ctx);
+   GLboolean linked = ctx->iface->ShaderProgramLink(n2p(program), NULL);
+   assert(linked);
+}
+
+void glShaderSource(GLuint shader, GLsizei count, const GLchar** string, const GLint* length)
+{
+   GLES2_GET_CONST_CONTEXT(ctx);
+   ctx->iface->ShaderSource(n2s(shader), count, string, length);
+}
+
+void glUniform1f(GLint location, GLfloat x)
+{
+   GLES2_GET_CONST_CONTEXT(ctx);
+   int sampler = ctx->iface->ShaderUniform(ctx->rasterizer.CurrentProgram, location, 1, &x, GL_FLOAT);
+   assert(0 > sampler); // should be assigning to sampler
+}
+
+void glUniform1i(GLint location, GLint x)
+{
+   GLES2_GET_CONST_CONTEXT(ctx);
+   const float params[1] = {x};
+   int sampler = ctx->iface->ShaderUniform(ctx->rasterizer.CurrentProgram, location, 1, params, GL_INT);
+   if (0 <= sampler) {
+//      LOGD("\n*\n* agl2: glUniform1i updated sampler=%d tmu=%d location=%d\n*", sampler, x, location);
+      assert(0 <= x && GGL_MAXCOMBINEDTEXTUREIMAGEUNITS > x);
+//      LOGD("tmu%u: format=0x%.2X w=%u h=%u levels=%p", x, ctx->tex.tmus[x]->format, 
+//         ctx->tex.tmus[x]->width, ctx->tex.tmus[x]->height, ctx->tex.tmus[x]->format);
+      ctx->tex.sampler2tmu[sampler] = x;
+      ctx->tex.UpdateSampler(ctx->iface, x);
+   }
+}
+
+void glUniform2f(GLint location, GLfloat x, GLfloat y)
+{
+   GLES2_GET_CONST_CONTEXT(ctx);
+   const float params[4] = {x, y};
+   ctx->iface->ShaderUniform(ctx->rasterizer.CurrentProgram, location, 1, params, GL_FLOAT_VEC2);
+}
+
+void glUniform4f(GLint location, GLfloat x, GLfloat y, GLfloat z, GLfloat w)
+{
+   GLES2_GET_CONST_CONTEXT(ctx);
+   const float params[4] = {x, y, z, w};
+//   LOGD("agl2: glUniform4f location=%d %f,%f,%f,%f", location, x, y, z, w);
+   ctx->iface->ShaderUniform(ctx->rasterizer.CurrentProgram, location, 1, params, GL_FLOAT_VEC4);
+}
+
+void glUniformMatrix4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value)
+{
+   GLES2_GET_CONST_CONTEXT(ctx);
+//   const gl_shader_program * program = ctx->rasterizer.CurrentProgram;
+//   if (strstr(program->Shaders[MESA_SHADER_FRAGMENT]->Source, ").a;")) {
+//   LOGD("agl2: glUniformMatrix4fv location=%d count=%d transpose=%d", location, count, transpose);
+//   for (unsigned i = 0; i < 4; i++)
+//      LOGD("agl2: glUniformMatrix4fv %.2f \t %.2f \t %.2f \t %.2f", value[i * 4 + 0],
+//           value[i * 4 + 1], value[i * 4 + 2], value[i * 4 + 3]);
+//   }
+   ctx->iface->ShaderUniformMatrix(ctx->rasterizer.CurrentProgram, 4, 4, location, count, transpose, value);
+//   while (true)
+//      ;
+//   assert(0);
+}
+
+void glUseProgram(GLuint program)
+{
+   GLES2_GET_CONST_CONTEXT(ctx);
+//   LOGD("\n*\n*\n* agl2: glUseProgram %d \n*\n*\n*", program);
+   ctx->iface->ShaderUse(ctx->iface, n2p(program));
+   ctx->iface->ShaderUniformGetSamplers(n2p(program), ctx->tex.sampler2tmu);
+   for (unsigned i = 0; i < GGL_MAXCOMBINEDTEXTUREIMAGEUNITS; i++)
+      if (0 <= ctx->tex.sampler2tmu[i])
+         ctx->iface->SetSampler(ctx->iface, i, ctx->tex.tmus[ctx->tex.sampler2tmu[i]]);
+}
diff --git a/opengl/libagl2/src/state.cpp b/opengl/libagl2/src/state.cpp
new file mode 100644
index 0000000..22e73fa
--- /dev/null
+++ b/opengl/libagl2/src/state.cpp
@@ -0,0 +1,129 @@
+#include "gles2context.h"
+
+GLES2Context::GLES2Context()
+{
+   memset(this, 0, sizeof *this);
+
+   assert((void *)&rasterizer == &rasterizer.interface);
+   InitializeGGLState(&rasterizer.interface);
+   iface = &rasterizer.interface;
+   printf("gl->rasterizer.PickScanLine(%p) = %p \n", &rasterizer.PickScanLine, rasterizer.PickScanLine);
+   assert(rasterizer.PickRaster);
+   assert(rasterizer.PickScanLine);
+
+   InitializeTextures();
+   InitializeVertices();
+}
+
+GLES2Context::~GLES2Context()
+{
+   UninitializeTextures();
+   UninitializeVertices();
+   UninitializeGGLState(&rasterizer.interface);
+}
+
+void glBlendColor(GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha)
+{
+   GLES2_GET_CONST_CONTEXT(ctx);
+   ctx->iface->BlendColor(ctx->iface, red, green, blue, alpha);
+}
+
+void glBlendEquation( GLenum mode )
+{
+   GLES2_GET_CONST_CONTEXT(ctx);
+   ctx->iface->BlendEquationSeparate(ctx->iface, mode, mode);
+}
+
+void glBlendEquationSeparate(GLenum modeRGB, GLenum modeAlpha)
+{
+   GLES2_GET_CONST_CONTEXT(ctx);
+   ctx->iface->BlendEquationSeparate(ctx->iface, modeRGB, modeAlpha);
+}
+
+void glBlendFunc(GLenum sfactor, GLenum dfactor)
+{
+   GLES2_GET_CONST_CONTEXT(ctx);
+   ctx->iface->BlendFuncSeparate(ctx->iface, sfactor, dfactor, sfactor, dfactor);
+}
+
+void glBlendFuncSeparate(GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha)
+{
+   GLES2_GET_CONST_CONTEXT(ctx);
+   ctx->iface->BlendFuncSeparate(ctx->iface, srcRGB, dstRGB, srcAlpha, dstAlpha);
+}
+
+void glClear(GLbitfield mask)
+{
+   GLES2_GET_CONST_CONTEXT(ctx);
+   ctx->iface->Clear(ctx->iface, mask);
+}
+
+void glClearColor(GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha)
+{
+   GLES2_GET_CONST_CONTEXT(ctx);
+   ctx->iface->ClearColor(ctx->iface, red, green, blue, alpha);
+}
+
+void glClearDepthf(GLclampf depth)
+{
+   GLES2_GET_CONST_CONTEXT(ctx);
+   ctx->iface->ClearDepthf(ctx->iface, depth);
+}
+
+void glClearStencil(GLint s)
+{
+   GLES2_GET_CONST_CONTEXT(ctx);
+   ctx->iface->ClearStencil(ctx->iface, s);
+}
+
+void glCullFace(GLenum mode)
+{
+   GLES2_GET_CONST_CONTEXT(ctx);
+   ctx->iface->CullFace(ctx->iface, mode);
+}
+
+void glDisable(GLenum cap)
+{
+   GLES2_GET_CONST_CONTEXT(ctx);
+   ctx->iface->EnableDisable(ctx->iface, cap, false);
+}
+
+void glEnable(GLenum cap)
+{
+   GLES2_GET_CONST_CONTEXT(ctx);
+   ctx->iface->EnableDisable(ctx->iface, cap, true);
+}
+
+void glFinish(void)
+{
+   // do nothing
+}
+
+void glFrontFace(GLenum mode)
+{
+   GLES2_GET_CONST_CONTEXT(ctx);
+   ctx->iface->FrontFace(ctx->iface, mode);
+}
+
+void glFlush(void)
+{
+   // do nothing
+}
+
+void glHint(GLenum target, GLenum mode)
+{
+   // do nothing
+}
+
+void glScissor(GLint x, GLint y, GLsizei width, GLsizei height)
+{
+//   LOGD("agl2: glScissor not implemented x=%d y=%d width=%d height=%d", x, y, width, height);
+   //CALL_GL_API(glScissor, x, y, width, height);
+}
+
+void glViewport(GLint x, GLint y, GLsizei width, GLsizei height)
+{
+   GLES2_GET_CONST_CONTEXT(ctx);
+//   LOGD("agl2: glViewport x=%d y=%d width=%d height=%d", x, y, width, height);
+   ctx->iface->Viewport(ctx->iface, x, y, width, height);
+}
diff --git a/opengl/libagl2/src/texture.cpp b/opengl/libagl2/src/texture.cpp
new file mode 100644
index 0000000..4de1f16
--- /dev/null
+++ b/opengl/libagl2/src/texture.cpp
@@ -0,0 +1,534 @@
+#include "gles2context.h"
+
+//#undef LOGD
+//#define LOGD(...) 
+
+#define API_ENTRY
+#define CALL_GL_API(NAME,...) LOGD("?"#NAME); assert(0);
+#define CALL_GL_API_RETURN(NAME,...) LOGD("?"#NAME); assert(0); return 0;
+
+static inline GGLTexture * AllocTexture()
+{
+   GGLTexture * tex = (GGLTexture *)calloc(1, sizeof(GGLTexture));
+   tex->minFilter = GGLTexture::GGL_LINEAR; // should be NEAREST_ MIPMAP_LINEAR
+   tex->magFilter = GGLTexture::GGL_LINEAR;
+   return tex;
+}
+
+void GLES2Context::InitializeTextures()
+{
+   tex.textures = std::map<GLuint, GGLTexture *>(); // the entire struct has been zeroed in constructor
+   tex.tex2D = AllocTexture();
+   tex.textures[GL_TEXTURE_2D] = tex.tex2D;
+   tex.texCube = AllocTexture();
+   tex.textures[GL_TEXTURE_CUBE_MAP] = tex.texCube;
+   for (unsigned i = 0; i < GGL_MAXCOMBINEDTEXTUREIMAGEUNITS; i++) {
+      tex.tmus[i] = NULL;
+      tex.sampler2tmu[i] = NULL;
+   }
+
+   tex.active = 0;
+
+   tex.free = max(GL_TEXTURE_2D, GL_TEXTURE_CUBE_MAP) + 1;
+
+   tex.tex2D->format = GGL_PIXEL_FORMAT_RGBA_8888;
+   tex.tex2D->type = GL_TEXTURE_2D;
+   tex.tex2D->levelCount = 1;
+   tex.tex2D->wrapS = tex.tex2D->wrapT = GGLTexture::GGL_REPEAT;
+   tex.tex2D->minFilter = tex.tex2D->magFilter = GGLTexture::GGL_NEAREST;
+   tex.tex2D->width = tex.tex2D->height = 1;
+   tex.tex2D->levels = malloc(4);
+   *(unsigned *)tex.tex2D->levels = 0xff000000;
+
+
+   tex.texCube->format = GGL_PIXEL_FORMAT_RGBA_8888;
+   tex.texCube->type = GL_TEXTURE_CUBE_MAP;
+   tex.texCube->levelCount = 1;
+   tex.texCube->wrapS = tex.texCube->wrapT = GGLTexture::GGL_REPEAT;
+   tex.texCube->minFilter = tex.texCube->magFilter = GGLTexture::GGL_NEAREST;
+   tex.texCube->width = tex.texCube->height = 1;
+   tex.texCube->levels = malloc(4 * 6);
+   static unsigned texels [6] = {0xff0000ff, 0xff00ff00, 0xffff0000,
+                                 0xff00ffff, 0xffffff00, 0xffff00ff
+                                };
+   memcpy(tex.texCube->levels, texels, sizeof texels);
+
+   //texture.levelCount = GenerateMipmaps(texture.levels, texture.width, texture.height);
+
+   //    static unsigned texels [6] = {0xff0000ff, 0xff00ff00, 0xffff0000,
+   //    0xff00ffff, 0xffffff00, 0xffff00ff};
+   //    memcpy(texture.levels[0], texels, sizeof texels);
+   //    texture.format = GGL_PIXEL_FORMAT_RGBA_8888;
+   //    texture.width = texture.height = 1;
+   //texture.height /= 6;
+   //texture.type = GL_TEXTURE_CUBE_MAP;
+   
+   tex.unpack = 4;
+}
+
+void GLES2Context::TextureState::UpdateSampler(GGLInterface * iface, unsigned tmu)
+{
+   for (unsigned i = 0; i < GGL_MAXCOMBINEDTEXTUREIMAGEUNITS; i++)
+      if (tmu == sampler2tmu[i])
+         iface->SetSampler(iface, i, tmus[tmu]);
+}
+
+void GLES2Context::UninitializeTextures()
+{
+   for (std::map<GLuint, GGLTexture *>::iterator it = tex.textures.begin(); it != tex.textures.end(); it++) {
+      if (!it->second)
+         continue;
+      free(it->second->levels);
+      free(it->second);
+   }
+}
+
+static inline void GetFormatAndBytesPerPixel(const GLenum format, unsigned * bytesPerPixel,
+      GGLPixelFormat * texFormat)
+{
+   switch (format) {
+   case GL_ALPHA:
+      *texFormat = GGL_PIXEL_FORMAT_A_8;
+      *bytesPerPixel = 1;
+      break;
+   case GL_LUMINANCE:
+      *texFormat = GGL_PIXEL_FORMAT_L_8;
+      *bytesPerPixel = 1;
+      break;
+   case GL_LUMINANCE_ALPHA:
+      *texFormat = GGL_PIXEL_FORMAT_LA_88;
+      *bytesPerPixel = 2;
+      break;
+   case GL_RGB:
+      *texFormat = GGL_PIXEL_FORMAT_RGB_888;
+      *bytesPerPixel = 3;
+      break;
+   case GL_RGBA:
+      *texFormat = GGL_PIXEL_FORMAT_RGBA_8888;
+      *bytesPerPixel = 4;
+      break;
+
+      // internal formats to avoid conversion
+   case GL_UNSIGNED_SHORT_5_6_5:
+      *texFormat = GGL_PIXEL_FORMAT_RGB_565;
+      *bytesPerPixel = 2;
+      break;
+
+   default:
+      assert(0);
+      return;
+   }
+}
+
+static inline void CopyTexture(char * dst, const char * src, const unsigned bytesPerPixel,
+                               const unsigned sx, const unsigned sy,  const unsigned sw,
+                               const unsigned dx, const unsigned dy, const unsigned dw,
+                               const unsigned w, const unsigned h)
+{
+   const unsigned bpp = bytesPerPixel;
+   if (dw == sw && dw == w && sx == 0 && dx == 0)
+      memcpy(dst + dy * dw * bpp, src + sy * sw * bpp, w * h * bpp);
+   else
+      for (unsigned y = 0; y < h; y++)
+         memcpy(dst + ((dy + y) * dw + dx) * bpp, src + ((sy + y) * sw + sx) * bpp, w * bpp); 
+}
+
+void glActiveTexture(GLenum texture)
+{
+   GLES2_GET_CONST_CONTEXT(ctx);
+   unsigned index = texture - GL_TEXTURE0;
+   assert(NELEM(ctx->tex.tmus) > index);
+//   LOGD("agl2: glActiveTexture %u", index);
+   ctx->tex.active = index;
+}
+
+void glBindTexture(GLenum target, GLuint texture)
+{
+   GLES2_GET_CONST_CONTEXT(ctx);
+//   LOGD("agl2: glBindTexture target=0x%.4X texture=%u active=%u", target, texture, ctx->tex.active);
+   std::map<GLuint, GGLTexture *>::iterator it = ctx->tex.textures.find(texture);
+   GGLTexture * tex = NULL;
+   if (it != ctx->tex.textures.end()) {
+      tex = it->second;
+      if (!tex) {
+         tex = AllocTexture();
+         tex->type = target;
+         it->second = tex;
+//         LOGD("agl2: glBindTexture allocTexture");
+      }
+//      else
+//         LOGD("agl2: glBindTexture bind existing texture");
+      assert(target == tex->type);
+   } else if (0 == texture) {
+      if (GL_TEXTURE_2D == target)
+      {
+         tex = ctx->tex.tex2D;
+//         LOGD("agl2: glBindTexture bind default tex2D");
+      }
+      else if (GL_TEXTURE_CUBE_MAP == target)
+      {
+         tex = ctx->tex.texCube;
+//         LOGD("agl2: glBindTexture bind default texCube");
+      }
+      else
+         assert(0);
+   } else {
+      if (texture <= ctx->tex.free)
+         ctx->tex.free = texture + 1;
+      tex = AllocTexture();
+      tex->type = target;
+      ctx->tex.textures[texture] = tex;
+//      LOGD("agl2: glBindTexture new texture=%u", texture);
+   }
+   ctx->tex.tmus[ctx->tex.active] = tex;
+//   LOGD("agl2: glBindTexture format=0x%.2X w=%u h=%u levels=%p", tex->format,
+//      tex->width, tex->height, tex->levels);
+   ctx->tex.UpdateSampler(ctx->iface, ctx->tex.active);
+}
+
+void API_ENTRY(glCompressedTexImage2D)(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const GLvoid* data)
+{
+   CALL_GL_API(glCompressedTexImage2D, target, level, internalformat, width, height, border, imageSize, data);
+}
+
+void API_ENTRY(glCompressedTexSubImage2D)(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const GLvoid* data)
+{
+   CALL_GL_API(glCompressedTexSubImage2D, target, level, xoffset, yoffset, width, height, format, imageSize, data);
+}
+
+void glCopyTexImage2D(GLenum target, GLint level, GLenum internalformat,
+                      GLint x, GLint y, GLsizei width, GLsizei height, GLint border)
+{
+   GLES2_GET_CONST_CONTEXT(ctx);
+//   LOGD("agl2: glCopyTexImage2D target=0x%.4X internalformat=0x%.4X", target, internalformat);
+//   LOGD("x=%d y=%d width=%d height=%d border=%d level=%d ", x, y, width, height, border, level);
+   assert(0 == border);
+   assert(0 == level);
+   unsigned bytesPerPixel = 0;
+   GGLPixelFormat texFormat = GGL_PIXEL_FORMAT_UNKNOWN;
+   GetFormatAndBytesPerPixel(internalformat, &bytesPerPixel, &texFormat);
+
+   assert(texFormat == ctx->rasterizer.frameSurface.format);
+//   LOGD("texFormat=0x%.2X bytesPerPixel=%d \n", texFormat, bytesPerPixel);
+   unsigned offset = 0, size = width * height * bytesPerPixel, totalSize = size;
+
+   assert(ctx->tex.tmus[ctx->tex.active]);
+   assert(y + height <= ctx->rasterizer.frameSurface.height);
+   assert(x + width <= ctx->rasterizer.frameSurface.width);
+   GGLTexture & tex = *ctx->tex.tmus[ctx->tex.active];
+   tex.width = width;
+   tex.height = height;
+   tex.levelCount = 1;
+   tex.format = texFormat;
+   switch (target) {
+   case GL_TEXTURE_2D:
+      tex.levels = realloc(tex.levels, totalSize);
+      CopyTexture((char *)tex.levels, (const char *)ctx->rasterizer.frameSurface.data, bytesPerPixel,
+                  x, y, ctx->rasterizer.frameSurface.width, 0, 0, width, width, height);
+      break;
+   default:
+      assert(0);
+      return;
+   }
+   ctx->tex.UpdateSampler(ctx->iface, ctx->tex.active);
+}
+
+void glCopyTexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height)
+{
+   // x, y are src offset
+   // xoffset and yoffset are dst offset
+   GLES2_GET_CONST_CONTEXT(ctx);
+//   LOGD("agl2: glCopyTexSubImage2D target=0x%.4X level=%d", target, level);
+//   LOGD("xoffset=%d yoffset=%d x=%d y=%d width=%d height=%d", xoffset, yoffset, x, y, width, height);
+   assert(0 == level);
+
+   unsigned bytesPerPixel = 4;
+   unsigned offset = 0, size = width * height * bytesPerPixel, totalSize = size;
+
+   assert(ctx->tex.tmus[ctx->tex.active]);
+   GGLTexture & tex = *ctx->tex.tmus[ctx->tex.active];
+
+   assert(tex.format == ctx->rasterizer.frameSurface.format);
+   assert(GGL_PIXEL_FORMAT_RGBA_8888 == tex.format);
+
+   const unsigned srcWidth = ctx->rasterizer.frameSurface.width;
+   const unsigned srcHeight = ctx->rasterizer.frameSurface.height;
+
+   assert(x >= 0 && y >= 0);
+   assert(xoffset >= 0 && yoffset >= 0);
+   assert(x + width <= srcWidth);
+   assert(y + height <= srcHeight);
+   assert(xoffset + width <= tex.width);
+   assert(yoffset + height <= tex.height);
+
+   switch (target) {
+   case GL_TEXTURE_2D:
+      CopyTexture((char *)tex.levels, (const char *)ctx->rasterizer.frameSurface.data, bytesPerPixel,
+                  x, y, srcWidth, xoffset, yoffset, tex.width, width, height);
+      break;
+   default:
+      assert(0);
+      return;
+   }
+   ctx->tex.UpdateSampler(ctx->iface, ctx->tex.active);
+}
+
+void glDeleteTextures(GLsizei n, const GLuint* textures)
+{
+   GLES2_GET_CONST_CONTEXT(ctx);
+   for (unsigned i = 0; i < n; i++) {
+      std::map<GLuint, GGLTexture *>::iterator it = ctx->tex.textures.find(textures[i]);
+      if (it == ctx->tex.textures.end())
+         continue;
+      ctx->tex.free = min(ctx->tex.free, textures[i]);
+      for (unsigned i = 0; i <  GGL_MAXCOMBINEDTEXTUREIMAGEUNITS; i++)
+         if (ctx->tex.tmus[i] == it->second) {
+            if (GL_TEXTURE_2D == it->second->type)
+               ctx->tex.tmus[i] = ctx->tex.tex2D;
+            else if (GL_TEXTURE_CUBE_MAP == it->second->type)
+               ctx->tex.tmus[i] = ctx->tex.texCube;
+            else
+               assert(0);
+            ctx->tex.UpdateSampler(ctx->iface, i);
+         }
+      if (it->second) {
+         free(it->second->levels);
+         free(it->second);
+      }
+      ctx->tex.textures.erase(it);
+   }
+}
+
+void glGenTextures(GLsizei n, GLuint* textures)
+{
+   GLES2_GET_CONST_CONTEXT(ctx);
+   for (unsigned i = 0; i < n; i++) {
+      textures[i] = 0;
+      for (ctx->tex.free; ctx->tex.free < 0xffffffffu; ctx->tex.free++)
+         if (ctx->tex.textures.find(ctx->tex.free) == ctx->tex.textures.end()) {
+            ctx->tex.textures[ctx->tex.free] = NULL;
+            textures[i] = ctx->tex.free;
+            ctx->tex.free++;
+            break;
+         }
+      assert(textures[i]);
+   }
+}
+
+void API_ENTRY(glGetTexParameterfv)(GLenum target, GLenum pname, GLfloat* params)
+{
+   CALL_GL_API(glGetTexParameterfv, target, pname, params);
+}
+void API_ENTRY(glGetTexParameteriv)(GLenum target, GLenum pname, GLint* params)
+{
+   CALL_GL_API(glGetTexParameteriv, target, pname, params);
+}
+
+GLboolean glIsTexture(GLuint texture)
+{
+   GLES2_GET_CONST_CONTEXT(ctx);
+   if (ctx->tex.textures.find(texture) == ctx->tex.textures.end())
+      return GL_FALSE;
+   else
+      return GL_TRUE;
+}
+
+void glPixelStorei(GLenum pname, GLint param)
+{
+   GLES2_GET_CONST_CONTEXT(ctx);
+   assert(GL_UNPACK_ALIGNMENT == pname);
+   assert(1 == param || 2 == param || 4 == param || 8 == param);
+//   LOGD("\n*\n* agl2: glPixelStorei not implemented pname=0x%.4X param=%d \n*", pname, param);
+   ctx->tex.unpack = param;
+//   CALL_GL_API(glPixelStorei, pname, param);
+}
+void glTexImage2D(GLenum target, GLint level, GLint internalformat, GLsizei width,
+                  GLsizei height, GLint border, GLenum format, GLenum type, const GLvoid* pixels)
+{
+   GLES2_GET_CONST_CONTEXT(ctx);
+//   LOGD("agl2: glTexImage2D internalformat=0x%.4X format=0x%.4X type=0x%.4X \n", internalformat, format, type);
+//   LOGD("width=%d height=%d border=%d level=%d pixels=%p \n", width, height, border, level, pixels);
+   switch (type) {
+   case GL_UNSIGNED_BYTE:
+      break;
+   case GL_UNSIGNED_SHORT_5_6_5:
+      internalformat = format = GL_UNSIGNED_SHORT_5_6_5;
+      assert(4 == ctx->tex.unpack);
+      break;
+   default:
+      assert(0);
+   }
+   assert(internalformat == format);
+   assert(0 == border);
+   if (0 != level) {
+      LOGD("agl2: glTexImage2D level=%d", level);
+      return;
+   }
+   unsigned bytesPerPixel = 0;
+   GGLPixelFormat texFormat = GGL_PIXEL_FORMAT_UNKNOWN;
+   GetFormatAndBytesPerPixel(format, &bytesPerPixel, &texFormat);
+
+   assert(texFormat && bytesPerPixel);
+//   LOGD("texFormat=0x%.2X bytesPerPixel=%d active=%u", texFormat, bytesPerPixel, ctx->tex.active);
+   unsigned offset = 0, size = width * height * bytesPerPixel, totalSize = size;
+
+   assert(ctx->tex.tmus[ctx->tex.active]);
+
+   GGLTexture & tex = *ctx->tex.tmus[ctx->tex.active];
+   tex.width = width;
+   tex.height = height;
+   tex.levelCount = 1;
+   tex.format = texFormat;
+
+   switch (target) {
+   case GL_TEXTURE_2D:
+      assert(GL_TEXTURE_2D == ctx->tex.tmus[ctx->tex.active]->type);
+      offset = 0;
+      break;
+      break;
+   case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
+   case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
+   case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
+   case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
+   case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
+   case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
+      assert(GL_TEXTURE_CUBE_MAP == ctx->tex.tmus[ctx->tex.active]->type);
+      assert(width == height);
+      offset = (target - GL_TEXTURE_CUBE_MAP_POSITIVE_X) * size;
+      totalSize = 6 * size;
+      break;
+   default:
+      assert(0);
+      return;
+   }
+
+   tex.levels = realloc(tex.levels, totalSize);
+   if (pixels)
+      CopyTexture((char *)tex.levels, (const char *)pixels, bytesPerPixel, 0, 0, width, 0, 0, width, width, height);
+   ctx->tex.UpdateSampler(ctx->iface, ctx->tex.active);
+}
+
+void glTexParameterf(GLenum target, GLenum pname, GLfloat param)
+{
+//   LOGD("agl2: glTexParameterf target=0x%.4X pname=0x%.4X param=%f", target, pname, param);
+   glTexParameteri(target, pname, param);
+}
+void API_ENTRY(glTexParameterfv)(GLenum target, GLenum pname, const GLfloat* params)
+{
+   CALL_GL_API(glTexParameterfv, target, pname, params);
+}
+void glTexParameteri(GLenum target, GLenum pname, GLint param)
+{
+   GLES2_GET_CONST_CONTEXT(ctx);
+//   LOGD("alg2: glTexParameteri target=0x%.0X pname=0x%.4X param=0x%.4X",
+//        target, pname, param);
+   assert(ctx->tex.tmus[ctx->tex.active]);
+   assert(target == ctx->tex.tmus[ctx->tex.active]->type);
+   GGLTexture & tex = *ctx->tex.tmus[ctx->tex.active];
+   switch (pname) {
+   case GL_TEXTURE_WRAP_S:
+   case GL_TEXTURE_WRAP_T:
+      GGLTexture::GGLTextureWrap wrap;
+      switch (param) {
+      case GL_REPEAT:
+         wrap = GGLTexture::GGL_REPEAT;
+         break;
+      case GL_CLAMP_TO_EDGE:
+         wrap = GGLTexture::GGL_CLAMP_TO_EDGE;
+         break;
+      case GL_MIRRORED_REPEAT:
+         wrap = GGLTexture::GGL_MIRRORED_REPEAT;
+         break;
+      default:
+         assert(0);
+         return;
+      }
+      if (GL_TEXTURE_WRAP_S == pname)
+         tex.wrapS = wrap;
+      else
+         tex.wrapT = wrap;
+      break;
+   case GL_TEXTURE_MIN_FILTER:
+      switch (param) {
+      case GL_NEAREST:
+         tex.minFilter = GGLTexture::GGL_NEAREST;
+         break;
+      case GL_LINEAR:
+         tex.minFilter = GGLTexture::GGL_LINEAR;
+         break;
+      case GL_NEAREST_MIPMAP_NEAREST:
+//         tex.minFilter = GGLTexture::GGL_NEAREST_MIPMAP_NEAREST;
+         break;
+      case GL_NEAREST_MIPMAP_LINEAR:
+//         tex.minFilter = GGLTexture::GGL_NEAREST_MIPMAP_LINEAR;
+         break;
+      case GL_LINEAR_MIPMAP_NEAREST:
+//         tex.minFilter = GGLTexture::GGL_LINEAR_MIPMAP_NEAREST;
+         break;
+      case GL_LINEAR_MIPMAP_LINEAR:
+//         tex.minFilter = GGLTexture::GGL_LINEAR_MIPMAP_LINEAR;
+         break;
+      default:
+         assert(0);
+         return;
+      }
+      break;
+   case GL_TEXTURE_MAG_FILTER:
+      switch (param) {
+      case GL_NEAREST:
+         tex.minFilter = GGLTexture::GGL_NEAREST;
+         break;
+      case GL_LINEAR:
+         tex.minFilter = GGLTexture::GGL_LINEAR;
+         break;
+      default:
+         assert(0);
+         return;
+      }
+      break;
+   default:
+      assert(0);
+      return;
+   }
+   // implementation restriction
+   if (tex.magFilter != tex.minFilter)
+      tex.magFilter = tex.minFilter = GGLTexture::GGL_LINEAR;
+   ctx->tex.UpdateSampler(ctx->iface, ctx->tex.active);
+}
+void API_ENTRY(glTexParameteriv)(GLenum target, GLenum pname, const GLint* params)
+{
+   CALL_GL_API(glTexParameteriv, target, pname, params);
+}
+void glTexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid* pixels)
+{
+   GLES2_GET_CONST_CONTEXT(ctx);
+//   LOGD("agl2: glTexSubImage2D target=0x%.4X level=%d xoffset=%d yoffset=%d width=%d height=%d format=0x%.4X type=0x%.4X pixels=%p",
+//        target, level, xoffset, yoffset, width, height, format, type, pixels);
+   assert(0 == level);
+   assert(target == ctx->tex.tmus[ctx->tex.active]->type);
+   switch (type) {
+   case GL_UNSIGNED_BYTE:
+      break;
+   case GL_UNSIGNED_SHORT_5_6_5:
+      format = GL_UNSIGNED_SHORT_5_6_5;
+      assert(4 == ctx->tex.unpack);
+      break;
+   default:
+      assert(0);
+   }
+   GGLTexture & tex = *ctx->tex.tmus[ctx->tex.active];
+   GGLPixelFormat texFormat = GGL_PIXEL_FORMAT_UNKNOWN;
+   unsigned bytesPerPixel = 0;
+   GetFormatAndBytesPerPixel(format, &bytesPerPixel, &texFormat);
+   assert(texFormat == tex.format);
+   assert(GL_UNSIGNED_BYTE == type);
+   switch (target) {
+   case GL_TEXTURE_2D:
+      CopyTexture((char *)tex.levels, (const char *)pixels, bytesPerPixel, 0, 0, width, xoffset,
+                  yoffset, tex.width, width, height);
+      break;
+   default:
+      assert(0);
+   }
+   ctx->tex.UpdateSampler(ctx->iface, ctx->tex.active);
+}
diff --git a/opengl/libagl2/src/vertex.cpp b/opengl/libagl2/src/vertex.cpp
new file mode 100644
index 0000000..021b82b
--- /dev/null
+++ b/opengl/libagl2/src/vertex.cpp
@@ -0,0 +1,373 @@
+#include "gles2context.h"
+
+//#undef LOGD
+//#define LOGD(...)
+
+void GLES2Context::InitializeVertices()
+{
+   vert.vbos = std::map<GLuint, VBO *>(); // the entire struct has been zeroed in constructor
+   vert.free = 1;
+   vert.vbo = NULL;
+   vert.indices = NULL;
+   for (unsigned i = 0; i < GGL_MAXVERTEXATTRIBS; i++)
+      vert.defaultAttribs[i] = Vector4(0,0,0,1);
+}
+
+void GLES2Context::UninitializeVertices()
+{
+   for (std::map<GLuint, VBO *>::iterator it = vert.vbos.begin(); it != vert.vbos.end(); it++) {
+      if (!it->second)
+         continue;
+      free(it->second->data);
+      free(it->second);
+   }
+}
+
+static inline void FetchElement(const GLES2Context * ctx, const unsigned index,
+                                const unsigned maxAttrib, VertexInput * elem)
+{
+   for (unsigned i = 0; i < maxAttrib; i++) {
+      {
+         unsigned size = 0;
+         if (ctx->vert.attribs[i].enabled) {
+            const char * ptr = (const char *)ctx->vert.attribs[i].ptr;
+            ptr += ctx->vert.attribs[i].stride * index;
+            memcpy(elem->attributes + i, ptr, ctx->vert.attribs[i].size * sizeof(float));
+            size = ctx->vert.attribs[i].size;
+//            LOGD("agl2: FetchElement %d attribs size=%d %.2f,%.2f,%.2f,%.2f", i, size, elem->attributes[i].x,
+//                 elem->attributes[i].y, elem->attributes[i].z, elem->attributes[i].w);
+         } else {
+//            LOGD("agl2: FetchElement %d default %.2f,%.2f,%.2f,%.2f", i, ctx->vert.defaultAttribs[i].x,
+//                 ctx->vert.defaultAttribs[i].y, ctx->vert.defaultAttribs[i].z, ctx->vert.defaultAttribs[i].w);
+         }
+
+         switch (size) {
+         case 0: // fall through
+            elem->attributes[i].x = ctx->vert.defaultAttribs[i].x;
+         case 1: // fall through
+            elem->attributes[i].y = ctx->vert.defaultAttribs[i].y;
+         case 2: // fall through
+            elem->attributes[i].z = ctx->vert.defaultAttribs[i].z;
+         case 3: // fall through
+            elem->attributes[i].w = ctx->vert.defaultAttribs[i].w;
+         case 4:
+            break;
+         default:
+            assert(0);
+            break;
+         }
+//         LOGD("agl2: FetchElement %d size=%d %.2f,%.2f,%.2f,%.2f", i, size, elem->attributes[i].x,
+//              elem->attributes[i].y, elem->attributes[i].z, elem->attributes[i].w);
+      }
+   }
+}
+
+template<typename IndexT> static void DrawElementsTriangles(const GLES2Context * ctx,
+      const unsigned count, const IndexT * indices, const unsigned maxAttrib)
+{
+   VertexInput v[3];
+   if (ctx->vert.indices)
+      indices = (IndexT *)((char *)ctx->vert.indices->data + (long)indices);
+   for (unsigned i = 0; i < count; i += 3) {
+      for (unsigned j = 0; j < 3; j++)
+         FetchElement(ctx, indices[i + j], maxAttrib, v + j);
+      ctx->iface->DrawTriangle(ctx->iface, v, v + 1, v + 2);
+   }
+}
+
+static void DrawArraysTriangles(const GLES2Context * ctx, const unsigned first,
+                                const unsigned count, const unsigned maxAttrib)
+{
+//   LOGD("agl: DrawArraysTriangles=%p", DrawArraysTriangles);
+   VertexInput v[3];
+   for (unsigned i = 2; i < count; i+=3) {
+      // TODO: fix order
+      FetchElement(ctx, first + i - 2, maxAttrib, v + 0);
+      FetchElement(ctx, first + i - 1, maxAttrib, v + 1);
+      FetchElement(ctx, first + i - 0, maxAttrib, v + 2);
+      ctx->iface->DrawTriangle(ctx->iface, v + 0, v + 1, v + 2);
+   }
+//   LOGD("agl: DrawArraysTriangles end");
+}
+
+template<typename IndexT> static void DrawElementsTriangleStrip(const GLES2Context * ctx,
+      const unsigned count, const IndexT * indices, const unsigned maxAttrib)
+{
+   VertexInput v[3];
+   if (ctx->vert.indices)
+      indices = (IndexT *)((char *)ctx->vert.indices->data + (long)indices);
+      
+//   LOGD("agl2: DrawElementsTriangleStrip");
+//   for (unsigned i = 0; i < count; i++)
+//      LOGD("indices[%d] = %d", i, indices[i]);
+
+   FetchElement(ctx, indices[0], maxAttrib, v + 0);
+   FetchElement(ctx, indices[1], maxAttrib, v + 1);
+   for (unsigned i = 2; i < count; i ++) {
+      FetchElement(ctx, indices[i], maxAttrib, v + i % 3);
+      ctx->iface->DrawTriangle(ctx->iface, v + (i - 2) % 3, v + (i - 1) % 3 , v + (i + 0) % 3);
+   }
+
+//   for (unsigned i = 2; i < count; i++) {
+//      FetchElement(ctx, indices[i - 2], maxAttrib, v + 0);
+//      FetchElement(ctx, indices[i - 1], maxAttrib, v + 1);
+//      FetchElement(ctx, indices[i - 0], maxAttrib, v + 2);
+//      ctx->iface->DrawTriangle(ctx->iface, v + 0, v + 1, v + 2);
+//   }
+}
+
+static void DrawArraysTriangleStrip(const GLES2Context * ctx, const unsigned first,
+                                    const unsigned count, const unsigned maxAttrib)
+{
+   VertexInput v[3];
+   FetchElement(ctx, first, maxAttrib, v + 0);
+   FetchElement(ctx, first + 1, maxAttrib, v + 1);
+   for (unsigned i = 2; i < count; i++) {
+      // TODO: fix order
+      FetchElement(ctx, first + i, maxAttrib, v + i % 3);
+      ctx->iface->DrawTriangle(ctx->iface, v + (i - 2) % 3, v + (i - 1) % 3 , v + (i + 0) % 3);
+   }
+}
+
+void glBindBuffer(GLenum target, GLuint buffer)
+{
+   GLES2_GET_CONST_CONTEXT(ctx);
+   VBO * vbo = NULL;
+   if (0 != buffer) {
+      std::map<GLuint, VBO *>::iterator it = ctx->vert.vbos.find(buffer);
+      if (it != ctx->vert.vbos.end()) {
+         vbo = it->second;
+         if (!vbo)
+            vbo = (VBO *)calloc(1, sizeof(VBO));
+         it->second = vbo;
+      } else
+         assert(0);
+   }
+   if (GL_ARRAY_BUFFER == target)
+      ctx->vert.vbo = vbo;
+   else if (GL_ELEMENT_ARRAY_BUFFER == target)
+      ctx->vert.indices = vbo;
+   else
+      assert(0);
+   assert(vbo || buffer == 0);
+//   LOGD("\n*\n glBindBuffer 0x%.4X=%d ", target, buffer);
+}
+
+void glBufferData(GLenum target, GLsizeiptr size, const GLvoid* data, GLenum usage)
+{
+   GLES2_GET_CONST_CONTEXT(ctx);
+   if (GL_ARRAY_BUFFER == target) {
+      assert(ctx->vert.vbo);
+      ctx->vert.vbo->data = realloc(ctx->vert.vbo->data, size);
+      ctx->vert.vbo->size = size;
+      ctx->vert.vbo->usage = usage;
+      if (data)
+         memcpy(ctx->vert.vbo->data, data, size);
+   } else if (GL_ELEMENT_ARRAY_BUFFER == target) {
+      assert(ctx->vert.indices);
+      ctx->vert.indices->data = realloc(ctx->vert.indices->data, size);
+      ctx->vert.indices->size = size;
+      ctx->vert.indices->usage = usage;
+      if (data)
+         memcpy(ctx->vert.indices->data, data, size);
+   } else
+      assert(0);
+//   LOGD("\n*\n glBufferData target=0x%.4X size=%u data=%p usage=0x%.4X \n",
+//        target, size, data, usage);
+}
+
+void glBufferSubData(GLenum target, GLintptr offset, GLsizeiptr size, const GLvoid* data)
+{
+   GLES2_GET_CONST_CONTEXT(ctx);
+   if (GL_ARRAY_BUFFER == target)
+   {
+      assert(ctx->vert.vbo);
+      assert(0 <= offset);
+      assert(0 <= size);
+      assert(offset + size <= ctx->vert.vbo->size);
+      memcpy((char *)ctx->vert.vbo->data + offset, data, size);
+   }
+   else
+      assert(0);
+}
+
+void glDeleteBuffers(GLsizei n, const GLuint* buffers)
+{
+   GLES2_GET_CONST_CONTEXT(ctx);
+   for (unsigned i = 0; i < n; i++) {
+      std::map<GLuint, VBO*>::iterator it = ctx->vert.vbos.find(buffers[i]);
+      if (it == ctx->vert.vbos.end())
+         continue;
+      ctx->vert.free = min(ctx->vert.free, buffers[i]);
+      if (it->second == ctx->vert.vbo)
+         ctx->vert.vbo = NULL;
+      else if (it->second == ctx->vert.indices)
+         ctx->vert.indices = NULL;
+      if (it->second) {
+         free(it->second->data);
+         free(it->second);
+      }
+   }
+}
+
+void glDisableVertexAttribArray(GLuint index)
+{
+   GLES2_GET_CONST_CONTEXT(ctx);
+   assert(GGL_MAXVERTEXATTRIBS > index);
+   ctx->vert.attribs[index].enabled = false;
+}
+
+void glDrawArrays(GLenum mode, GLint first, GLsizei count)
+{
+   GLES2_GET_CONST_CONTEXT(ctx);
+//   LOGD("agl2: glDrawArrays=%p", glDrawArrays);
+   assert(ctx->rasterizer.CurrentProgram);
+   assert(0 <= first);
+   int maxAttrib = -1;
+   ctx->iface->ShaderProgramGetiv(ctx->rasterizer.CurrentProgram, GL_ACTIVE_ATTRIBUTES, &maxAttrib);
+   assert(0 <= maxAttrib && GGL_MAXVERTEXATTRIBS >= maxAttrib);
+   switch (mode) {
+   case GL_TRIANGLE_STRIP:
+      DrawArraysTriangleStrip(ctx, first, count, maxAttrib);
+      break;
+   case GL_TRIANGLES:
+      DrawArraysTriangles(ctx, first, count, maxAttrib);
+      break;
+   default:
+      LOGE("agl2: glDrawArrays unsupported mode: 0x%.4X \n", mode);
+      assert(0);
+      break;
+   }
+//   LOGD("agl2: glDrawArrays end");
+}
+
+void glDrawElements(GLenum mode, GLsizei count, GLenum type, const GLvoid* indices)
+{
+   GLES2_GET_CONST_CONTEXT(ctx);
+//   LOGD("agl2: glDrawElements=%p mode=0x%.4X count=%d type=0x%.4X indices=%p",
+//        glDrawElements, mode, count, type, indices);
+   if (!ctx->rasterizer.CurrentProgram)
+      return;
+
+   int maxAttrib = -1;
+   ctx->iface->ShaderProgramGetiv(ctx->rasterizer.CurrentProgram, GL_ACTIVE_ATTRIBUTES, &maxAttrib);
+   assert(0 <= maxAttrib && GGL_MAXVERTEXATTRIBS >= maxAttrib);
+//   LOGD("agl2: glDrawElements mode=0x%.4X type=0x%.4X count=%d program=%p indices=%p \n",
+//        mode, type, count, ctx->rasterizer.CurrentProgram, indices);
+   switch (mode) {
+   case GL_TRIANGLES:
+      if (GL_UNSIGNED_SHORT == type)
+         DrawElementsTriangles<unsigned short>(ctx, count, (unsigned short *)indices, maxAttrib);
+      else
+         assert(0);
+      break;
+   case GL_TRIANGLE_STRIP:
+      if (GL_UNSIGNED_SHORT == type)
+         DrawElementsTriangleStrip<unsigned short>(ctx, count, (unsigned short *)indices, maxAttrib);
+      else
+         assert(0);
+      break;
+   default:
+      assert(0);
+   }
+//   LOGD("agl2: glDrawElements end");
+}
+
+void glEnableVertexAttribArray(GLuint index)
+{
+   GLES2_GET_CONST_CONTEXT(ctx);
+   ctx->vert.attribs[index].enabled = true;
+//   LOGD("agl2: glEnableVertexAttribArray %d \n", index);
+}
+
+void glGenBuffers(GLsizei n, GLuint* buffers)
+{
+   GLES2_GET_CONST_CONTEXT(ctx);
+   for (unsigned i = 0; i < n; i++) {
+      buffers[i] = 0;
+      for (ctx->vert.free; ctx->vert.free < 0xffffffffu; ctx->vert.free++) {
+         if (ctx->vert.vbos.find(ctx->vert.free) == ctx->vert.vbos.end()) {
+            ctx->vert.vbos[ctx->vert.free] = NULL;
+            buffers[i] = ctx->vert.free;
+//            LOGD("glGenBuffers %d \n", buffers[i]);
+            ctx->vert.free++;
+            break;
+         }
+      }
+      assert(buffers[i]);
+   }
+}
+
+void glVertexAttribPointer(GLuint index, GLint size, GLenum type, GLboolean normalized,
+                           GLsizei stride, const GLvoid* ptr)
+{
+   GLES2_GET_CONST_CONTEXT(ctx);
+   assert(GL_FLOAT == type);
+   assert(0 < size && 4 >= size);
+   ctx->vert.attribs[index].size = size;
+   ctx->vert.attribs[index].type = type;
+   ctx->vert.attribs[index].normalized = normalized;
+   if (0 == stride)
+      ctx->vert.attribs[index].stride = size * sizeof(float);
+   else if (stride > 0)
+      ctx->vert.attribs[index].stride = stride;
+   else
+      assert(0);
+//   LOGD("\n*\n*\n* agl2: glVertexAttribPointer program=%u index=%d size=%d stride=%d ptr=%p \n*\n*",
+//        unsigned(ctx->rasterizer.CurrentProgram) ^ 0x04dc18f9, index, size, stride, ptr);
+   if (ctx->vert.vbo)
+      ctx->vert.attribs[index].ptr = (char *)ctx->vert.vbo->data + (long)ptr;
+   else
+      ctx->vert.attribs[index].ptr = ptr;
+//   const float * attrib = (const float *)ctx->vert.attribs[index].ptr;
+//   for (unsigned i = 0; i < 3; i++)
+//      if (3 == size)
+//         LOGD("%.2f %.2f %.2f", attrib[i * 3 + 0], attrib[i * 3 + 1], attrib[i * 3 + 2]);
+//      else if (2 == size)
+//         LOGD("%.2f %.2f", attrib[i * 3 + 0], attrib[i * 3 + 1]);
+   
+}
+
+void glVertexAttrib1f(GLuint indx, GLfloat x)
+{
+   glVertexAttrib4f(indx, x,0,0,1);
+}
+
+void glVertexAttrib1fv(GLuint indx, const GLfloat* values)
+{
+   glVertexAttrib4f(indx, values[0],0,0,1);
+}
+
+void glVertexAttrib2f(GLuint indx, GLfloat x, GLfloat y)
+{
+   glVertexAttrib4f(indx, x,y,0,1);
+}
+
+void glVertexAttrib2fv(GLuint indx, const GLfloat* values)
+{
+   glVertexAttrib4f(indx, values[0],values[1],0,1);
+}
+
+void glVertexAttrib3f(GLuint indx, GLfloat x, GLfloat y, GLfloat z)
+{
+   glVertexAttrib4f(indx, x,y,z,1);
+}
+
+void glVertexAttrib3fv(GLuint indx, const GLfloat* values)
+{
+   glVertexAttrib4f(indx, values[0],values[1],values[2],1);
+}
+
+void glVertexAttrib4f(GLuint indx, GLfloat x, GLfloat y, GLfloat z, GLfloat w)
+{
+   assert(GGL_MAXVERTEXATTRIBS > indx);
+   GLES2_GET_CONST_CONTEXT(ctx);
+//   LOGD("\n*\n*\n agl2: glVertexAttrib4f %d %.2f,%.2f,%.2f,%.2f \n*\n*", indx, x, y, z, w);
+   ctx->vert.defaultAttribs[indx] = Vector4(x,y,z,w);
+   assert(0);
+}
+
+void glVertexAttrib4fv(GLuint indx, const GLfloat* values)
+{
+   glVertexAttrib4f(indx, values[0], values[1], values[2], values[3]);
+}
diff --git a/opengl/libs/Android.mk b/opengl/libs/Android.mk
index c8041fc..123306b6 100644
--- a/opengl/libs/Android.mk
+++ b/opengl/libs/Android.mk
@@ -13,11 +13,11 @@
 	EGL/hooks.cpp 	       \
 	EGL/Loader.cpp 	       \
 #
-
-LOCAL_SHARED_LIBRARIES += libcutils libutils
+LOCAL_STATIC_LIBRARIES += libGLESv2_dbg libprotobuf-cpp-2.3.0-lite
+LOCAL_SHARED_LIBRARIES += libcutils libutils libstlport
 LOCAL_LDLIBS := -lpthread -ldl
 LOCAL_MODULE:= libEGL
-
+LOCAL_LDFLAGS += -Wl,--exclude-libs=ALL
 # needed on sim build because of weird logging issues
 ifeq ($(TARGET_SIMULATOR),true)
 else
@@ -164,3 +164,6 @@
 LOCAL_MODULE:= libETC1
 
 include $(BUILD_SHARED_LIBRARY)
+
+include $(call all-makefiles-under,$(LOCAL_PATH))
+
diff --git a/opengl/libs/EGL/Loader.cpp b/opengl/libs/EGL/Loader.cpp
index 747c829..2502f15 100644
--- a/opengl/libs/EGL/Loader.cpp
+++ b/opengl/libs/EGL/Loader.cpp
@@ -30,6 +30,7 @@
 #include "egl_impl.h"
 
 #include "Loader.h"
+#include "glesv2dbg.h"
 
 // ----------------------------------------------------------------------------
 namespace android {
@@ -114,6 +115,7 @@
 
 Loader::~Loader()
 {
+    StopDebugServer();
 }
 
 const char* Loader::getTag(int dpy, int impl)
diff --git a/opengl/libs/EGL/egl.cpp b/opengl/libs/EGL/egl.cpp
index 3d5a4d1..75f7078 100644
--- a/opengl/libs/EGL/egl.cpp
+++ b/opengl/libs/EGL/egl.cpp
@@ -45,6 +45,7 @@
 #include "hooks.h"
 #include "egl_impl.h"
 #include "Loader.h"
+#include "glesv2dbg.h"
 
 #define setError(_e, _r) setErrorEtc(__FUNCTION__, __LINE__, _e, _r)
 
@@ -223,9 +224,15 @@
     egl_context_t(EGLDisplay dpy, EGLContext context, EGLConfig config,
             int impl, egl_connection_t const* cnx, int version) 
     : dpy(dpy), context(context), config(config), read(0), draw(0), impl(impl),
-      cnx(cnx), version(version)
+      cnx(cnx), version(version), dbg(NULL)
     {
     }
+    ~egl_context_t()
+    {
+        if (dbg)
+            DestroyDbgContext(dbg);
+        dbg = NULL;
+    }
     EGLDisplay                  dpy;
     EGLContext                  context;
     EGLConfig                   config;
@@ -234,6 +241,7 @@
     int                         impl;
     egl_connection_t const*     cnx;
     int                         version;
+    DbgContext *                dbg;
 };
 
 struct egl_image_t : public egl_object_t
@@ -296,9 +304,9 @@
 
 // ----------------------------------------------------------------------------
 
-static int gEGLTraceLevel;
+static int gEGLTraceLevel, gEGLDebugLevel;
 static int gEGLApplicationTraceLevel;
-extern EGLAPI gl_hooks_t gHooksTrace;
+extern EGLAPI gl_hooks_t gHooksTrace, gHooksDebug;
 
 static inline void setGlTraceThreadSpecific(gl_hooks_t const *value) {
     pthread_setspecific(gGLTraceKey, value);
@@ -314,12 +322,37 @@
     int propertyLevel = atoi(value);
     int applicationLevel = gEGLApplicationTraceLevel;
     gEGLTraceLevel = propertyLevel > applicationLevel ? propertyLevel : applicationLevel;
+    
+    property_get("debug.egl.debug_proc", value, "");
+    long pid = getpid();
+    char procPath[128] = {};
+    sprintf(procPath, "/proc/%ld/cmdline", pid);
+    FILE * file = fopen(procPath, "r");
+    if (file)
+    {
+        char cmdline[256] = {};
+        if (fgets(cmdline, sizeof(cmdline) - 1, file))
+        {
+            if (!strcmp(value, cmdline))
+                gEGLDebugLevel = 1;
+        }    
+        fclose(file);
+    }
+    
+    if (gEGLDebugLevel > 0)
+    {
+        property_get("debug.egl.debug_port", value, "5039");
+        StartDebugServer(atoi(value));
+    }
 }
 
 static void setGLHooksThreadSpecific(gl_hooks_t const *value) {
     if (gEGLTraceLevel > 0) {
         setGlTraceThreadSpecific(value);
         setGlThreadSpecific(&gHooksTrace);
+    } else if (gEGLDebugLevel > 0 && value != &gHooksNoContext) {
+        setGlTraceThreadSpecific(value);
+        setGlThreadSpecific(&gHooksDebug);
     } else {
         setGlThreadSpecific(value);
     }
@@ -561,6 +594,11 @@
     return egl_to_native_cast<egl_context_t>(context);
 }
 
+DbgContext * getDbgContextThreadSpecific()
+{
+    return get_context(getContext())->dbg;
+}
+
 static inline
 egl_image_t* get_image(EGLImageKHR image) {
     return egl_to_native_cast<egl_image_t>(image);
@@ -1094,6 +1132,16 @@
         EGLConfig iConfig = dp->configs[intptr_t(config)].config;
         EGLint format;
 
+        // for now fail if the window is not a Surface.
+        int type = -1;
+        ANativeWindow* anw = reinterpret_cast<ANativeWindow*>(window);
+        if ((anw->query(window, NATIVE_WINDOW_CONCRETE_TYPE, &type) != 0) ||
+                (type == NATIVE_WINDOW_SURFACE_TEXTURE_CLIENT)) {
+            LOGE("native window is a SurfaceTextureClient (currently "
+                    "unsupported)");
+            return setError(EGL_BAD_NATIVE_WINDOW, EGL_NO_SURFACE);
+        }
+
         // set the native window's buffers format to match this config
         if (cnx->egl.eglGetConfigAttrib(iDpy,
                 iConfig, EGL_NATIVE_VISUAL_ID, &format)) {
@@ -1368,6 +1416,8 @@
         loseCurrent(cur_c);
 
         if (ctx != EGL_NO_CONTEXT) {
+            if (!c->dbg && gEGLDebugLevel > 0)
+                c->dbg = CreateDbgContext(c->version, c->cnx->hooks[c->version]);
             setGLHooksThreadSpecific(c->cnx->hooks[c->version]);
             setContext(ctx);
             _c.acquire();
@@ -1597,7 +1647,7 @@
                     cnx->hooks[GLESv1_INDEX]->ext.extensions[slot] =
                     cnx->hooks[GLESv2_INDEX]->ext.extensions[slot] =
 #if EGL_TRACE
-                    gHooksTrace.ext.extensions[slot] =
+                    gHooksDebug.ext.extensions[slot] = gHooksTrace.ext.extensions[slot] =
 #endif
                             cnx->egl.eglGetProcAddress(procname);
                 }
@@ -1625,6 +1675,10 @@
 
 EGLBoolean eglSwapBuffers(EGLDisplay dpy, EGLSurface draw)
 {
+    EGLBoolean Debug_eglSwapBuffers(EGLDisplay dpy, EGLSurface draw);
+    if (gEGLDebugLevel > 0)
+        Debug_eglSwapBuffers(dpy, draw);
+
     clearError();
 
     SurfaceRef _s(draw);
@@ -2067,14 +2121,15 @@
     if (!validate_display_context(dpy, ctx))
         return EGL_FALSE;
 
+    EGLBoolean result = EGL_FALSE;
     egl_context_t * const c = get_context(ctx);
-
     if (c->cnx->egl.eglDestroySyncKHR) {
-        return c->cnx->egl.eglDestroySyncKHR(
+        result = c->cnx->egl.eglDestroySyncKHR(
                 dp->disp[c->impl].dpy, syncObject->sync);
+        if (result)
+            _s.terminate();
     }
-
-    return EGL_FALSE;
+    return result;
 }
 
 EGLint eglClientWaitSyncKHR(EGLDisplay dpy, EGLSyncKHR sync, EGLint flags, EGLTimeKHR timeout)
diff --git a/opengl/libs/EGL/trace.cpp b/opengl/libs/EGL/trace.cpp
index d3e96ba..f3e101b 100644
--- a/opengl/libs/EGL/trace.cpp
+++ b/opengl/libs/EGL/trace.cpp
@@ -325,7 +325,7 @@
 
 #define TRACE_GL(_type, _api, _args, _argList, ...)                       \
 static _type Tracing_ ## _api _args {                                     \
-    TraceGL(#_api, __VA_ARGS__);                                          \
+    TraceGL(#_api, __VA_ARGS__);                                        \
     gl_hooks_t::gl_t const * const _c = &getGLTraceThreadSpecific()->gl;  \
     return _c->_api _argList;                                             \
 }
@@ -333,11 +333,11 @@
 extern "C" {
 #include "../trace.in"
 }
+
 #undef TRACE_GL_VOID
 #undef TRACE_GL
 
 #define GL_ENTRY(_r, _api, ...) Tracing_ ## _api,
-
 EGLAPI gl_hooks_t gHooksTrace = {
     {
         #include "entries.in"
@@ -348,6 +348,48 @@
 };
 #undef GL_ENTRY
 
+
+#undef TRACE_GL_VOID
+#undef TRACE_GL
+
+// define the ES 1.0 Debug_gl* functions as Tracing_gl functions
+#define TRACE_GL_VOID(_api, _args, _argList, ...)                         \
+static void Debug_ ## _api _args {                                      \
+    TraceGL(#_api, __VA_ARGS__);                                          \
+    gl_hooks_t::gl_t const * const _c = &getGLTraceThreadSpecific()->gl;  \
+    _c->_api _argList;                                                    \
+}
+
+#define TRACE_GL(_type, _api, _args, _argList, ...)                       \
+static _type Debug_ ## _api _args {                                     \
+    TraceGL(#_api, __VA_ARGS__);                                        \
+    gl_hooks_t::gl_t const * const _c = &getGLTraceThreadSpecific()->gl;  \
+    return _c->_api _argList;                                             \
+}
+
+extern "C" {
+#include "../debug.in"
+}
+
+#undef TRACE_GL_VOID
+#undef TRACE_GL
+
+// declare all Debug_gl* functions
+#define GL_ENTRY(_r, _api, ...) _r Debug_##_api ( __VA_ARGS__ );
+#include "glesv2dbg_functions.h"
+#undef GL_ENTRY
+
+#define GL_ENTRY(_r, _api, ...) Debug_ ## _api,
+EGLAPI gl_hooks_t gHooksDebug = {
+    {
+        #include "entries.in"
+    },
+    {
+        {0}
+    }
+};
+#undef GL_ENTRY
+
 // ----------------------------------------------------------------------------
 }; // namespace android
 // ----------------------------------------------------------------------------
diff --git a/opengl/libs/GLES2_dbg/Android.mk b/opengl/libs/GLES2_dbg/Android.mk
new file mode 100644
index 0000000..e593c32
--- /dev/null
+++ b/opengl/libs/GLES2_dbg/Android.mk
@@ -0,0 +1,45 @@
+LOCAL_PATH:= $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := \
+    src/api.cpp \
+    src/dbgcontext.cpp \
+    src/debugger_message.pb.cpp \
+    src/egl.cpp \
+    src/server.cpp \
+    src/texture.cpp \
+    src/vertex.cpp
+
+LOCAL_C_INCLUDES :=	\
+    $(LOCAL_PATH) \
+    $(LOCAL_PATH)/../ \
+    external/stlport/stlport \
+    external/protobuf/src \
+    bionic
+
+#LOCAL_CFLAGS += -O0 -g -DDEBUG -UNDEBUG
+LOCAL_CFLAGS := -DGOOGLE_PROTOBUF_NO_RTTI
+
+ifeq ($(TARGET_ARCH),arm)
+	LOCAL_CFLAGS += -fstrict-aliasing
+endif
+
+ifeq ($(ARCH_ARM_HAVE_TLS_REGISTER),true)
+    LOCAL_CFLAGS += -DHAVE_ARM_TLS_REGISTER
+endif
+
+ifneq ($(TARGET_SIMULATOR),true)
+    # we need to access the private Bionic header <bionic_tls.h>
+    # on ARM platforms, we need to mirror the ARCH_ARM_HAVE_TLS_REGISTER
+    # behavior from the bionic Android.mk file
+    ifeq ($(TARGET_ARCH)-$(ARCH_ARM_HAVE_TLS_REGISTER),arm-true)
+        LOCAL_CFLAGS += -DHAVE_ARM_TLS_REGISTER
+    endif
+    LOCAL_C_INCLUDES += bionic/libc/private
+endif
+
+LOCAL_MODULE:= libGLESv2_dbg
+LOCAL_MODULE_TAGS := optional
+
+include $(BUILD_STATIC_LIBRARY)
diff --git a/opengl/libs/GLES2_dbg/generate_api_cpp.py b/opengl/libs/GLES2_dbg/generate_api_cpp.py
new file mode 100755
index 0000000..5b024ad
--- /dev/null
+++ b/opengl/libs/GLES2_dbg/generate_api_cpp.py
@@ -0,0 +1,207 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+
+#
+# Copyright 2011, The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+import os
+import sys
+
+def RemoveAnnotation(line):
+    if line.find(":") >= 0:
+        annotation = line[line.find(":"): line.find(" ", line.find(":"))]
+        return line.replace(annotation, "*")
+    else:
+        return line
+    
+def generate_api(lines):
+    externs = []
+    i = 0
+    # these have been hand written
+    skipFunctions = ["glTexImage2D", "glTexSubImage2D", "glReadPixels",
+"glDrawArrays", "glDrawElements"]
+    
+    # these have an EXTEND_Debug_* macro for getting data
+    extendFunctions = ["glCopyTexImage2D", "glCopyTexSubImage2D", "glShaderSource"]
+    
+    # these also needs to be forwarded to DbgContext
+    contextFunctions = ["glUseProgram", "glEnableVertexAttribArray", "glDisableVertexAttribArray", 
+"glVertexAttribPointer", "glBindBuffer", "glBufferData", "glBufferSubData", "glDeleteBuffers",]
+    
+    for line in lines:
+        if line.find("API_ENTRY(") >= 0: # a function prototype
+            returnType = line[0: line.find(" API_ENTRY(")]
+            functionName = line[line.find("(") + 1: line.find(")")] #extract GL function name
+            parameterList = line[line.find(")(") + 2: line.find(") {")]
+            
+            #if line.find("*") >= 0:
+            #    extern = "%s Debug_%s(%s);" % (returnType, functionName, parameterList)
+            #    externs.append(extern)
+            #    continue
+            
+            if functionName in skipFunctions:
+                sys.stderr.write("!\n! skipping function '%s'\n!\n" % (functionName))
+                continue
+                
+            parameters = parameterList.split(',')
+            paramIndex = 0
+            if line.find("*") >= 0 and (line.find("*") < line.find(":") or line.find("*") > line.rfind(":")): # unannotated pointer
+                if not functionName in extendFunctions:
+                    # add function to list of functions that should be hand written, but generate code anyways
+                    extern = "%s Debug_%s(%s);" % (returnType, functionName, RemoveAnnotation(parameterList))
+                    sys.stderr.write("%s should be hand written\n" % (extern))
+                    print "// FIXME: this function has pointers, it should be hand written"
+                    externs.append(extern)
+                
+            print "%s Debug_%s(%s)\n{" % (returnType, functionName, RemoveAnnotation(parameterList))
+            print """    glesv2debugger::Message msg;
+    const bool expectResponse = false;"""
+    
+            if parameterList == "void":
+                parameters = []
+            arguments = ""
+            paramNames = []
+            inout = ""
+            getData = ""
+            
+            callerMembers = ""
+            setCallerMembers = ""
+            setMsgParameters = ""
+            
+            for parameter in parameters:
+                const = parameter.find("const")
+                parameter = parameter.replace("const", "")
+                parameter = parameter.strip()
+                paramType = parameter.split(' ')[0]
+                paramName = parameter.split(' ')[1]
+                annotation = ""
+                arguments += paramName
+                if parameter.find(":") >= 0: # has annotation
+                    assert inout == "" # only one parameter should be annotated
+                    sys.stderr.write("%s is annotated: %s \n" % (functionName, paramType))
+                    inout = paramType.split(":")[2]
+                    annotation = paramType.split(":")[1]
+                    paramType = paramType.split(":")[0]
+                    count = 1
+                    countArg = ""
+                    if annotation.find("*") >= 0: # [1,n] * param
+                        count = int(annotation.split("*")[0])
+                        countArg = annotation.split("*")[1]
+                        assert countArg in paramNames
+                    elif annotation in paramNames:
+                        count = 1
+                        countArg = annotation
+                    elif annotation == "GLstring":
+                        annotation = "strlen(%s)" % (paramName)
+                    else:
+                        count = int(annotation)
+            
+                    setMsgParameters += "    msg.set_arg%d(ToInt(%s));\n" % (paramIndex, paramName)
+                    if paramType.find("void") >= 0:
+                        getData += "    msg.mutable_data()->assign(reinterpret_cast<const char *>(%s), %s * sizeof(char));" % (paramName, annotation)
+                    else:
+                        getData += "    msg.mutable_data()->assign(reinterpret_cast<const char *>(%s), %s * sizeof(%s));" % (paramName, annotation, paramType)
+                    paramType += "*"
+                else:     
+                    if paramType == "GLfloat" or paramType == "GLclampf" or paramType.find("*") >= 0:
+                        setMsgParameters += "    msg.set_arg%d(ToInt(%s));\n" % (paramIndex, paramName)
+                    else: 
+                        setMsgParameters += "    msg.set_arg%d(%s);\n" % (paramIndex, paramName)
+                if paramIndex < len(parameters) - 1:
+                        arguments += ', '
+                if const >= 0:
+                    paramType = "const " + paramType
+                paramNames.append(paramName)
+                paramIndex += 1
+                callerMembers += "        %s %s;\n" % (paramType, paramName)
+                setCallerMembers += "    caller.%s = %s;\n" % (paramName, paramName)
+            
+            print "    struct : public FunctionCall {"
+            print callerMembers
+            print "        const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {"
+            if inout in ["out", "inout"]: # get timing excluding output data copy
+                print "            nsecs_t c0 = systemTime(timeMode);"
+            if returnType == "void":
+                print "            _c->%s(%s);" % (functionName, arguments)
+            else:
+                print "            const int * ret = reinterpret_cast<const int *>(_c->%s(%s));" % (functionName, arguments)
+                print "            msg.set_ret(ToInt(ret));"
+            if inout in ["out", "inout"]:
+                print "            msg.set_time((systemTime(timeMode) - c0) * 1e-6f);"
+                print "        " + getData
+            if functionName in contextFunctions:
+                print "            getDbgContextThreadSpecific()->%s(%s);" % (functionName, arguments)
+            if returnType == "void":
+                print "            return 0;"
+            else:
+                print "            return ret;"
+            print """        }
+    } caller;"""
+            print setCallerMembers
+            print setMsgParameters
+    
+            if line.find("*") >= 0 or line.find(":") >= 0:
+                print "    // FIXME: check for pointer usage"
+            if inout in ["in", "inout"]:
+                print getData
+            if functionName in extendFunctions:
+                print "    EXTEND_Debug_%s;" % (functionName) 
+            print "    int * ret = MessageLoop(caller, msg, expectResponse,"
+            print "                            glesv2debugger::Message_Function_%s);" % (functionName)
+            if returnType != "void":
+                if returnType == "GLboolean":
+                    print "    return static_cast<GLboolean>(reinterpret_cast<int>(ret));"
+                else:
+                    print "    return reinterpret_cast<%s>(ret);" % (returnType)
+            print "}\n"
+                        
+            
+    print "// FIXME: the following functions should be written by hand"
+    for extern in externs:
+        print extern
+
+if __name__ == "__main__":
+    print """\
+/*
+ ** Copyright 2011, The Android Open Source Project
+ **
+ ** Licensed under the Apache License, Version 2.0 (the "License");
+ ** you may not use this file except in compliance with the License.
+ ** You may obtain a copy of the License at
+ **
+ **     http://www.apache.org/licenses/LICENSE-2.0
+ **
+ ** Unless required by applicable law or agreed to in writing, software
+ ** distributed under the License is distributed on an "AS IS" BASIS,
+ ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ** See the License for the specific language governing permissions and
+ ** limitations under the License.
+ */
+ 
+// auto generated by generate_api_cpp.py
+
+#include "src/header.h"
+#include "src/api.h"
+
+template<typename T> static int ToInt(const T & t) { STATIC_ASSERT(sizeof(T) == sizeof(int), bitcast); return (int &)t; }
+template<typename T> static T FromInt(const int & t) { STATIC_ASSERT(sizeof(T) == sizeof(int), bitcast); return (T &)t; }
+"""    
+    lines = open("gl2_api_annotated.in").readlines()
+    generate_api(lines)
+    #lines = open("gl2ext_api.in").readlines()
+    #generate_api(lines)
+            
+
diff --git a/opengl/libs/GLES2_dbg/generate_debug_in.py b/opengl/libs/GLES2_dbg/generate_debug_in.py
new file mode 100755
index 0000000..1280c6f
--- /dev/null
+++ b/opengl/libs/GLES2_dbg/generate_debug_in.py
@@ -0,0 +1,80 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+
+#
+# Copyright 2011, The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+import os
+import sys
+
+def append_functions(functions, lines):
+	i = 0
+	for line in lines:
+		if line.find("API_ENTRY(") >= 0: # a function prototype
+			returnType = line[0: line.find(" API_ENTRY(")]
+			functionName = line[line.find("(") + 1: line.find(")")] #extract GL function name
+			parameterList = line[line.find(")(") + 2: line.find(") {")]
+			
+			functions.append(functionName)
+			#print functionName
+			continue
+				
+			parameters = parameterList.split(',')
+			paramIndex = 0
+			if line.find("*") >= 0:
+				print "// FIXME: this function has pointers, it should be hand written"
+				externs.append("%s Tracing_%s(%s);" % (returnType, functionName, parameterList))
+			print "%s Tracing_%s(%s)\n{" % (returnType, functionName, parameterList)
+			
+			if parameterList == "void":
+				parameters = []
+			
+			arguments = ""
+			 
+			for parameter in parameters:
+				parameter = parameter.replace("const", "")
+				parameter = parameter.strip()
+				paramType = parameter.split(' ')[0]
+				paramName = parameter.split(' ')[1]
+				
+				paramIndex += 1
+				
+	return functions
+	
+
+
+if __name__ == "__main__":
+	definedFunctions = []
+	lines = open("gl2_api_annotated.in").readlines()
+	definedFunctions = append_functions(definedFunctions, lines)
+	
+	output = open("../debug.in", "w")
+	lines = open("../trace.in").readlines()
+	output.write("// the following functions are not defined in GLESv2_dbg\n")
+	for line in lines:
+		functionName = ""
+		if line.find("TRACE_GL(") >= 0: # a function prototype
+			functionName = line.split(',')[1].strip()
+		elif line.find("TRACE_GL_VOID(") >= 0: # a function prototype
+			functionName = line[line.find("(") + 1: line.find(",")] #extract GL function name
+		else:
+			continue
+		if functionName in definedFunctions:
+			#print functionName
+			continue
+		else:
+			output.write(line)
+	
diff --git a/opengl/libs/GLES2_dbg/generate_debugger_message_proto.py b/opengl/libs/GLES2_dbg/generate_debugger_message_proto.py
new file mode 100755
index 0000000..48a29da
--- /dev/null
+++ b/opengl/libs/GLES2_dbg/generate_debugger_message_proto.py
@@ -0,0 +1,136 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+
+#
+# Copyright 2011, The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+import os
+
+def generate_egl_entries(output, lines, i):
+    for line in lines:
+        if line.find("EGL_ENTRY(") >= 0:
+            line = line.split(",")[1].strip() #extract EGL function name
+            output.write("        %s = %d;\n" % (line, i))
+            i += 1
+    return i    
+
+
+def generate_gl_entries(output,lines,i):
+    for line in lines:
+        if line.find("API_ENTRY(") >= 0:
+            line = line[line.find("(") + 1: line.find(")")] #extract GL function name
+            output.write("        %s = %d;\n" % (line, i))
+            i += 1
+    return i
+
+
+if __name__ == "__main__":
+    output = open("debugger_message.proto",'w')
+    output.write("""\
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// do not edit; auto generated by generate_debugger_message_proto.py
+
+package com.android.glesv2debugger;
+
+option optimize_for = LITE_RUNTIME;
+
+message Message
+{
+    required int32 context_id = 1; // GL context id
+    enum Function
+    {
+""")
+
+    i = 0;
+    
+    lines = open("gl2_api_annotated.in").readlines()
+    i = generate_gl_entries(output, lines, i)
+    output.write("        // end of GL functions\n")
+    
+    #lines = open("gl2ext_api.in").readlines()
+    #i = generate_gl_entries(output, lines, i)
+    #output.write("        // end of GL EXT functions\n")
+    
+    lines = open("../EGL/egl_entries.in").readlines()
+    i = generate_egl_entries(output, lines, i)
+    output.write("        // end of GL EXT functions\n")
+    
+    output.write("        ACK = %d;\n" % (i))
+    i += 1
+    
+    output.write("        NEG = %d;\n" % (i))
+    i += 1
+    
+    output.write("        CONTINUE = %d;\n" % (i))
+    i += 1
+    
+    output.write("        SKIP = %d;\n" % (i))
+    i += 1
+    
+    output.write("        SETPROP = %d;\n" % (i))
+    i += 1
+    
+    output.write("""    }
+    required Function function = 2 [default = NEG]; // type/function of message
+    enum Type
+    {
+        BeforeCall = 0;
+        AfterCall = 1;
+        Response = 2; // currently used for misc messages
+    }
+    required Type type = 3;
+    required bool expect_response = 4;
+    optional int32 ret = 5; // return value from previous GL call
+    optional int32 arg0 = 6; // args to GL call
+    optional int32 arg1 = 7;
+    optional int32 arg2 = 8;
+    optional int32 arg3 = 9;
+    optional int32 arg4 = 16;
+    optional int32 arg5 = 17;
+    optional int32 arg6 = 18;
+    optional int32 arg7 = 19;
+    optional int32 arg8 = 20;
+    optional bytes data = 10; // variable length data used for GL call
+    optional float time = 11; // duration of previous GL call (ms)
+    enum Prop
+    {
+        Capture = 0; // arg0 = true | false
+        TimeMode = 1; // arg0 = SYSTEM_TIME_* in utils/Timers.h
+    };
+    optional Prop prop = 21; // used with SETPROP, value in arg0
+    optional float clock = 22; // wall clock in seconds
+}
+""")
+
+    output.close()
+    
+    os.system("aprotoc --cpp_out=src --java_out=../../../../../development/tools/glesv2debugger/src debugger_message.proto")
+    os.system('mv -f "src/debugger_message.pb.cc" "src/debugger_message.pb.cpp"')
diff --git a/opengl/libs/GLES2_dbg/gl2_api_annotated.in b/opengl/libs/GLES2_dbg/gl2_api_annotated.in
new file mode 100644
index 0000000..227e2eb
--- /dev/null
+++ b/opengl/libs/GLES2_dbg/gl2_api_annotated.in
@@ -0,0 +1,426 @@
+void API_ENTRY(glActiveTexture)(GLenum texture) {
+    CALL_GL_API(glActiveTexture, texture);
+}
+void API_ENTRY(glAttachShader)(GLuint program, GLuint shader) {
+    CALL_GL_API(glAttachShader, program, shader);
+}
+void API_ENTRY(glBindAttribLocation)(GLuint program, GLuint index, const GLchar:GLstring:in name) {
+    CALL_GL_API(glBindAttribLocation, program, index, name);
+}
+void API_ENTRY(glBindBuffer)(GLenum target, GLuint buffer) {
+    CALL_GL_API(glBindBuffer, target, buffer);
+}
+void API_ENTRY(glBindFramebuffer)(GLenum target, GLuint framebuffer) {
+    CALL_GL_API(glBindFramebuffer, target, framebuffer);
+}
+void API_ENTRY(glBindRenderbuffer)(GLenum target, GLuint renderbuffer) {
+    CALL_GL_API(glBindRenderbuffer, target, renderbuffer);
+}
+void API_ENTRY(glBindTexture)(GLenum target, GLuint texture) {
+    CALL_GL_API(glBindTexture, target, texture);
+}
+void API_ENTRY(glBlendColor)(GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha) {
+    CALL_GL_API(glBlendColor, red, green, blue, alpha);
+}
+void API_ENTRY(glBlendEquation)( GLenum mode ) {
+    CALL_GL_API(glBlendEquation, mode);
+}
+void API_ENTRY(glBlendEquationSeparate)(GLenum modeRGB, GLenum modeAlpha) {
+    CALL_GL_API(glBlendEquationSeparate, modeRGB, modeAlpha);
+}
+void API_ENTRY(glBlendFunc)(GLenum sfactor, GLenum dfactor) {
+    CALL_GL_API(glBlendFunc, sfactor, dfactor);
+}
+void API_ENTRY(glBlendFuncSeparate)(GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha) {
+    CALL_GL_API(glBlendFuncSeparate, srcRGB, dstRGB, srcAlpha, dstAlpha);
+}
+void API_ENTRY(glBufferData)(GLenum target, GLsizeiptr size, const GLvoid:size:in data, GLenum usage) {
+    CALL_GL_API(glBufferData, target, size, data, usage);
+}
+void API_ENTRY(glBufferSubData)(GLenum target, GLintptr offset, GLsizeiptr size, const GLvoid:size:in data) {
+    CALL_GL_API(glBufferSubData, target, offset, size, data);
+}
+GLenum API_ENTRY(glCheckFramebufferStatus)(GLenum target) {
+    CALL_GL_API_RETURN(glCheckFramebufferStatus, target);
+}
+void API_ENTRY(glClear)(GLbitfield mask) {
+    CALL_GL_API(glClear, mask);
+}
+void API_ENTRY(glClearColor)(GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha) {
+    CALL_GL_API(glClearColor, red, green, blue, alpha);
+}
+void API_ENTRY(glClearDepthf)(GLclampf depth) {
+    CALL_GL_API(glClearDepthf, depth);
+}
+void API_ENTRY(glClearStencil)(GLint s) {
+    CALL_GL_API(glClearStencil, s);
+}
+void API_ENTRY(glColorMask)(GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha) {
+    CALL_GL_API(glColorMask, red, green, blue, alpha);
+}
+void API_ENTRY(glCompileShader)(GLuint shader) {
+    CALL_GL_API(glCompileShader, shader);
+}
+void API_ENTRY(glCompressedTexImage2D)(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const GLvoid* data) {
+    CALL_GL_API(glCompressedTexImage2D, target, level, internalformat, width, height, border, imageSize, data);
+}
+void API_ENTRY(glCompressedTexSubImage2D)(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const GLvoid* data) {
+    CALL_GL_API(glCompressedTexSubImage2D, target, level, xoffset, yoffset, width, height, format, imageSize, data);
+}
+void API_ENTRY(glCopyTexImage2D)(GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border) {
+    CALL_GL_API(glCopyTexImage2D, target, level, internalformat, x, y, width, height, border);
+}
+void API_ENTRY(glCopyTexSubImage2D)(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height) {
+    CALL_GL_API(glCopyTexSubImage2D, target, level, xoffset, yoffset, x, y, width, height);
+}
+GLuint API_ENTRY(glCreateProgram)(void) {
+    CALL_GL_API_RETURN(glCreateProgram);
+}
+GLuint API_ENTRY(glCreateShader)(GLenum type) {
+    CALL_GL_API_RETURN(glCreateShader, type);
+}
+void API_ENTRY(glCullFace)(GLenum mode) {
+    CALL_GL_API(glCullFace, mode);
+}
+void API_ENTRY(glDeleteBuffers)(GLsizei n, const GLuint:n:in buffers) {
+    CALL_GL_API(glDeleteBuffers, n, buffers);
+}
+void API_ENTRY(glDeleteFramebuffers)(GLsizei n, const GLuint:n:in framebuffers) {
+    CALL_GL_API(glDeleteFramebuffers, n, framebuffers);
+}
+void API_ENTRY(glDeleteProgram)(GLuint program) {
+    CALL_GL_API(glDeleteProgram, program);
+}
+void API_ENTRY(glDeleteRenderbuffers)(GLsizei n, const GLuint:n:in renderbuffers) {
+    CALL_GL_API(glDeleteRenderbuffers, n, renderbuffers);
+}
+void API_ENTRY(glDeleteShader)(GLuint shader) {
+    CALL_GL_API(glDeleteShader, shader);
+}
+void API_ENTRY(glDeleteTextures)(GLsizei n, const GLuint:n:in textures) {
+    CALL_GL_API(glDeleteTextures, n, textures);
+}
+void API_ENTRY(glDepthFunc)(GLenum func) {
+    CALL_GL_API(glDepthFunc, func);
+}
+void API_ENTRY(glDepthMask)(GLboolean flag) {
+    CALL_GL_API(glDepthMask, flag);
+}
+void API_ENTRY(glDepthRangef)(GLclampf zNear, GLclampf zFar) {
+    CALL_GL_API(glDepthRangef, zNear, zFar);
+}
+void API_ENTRY(glDetachShader)(GLuint program, GLuint shader) {
+    CALL_GL_API(glDetachShader, program, shader);
+}
+void API_ENTRY(glDisable)(GLenum cap) {
+    CALL_GL_API(glDisable, cap);
+}
+void API_ENTRY(glDisableVertexAttribArray)(GLuint index) {
+    CALL_GL_API(glDisableVertexAttribArray, index);
+}
+void API_ENTRY(glDrawArrays)(GLenum mode, GLint first, GLsizei count) {
+    CALL_GL_API(glDrawArrays, mode, first, count);
+}
+void API_ENTRY(glDrawElements)(GLenum mode, GLsizei count, GLenum type, const GLvoid* indices) {
+    CALL_GL_API(glDrawElements, mode, count, type, indices);
+}
+void API_ENTRY(glEnable)(GLenum cap) {
+    CALL_GL_API(glEnable, cap);
+}
+void API_ENTRY(glEnableVertexAttribArray)(GLuint index) {
+    CALL_GL_API(glEnableVertexAttribArray, index);
+}
+void API_ENTRY(glFinish)(void) {
+    CALL_GL_API(glFinish);
+}
+void API_ENTRY(glFlush)(void) {
+    CALL_GL_API(glFlush);
+}
+void API_ENTRY(glFramebufferRenderbuffer)(GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer) {
+    CALL_GL_API(glFramebufferRenderbuffer, target, attachment, renderbuffertarget, renderbuffer);
+}
+void API_ENTRY(glFramebufferTexture2D)(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level) {
+    CALL_GL_API(glFramebufferTexture2D, target, attachment, textarget, texture, level);
+}
+void API_ENTRY(glFrontFace)(GLenum mode) {
+    CALL_GL_API(glFrontFace, mode);
+}
+void API_ENTRY(glGenBuffers)(GLsizei n, GLuint:n:out buffers) {
+    CALL_GL_API(glGenBuffers, n, buffers);
+}
+void API_ENTRY(glGenerateMipmap)(GLenum target) {
+    CALL_GL_API(glGenerateMipmap, target);
+}
+void API_ENTRY(glGenFramebuffers)(GLsizei n, GLuint:n:out framebuffers) {
+    CALL_GL_API(glGenFramebuffers, n, framebuffers);
+}
+void API_ENTRY(glGenRenderbuffers)(GLsizei n, GLuint:n:out renderbuffers) {
+    CALL_GL_API(glGenRenderbuffers, n, renderbuffers);
+}
+void API_ENTRY(glGenTextures)(GLsizei n, GLuint:n:out textures) {
+    CALL_GL_API(glGenTextures, n, textures);
+}
+void API_ENTRY(glGetActiveAttrib)(GLuint program, GLuint index, GLsizei bufsize, GLsizei* length, GLint* size, GLenum* type, GLchar:GLstring:in name) {
+    CALL_GL_API(glGetActiveAttrib, program, index, bufsize, length, size, type, name);
+}
+void API_ENTRY(glGetActiveUniform)(GLuint program, GLuint index, GLsizei bufsize, GLsizei* length, GLint* size, GLenum* type, GLchar:GLstring:in name) {
+    CALL_GL_API(glGetActiveUniform, program, index, bufsize, length, size, type, name);
+}
+void API_ENTRY(glGetAttachedShaders)(GLuint program, GLsizei maxcount, GLsizei* count, GLuint* shaders) {
+    CALL_GL_API(glGetAttachedShaders, program, maxcount, count, shaders);
+}
+int API_ENTRY(glGetAttribLocation)(GLuint program, const GLchar:GLstring:in name) {
+    CALL_GL_API_RETURN(glGetAttribLocation, program, name);
+}
+void API_ENTRY(glGetBooleanv)(GLenum pname, GLboolean* params) {
+    CALL_GL_API(glGetBooleanv, pname, params);
+}
+void API_ENTRY(glGetBufferParameteriv)(GLenum target, GLenum pname, GLint* params) {
+    CALL_GL_API(glGetBufferParameteriv, target, pname, params);
+}
+GLenum API_ENTRY(glGetError)(void) {
+    CALL_GL_API_RETURN(glGetError);
+}
+void API_ENTRY(glGetFloatv)(GLenum pname, GLfloat* params) {
+    CALL_GL_API(glGetFloatv, pname, params);
+}
+void API_ENTRY(glGetFramebufferAttachmentParameteriv)(GLenum target, GLenum attachment, GLenum pname, GLint* params) {
+    CALL_GL_API(glGetFramebufferAttachmentParameteriv, target, attachment, pname, params);
+}
+void API_ENTRY(glGetIntegerv)(GLenum pname, GLint* params) {
+    CALL_GL_API(glGetIntegerv, pname, params);
+}
+void API_ENTRY(glGetProgramiv)(GLuint program, GLenum pname, GLint:1:out params) {
+    CALL_GL_API(glGetProgramiv, program, pname, params);
+}
+void API_ENTRY(glGetProgramInfoLog)(GLuint program, GLsizei bufsize, GLsizei* length, GLchar:GLstring:out infolog) {
+    CALL_GL_API(glGetProgramInfoLog, program, bufsize, length, infolog);
+}
+void API_ENTRY(glGetRenderbufferParameteriv)(GLenum target, GLenum pname, GLint* params) {
+    CALL_GL_API(glGetRenderbufferParameteriv, target, pname, params);
+}
+void API_ENTRY(glGetShaderiv)(GLuint shader, GLenum pname, GLint:1:out params) {
+    CALL_GL_API(glGetShaderiv, shader, pname, params);
+}
+void API_ENTRY(glGetShaderInfoLog)(GLuint shader, GLsizei bufsize, GLsizei* length, GLchar:GLstring:out infolog) {
+    CALL_GL_API(glGetShaderInfoLog, shader, bufsize, length, infolog);
+}
+void API_ENTRY(glGetShaderPrecisionFormat)(GLenum shadertype, GLenum precisiontype, GLint* range, GLint* precision) {
+    CALL_GL_API(glGetShaderPrecisionFormat, shadertype, precisiontype, range, precision);
+}
+void API_ENTRY(glGetShaderSource)(GLuint shader, GLsizei bufsize, GLsizei* length, GLchar:GLstring:out source) {
+    CALL_GL_API(glGetShaderSource, shader, bufsize, length, source);
+}
+const GLubyte* API_ENTRY(glGetString)(GLenum name) {
+    CALL_GL_API_RETURN(glGetString, name);
+}
+void API_ENTRY(glGetTexParameterfv)(GLenum target, GLenum pname, GLfloat* params) {
+    CALL_GL_API(glGetTexParameterfv, target, pname, params);
+}
+void API_ENTRY(glGetTexParameteriv)(GLenum target, GLenum pname, GLint* params) {
+    CALL_GL_API(glGetTexParameteriv, target, pname, params);
+}
+void API_ENTRY(glGetUniformfv)(GLuint program, GLint location, GLfloat* params) {
+    CALL_GL_API(glGetUniformfv, program, location, params);
+}
+void API_ENTRY(glGetUniformiv)(GLuint program, GLint location, GLint* params) {
+    CALL_GL_API(glGetUniformiv, program, location, params);
+}
+int API_ENTRY(glGetUniformLocation)(GLuint program, const GLchar:GLstring:in name) {
+    CALL_GL_API_RETURN(glGetUniformLocation, program, name);
+}
+void API_ENTRY(glGetVertexAttribfv)(GLuint index, GLenum pname, GLfloat* params) {
+    CALL_GL_API(glGetVertexAttribfv, index, pname, params);
+}
+void API_ENTRY(glGetVertexAttribiv)(GLuint index, GLenum pname, GLint* params) {
+    CALL_GL_API(glGetVertexAttribiv, index, pname, params);
+}
+void API_ENTRY(glGetVertexAttribPointerv)(GLuint index, GLenum pname, GLvoid** pointer) {
+    CALL_GL_API(glGetVertexAttribPointerv, index, pname, pointer);
+}
+void API_ENTRY(glHint)(GLenum target, GLenum mode) {
+    CALL_GL_API(glHint, target, mode);
+}
+GLboolean API_ENTRY(glIsBuffer)(GLuint buffer) {
+    CALL_GL_API_RETURN(glIsBuffer, buffer);
+}
+GLboolean API_ENTRY(glIsEnabled)(GLenum cap) {
+    CALL_GL_API_RETURN(glIsEnabled, cap);
+}
+GLboolean API_ENTRY(glIsFramebuffer)(GLuint framebuffer) {
+    CALL_GL_API_RETURN(glIsFramebuffer, framebuffer);
+}
+GLboolean API_ENTRY(glIsProgram)(GLuint program) {
+    CALL_GL_API_RETURN(glIsProgram, program);
+}
+GLboolean API_ENTRY(glIsRenderbuffer)(GLuint renderbuffer) {
+    CALL_GL_API_RETURN(glIsRenderbuffer, renderbuffer);
+}
+GLboolean API_ENTRY(glIsShader)(GLuint shader) {
+    CALL_GL_API_RETURN(glIsShader, shader);
+}
+GLboolean API_ENTRY(glIsTexture)(GLuint texture) {
+    CALL_GL_API_RETURN(glIsTexture, texture);
+}
+void API_ENTRY(glLineWidth)(GLfloat width) {
+    CALL_GL_API(glLineWidth, width);
+}
+void API_ENTRY(glLinkProgram)(GLuint program) {
+    CALL_GL_API(glLinkProgram, program);
+}
+void API_ENTRY(glPixelStorei)(GLenum pname, GLint param) {
+    CALL_GL_API(glPixelStorei, pname, param);
+}
+void API_ENTRY(glPolygonOffset)(GLfloat factor, GLfloat units) {
+    CALL_GL_API(glPolygonOffset, factor, units);
+}
+void API_ENTRY(glReadPixels)(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLvoid* pixels) {
+    CALL_GL_API(glReadPixels, x, y, width, height, format, type, pixels);
+}
+void API_ENTRY(glReleaseShaderCompiler)(void) {
+    CALL_GL_API(glReleaseShaderCompiler);
+}
+void API_ENTRY(glRenderbufferStorage)(GLenum target, GLenum internalformat, GLsizei width, GLsizei height) {
+    CALL_GL_API(glRenderbufferStorage, target, internalformat, width, height);
+}
+void API_ENTRY(glSampleCoverage)(GLclampf value, GLboolean invert) {
+    CALL_GL_API(glSampleCoverage, value, invert);
+}
+void API_ENTRY(glScissor)(GLint x, GLint y, GLsizei width, GLsizei height) {
+    CALL_GL_API(glScissor, x, y, width, height);
+}
+void API_ENTRY(glShaderBinary)(GLsizei n, const GLuint* shaders, GLenum binaryformat, const GLvoid* binary, GLsizei length) {
+    CALL_GL_API(glShaderBinary, n, shaders, binaryformat, binary, length);
+}
+void API_ENTRY(glShaderSource)(GLuint shader, GLsizei count, const GLchar** string, const GLint* length) {
+    CALL_GL_API(glShaderSource, shader, count, string, length);
+}
+void API_ENTRY(glStencilFunc)(GLenum func, GLint ref, GLuint mask) {
+    CALL_GL_API(glStencilFunc, func, ref, mask);
+}
+void API_ENTRY(glStencilFuncSeparate)(GLenum face, GLenum func, GLint ref, GLuint mask) {
+    CALL_GL_API(glStencilFuncSeparate, face, func, ref, mask);
+}
+void API_ENTRY(glStencilMask)(GLuint mask) {
+    CALL_GL_API(glStencilMask, mask);
+}
+void API_ENTRY(glStencilMaskSeparate)(GLenum face, GLuint mask) {
+    CALL_GL_API(glStencilMaskSeparate, face, mask);
+}
+void API_ENTRY(glStencilOp)(GLenum fail, GLenum zfail, GLenum zpass) {
+    CALL_GL_API(glStencilOp, fail, zfail, zpass);
+}
+void API_ENTRY(glStencilOpSeparate)(GLenum face, GLenum fail, GLenum zfail, GLenum zpass) {
+    CALL_GL_API(glStencilOpSeparate, face, fail, zfail, zpass);
+}
+void API_ENTRY(glTexImage2D)(GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const GLvoid* pixels) {
+    CALL_GL_API(glTexImage2D, target, level, internalformat, width, height, border, format, type, pixels);
+}
+void API_ENTRY(glTexParameterf)(GLenum target, GLenum pname, GLfloat param) {
+    CALL_GL_API(glTexParameterf, target, pname, param);
+}
+void API_ENTRY(glTexParameterfv)(GLenum target, GLenum pname, const GLfloat* params) {
+    CALL_GL_API(glTexParameterfv, target, pname, params);
+}
+void API_ENTRY(glTexParameteri)(GLenum target, GLenum pname, GLint param) {
+    CALL_GL_API(glTexParameteri, target, pname, param);
+}
+void API_ENTRY(glTexParameteriv)(GLenum target, GLenum pname, const GLint* params) {
+    CALL_GL_API(glTexParameteriv, target, pname, params);
+}
+void API_ENTRY(glTexSubImage2D)(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid* pixels) {
+    CALL_GL_API(glTexSubImage2D, target, level, xoffset, yoffset, width, height, format, type, pixels);
+}
+void API_ENTRY(glUniform1f)(GLint location, GLfloat x) {
+    CALL_GL_API(glUniform1f, location, x);
+}
+void API_ENTRY(glUniform1fv)(GLint location, GLsizei count, const GLfloat:1*count:in v) {
+    CALL_GL_API(glUniform1fv, location, count, v);
+}
+void API_ENTRY(glUniform1i)(GLint location, GLint x) {
+    CALL_GL_API(glUniform1i, location, x);
+}
+void API_ENTRY(glUniform1iv)(GLint location, GLsizei count, const GLint:1*count:in v) {
+    CALL_GL_API(glUniform1iv, location, count, v);
+}
+void API_ENTRY(glUniform2f)(GLint location, GLfloat x, GLfloat y) {
+    CALL_GL_API(glUniform2f, location, x, y);
+}
+void API_ENTRY(glUniform2fv)(GLint location, GLsizei count, const GLfloat:2*count:in v) {
+    CALL_GL_API(glUniform2fv, location, count, v);
+}
+void API_ENTRY(glUniform2i)(GLint location, GLint x, GLint y) {
+    CALL_GL_API(glUniform2i, location, x, y);
+}
+void API_ENTRY(glUniform2iv)(GLint location, GLsizei count, const GLint:2*count:in v) {
+    CALL_GL_API(glUniform2iv, location, count, v);
+}
+void API_ENTRY(glUniform3f)(GLint location, GLfloat x, GLfloat y, GLfloat z) {
+    CALL_GL_API(glUniform3f, location, x, y, z);
+}
+void API_ENTRY(glUniform3fv)(GLint location, GLsizei count, const GLfloat:3*count:in v) {
+    CALL_GL_API(glUniform3fv, location, count, v);
+}
+void API_ENTRY(glUniform3i)(GLint location, GLint x, GLint y, GLint z) {
+    CALL_GL_API(glUniform3i, location, x, y, z);
+}
+void API_ENTRY(glUniform3iv)(GLint location, GLsizei count, const GLint:3*count:in v) {
+    CALL_GL_API(glUniform3iv, location, count, v);
+}
+void API_ENTRY(glUniform4f)(GLint location, GLfloat x, GLfloat y, GLfloat z, GLfloat w) {
+    CALL_GL_API(glUniform4f, location, x, y, z, w);
+}
+void API_ENTRY(glUniform4fv)(GLint location, GLsizei count, const GLfloat:4*count:in v) {
+    CALL_GL_API(glUniform4fv, location, count, v);
+}
+void API_ENTRY(glUniform4i)(GLint location, GLint x, GLint y, GLint z, GLint w) {
+    CALL_GL_API(glUniform4i, location, x, y, z, w);
+}
+void API_ENTRY(glUniform4iv)(GLint location, GLsizei count, const GLint:4*count:in v) {
+    CALL_GL_API(glUniform4iv, location, count, v);
+}
+void API_ENTRY(glUniformMatrix2fv)(GLint location, GLsizei count, GLboolean transpose, const GLfloat:4*count:in value) {
+    CALL_GL_API(glUniformMatrix2fv, location, count, transpose, value);
+}
+void API_ENTRY(glUniformMatrix3fv)(GLint location, GLsizei count, GLboolean transpose, const GLfloat:9*count:in value) {
+    CALL_GL_API(glUniformMatrix3fv, location, count, transpose, value);
+}
+void API_ENTRY(glUniformMatrix4fv)(GLint location, GLsizei count, GLboolean transpose, const GLfloat:16*count:in value) {
+    CALL_GL_API(glUniformMatrix4fv, location, count, transpose, value);
+}
+void API_ENTRY(glUseProgram)(GLuint program) {
+    CALL_GL_API(glUseProgram, program);
+}
+void API_ENTRY(glValidateProgram)(GLuint program) {
+    CALL_GL_API(glValidateProgram, program);
+}
+void API_ENTRY(glVertexAttrib1f)(GLuint indx, GLfloat x) {
+    CALL_GL_API(glVertexAttrib1f, indx, x);
+}
+void API_ENTRY(glVertexAttrib1fv)(GLuint indx, const GLfloat:1:in values) {
+    CALL_GL_API(glVertexAttrib1fv, indx, values);
+}
+void API_ENTRY(glVertexAttrib2f)(GLuint indx, GLfloat x, GLfloat y) {
+    CALL_GL_API(glVertexAttrib2f, indx, x, y);
+}
+void API_ENTRY(glVertexAttrib2fv)(GLuint indx, const GLfloat:2:in values) {
+    CALL_GL_API(glVertexAttrib2fv, indx, values);
+}
+void API_ENTRY(glVertexAttrib3f)(GLuint indx, GLfloat x, GLfloat y, GLfloat z) {
+    CALL_GL_API(glVertexAttrib3f, indx, x, y, z);
+}
+void API_ENTRY(glVertexAttrib3fv)(GLuint indx, const GLfloat:3:in values) {
+    CALL_GL_API(glVertexAttrib3fv, indx, values);
+}
+void API_ENTRY(glVertexAttrib4f)(GLuint indx, GLfloat x, GLfloat y, GLfloat z, GLfloat w) {
+    CALL_GL_API(glVertexAttrib4f, indx, x, y, z, w);
+}
+void API_ENTRY(glVertexAttrib4fv)(GLuint indx, const GLfloat:4:in values) {
+    CALL_GL_API(glVertexAttrib4fv, indx, values);
+}
+void API_ENTRY(glVertexAttribPointer)(GLuint indx, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const GLvoid* ptr) {
+    CALL_GL_API(glVertexAttribPointer, indx, size, type, normalized, stride, ptr);
+}
+void API_ENTRY(glViewport)(GLint x, GLint y, GLsizei width, GLsizei height) {
+    CALL_GL_API(glViewport, x, y, width, height);
+}
diff --git a/opengl/libs/GLES2_dbg/src/api.cpp b/opengl/libs/GLES2_dbg/src/api.cpp
new file mode 100644
index 0000000..7094ca7
--- /dev/null
+++ b/opengl/libs/GLES2_dbg/src/api.cpp
@@ -0,0 +1,3653 @@
+/*
+ ** Copyright 2011, The Android Open Source Project
+ **
+ ** Licensed under the Apache License, Version 2.0 (the "License");
+ ** you may not use this file except in compliance with the License.
+ ** You may obtain a copy of the License at
+ **
+ **     http://www.apache.org/licenses/LICENSE-2.0
+ **
+ ** Unless required by applicable law or agreed to in writing, software
+ ** distributed under the License is distributed on an "AS IS" BASIS,
+ ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ** See the License for the specific language governing permissions and
+ ** limitations under the License.
+ */
+ 
+// auto generated by generate_api_cpp.py
+
+#include "src/header.h"
+#include "src/api.h"
+
+template<typename T> static int ToInt(const T & t) { STATIC_ASSERT(sizeof(T) == sizeof(int), bitcast); return (int &)t; }
+template<typename T> static T FromInt(const int & t) { STATIC_ASSERT(sizeof(T) == sizeof(int), bitcast); return (T &)t; }
+
+void Debug_glActiveTexture(GLenum texture)
+{
+    glesv2debugger::Message msg;
+    const bool expectResponse = false;
+    struct : public FunctionCall {
+        GLenum texture;
+
+        const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
+            _c->glActiveTexture(texture);
+            return 0;
+        }
+    } caller;
+    caller.texture = texture;
+
+    msg.set_arg0(texture);
+
+    int * ret = MessageLoop(caller, msg, expectResponse,
+                            glesv2debugger::Message_Function_glActiveTexture);
+}
+
+void Debug_glAttachShader(GLuint program, GLuint shader)
+{
+    glesv2debugger::Message msg;
+    const bool expectResponse = false;
+    struct : public FunctionCall {
+        GLuint program;
+        GLuint shader;
+
+        const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
+            _c->glAttachShader(program, shader);
+            return 0;
+        }
+    } caller;
+    caller.program = program;
+    caller.shader = shader;
+
+    msg.set_arg0(program);
+    msg.set_arg1(shader);
+
+    int * ret = MessageLoop(caller, msg, expectResponse,
+                            glesv2debugger::Message_Function_glAttachShader);
+}
+
+void Debug_glBindAttribLocation(GLuint program, GLuint index, const GLchar* name)
+{
+    glesv2debugger::Message msg;
+    const bool expectResponse = false;
+    struct : public FunctionCall {
+        GLuint program;
+        GLuint index;
+        const GLchar* name;
+
+        const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
+            _c->glBindAttribLocation(program, index, name);
+            return 0;
+        }
+    } caller;
+    caller.program = program;
+    caller.index = index;
+    caller.name = name;
+
+    msg.set_arg0(program);
+    msg.set_arg1(index);
+    msg.set_arg2(ToInt(name));
+
+    // FIXME: check for pointer usage
+    msg.mutable_data()->assign(reinterpret_cast<const char *>(name), strlen(name) * sizeof(GLchar));
+    int * ret = MessageLoop(caller, msg, expectResponse,
+                            glesv2debugger::Message_Function_glBindAttribLocation);
+}
+
+void Debug_glBindBuffer(GLenum target, GLuint buffer)
+{
+    glesv2debugger::Message msg;
+    const bool expectResponse = false;
+    struct : public FunctionCall {
+        GLenum target;
+        GLuint buffer;
+
+        const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
+            _c->glBindBuffer(target, buffer);
+            getDbgContextThreadSpecific()->glBindBuffer(target, buffer);
+            return 0;
+        }
+    } caller;
+    caller.target = target;
+    caller.buffer = buffer;
+
+    msg.set_arg0(target);
+    msg.set_arg1(buffer);
+
+    int * ret = MessageLoop(caller, msg, expectResponse,
+                            glesv2debugger::Message_Function_glBindBuffer);
+}
+
+void Debug_glBindFramebuffer(GLenum target, GLuint framebuffer)
+{
+    glesv2debugger::Message msg;
+    const bool expectResponse = false;
+    struct : public FunctionCall {
+        GLenum target;
+        GLuint framebuffer;
+
+        const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
+            _c->glBindFramebuffer(target, framebuffer);
+            return 0;
+        }
+    } caller;
+    caller.target = target;
+    caller.framebuffer = framebuffer;
+
+    msg.set_arg0(target);
+    msg.set_arg1(framebuffer);
+
+    int * ret = MessageLoop(caller, msg, expectResponse,
+                            glesv2debugger::Message_Function_glBindFramebuffer);
+}
+
+void Debug_glBindRenderbuffer(GLenum target, GLuint renderbuffer)
+{
+    glesv2debugger::Message msg;
+    const bool expectResponse = false;
+    struct : public FunctionCall {
+        GLenum target;
+        GLuint renderbuffer;
+
+        const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
+            _c->glBindRenderbuffer(target, renderbuffer);
+            return 0;
+        }
+    } caller;
+    caller.target = target;
+    caller.renderbuffer = renderbuffer;
+
+    msg.set_arg0(target);
+    msg.set_arg1(renderbuffer);
+
+    int * ret = MessageLoop(caller, msg, expectResponse,
+                            glesv2debugger::Message_Function_glBindRenderbuffer);
+}
+
+void Debug_glBindTexture(GLenum target, GLuint texture)
+{
+    glesv2debugger::Message msg;
+    const bool expectResponse = false;
+    struct : public FunctionCall {
+        GLenum target;
+        GLuint texture;
+
+        const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
+            _c->glBindTexture(target, texture);
+            return 0;
+        }
+    } caller;
+    caller.target = target;
+    caller.texture = texture;
+
+    msg.set_arg0(target);
+    msg.set_arg1(texture);
+
+    int * ret = MessageLoop(caller, msg, expectResponse,
+                            glesv2debugger::Message_Function_glBindTexture);
+}
+
+void Debug_glBlendColor(GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha)
+{
+    glesv2debugger::Message msg;
+    const bool expectResponse = false;
+    struct : public FunctionCall {
+        GLclampf red;
+        GLclampf green;
+        GLclampf blue;
+        GLclampf alpha;
+
+        const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
+            _c->glBlendColor(red, green, blue, alpha);
+            return 0;
+        }
+    } caller;
+    caller.red = red;
+    caller.green = green;
+    caller.blue = blue;
+    caller.alpha = alpha;
+
+    msg.set_arg0(ToInt(red));
+    msg.set_arg1(ToInt(green));
+    msg.set_arg2(ToInt(blue));
+    msg.set_arg3(ToInt(alpha));
+
+    int * ret = MessageLoop(caller, msg, expectResponse,
+                            glesv2debugger::Message_Function_glBlendColor);
+}
+
+void Debug_glBlendEquation( GLenum mode )
+{
+    glesv2debugger::Message msg;
+    const bool expectResponse = false;
+    struct : public FunctionCall {
+        GLenum mode;
+
+        const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
+            _c->glBlendEquation(mode);
+            return 0;
+        }
+    } caller;
+    caller.mode = mode;
+
+    msg.set_arg0(mode);
+
+    int * ret = MessageLoop(caller, msg, expectResponse,
+                            glesv2debugger::Message_Function_glBlendEquation);
+}
+
+void Debug_glBlendEquationSeparate(GLenum modeRGB, GLenum modeAlpha)
+{
+    glesv2debugger::Message msg;
+    const bool expectResponse = false;
+    struct : public FunctionCall {
+        GLenum modeRGB;
+        GLenum modeAlpha;
+
+        const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
+            _c->glBlendEquationSeparate(modeRGB, modeAlpha);
+            return 0;
+        }
+    } caller;
+    caller.modeRGB = modeRGB;
+    caller.modeAlpha = modeAlpha;
+
+    msg.set_arg0(modeRGB);
+    msg.set_arg1(modeAlpha);
+
+    int * ret = MessageLoop(caller, msg, expectResponse,
+                            glesv2debugger::Message_Function_glBlendEquationSeparate);
+}
+
+void Debug_glBlendFunc(GLenum sfactor, GLenum dfactor)
+{
+    glesv2debugger::Message msg;
+    const bool expectResponse = false;
+    struct : public FunctionCall {
+        GLenum sfactor;
+        GLenum dfactor;
+
+        const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
+            _c->glBlendFunc(sfactor, dfactor);
+            return 0;
+        }
+    } caller;
+    caller.sfactor = sfactor;
+    caller.dfactor = dfactor;
+
+    msg.set_arg0(sfactor);
+    msg.set_arg1(dfactor);
+
+    int * ret = MessageLoop(caller, msg, expectResponse,
+                            glesv2debugger::Message_Function_glBlendFunc);
+}
+
+void Debug_glBlendFuncSeparate(GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha)
+{
+    glesv2debugger::Message msg;
+    const bool expectResponse = false;
+    struct : public FunctionCall {
+        GLenum srcRGB;
+        GLenum dstRGB;
+        GLenum srcAlpha;
+        GLenum dstAlpha;
+
+        const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
+            _c->glBlendFuncSeparate(srcRGB, dstRGB, srcAlpha, dstAlpha);
+            return 0;
+        }
+    } caller;
+    caller.srcRGB = srcRGB;
+    caller.dstRGB = dstRGB;
+    caller.srcAlpha = srcAlpha;
+    caller.dstAlpha = dstAlpha;
+
+    msg.set_arg0(srcRGB);
+    msg.set_arg1(dstRGB);
+    msg.set_arg2(srcAlpha);
+    msg.set_arg3(dstAlpha);
+
+    int * ret = MessageLoop(caller, msg, expectResponse,
+                            glesv2debugger::Message_Function_glBlendFuncSeparate);
+}
+
+void Debug_glBufferData(GLenum target, GLsizeiptr size, const GLvoid* data, GLenum usage)
+{
+    glesv2debugger::Message msg;
+    const bool expectResponse = false;
+    struct : public FunctionCall {
+        GLenum target;
+        GLsizeiptr size;
+        const GLvoid* data;
+        GLenum usage;
+
+        const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
+            _c->glBufferData(target, size, data, usage);
+            getDbgContextThreadSpecific()->glBufferData(target, size, data, usage);
+            return 0;
+        }
+    } caller;
+    caller.target = target;
+    caller.size = size;
+    caller.data = data;
+    caller.usage = usage;
+
+    msg.set_arg0(target);
+    msg.set_arg1(size);
+    msg.set_arg2(ToInt(data));
+    msg.set_arg3(usage);
+
+    // FIXME: check for pointer usage
+    msg.mutable_data()->assign(reinterpret_cast<const char *>(data), size * sizeof(char));
+    int * ret = MessageLoop(caller, msg, expectResponse,
+                            glesv2debugger::Message_Function_glBufferData);
+}
+
+void Debug_glBufferSubData(GLenum target, GLintptr offset, GLsizeiptr size, const GLvoid* data)
+{
+    glesv2debugger::Message msg;
+    const bool expectResponse = false;
+    struct : public FunctionCall {
+        GLenum target;
+        GLintptr offset;
+        GLsizeiptr size;
+        const GLvoid* data;
+
+        const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
+            _c->glBufferSubData(target, offset, size, data);
+            getDbgContextThreadSpecific()->glBufferSubData(target, offset, size, data);
+            return 0;
+        }
+    } caller;
+    caller.target = target;
+    caller.offset = offset;
+    caller.size = size;
+    caller.data = data;
+
+    msg.set_arg0(target);
+    msg.set_arg1(offset);
+    msg.set_arg2(size);
+    msg.set_arg3(ToInt(data));
+
+    // FIXME: check for pointer usage
+    msg.mutable_data()->assign(reinterpret_cast<const char *>(data), size * sizeof(char));
+    int * ret = MessageLoop(caller, msg, expectResponse,
+                            glesv2debugger::Message_Function_glBufferSubData);
+}
+
+GLenum Debug_glCheckFramebufferStatus(GLenum target)
+{
+    glesv2debugger::Message msg;
+    const bool expectResponse = false;
+    struct : public FunctionCall {
+        GLenum target;
+
+        const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
+            const int * ret = reinterpret_cast<const int *>(_c->glCheckFramebufferStatus(target));
+            msg.set_ret(ToInt(ret));
+            return ret;
+        }
+    } caller;
+    caller.target = target;
+
+    msg.set_arg0(target);
+
+    int * ret = MessageLoop(caller, msg, expectResponse,
+                            glesv2debugger::Message_Function_glCheckFramebufferStatus);
+    return reinterpret_cast<GLenum>(ret);
+}
+
+void Debug_glClear(GLbitfield mask)
+{
+    glesv2debugger::Message msg;
+    const bool expectResponse = false;
+    struct : public FunctionCall {
+        GLbitfield mask;
+
+        const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
+            _c->glClear(mask);
+            return 0;
+        }
+    } caller;
+    caller.mask = mask;
+
+    msg.set_arg0(mask);
+
+    int * ret = MessageLoop(caller, msg, expectResponse,
+                            glesv2debugger::Message_Function_glClear);
+}
+
+void Debug_glClearColor(GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha)
+{
+    glesv2debugger::Message msg;
+    const bool expectResponse = false;
+    struct : public FunctionCall {
+        GLclampf red;
+        GLclampf green;
+        GLclampf blue;
+        GLclampf alpha;
+
+        const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
+            _c->glClearColor(red, green, blue, alpha);
+            return 0;
+        }
+    } caller;
+    caller.red = red;
+    caller.green = green;
+    caller.blue = blue;
+    caller.alpha = alpha;
+
+    msg.set_arg0(ToInt(red));
+    msg.set_arg1(ToInt(green));
+    msg.set_arg2(ToInt(blue));
+    msg.set_arg3(ToInt(alpha));
+
+    int * ret = MessageLoop(caller, msg, expectResponse,
+                            glesv2debugger::Message_Function_glClearColor);
+}
+
+void Debug_glClearDepthf(GLclampf depth)
+{
+    glesv2debugger::Message msg;
+    const bool expectResponse = false;
+    struct : public FunctionCall {
+        GLclampf depth;
+
+        const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
+            _c->glClearDepthf(depth);
+            return 0;
+        }
+    } caller;
+    caller.depth = depth;
+
+    msg.set_arg0(ToInt(depth));
+
+    int * ret = MessageLoop(caller, msg, expectResponse,
+                            glesv2debugger::Message_Function_glClearDepthf);
+}
+
+void Debug_glClearStencil(GLint s)
+{
+    glesv2debugger::Message msg;
+    const bool expectResponse = false;
+    struct : public FunctionCall {
+        GLint s;
+
+        const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
+            _c->glClearStencil(s);
+            return 0;
+        }
+    } caller;
+    caller.s = s;
+
+    msg.set_arg0(s);
+
+    int * ret = MessageLoop(caller, msg, expectResponse,
+                            glesv2debugger::Message_Function_glClearStencil);
+}
+
+void Debug_glColorMask(GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha)
+{
+    glesv2debugger::Message msg;
+    const bool expectResponse = false;
+    struct : public FunctionCall {
+        GLboolean red;
+        GLboolean green;
+        GLboolean blue;
+        GLboolean alpha;
+
+        const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
+            _c->glColorMask(red, green, blue, alpha);
+            return 0;
+        }
+    } caller;
+    caller.red = red;
+    caller.green = green;
+    caller.blue = blue;
+    caller.alpha = alpha;
+
+    msg.set_arg0(red);
+    msg.set_arg1(green);
+    msg.set_arg2(blue);
+    msg.set_arg3(alpha);
+
+    int * ret = MessageLoop(caller, msg, expectResponse,
+                            glesv2debugger::Message_Function_glColorMask);
+}
+
+void Debug_glCompileShader(GLuint shader)
+{
+    glesv2debugger::Message msg;
+    const bool expectResponse = false;
+    struct : public FunctionCall {
+        GLuint shader;
+
+        const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
+            _c->glCompileShader(shader);
+            return 0;
+        }
+    } caller;
+    caller.shader = shader;
+
+    msg.set_arg0(shader);
+
+    int * ret = MessageLoop(caller, msg, expectResponse,
+                            glesv2debugger::Message_Function_glCompileShader);
+}
+
+// FIXME: this function has pointers, it should be hand written
+void Debug_glCompressedTexImage2D(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const GLvoid* data)
+{
+    glesv2debugger::Message msg;
+    const bool expectResponse = false;
+    struct : public FunctionCall {
+        GLenum target;
+        GLint level;
+        GLenum internalformat;
+        GLsizei width;
+        GLsizei height;
+        GLint border;
+        GLsizei imageSize;
+        const GLvoid* data;
+
+        const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
+            _c->glCompressedTexImage2D(target, level, internalformat, width, height, border, imageSize, data);
+            return 0;
+        }
+    } caller;
+    caller.target = target;
+    caller.level = level;
+    caller.internalformat = internalformat;
+    caller.width = width;
+    caller.height = height;
+    caller.border = border;
+    caller.imageSize = imageSize;
+    caller.data = data;
+
+    msg.set_arg0(target);
+    msg.set_arg1(level);
+    msg.set_arg2(internalformat);
+    msg.set_arg3(width);
+    msg.set_arg4(height);
+    msg.set_arg5(border);
+    msg.set_arg6(imageSize);
+    msg.set_arg7(ToInt(data));
+
+    // FIXME: check for pointer usage
+    int * ret = MessageLoop(caller, msg, expectResponse,
+                            glesv2debugger::Message_Function_glCompressedTexImage2D);
+}
+
+// FIXME: this function has pointers, it should be hand written
+void Debug_glCompressedTexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const GLvoid* data)
+{
+    glesv2debugger::Message msg;
+    const bool expectResponse = false;
+    struct : public FunctionCall {
+        GLenum target;
+        GLint level;
+        GLint xoffset;
+        GLint yoffset;
+        GLsizei width;
+        GLsizei height;
+        GLenum format;
+        GLsizei imageSize;
+        const GLvoid* data;
+
+        const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
+            _c->glCompressedTexSubImage2D(target, level, xoffset, yoffset, width, height, format, imageSize, data);
+            return 0;
+        }
+    } caller;
+    caller.target = target;
+    caller.level = level;
+    caller.xoffset = xoffset;
+    caller.yoffset = yoffset;
+    caller.width = width;
+    caller.height = height;
+    caller.format = format;
+    caller.imageSize = imageSize;
+    caller.data = data;
+
+    msg.set_arg0(target);
+    msg.set_arg1(level);
+    msg.set_arg2(xoffset);
+    msg.set_arg3(yoffset);
+    msg.set_arg4(width);
+    msg.set_arg5(height);
+    msg.set_arg6(format);
+    msg.set_arg7(imageSize);
+    msg.set_arg8(ToInt(data));
+
+    // FIXME: check for pointer usage
+    int * ret = MessageLoop(caller, msg, expectResponse,
+                            glesv2debugger::Message_Function_glCompressedTexSubImage2D);
+}
+
+void Debug_glCopyTexImage2D(GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border)
+{
+    glesv2debugger::Message msg;
+    const bool expectResponse = false;
+    struct : public FunctionCall {
+        GLenum target;
+        GLint level;
+        GLenum internalformat;
+        GLint x;
+        GLint y;
+        GLsizei width;
+        GLsizei height;
+        GLint border;
+
+        const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
+            _c->glCopyTexImage2D(target, level, internalformat, x, y, width, height, border);
+            return 0;
+        }
+    } caller;
+    caller.target = target;
+    caller.level = level;
+    caller.internalformat = internalformat;
+    caller.x = x;
+    caller.y = y;
+    caller.width = width;
+    caller.height = height;
+    caller.border = border;
+
+    msg.set_arg0(target);
+    msg.set_arg1(level);
+    msg.set_arg2(internalformat);
+    msg.set_arg3(x);
+    msg.set_arg4(y);
+    msg.set_arg5(width);
+    msg.set_arg6(height);
+    msg.set_arg7(border);
+
+    EXTEND_Debug_glCopyTexImage2D;
+    int * ret = MessageLoop(caller, msg, expectResponse,
+                            glesv2debugger::Message_Function_glCopyTexImage2D);
+}
+
+void Debug_glCopyTexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height)
+{
+    glesv2debugger::Message msg;
+    const bool expectResponse = false;
+    struct : public FunctionCall {
+        GLenum target;
+        GLint level;
+        GLint xoffset;
+        GLint yoffset;
+        GLint x;
+        GLint y;
+        GLsizei width;
+        GLsizei height;
+
+        const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
+            _c->glCopyTexSubImage2D(target, level, xoffset, yoffset, x, y, width, height);
+            return 0;
+        }
+    } caller;
+    caller.target = target;
+    caller.level = level;
+    caller.xoffset = xoffset;
+    caller.yoffset = yoffset;
+    caller.x = x;
+    caller.y = y;
+    caller.width = width;
+    caller.height = height;
+
+    msg.set_arg0(target);
+    msg.set_arg1(level);
+    msg.set_arg2(xoffset);
+    msg.set_arg3(yoffset);
+    msg.set_arg4(x);
+    msg.set_arg5(y);
+    msg.set_arg6(width);
+    msg.set_arg7(height);
+
+    EXTEND_Debug_glCopyTexSubImage2D;
+    int * ret = MessageLoop(caller, msg, expectResponse,
+                            glesv2debugger::Message_Function_glCopyTexSubImage2D);
+}
+
+GLuint Debug_glCreateProgram(void)
+{
+    glesv2debugger::Message msg;
+    const bool expectResponse = false;
+    struct : public FunctionCall {
+
+        const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
+            const int * ret = reinterpret_cast<const int *>(_c->glCreateProgram());
+            msg.set_ret(ToInt(ret));
+            return ret;
+        }
+    } caller;
+
+
+    int * ret = MessageLoop(caller, msg, expectResponse,
+                            glesv2debugger::Message_Function_glCreateProgram);
+    return reinterpret_cast<GLuint>(ret);
+}
+
+GLuint Debug_glCreateShader(GLenum type)
+{
+    glesv2debugger::Message msg;
+    const bool expectResponse = false;
+    struct : public FunctionCall {
+        GLenum type;
+
+        const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
+            const int * ret = reinterpret_cast<const int *>(_c->glCreateShader(type));
+            msg.set_ret(ToInt(ret));
+            return ret;
+        }
+    } caller;
+    caller.type = type;
+
+    msg.set_arg0(type);
+
+    int * ret = MessageLoop(caller, msg, expectResponse,
+                            glesv2debugger::Message_Function_glCreateShader);
+    return reinterpret_cast<GLuint>(ret);
+}
+
+void Debug_glCullFace(GLenum mode)
+{
+    glesv2debugger::Message msg;
+    const bool expectResponse = false;
+    struct : public FunctionCall {
+        GLenum mode;
+
+        const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
+            _c->glCullFace(mode);
+            return 0;
+        }
+    } caller;
+    caller.mode = mode;
+
+    msg.set_arg0(mode);
+
+    int * ret = MessageLoop(caller, msg, expectResponse,
+                            glesv2debugger::Message_Function_glCullFace);
+}
+
+void Debug_glDeleteBuffers(GLsizei n, const GLuint* buffers)
+{
+    glesv2debugger::Message msg;
+    const bool expectResponse = false;
+    struct : public FunctionCall {
+        GLsizei n;
+        const GLuint* buffers;
+
+        const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
+            _c->glDeleteBuffers(n, buffers);
+            getDbgContextThreadSpecific()->glDeleteBuffers(n, buffers);
+            return 0;
+        }
+    } caller;
+    caller.n = n;
+    caller.buffers = buffers;
+
+    msg.set_arg0(n);
+    msg.set_arg1(ToInt(buffers));
+
+    // FIXME: check for pointer usage
+    msg.mutable_data()->assign(reinterpret_cast<const char *>(buffers), n * sizeof(GLuint));
+    int * ret = MessageLoop(caller, msg, expectResponse,
+                            glesv2debugger::Message_Function_glDeleteBuffers);
+}
+
+void Debug_glDeleteFramebuffers(GLsizei n, const GLuint* framebuffers)
+{
+    glesv2debugger::Message msg;
+    const bool expectResponse = false;
+    struct : public FunctionCall {
+        GLsizei n;
+        const GLuint* framebuffers;
+
+        const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
+            _c->glDeleteFramebuffers(n, framebuffers);
+            return 0;
+        }
+    } caller;
+    caller.n = n;
+    caller.framebuffers = framebuffers;
+
+    msg.set_arg0(n);
+    msg.set_arg1(ToInt(framebuffers));
+
+    // FIXME: check for pointer usage
+    msg.mutable_data()->assign(reinterpret_cast<const char *>(framebuffers), n * sizeof(GLuint));
+    int * ret = MessageLoop(caller, msg, expectResponse,
+                            glesv2debugger::Message_Function_glDeleteFramebuffers);
+}
+
+void Debug_glDeleteProgram(GLuint program)
+{
+    glesv2debugger::Message msg;
+    const bool expectResponse = false;
+    struct : public FunctionCall {
+        GLuint program;
+
+        const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
+            _c->glDeleteProgram(program);
+            return 0;
+        }
+    } caller;
+    caller.program = program;
+
+    msg.set_arg0(program);
+
+    int * ret = MessageLoop(caller, msg, expectResponse,
+                            glesv2debugger::Message_Function_glDeleteProgram);
+}
+
+void Debug_glDeleteRenderbuffers(GLsizei n, const GLuint* renderbuffers)
+{
+    glesv2debugger::Message msg;
+    const bool expectResponse = false;
+    struct : public FunctionCall {
+        GLsizei n;
+        const GLuint* renderbuffers;
+
+        const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
+            _c->glDeleteRenderbuffers(n, renderbuffers);
+            return 0;
+        }
+    } caller;
+    caller.n = n;
+    caller.renderbuffers = renderbuffers;
+
+    msg.set_arg0(n);
+    msg.set_arg1(ToInt(renderbuffers));
+
+    // FIXME: check for pointer usage
+    msg.mutable_data()->assign(reinterpret_cast<const char *>(renderbuffers), n * sizeof(GLuint));
+    int * ret = MessageLoop(caller, msg, expectResponse,
+                            glesv2debugger::Message_Function_glDeleteRenderbuffers);
+}
+
+void Debug_glDeleteShader(GLuint shader)
+{
+    glesv2debugger::Message msg;
+    const bool expectResponse = false;
+    struct : public FunctionCall {
+        GLuint shader;
+
+        const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
+            _c->glDeleteShader(shader);
+            return 0;
+        }
+    } caller;
+    caller.shader = shader;
+
+    msg.set_arg0(shader);
+
+    int * ret = MessageLoop(caller, msg, expectResponse,
+                            glesv2debugger::Message_Function_glDeleteShader);
+}
+
+void Debug_glDeleteTextures(GLsizei n, const GLuint* textures)
+{
+    glesv2debugger::Message msg;
+    const bool expectResponse = false;
+    struct : public FunctionCall {
+        GLsizei n;
+        const GLuint* textures;
+
+        const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
+            _c->glDeleteTextures(n, textures);
+            return 0;
+        }
+    } caller;
+    caller.n = n;
+    caller.textures = textures;
+
+    msg.set_arg0(n);
+    msg.set_arg1(ToInt(textures));
+
+    // FIXME: check for pointer usage
+    msg.mutable_data()->assign(reinterpret_cast<const char *>(textures), n * sizeof(GLuint));
+    int * ret = MessageLoop(caller, msg, expectResponse,
+                            glesv2debugger::Message_Function_glDeleteTextures);
+}
+
+void Debug_glDepthFunc(GLenum func)
+{
+    glesv2debugger::Message msg;
+    const bool expectResponse = false;
+    struct : public FunctionCall {
+        GLenum func;
+
+        const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
+            _c->glDepthFunc(func);
+            return 0;
+        }
+    } caller;
+    caller.func = func;
+
+    msg.set_arg0(func);
+
+    int * ret = MessageLoop(caller, msg, expectResponse,
+                            glesv2debugger::Message_Function_glDepthFunc);
+}
+
+void Debug_glDepthMask(GLboolean flag)
+{
+    glesv2debugger::Message msg;
+    const bool expectResponse = false;
+    struct : public FunctionCall {
+        GLboolean flag;
+
+        const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
+            _c->glDepthMask(flag);
+            return 0;
+        }
+    } caller;
+    caller.flag = flag;
+
+    msg.set_arg0(flag);
+
+    int * ret = MessageLoop(caller, msg, expectResponse,
+                            glesv2debugger::Message_Function_glDepthMask);
+}
+
+void Debug_glDepthRangef(GLclampf zNear, GLclampf zFar)
+{
+    glesv2debugger::Message msg;
+    const bool expectResponse = false;
+    struct : public FunctionCall {
+        GLclampf zNear;
+        GLclampf zFar;
+
+        const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
+            _c->glDepthRangef(zNear, zFar);
+            return 0;
+        }
+    } caller;
+    caller.zNear = zNear;
+    caller.zFar = zFar;
+
+    msg.set_arg0(ToInt(zNear));
+    msg.set_arg1(ToInt(zFar));
+
+    int * ret = MessageLoop(caller, msg, expectResponse,
+                            glesv2debugger::Message_Function_glDepthRangef);
+}
+
+void Debug_glDetachShader(GLuint program, GLuint shader)
+{
+    glesv2debugger::Message msg;
+    const bool expectResponse = false;
+    struct : public FunctionCall {
+        GLuint program;
+        GLuint shader;
+
+        const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
+            _c->glDetachShader(program, shader);
+            return 0;
+        }
+    } caller;
+    caller.program = program;
+    caller.shader = shader;
+
+    msg.set_arg0(program);
+    msg.set_arg1(shader);
+
+    int * ret = MessageLoop(caller, msg, expectResponse,
+                            glesv2debugger::Message_Function_glDetachShader);
+}
+
+void Debug_glDisable(GLenum cap)
+{
+    glesv2debugger::Message msg;
+    const bool expectResponse = false;
+    struct : public FunctionCall {
+        GLenum cap;
+
+        const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
+            _c->glDisable(cap);
+            return 0;
+        }
+    } caller;
+    caller.cap = cap;
+
+    msg.set_arg0(cap);
+
+    int * ret = MessageLoop(caller, msg, expectResponse,
+                            glesv2debugger::Message_Function_glDisable);
+}
+
+void Debug_glDisableVertexAttribArray(GLuint index)
+{
+    glesv2debugger::Message msg;
+    const bool expectResponse = false;
+    struct : public FunctionCall {
+        GLuint index;
+
+        const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
+            _c->glDisableVertexAttribArray(index);
+            getDbgContextThreadSpecific()->glDisableVertexAttribArray(index);
+            return 0;
+        }
+    } caller;
+    caller.index = index;
+
+    msg.set_arg0(index);
+
+    int * ret = MessageLoop(caller, msg, expectResponse,
+                            glesv2debugger::Message_Function_glDisableVertexAttribArray);
+}
+
+void Debug_glEnable(GLenum cap)
+{
+    glesv2debugger::Message msg;
+    const bool expectResponse = false;
+    struct : public FunctionCall {
+        GLenum cap;
+
+        const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
+            _c->glEnable(cap);
+            return 0;
+        }
+    } caller;
+    caller.cap = cap;
+
+    msg.set_arg0(cap);
+
+    int * ret = MessageLoop(caller, msg, expectResponse,
+                            glesv2debugger::Message_Function_glEnable);
+}
+
+void Debug_glEnableVertexAttribArray(GLuint index)
+{
+    glesv2debugger::Message msg;
+    const bool expectResponse = false;
+    struct : public FunctionCall {
+        GLuint index;
+
+        const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
+            _c->glEnableVertexAttribArray(index);
+            getDbgContextThreadSpecific()->glEnableVertexAttribArray(index);
+            return 0;
+        }
+    } caller;
+    caller.index = index;
+
+    msg.set_arg0(index);
+
+    int * ret = MessageLoop(caller, msg, expectResponse,
+                            glesv2debugger::Message_Function_glEnableVertexAttribArray);
+}
+
+void Debug_glFinish(void)
+{
+    glesv2debugger::Message msg;
+    const bool expectResponse = false;
+    struct : public FunctionCall {
+
+        const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
+            _c->glFinish();
+            return 0;
+        }
+    } caller;
+
+
+    int * ret = MessageLoop(caller, msg, expectResponse,
+                            glesv2debugger::Message_Function_glFinish);
+}
+
+void Debug_glFlush(void)
+{
+    glesv2debugger::Message msg;
+    const bool expectResponse = false;
+    struct : public FunctionCall {
+
+        const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
+            _c->glFlush();
+            return 0;
+        }
+    } caller;
+
+
+    int * ret = MessageLoop(caller, msg, expectResponse,
+                            glesv2debugger::Message_Function_glFlush);
+}
+
+void Debug_glFramebufferRenderbuffer(GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer)
+{
+    glesv2debugger::Message msg;
+    const bool expectResponse = false;
+    struct : public FunctionCall {
+        GLenum target;
+        GLenum attachment;
+        GLenum renderbuffertarget;
+        GLuint renderbuffer;
+
+        const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
+            _c->glFramebufferRenderbuffer(target, attachment, renderbuffertarget, renderbuffer);
+            return 0;
+        }
+    } caller;
+    caller.target = target;
+    caller.attachment = attachment;
+    caller.renderbuffertarget = renderbuffertarget;
+    caller.renderbuffer = renderbuffer;
+
+    msg.set_arg0(target);
+    msg.set_arg1(attachment);
+    msg.set_arg2(renderbuffertarget);
+    msg.set_arg3(renderbuffer);
+
+    int * ret = MessageLoop(caller, msg, expectResponse,
+                            glesv2debugger::Message_Function_glFramebufferRenderbuffer);
+}
+
+void Debug_glFramebufferTexture2D(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level)
+{
+    glesv2debugger::Message msg;
+    const bool expectResponse = false;
+    struct : public FunctionCall {
+        GLenum target;
+        GLenum attachment;
+        GLenum textarget;
+        GLuint texture;
+        GLint level;
+
+        const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
+            _c->glFramebufferTexture2D(target, attachment, textarget, texture, level);
+            return 0;
+        }
+    } caller;
+    caller.target = target;
+    caller.attachment = attachment;
+    caller.textarget = textarget;
+    caller.texture = texture;
+    caller.level = level;
+
+    msg.set_arg0(target);
+    msg.set_arg1(attachment);
+    msg.set_arg2(textarget);
+    msg.set_arg3(texture);
+    msg.set_arg4(level);
+
+    int * ret = MessageLoop(caller, msg, expectResponse,
+                            glesv2debugger::Message_Function_glFramebufferTexture2D);
+}
+
+void Debug_glFrontFace(GLenum mode)
+{
+    glesv2debugger::Message msg;
+    const bool expectResponse = false;
+    struct : public FunctionCall {
+        GLenum mode;
+
+        const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
+            _c->glFrontFace(mode);
+            return 0;
+        }
+    } caller;
+    caller.mode = mode;
+
+    msg.set_arg0(mode);
+
+    int * ret = MessageLoop(caller, msg, expectResponse,
+                            glesv2debugger::Message_Function_glFrontFace);
+}
+
+void Debug_glGenBuffers(GLsizei n, GLuint* buffers)
+{
+    glesv2debugger::Message msg;
+    const bool expectResponse = false;
+    struct : public FunctionCall {
+        GLsizei n;
+        GLuint* buffers;
+
+        const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
+            nsecs_t c0 = systemTime(timeMode);
+            _c->glGenBuffers(n, buffers);
+            msg.set_time((systemTime(timeMode) - c0) * 1e-6f);
+            msg.mutable_data()->assign(reinterpret_cast<const char *>(buffers), n * sizeof(GLuint));
+            return 0;
+        }
+    } caller;
+    caller.n = n;
+    caller.buffers = buffers;
+
+    msg.set_arg0(n);
+    msg.set_arg1(ToInt(buffers));
+
+    // FIXME: check for pointer usage
+    int * ret = MessageLoop(caller, msg, expectResponse,
+                            glesv2debugger::Message_Function_glGenBuffers);
+}
+
+void Debug_glGenerateMipmap(GLenum target)
+{
+    glesv2debugger::Message msg;
+    const bool expectResponse = false;
+    struct : public FunctionCall {
+        GLenum target;
+
+        const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
+            _c->glGenerateMipmap(target);
+            return 0;
+        }
+    } caller;
+    caller.target = target;
+
+    msg.set_arg0(target);
+
+    int * ret = MessageLoop(caller, msg, expectResponse,
+                            glesv2debugger::Message_Function_glGenerateMipmap);
+}
+
+void Debug_glGenFramebuffers(GLsizei n, GLuint* framebuffers)
+{
+    glesv2debugger::Message msg;
+    const bool expectResponse = false;
+    struct : public FunctionCall {
+        GLsizei n;
+        GLuint* framebuffers;
+
+        const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
+            nsecs_t c0 = systemTime(timeMode);
+            _c->glGenFramebuffers(n, framebuffers);
+            msg.set_time((systemTime(timeMode) - c0) * 1e-6f);
+            msg.mutable_data()->assign(reinterpret_cast<const char *>(framebuffers), n * sizeof(GLuint));
+            return 0;
+        }
+    } caller;
+    caller.n = n;
+    caller.framebuffers = framebuffers;
+
+    msg.set_arg0(n);
+    msg.set_arg1(ToInt(framebuffers));
+
+    // FIXME: check for pointer usage
+    int * ret = MessageLoop(caller, msg, expectResponse,
+                            glesv2debugger::Message_Function_glGenFramebuffers);
+}
+
+void Debug_glGenRenderbuffers(GLsizei n, GLuint* renderbuffers)
+{
+    glesv2debugger::Message msg;
+    const bool expectResponse = false;
+    struct : public FunctionCall {
+        GLsizei n;
+        GLuint* renderbuffers;
+
+        const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
+            nsecs_t c0 = systemTime(timeMode);
+            _c->glGenRenderbuffers(n, renderbuffers);
+            msg.set_time((systemTime(timeMode) - c0) * 1e-6f);
+            msg.mutable_data()->assign(reinterpret_cast<const char *>(renderbuffers), n * sizeof(GLuint));
+            return 0;
+        }
+    } caller;
+    caller.n = n;
+    caller.renderbuffers = renderbuffers;
+
+    msg.set_arg0(n);
+    msg.set_arg1(ToInt(renderbuffers));
+
+    // FIXME: check for pointer usage
+    int * ret = MessageLoop(caller, msg, expectResponse,
+                            glesv2debugger::Message_Function_glGenRenderbuffers);
+}
+
+void Debug_glGenTextures(GLsizei n, GLuint* textures)
+{
+    glesv2debugger::Message msg;
+    const bool expectResponse = false;
+    struct : public FunctionCall {
+        GLsizei n;
+        GLuint* textures;
+
+        const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
+            nsecs_t c0 = systemTime(timeMode);
+            _c->glGenTextures(n, textures);
+            msg.set_time((systemTime(timeMode) - c0) * 1e-6f);
+            msg.mutable_data()->assign(reinterpret_cast<const char *>(textures), n * sizeof(GLuint));
+            return 0;
+        }
+    } caller;
+    caller.n = n;
+    caller.textures = textures;
+
+    msg.set_arg0(n);
+    msg.set_arg1(ToInt(textures));
+
+    // FIXME: check for pointer usage
+    int * ret = MessageLoop(caller, msg, expectResponse,
+                            glesv2debugger::Message_Function_glGenTextures);
+}
+
+// FIXME: this function has pointers, it should be hand written
+void Debug_glGetActiveAttrib(GLuint program, GLuint index, GLsizei bufsize, GLsizei* length, GLint* size, GLenum* type, GLchar* name)
+{
+    glesv2debugger::Message msg;
+    const bool expectResponse = false;
+    struct : public FunctionCall {
+        GLuint program;
+        GLuint index;
+        GLsizei bufsize;
+        GLsizei* length;
+        GLint* size;
+        GLenum* type;
+        GLchar* name;
+
+        const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
+            _c->glGetActiveAttrib(program, index, bufsize, length, size, type, name);
+            return 0;
+        }
+    } caller;
+    caller.program = program;
+    caller.index = index;
+    caller.bufsize = bufsize;
+    caller.length = length;
+    caller.size = size;
+    caller.type = type;
+    caller.name = name;
+
+    msg.set_arg0(program);
+    msg.set_arg1(index);
+    msg.set_arg2(bufsize);
+    msg.set_arg3(ToInt(length));
+    msg.set_arg4(ToInt(size));
+    msg.set_arg5(ToInt(type));
+    msg.set_arg6(ToInt(name));
+
+    // FIXME: check for pointer usage
+    msg.mutable_data()->assign(reinterpret_cast<const char *>(name), strlen(name) * sizeof(GLchar));
+    int * ret = MessageLoop(caller, msg, expectResponse,
+                            glesv2debugger::Message_Function_glGetActiveAttrib);
+}
+
+// FIXME: this function has pointers, it should be hand written
+void Debug_glGetActiveUniform(GLuint program, GLuint index, GLsizei bufsize, GLsizei* length, GLint* size, GLenum* type, GLchar* name)
+{
+    glesv2debugger::Message msg;
+    const bool expectResponse = false;
+    struct : public FunctionCall {
+        GLuint program;
+        GLuint index;
+        GLsizei bufsize;
+        GLsizei* length;
+        GLint* size;
+        GLenum* type;
+        GLchar* name;
+
+        const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
+            _c->glGetActiveUniform(program, index, bufsize, length, size, type, name);
+            return 0;
+        }
+    } caller;
+    caller.program = program;
+    caller.index = index;
+    caller.bufsize = bufsize;
+    caller.length = length;
+    caller.size = size;
+    caller.type = type;
+    caller.name = name;
+
+    msg.set_arg0(program);
+    msg.set_arg1(index);
+    msg.set_arg2(bufsize);
+    msg.set_arg3(ToInt(length));
+    msg.set_arg4(ToInt(size));
+    msg.set_arg5(ToInt(type));
+    msg.set_arg6(ToInt(name));
+
+    // FIXME: check for pointer usage
+    msg.mutable_data()->assign(reinterpret_cast<const char *>(name), strlen(name) * sizeof(GLchar));
+    int * ret = MessageLoop(caller, msg, expectResponse,
+                            glesv2debugger::Message_Function_glGetActiveUniform);
+}
+
+// FIXME: this function has pointers, it should be hand written
+void Debug_glGetAttachedShaders(GLuint program, GLsizei maxcount, GLsizei* count, GLuint* shaders)
+{
+    glesv2debugger::Message msg;
+    const bool expectResponse = false;
+    struct : public FunctionCall {
+        GLuint program;
+        GLsizei maxcount;
+        GLsizei* count;
+        GLuint* shaders;
+
+        const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
+            _c->glGetAttachedShaders(program, maxcount, count, shaders);
+            return 0;
+        }
+    } caller;
+    caller.program = program;
+    caller.maxcount = maxcount;
+    caller.count = count;
+    caller.shaders = shaders;
+
+    msg.set_arg0(program);
+    msg.set_arg1(maxcount);
+    msg.set_arg2(ToInt(count));
+    msg.set_arg3(ToInt(shaders));
+
+    // FIXME: check for pointer usage
+    int * ret = MessageLoop(caller, msg, expectResponse,
+                            glesv2debugger::Message_Function_glGetAttachedShaders);
+}
+
+int Debug_glGetAttribLocation(GLuint program, const GLchar* name)
+{
+    glesv2debugger::Message msg;
+    const bool expectResponse = false;
+    struct : public FunctionCall {
+        GLuint program;
+        const GLchar* name;
+
+        const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
+            const int * ret = reinterpret_cast<const int *>(_c->glGetAttribLocation(program, name));
+            msg.set_ret(ToInt(ret));
+            return ret;
+        }
+    } caller;
+    caller.program = program;
+    caller.name = name;
+
+    msg.set_arg0(program);
+    msg.set_arg1(ToInt(name));
+
+    // FIXME: check for pointer usage
+    msg.mutable_data()->assign(reinterpret_cast<const char *>(name), strlen(name) * sizeof(GLchar));
+    int * ret = MessageLoop(caller, msg, expectResponse,
+                            glesv2debugger::Message_Function_glGetAttribLocation);
+    return reinterpret_cast<int>(ret);
+}
+
+// FIXME: this function has pointers, it should be hand written
+void Debug_glGetBooleanv(GLenum pname, GLboolean* params)
+{
+    glesv2debugger::Message msg;
+    const bool expectResponse = false;
+    struct : public FunctionCall {
+        GLenum pname;
+        GLboolean* params;
+
+        const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
+            _c->glGetBooleanv(pname, params);
+            return 0;
+        }
+    } caller;
+    caller.pname = pname;
+    caller.params = params;
+
+    msg.set_arg0(pname);
+    msg.set_arg1(ToInt(params));
+
+    // FIXME: check for pointer usage
+    int * ret = MessageLoop(caller, msg, expectResponse,
+                            glesv2debugger::Message_Function_glGetBooleanv);
+}
+
+// FIXME: this function has pointers, it should be hand written
+void Debug_glGetBufferParameteriv(GLenum target, GLenum pname, GLint* params)
+{
+    glesv2debugger::Message msg;
+    const bool expectResponse = false;
+    struct : public FunctionCall {
+        GLenum target;
+        GLenum pname;
+        GLint* params;
+
+        const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
+            _c->glGetBufferParameteriv(target, pname, params);
+            return 0;
+        }
+    } caller;
+    caller.target = target;
+    caller.pname = pname;
+    caller.params = params;
+
+    msg.set_arg0(target);
+    msg.set_arg1(pname);
+    msg.set_arg2(ToInt(params));
+
+    // FIXME: check for pointer usage
+    int * ret = MessageLoop(caller, msg, expectResponse,
+                            glesv2debugger::Message_Function_glGetBufferParameteriv);
+}
+
+GLenum Debug_glGetError(void)
+{
+    glesv2debugger::Message msg;
+    const bool expectResponse = false;
+    struct : public FunctionCall {
+
+        const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
+            const int * ret = reinterpret_cast<const int *>(_c->glGetError());
+            msg.set_ret(ToInt(ret));
+            return ret;
+        }
+    } caller;
+
+
+    int * ret = MessageLoop(caller, msg, expectResponse,
+                            glesv2debugger::Message_Function_glGetError);
+    return reinterpret_cast<GLenum>(ret);
+}
+
+// FIXME: this function has pointers, it should be hand written
+void Debug_glGetFloatv(GLenum pname, GLfloat* params)
+{
+    glesv2debugger::Message msg;
+    const bool expectResponse = false;
+    struct : public FunctionCall {
+        GLenum pname;
+        GLfloat* params;
+
+        const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
+            _c->glGetFloatv(pname, params);
+            return 0;
+        }
+    } caller;
+    caller.pname = pname;
+    caller.params = params;
+
+    msg.set_arg0(pname);
+    msg.set_arg1(ToInt(params));
+
+    // FIXME: check for pointer usage
+    int * ret = MessageLoop(caller, msg, expectResponse,
+                            glesv2debugger::Message_Function_glGetFloatv);
+}
+
+// FIXME: this function has pointers, it should be hand written
+void Debug_glGetFramebufferAttachmentParameteriv(GLenum target, GLenum attachment, GLenum pname, GLint* params)
+{
+    glesv2debugger::Message msg;
+    const bool expectResponse = false;
+    struct : public FunctionCall {
+        GLenum target;
+        GLenum attachment;
+        GLenum pname;
+        GLint* params;
+
+        const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
+            _c->glGetFramebufferAttachmentParameteriv(target, attachment, pname, params);
+            return 0;
+        }
+    } caller;
+    caller.target = target;
+    caller.attachment = attachment;
+    caller.pname = pname;
+    caller.params = params;
+
+    msg.set_arg0(target);
+    msg.set_arg1(attachment);
+    msg.set_arg2(pname);
+    msg.set_arg3(ToInt(params));
+
+    // FIXME: check for pointer usage
+    int * ret = MessageLoop(caller, msg, expectResponse,
+                            glesv2debugger::Message_Function_glGetFramebufferAttachmentParameteriv);
+}
+
+// FIXME: this function has pointers, it should be hand written
+void Debug_glGetIntegerv(GLenum pname, GLint* params)
+{
+    glesv2debugger::Message msg;
+    const bool expectResponse = false;
+    struct : public FunctionCall {
+        GLenum pname;
+        GLint* params;
+
+        const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
+            _c->glGetIntegerv(pname, params);
+            return 0;
+        }
+    } caller;
+    caller.pname = pname;
+    caller.params = params;
+
+    msg.set_arg0(pname);
+    msg.set_arg1(ToInt(params));
+
+    // FIXME: check for pointer usage
+    int * ret = MessageLoop(caller, msg, expectResponse,
+                            glesv2debugger::Message_Function_glGetIntegerv);
+}
+
+void Debug_glGetProgramiv(GLuint program, GLenum pname, GLint* params)
+{
+    glesv2debugger::Message msg;
+    const bool expectResponse = false;
+    struct : public FunctionCall {
+        GLuint program;
+        GLenum pname;
+        GLint* params;
+
+        const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
+            nsecs_t c0 = systemTime(timeMode);
+            _c->glGetProgramiv(program, pname, params);
+            msg.set_time((systemTime(timeMode) - c0) * 1e-6f);
+            msg.mutable_data()->assign(reinterpret_cast<const char *>(params), 1 * sizeof(GLint));
+            return 0;
+        }
+    } caller;
+    caller.program = program;
+    caller.pname = pname;
+    caller.params = params;
+
+    msg.set_arg0(program);
+    msg.set_arg1(pname);
+    msg.set_arg2(ToInt(params));
+
+    // FIXME: check for pointer usage
+    int * ret = MessageLoop(caller, msg, expectResponse,
+                            glesv2debugger::Message_Function_glGetProgramiv);
+}
+
+// FIXME: this function has pointers, it should be hand written
+void Debug_glGetProgramInfoLog(GLuint program, GLsizei bufsize, GLsizei* length, GLchar* infolog)
+{
+    glesv2debugger::Message msg;
+    const bool expectResponse = false;
+    struct : public FunctionCall {
+        GLuint program;
+        GLsizei bufsize;
+        GLsizei* length;
+        GLchar* infolog;
+
+        const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
+            nsecs_t c0 = systemTime(timeMode);
+            _c->glGetProgramInfoLog(program, bufsize, length, infolog);
+            msg.set_time((systemTime(timeMode) - c0) * 1e-6f);
+            msg.mutable_data()->assign(reinterpret_cast<const char *>(infolog), strlen(infolog) * sizeof(GLchar));
+            return 0;
+        }
+    } caller;
+    caller.program = program;
+    caller.bufsize = bufsize;
+    caller.length = length;
+    caller.infolog = infolog;
+
+    msg.set_arg0(program);
+    msg.set_arg1(bufsize);
+    msg.set_arg2(ToInt(length));
+    msg.set_arg3(ToInt(infolog));
+
+    // FIXME: check for pointer usage
+    int * ret = MessageLoop(caller, msg, expectResponse,
+                            glesv2debugger::Message_Function_glGetProgramInfoLog);
+}
+
+// FIXME: this function has pointers, it should be hand written
+void Debug_glGetRenderbufferParameteriv(GLenum target, GLenum pname, GLint* params)
+{
+    glesv2debugger::Message msg;
+    const bool expectResponse = false;
+    struct : public FunctionCall {
+        GLenum target;
+        GLenum pname;
+        GLint* params;
+
+        const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
+            _c->glGetRenderbufferParameteriv(target, pname, params);
+            return 0;
+        }
+    } caller;
+    caller.target = target;
+    caller.pname = pname;
+    caller.params = params;
+
+    msg.set_arg0(target);
+    msg.set_arg1(pname);
+    msg.set_arg2(ToInt(params));
+
+    // FIXME: check for pointer usage
+    int * ret = MessageLoop(caller, msg, expectResponse,
+                            glesv2debugger::Message_Function_glGetRenderbufferParameteriv);
+}
+
+void Debug_glGetShaderiv(GLuint shader, GLenum pname, GLint* params)
+{
+    glesv2debugger::Message msg;
+    const bool expectResponse = false;
+    struct : public FunctionCall {
+        GLuint shader;
+        GLenum pname;
+        GLint* params;
+
+        const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
+            nsecs_t c0 = systemTime(timeMode);
+            _c->glGetShaderiv(shader, pname, params);
+            msg.set_time((systemTime(timeMode) - c0) * 1e-6f);
+            msg.mutable_data()->assign(reinterpret_cast<const char *>(params), 1 * sizeof(GLint));
+            return 0;
+        }
+    } caller;
+    caller.shader = shader;
+    caller.pname = pname;
+    caller.params = params;
+
+    msg.set_arg0(shader);
+    msg.set_arg1(pname);
+    msg.set_arg2(ToInt(params));
+
+    // FIXME: check for pointer usage
+    int * ret = MessageLoop(caller, msg, expectResponse,
+                            glesv2debugger::Message_Function_glGetShaderiv);
+}
+
+// FIXME: this function has pointers, it should be hand written
+void Debug_glGetShaderInfoLog(GLuint shader, GLsizei bufsize, GLsizei* length, GLchar* infolog)
+{
+    glesv2debugger::Message msg;
+    const bool expectResponse = false;
+    struct : public FunctionCall {
+        GLuint shader;
+        GLsizei bufsize;
+        GLsizei* length;
+        GLchar* infolog;
+
+        const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
+            nsecs_t c0 = systemTime(timeMode);
+            _c->glGetShaderInfoLog(shader, bufsize, length, infolog);
+            msg.set_time((systemTime(timeMode) - c0) * 1e-6f);
+            msg.mutable_data()->assign(reinterpret_cast<const char *>(infolog), strlen(infolog) * sizeof(GLchar));
+            return 0;
+        }
+    } caller;
+    caller.shader = shader;
+    caller.bufsize = bufsize;
+    caller.length = length;
+    caller.infolog = infolog;
+
+    msg.set_arg0(shader);
+    msg.set_arg1(bufsize);
+    msg.set_arg2(ToInt(length));
+    msg.set_arg3(ToInt(infolog));
+
+    // FIXME: check for pointer usage
+    int * ret = MessageLoop(caller, msg, expectResponse,
+                            glesv2debugger::Message_Function_glGetShaderInfoLog);
+}
+
+// FIXME: this function has pointers, it should be hand written
+void Debug_glGetShaderPrecisionFormat(GLenum shadertype, GLenum precisiontype, GLint* range, GLint* precision)
+{
+    glesv2debugger::Message msg;
+    const bool expectResponse = false;
+    struct : public FunctionCall {
+        GLenum shadertype;
+        GLenum precisiontype;
+        GLint* range;
+        GLint* precision;
+
+        const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
+            _c->glGetShaderPrecisionFormat(shadertype, precisiontype, range, precision);
+            return 0;
+        }
+    } caller;
+    caller.shadertype = shadertype;
+    caller.precisiontype = precisiontype;
+    caller.range = range;
+    caller.precision = precision;
+
+    msg.set_arg0(shadertype);
+    msg.set_arg1(precisiontype);
+    msg.set_arg2(ToInt(range));
+    msg.set_arg3(ToInt(precision));
+
+    // FIXME: check for pointer usage
+    int * ret = MessageLoop(caller, msg, expectResponse,
+                            glesv2debugger::Message_Function_glGetShaderPrecisionFormat);
+}
+
+// FIXME: this function has pointers, it should be hand written
+void Debug_glGetShaderSource(GLuint shader, GLsizei bufsize, GLsizei* length, GLchar* source)
+{
+    glesv2debugger::Message msg;
+    const bool expectResponse = false;
+    struct : public FunctionCall {
+        GLuint shader;
+        GLsizei bufsize;
+        GLsizei* length;
+        GLchar* source;
+
+        const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
+            nsecs_t c0 = systemTime(timeMode);
+            _c->glGetShaderSource(shader, bufsize, length, source);
+            msg.set_time((systemTime(timeMode) - c0) * 1e-6f);
+            msg.mutable_data()->assign(reinterpret_cast<const char *>(source), strlen(source) * sizeof(GLchar));
+            return 0;
+        }
+    } caller;
+    caller.shader = shader;
+    caller.bufsize = bufsize;
+    caller.length = length;
+    caller.source = source;
+
+    msg.set_arg0(shader);
+    msg.set_arg1(bufsize);
+    msg.set_arg2(ToInt(length));
+    msg.set_arg3(ToInt(source));
+
+    // FIXME: check for pointer usage
+    int * ret = MessageLoop(caller, msg, expectResponse,
+                            glesv2debugger::Message_Function_glGetShaderSource);
+}
+
+// FIXME: this function has pointers, it should be hand written
+const GLubyte* Debug_glGetString(GLenum name)
+{
+    glesv2debugger::Message msg;
+    const bool expectResponse = false;
+    struct : public FunctionCall {
+        GLenum name;
+
+        const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
+            const int * ret = reinterpret_cast<const int *>(_c->glGetString(name));
+            msg.set_ret(ToInt(ret));
+            return ret;
+        }
+    } caller;
+    caller.name = name;
+
+    msg.set_arg0(name);
+
+    // FIXME: check for pointer usage
+    int * ret = MessageLoop(caller, msg, expectResponse,
+                            glesv2debugger::Message_Function_glGetString);
+    return reinterpret_cast<const GLubyte*>(ret);
+}
+
+// FIXME: this function has pointers, it should be hand written
+void Debug_glGetTexParameterfv(GLenum target, GLenum pname, GLfloat* params)
+{
+    glesv2debugger::Message msg;
+    const bool expectResponse = false;
+    struct : public FunctionCall {
+        GLenum target;
+        GLenum pname;
+        GLfloat* params;
+
+        const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
+            _c->glGetTexParameterfv(target, pname, params);
+            return 0;
+        }
+    } caller;
+    caller.target = target;
+    caller.pname = pname;
+    caller.params = params;
+
+    msg.set_arg0(target);
+    msg.set_arg1(pname);
+    msg.set_arg2(ToInt(params));
+
+    // FIXME: check for pointer usage
+    int * ret = MessageLoop(caller, msg, expectResponse,
+                            glesv2debugger::Message_Function_glGetTexParameterfv);
+}
+
+// FIXME: this function has pointers, it should be hand written
+void Debug_glGetTexParameteriv(GLenum target, GLenum pname, GLint* params)
+{
+    glesv2debugger::Message msg;
+    const bool expectResponse = false;
+    struct : public FunctionCall {
+        GLenum target;
+        GLenum pname;
+        GLint* params;
+
+        const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
+            _c->glGetTexParameteriv(target, pname, params);
+            return 0;
+        }
+    } caller;
+    caller.target = target;
+    caller.pname = pname;
+    caller.params = params;
+
+    msg.set_arg0(target);
+    msg.set_arg1(pname);
+    msg.set_arg2(ToInt(params));
+
+    // FIXME: check for pointer usage
+    int * ret = MessageLoop(caller, msg, expectResponse,
+                            glesv2debugger::Message_Function_glGetTexParameteriv);
+}
+
+// FIXME: this function has pointers, it should be hand written
+void Debug_glGetUniformfv(GLuint program, GLint location, GLfloat* params)
+{
+    glesv2debugger::Message msg;
+    const bool expectResponse = false;
+    struct : public FunctionCall {
+        GLuint program;
+        GLint location;
+        GLfloat* params;
+
+        const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
+            _c->glGetUniformfv(program, location, params);
+            return 0;
+        }
+    } caller;
+    caller.program = program;
+    caller.location = location;
+    caller.params = params;
+
+    msg.set_arg0(program);
+    msg.set_arg1(location);
+    msg.set_arg2(ToInt(params));
+
+    // FIXME: check for pointer usage
+    int * ret = MessageLoop(caller, msg, expectResponse,
+                            glesv2debugger::Message_Function_glGetUniformfv);
+}
+
+// FIXME: this function has pointers, it should be hand written
+void Debug_glGetUniformiv(GLuint program, GLint location, GLint* params)
+{
+    glesv2debugger::Message msg;
+    const bool expectResponse = false;
+    struct : public FunctionCall {
+        GLuint program;
+        GLint location;
+        GLint* params;
+
+        const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
+            _c->glGetUniformiv(program, location, params);
+            return 0;
+        }
+    } caller;
+    caller.program = program;
+    caller.location = location;
+    caller.params = params;
+
+    msg.set_arg0(program);
+    msg.set_arg1(location);
+    msg.set_arg2(ToInt(params));
+
+    // FIXME: check for pointer usage
+    int * ret = MessageLoop(caller, msg, expectResponse,
+                            glesv2debugger::Message_Function_glGetUniformiv);
+}
+
+int Debug_glGetUniformLocation(GLuint program, const GLchar* name)
+{
+    glesv2debugger::Message msg;
+    const bool expectResponse = false;
+    struct : public FunctionCall {
+        GLuint program;
+        const GLchar* name;
+
+        const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
+            const int * ret = reinterpret_cast<const int *>(_c->glGetUniformLocation(program, name));
+            msg.set_ret(ToInt(ret));
+            return ret;
+        }
+    } caller;
+    caller.program = program;
+    caller.name = name;
+
+    msg.set_arg0(program);
+    msg.set_arg1(ToInt(name));
+
+    // FIXME: check for pointer usage
+    msg.mutable_data()->assign(reinterpret_cast<const char *>(name), strlen(name) * sizeof(GLchar));
+    int * ret = MessageLoop(caller, msg, expectResponse,
+                            glesv2debugger::Message_Function_glGetUniformLocation);
+    return reinterpret_cast<int>(ret);
+}
+
+// FIXME: this function has pointers, it should be hand written
+void Debug_glGetVertexAttribfv(GLuint index, GLenum pname, GLfloat* params)
+{
+    glesv2debugger::Message msg;
+    const bool expectResponse = false;
+    struct : public FunctionCall {
+        GLuint index;
+        GLenum pname;
+        GLfloat* params;
+
+        const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
+            _c->glGetVertexAttribfv(index, pname, params);
+            return 0;
+        }
+    } caller;
+    caller.index = index;
+    caller.pname = pname;
+    caller.params = params;
+
+    msg.set_arg0(index);
+    msg.set_arg1(pname);
+    msg.set_arg2(ToInt(params));
+
+    // FIXME: check for pointer usage
+    int * ret = MessageLoop(caller, msg, expectResponse,
+                            glesv2debugger::Message_Function_glGetVertexAttribfv);
+}
+
+// FIXME: this function has pointers, it should be hand written
+void Debug_glGetVertexAttribiv(GLuint index, GLenum pname, GLint* params)
+{
+    glesv2debugger::Message msg;
+    const bool expectResponse = false;
+    struct : public FunctionCall {
+        GLuint index;
+        GLenum pname;
+        GLint* params;
+
+        const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
+            _c->glGetVertexAttribiv(index, pname, params);
+            return 0;
+        }
+    } caller;
+    caller.index = index;
+    caller.pname = pname;
+    caller.params = params;
+
+    msg.set_arg0(index);
+    msg.set_arg1(pname);
+    msg.set_arg2(ToInt(params));
+
+    // FIXME: check for pointer usage
+    int * ret = MessageLoop(caller, msg, expectResponse,
+                            glesv2debugger::Message_Function_glGetVertexAttribiv);
+}
+
+// FIXME: this function has pointers, it should be hand written
+void Debug_glGetVertexAttribPointerv(GLuint index, GLenum pname, GLvoid** pointer)
+{
+    glesv2debugger::Message msg;
+    const bool expectResponse = false;
+    struct : public FunctionCall {
+        GLuint index;
+        GLenum pname;
+        GLvoid** pointer;
+
+        const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
+            _c->glGetVertexAttribPointerv(index, pname, pointer);
+            return 0;
+        }
+    } caller;
+    caller.index = index;
+    caller.pname = pname;
+    caller.pointer = pointer;
+
+    msg.set_arg0(index);
+    msg.set_arg1(pname);
+    msg.set_arg2(ToInt(pointer));
+
+    // FIXME: check for pointer usage
+    int * ret = MessageLoop(caller, msg, expectResponse,
+                            glesv2debugger::Message_Function_glGetVertexAttribPointerv);
+}
+
+void Debug_glHint(GLenum target, GLenum mode)
+{
+    glesv2debugger::Message msg;
+    const bool expectResponse = false;
+    struct : public FunctionCall {
+        GLenum target;
+        GLenum mode;
+
+        const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
+            _c->glHint(target, mode);
+            return 0;
+        }
+    } caller;
+    caller.target = target;
+    caller.mode = mode;
+
+    msg.set_arg0(target);
+    msg.set_arg1(mode);
+
+    int * ret = MessageLoop(caller, msg, expectResponse,
+                            glesv2debugger::Message_Function_glHint);
+}
+
+GLboolean Debug_glIsBuffer(GLuint buffer)
+{
+    glesv2debugger::Message msg;
+    const bool expectResponse = false;
+    struct : public FunctionCall {
+        GLuint buffer;
+
+        const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
+            const int * ret = reinterpret_cast<const int *>(_c->glIsBuffer(buffer));
+            msg.set_ret(ToInt(ret));
+            return ret;
+        }
+    } caller;
+    caller.buffer = buffer;
+
+    msg.set_arg0(buffer);
+
+    int * ret = MessageLoop(caller, msg, expectResponse,
+                            glesv2debugger::Message_Function_glIsBuffer);
+    return static_cast<GLboolean>(reinterpret_cast<int>(ret));
+}
+
+GLboolean Debug_glIsEnabled(GLenum cap)
+{
+    glesv2debugger::Message msg;
+    const bool expectResponse = false;
+    struct : public FunctionCall {
+        GLenum cap;
+
+        const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
+            const int * ret = reinterpret_cast<const int *>(_c->glIsEnabled(cap));
+            msg.set_ret(ToInt(ret));
+            return ret;
+        }
+    } caller;
+    caller.cap = cap;
+
+    msg.set_arg0(cap);
+
+    int * ret = MessageLoop(caller, msg, expectResponse,
+                            glesv2debugger::Message_Function_glIsEnabled);
+    return static_cast<GLboolean>(reinterpret_cast<int>(ret));
+}
+
+GLboolean Debug_glIsFramebuffer(GLuint framebuffer)
+{
+    glesv2debugger::Message msg;
+    const bool expectResponse = false;
+    struct : public FunctionCall {
+        GLuint framebuffer;
+
+        const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
+            const int * ret = reinterpret_cast<const int *>(_c->glIsFramebuffer(framebuffer));
+            msg.set_ret(ToInt(ret));
+            return ret;
+        }
+    } caller;
+    caller.framebuffer = framebuffer;
+
+    msg.set_arg0(framebuffer);
+
+    int * ret = MessageLoop(caller, msg, expectResponse,
+                            glesv2debugger::Message_Function_glIsFramebuffer);
+    return static_cast<GLboolean>(reinterpret_cast<int>(ret));
+}
+
+GLboolean Debug_glIsProgram(GLuint program)
+{
+    glesv2debugger::Message msg;
+    const bool expectResponse = false;
+    struct : public FunctionCall {
+        GLuint program;
+
+        const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
+            const int * ret = reinterpret_cast<const int *>(_c->glIsProgram(program));
+            msg.set_ret(ToInt(ret));
+            return ret;
+        }
+    } caller;
+    caller.program = program;
+
+    msg.set_arg0(program);
+
+    int * ret = MessageLoop(caller, msg, expectResponse,
+                            glesv2debugger::Message_Function_glIsProgram);
+    return static_cast<GLboolean>(reinterpret_cast<int>(ret));
+}
+
+GLboolean Debug_glIsRenderbuffer(GLuint renderbuffer)
+{
+    glesv2debugger::Message msg;
+    const bool expectResponse = false;
+    struct : public FunctionCall {
+        GLuint renderbuffer;
+
+        const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
+            const int * ret = reinterpret_cast<const int *>(_c->glIsRenderbuffer(renderbuffer));
+            msg.set_ret(ToInt(ret));
+            return ret;
+        }
+    } caller;
+    caller.renderbuffer = renderbuffer;
+
+    msg.set_arg0(renderbuffer);
+
+    int * ret = MessageLoop(caller, msg, expectResponse,
+                            glesv2debugger::Message_Function_glIsRenderbuffer);
+    return static_cast<GLboolean>(reinterpret_cast<int>(ret));
+}
+
+GLboolean Debug_glIsShader(GLuint shader)
+{
+    glesv2debugger::Message msg;
+    const bool expectResponse = false;
+    struct : public FunctionCall {
+        GLuint shader;
+
+        const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
+            const int * ret = reinterpret_cast<const int *>(_c->glIsShader(shader));
+            msg.set_ret(ToInt(ret));
+            return ret;
+        }
+    } caller;
+    caller.shader = shader;
+
+    msg.set_arg0(shader);
+
+    int * ret = MessageLoop(caller, msg, expectResponse,
+                            glesv2debugger::Message_Function_glIsShader);
+    return static_cast<GLboolean>(reinterpret_cast<int>(ret));
+}
+
+GLboolean Debug_glIsTexture(GLuint texture)
+{
+    glesv2debugger::Message msg;
+    const bool expectResponse = false;
+    struct : public FunctionCall {
+        GLuint texture;
+
+        const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
+            const int * ret = reinterpret_cast<const int *>(_c->glIsTexture(texture));
+            msg.set_ret(ToInt(ret));
+            return ret;
+        }
+    } caller;
+    caller.texture = texture;
+
+    msg.set_arg0(texture);
+
+    int * ret = MessageLoop(caller, msg, expectResponse,
+                            glesv2debugger::Message_Function_glIsTexture);
+    return static_cast<GLboolean>(reinterpret_cast<int>(ret));
+}
+
+void Debug_glLineWidth(GLfloat width)
+{
+    glesv2debugger::Message msg;
+    const bool expectResponse = false;
+    struct : public FunctionCall {
+        GLfloat width;
+
+        const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
+            _c->glLineWidth(width);
+            return 0;
+        }
+    } caller;
+    caller.width = width;
+
+    msg.set_arg0(ToInt(width));
+
+    int * ret = MessageLoop(caller, msg, expectResponse,
+                            glesv2debugger::Message_Function_glLineWidth);
+}
+
+void Debug_glLinkProgram(GLuint program)
+{
+    glesv2debugger::Message msg;
+    const bool expectResponse = false;
+    struct : public FunctionCall {
+        GLuint program;
+
+        const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
+            _c->glLinkProgram(program);
+            return 0;
+        }
+    } caller;
+    caller.program = program;
+
+    msg.set_arg0(program);
+
+    int * ret = MessageLoop(caller, msg, expectResponse,
+                            glesv2debugger::Message_Function_glLinkProgram);
+}
+
+void Debug_glPixelStorei(GLenum pname, GLint param)
+{
+    glesv2debugger::Message msg;
+    const bool expectResponse = false;
+    struct : public FunctionCall {
+        GLenum pname;
+        GLint param;
+
+        const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
+            _c->glPixelStorei(pname, param);
+            return 0;
+        }
+    } caller;
+    caller.pname = pname;
+    caller.param = param;
+
+    msg.set_arg0(pname);
+    msg.set_arg1(param);
+
+    int * ret = MessageLoop(caller, msg, expectResponse,
+                            glesv2debugger::Message_Function_glPixelStorei);
+}
+
+void Debug_glPolygonOffset(GLfloat factor, GLfloat units)
+{
+    glesv2debugger::Message msg;
+    const bool expectResponse = false;
+    struct : public FunctionCall {
+        GLfloat factor;
+        GLfloat units;
+
+        const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
+            _c->glPolygonOffset(factor, units);
+            return 0;
+        }
+    } caller;
+    caller.factor = factor;
+    caller.units = units;
+
+    msg.set_arg0(ToInt(factor));
+    msg.set_arg1(ToInt(units));
+
+    int * ret = MessageLoop(caller, msg, expectResponse,
+                            glesv2debugger::Message_Function_glPolygonOffset);
+}
+
+void Debug_glReleaseShaderCompiler(void)
+{
+    glesv2debugger::Message msg;
+    const bool expectResponse = false;
+    struct : public FunctionCall {
+
+        const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
+            _c->glReleaseShaderCompiler();
+            return 0;
+        }
+    } caller;
+
+
+    int * ret = MessageLoop(caller, msg, expectResponse,
+                            glesv2debugger::Message_Function_glReleaseShaderCompiler);
+}
+
+void Debug_glRenderbufferStorage(GLenum target, GLenum internalformat, GLsizei width, GLsizei height)
+{
+    glesv2debugger::Message msg;
+    const bool expectResponse = false;
+    struct : public FunctionCall {
+        GLenum target;
+        GLenum internalformat;
+        GLsizei width;
+        GLsizei height;
+
+        const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
+            _c->glRenderbufferStorage(target, internalformat, width, height);
+            return 0;
+        }
+    } caller;
+    caller.target = target;
+    caller.internalformat = internalformat;
+    caller.width = width;
+    caller.height = height;
+
+    msg.set_arg0(target);
+    msg.set_arg1(internalformat);
+    msg.set_arg2(width);
+    msg.set_arg3(height);
+
+    int * ret = MessageLoop(caller, msg, expectResponse,
+                            glesv2debugger::Message_Function_glRenderbufferStorage);
+}
+
+void Debug_glSampleCoverage(GLclampf value, GLboolean invert)
+{
+    glesv2debugger::Message msg;
+    const bool expectResponse = false;
+    struct : public FunctionCall {
+        GLclampf value;
+        GLboolean invert;
+
+        const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
+            _c->glSampleCoverage(value, invert);
+            return 0;
+        }
+    } caller;
+    caller.value = value;
+    caller.invert = invert;
+
+    msg.set_arg0(ToInt(value));
+    msg.set_arg1(invert);
+
+    int * ret = MessageLoop(caller, msg, expectResponse,
+                            glesv2debugger::Message_Function_glSampleCoverage);
+}
+
+void Debug_glScissor(GLint x, GLint y, GLsizei width, GLsizei height)
+{
+    glesv2debugger::Message msg;
+    const bool expectResponse = false;
+    struct : public FunctionCall {
+        GLint x;
+        GLint y;
+        GLsizei width;
+        GLsizei height;
+
+        const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
+            _c->glScissor(x, y, width, height);
+            return 0;
+        }
+    } caller;
+    caller.x = x;
+    caller.y = y;
+    caller.width = width;
+    caller.height = height;
+
+    msg.set_arg0(x);
+    msg.set_arg1(y);
+    msg.set_arg2(width);
+    msg.set_arg3(height);
+
+    int * ret = MessageLoop(caller, msg, expectResponse,
+                            glesv2debugger::Message_Function_glScissor);
+}
+
+// FIXME: this function has pointers, it should be hand written
+void Debug_glShaderBinary(GLsizei n, const GLuint* shaders, GLenum binaryformat, const GLvoid* binary, GLsizei length)
+{
+    glesv2debugger::Message msg;
+    const bool expectResponse = false;
+    struct : public FunctionCall {
+        GLsizei n;
+        const GLuint* shaders;
+        GLenum binaryformat;
+        const GLvoid* binary;
+        GLsizei length;
+
+        const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
+            _c->glShaderBinary(n, shaders, binaryformat, binary, length);
+            return 0;
+        }
+    } caller;
+    caller.n = n;
+    caller.shaders = shaders;
+    caller.binaryformat = binaryformat;
+    caller.binary = binary;
+    caller.length = length;
+
+    msg.set_arg0(n);
+    msg.set_arg1(ToInt(shaders));
+    msg.set_arg2(binaryformat);
+    msg.set_arg3(ToInt(binary));
+    msg.set_arg4(length);
+
+    // FIXME: check for pointer usage
+    int * ret = MessageLoop(caller, msg, expectResponse,
+                            glesv2debugger::Message_Function_glShaderBinary);
+}
+
+void Debug_glShaderSource(GLuint shader, GLsizei count, const GLchar** string, const GLint* length)
+{
+    glesv2debugger::Message msg;
+    const bool expectResponse = false;
+    struct : public FunctionCall {
+        GLuint shader;
+        GLsizei count;
+        const GLchar** string;
+        const GLint* length;
+
+        const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
+            _c->glShaderSource(shader, count, string, length);
+            return 0;
+        }
+    } caller;
+    caller.shader = shader;
+    caller.count = count;
+    caller.string = string;
+    caller.length = length;
+
+    msg.set_arg0(shader);
+    msg.set_arg1(count);
+    msg.set_arg2(ToInt(string));
+    msg.set_arg3(ToInt(length));
+
+    // FIXME: check for pointer usage
+    EXTEND_Debug_glShaderSource;
+    int * ret = MessageLoop(caller, msg, expectResponse,
+                            glesv2debugger::Message_Function_glShaderSource);
+}
+
+void Debug_glStencilFunc(GLenum func, GLint ref, GLuint mask)
+{
+    glesv2debugger::Message msg;
+    const bool expectResponse = false;
+    struct : public FunctionCall {
+        GLenum func;
+        GLint ref;
+        GLuint mask;
+
+        const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
+            _c->glStencilFunc(func, ref, mask);
+            return 0;
+        }
+    } caller;
+    caller.func = func;
+    caller.ref = ref;
+    caller.mask = mask;
+
+    msg.set_arg0(func);
+    msg.set_arg1(ref);
+    msg.set_arg2(mask);
+
+    int * ret = MessageLoop(caller, msg, expectResponse,
+                            glesv2debugger::Message_Function_glStencilFunc);
+}
+
+void Debug_glStencilFuncSeparate(GLenum face, GLenum func, GLint ref, GLuint mask)
+{
+    glesv2debugger::Message msg;
+    const bool expectResponse = false;
+    struct : public FunctionCall {
+        GLenum face;
+        GLenum func;
+        GLint ref;
+        GLuint mask;
+
+        const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
+            _c->glStencilFuncSeparate(face, func, ref, mask);
+            return 0;
+        }
+    } caller;
+    caller.face = face;
+    caller.func = func;
+    caller.ref = ref;
+    caller.mask = mask;
+
+    msg.set_arg0(face);
+    msg.set_arg1(func);
+    msg.set_arg2(ref);
+    msg.set_arg3(mask);
+
+    int * ret = MessageLoop(caller, msg, expectResponse,
+                            glesv2debugger::Message_Function_glStencilFuncSeparate);
+}
+
+void Debug_glStencilMask(GLuint mask)
+{
+    glesv2debugger::Message msg;
+    const bool expectResponse = false;
+    struct : public FunctionCall {
+        GLuint mask;
+
+        const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
+            _c->glStencilMask(mask);
+            return 0;
+        }
+    } caller;
+    caller.mask = mask;
+
+    msg.set_arg0(mask);
+
+    int * ret = MessageLoop(caller, msg, expectResponse,
+                            glesv2debugger::Message_Function_glStencilMask);
+}
+
+void Debug_glStencilMaskSeparate(GLenum face, GLuint mask)
+{
+    glesv2debugger::Message msg;
+    const bool expectResponse = false;
+    struct : public FunctionCall {
+        GLenum face;
+        GLuint mask;
+
+        const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
+            _c->glStencilMaskSeparate(face, mask);
+            return 0;
+        }
+    } caller;
+    caller.face = face;
+    caller.mask = mask;
+
+    msg.set_arg0(face);
+    msg.set_arg1(mask);
+
+    int * ret = MessageLoop(caller, msg, expectResponse,
+                            glesv2debugger::Message_Function_glStencilMaskSeparate);
+}
+
+void Debug_glStencilOp(GLenum fail, GLenum zfail, GLenum zpass)
+{
+    glesv2debugger::Message msg;
+    const bool expectResponse = false;
+    struct : public FunctionCall {
+        GLenum fail;
+        GLenum zfail;
+        GLenum zpass;
+
+        const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
+            _c->glStencilOp(fail, zfail, zpass);
+            return 0;
+        }
+    } caller;
+    caller.fail = fail;
+    caller.zfail = zfail;
+    caller.zpass = zpass;
+
+    msg.set_arg0(fail);
+    msg.set_arg1(zfail);
+    msg.set_arg2(zpass);
+
+    int * ret = MessageLoop(caller, msg, expectResponse,
+                            glesv2debugger::Message_Function_glStencilOp);
+}
+
+void Debug_glStencilOpSeparate(GLenum face, GLenum fail, GLenum zfail, GLenum zpass)
+{
+    glesv2debugger::Message msg;
+    const bool expectResponse = false;
+    struct : public FunctionCall {
+        GLenum face;
+        GLenum fail;
+        GLenum zfail;
+        GLenum zpass;
+
+        const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
+            _c->glStencilOpSeparate(face, fail, zfail, zpass);
+            return 0;
+        }
+    } caller;
+    caller.face = face;
+    caller.fail = fail;
+    caller.zfail = zfail;
+    caller.zpass = zpass;
+
+    msg.set_arg0(face);
+    msg.set_arg1(fail);
+    msg.set_arg2(zfail);
+    msg.set_arg3(zpass);
+
+    int * ret = MessageLoop(caller, msg, expectResponse,
+                            glesv2debugger::Message_Function_glStencilOpSeparate);
+}
+
+void Debug_glTexParameterf(GLenum target, GLenum pname, GLfloat param)
+{
+    glesv2debugger::Message msg;
+    const bool expectResponse = false;
+    struct : public FunctionCall {
+        GLenum target;
+        GLenum pname;
+        GLfloat param;
+
+        const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
+            _c->glTexParameterf(target, pname, param);
+            return 0;
+        }
+    } caller;
+    caller.target = target;
+    caller.pname = pname;
+    caller.param = param;
+
+    msg.set_arg0(target);
+    msg.set_arg1(pname);
+    msg.set_arg2(ToInt(param));
+
+    int * ret = MessageLoop(caller, msg, expectResponse,
+                            glesv2debugger::Message_Function_glTexParameterf);
+}
+
+// FIXME: this function has pointers, it should be hand written
+void Debug_glTexParameterfv(GLenum target, GLenum pname, const GLfloat* params)
+{
+    glesv2debugger::Message msg;
+    const bool expectResponse = false;
+    struct : public FunctionCall {
+        GLenum target;
+        GLenum pname;
+        const GLfloat* params;
+
+        const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
+            _c->glTexParameterfv(target, pname, params);
+            return 0;
+        }
+    } caller;
+    caller.target = target;
+    caller.pname = pname;
+    caller.params = params;
+
+    msg.set_arg0(target);
+    msg.set_arg1(pname);
+    msg.set_arg2(ToInt(params));
+
+    // FIXME: check for pointer usage
+    int * ret = MessageLoop(caller, msg, expectResponse,
+                            glesv2debugger::Message_Function_glTexParameterfv);
+}
+
+void Debug_glTexParameteri(GLenum target, GLenum pname, GLint param)
+{
+    glesv2debugger::Message msg;
+    const bool expectResponse = false;
+    struct : public FunctionCall {
+        GLenum target;
+        GLenum pname;
+        GLint param;
+
+        const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
+            _c->glTexParameteri(target, pname, param);
+            return 0;
+        }
+    } caller;
+    caller.target = target;
+    caller.pname = pname;
+    caller.param = param;
+
+    msg.set_arg0(target);
+    msg.set_arg1(pname);
+    msg.set_arg2(param);
+
+    int * ret = MessageLoop(caller, msg, expectResponse,
+                            glesv2debugger::Message_Function_glTexParameteri);
+}
+
+// FIXME: this function has pointers, it should be hand written
+void Debug_glTexParameteriv(GLenum target, GLenum pname, const GLint* params)
+{
+    glesv2debugger::Message msg;
+    const bool expectResponse = false;
+    struct : public FunctionCall {
+        GLenum target;
+        GLenum pname;
+        const GLint* params;
+
+        const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
+            _c->glTexParameteriv(target, pname, params);
+            return 0;
+        }
+    } caller;
+    caller.target = target;
+    caller.pname = pname;
+    caller.params = params;
+
+    msg.set_arg0(target);
+    msg.set_arg1(pname);
+    msg.set_arg2(ToInt(params));
+
+    // FIXME: check for pointer usage
+    int * ret = MessageLoop(caller, msg, expectResponse,
+                            glesv2debugger::Message_Function_glTexParameteriv);
+}
+
+void Debug_glUniform1f(GLint location, GLfloat x)
+{
+    glesv2debugger::Message msg;
+    const bool expectResponse = false;
+    struct : public FunctionCall {
+        GLint location;
+        GLfloat x;
+
+        const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
+            _c->glUniform1f(location, x);
+            return 0;
+        }
+    } caller;
+    caller.location = location;
+    caller.x = x;
+
+    msg.set_arg0(location);
+    msg.set_arg1(ToInt(x));
+
+    int * ret = MessageLoop(caller, msg, expectResponse,
+                            glesv2debugger::Message_Function_glUniform1f);
+}
+
+void Debug_glUniform1fv(GLint location, GLsizei count, const GLfloat* v)
+{
+    glesv2debugger::Message msg;
+    const bool expectResponse = false;
+    struct : public FunctionCall {
+        GLint location;
+        GLsizei count;
+        const GLfloat* v;
+
+        const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
+            _c->glUniform1fv(location, count, v);
+            return 0;
+        }
+    } caller;
+    caller.location = location;
+    caller.count = count;
+    caller.v = v;
+
+    msg.set_arg0(location);
+    msg.set_arg1(count);
+    msg.set_arg2(ToInt(v));
+
+    // FIXME: check for pointer usage
+    msg.mutable_data()->assign(reinterpret_cast<const char *>(v), 1*count * sizeof(GLfloat));
+    int * ret = MessageLoop(caller, msg, expectResponse,
+                            glesv2debugger::Message_Function_glUniform1fv);
+}
+
+void Debug_glUniform1i(GLint location, GLint x)
+{
+    glesv2debugger::Message msg;
+    const bool expectResponse = false;
+    struct : public FunctionCall {
+        GLint location;
+        GLint x;
+
+        const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
+            _c->glUniform1i(location, x);
+            return 0;
+        }
+    } caller;
+    caller.location = location;
+    caller.x = x;
+
+    msg.set_arg0(location);
+    msg.set_arg1(x);
+
+    int * ret = MessageLoop(caller, msg, expectResponse,
+                            glesv2debugger::Message_Function_glUniform1i);
+}
+
+void Debug_glUniform1iv(GLint location, GLsizei count, const GLint* v)
+{
+    glesv2debugger::Message msg;
+    const bool expectResponse = false;
+    struct : public FunctionCall {
+        GLint location;
+        GLsizei count;
+        const GLint* v;
+
+        const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
+            _c->glUniform1iv(location, count, v);
+            return 0;
+        }
+    } caller;
+    caller.location = location;
+    caller.count = count;
+    caller.v = v;
+
+    msg.set_arg0(location);
+    msg.set_arg1(count);
+    msg.set_arg2(ToInt(v));
+
+    // FIXME: check for pointer usage
+    msg.mutable_data()->assign(reinterpret_cast<const char *>(v), 1*count * sizeof(GLint));
+    int * ret = MessageLoop(caller, msg, expectResponse,
+                            glesv2debugger::Message_Function_glUniform1iv);
+}
+
+void Debug_glUniform2f(GLint location, GLfloat x, GLfloat y)
+{
+    glesv2debugger::Message msg;
+    const bool expectResponse = false;
+    struct : public FunctionCall {
+        GLint location;
+        GLfloat x;
+        GLfloat y;
+
+        const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
+            _c->glUniform2f(location, x, y);
+            return 0;
+        }
+    } caller;
+    caller.location = location;
+    caller.x = x;
+    caller.y = y;
+
+    msg.set_arg0(location);
+    msg.set_arg1(ToInt(x));
+    msg.set_arg2(ToInt(y));
+
+    int * ret = MessageLoop(caller, msg, expectResponse,
+                            glesv2debugger::Message_Function_glUniform2f);
+}
+
+void Debug_glUniform2fv(GLint location, GLsizei count, const GLfloat* v)
+{
+    glesv2debugger::Message msg;
+    const bool expectResponse = false;
+    struct : public FunctionCall {
+        GLint location;
+        GLsizei count;
+        const GLfloat* v;
+
+        const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
+            _c->glUniform2fv(location, count, v);
+            return 0;
+        }
+    } caller;
+    caller.location = location;
+    caller.count = count;
+    caller.v = v;
+
+    msg.set_arg0(location);
+    msg.set_arg1(count);
+    msg.set_arg2(ToInt(v));
+
+    // FIXME: check for pointer usage
+    msg.mutable_data()->assign(reinterpret_cast<const char *>(v), 2*count * sizeof(GLfloat));
+    int * ret = MessageLoop(caller, msg, expectResponse,
+                            glesv2debugger::Message_Function_glUniform2fv);
+}
+
+void Debug_glUniform2i(GLint location, GLint x, GLint y)
+{
+    glesv2debugger::Message msg;
+    const bool expectResponse = false;
+    struct : public FunctionCall {
+        GLint location;
+        GLint x;
+        GLint y;
+
+        const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
+            _c->glUniform2i(location, x, y);
+            return 0;
+        }
+    } caller;
+    caller.location = location;
+    caller.x = x;
+    caller.y = y;
+
+    msg.set_arg0(location);
+    msg.set_arg1(x);
+    msg.set_arg2(y);
+
+    int * ret = MessageLoop(caller, msg, expectResponse,
+                            glesv2debugger::Message_Function_glUniform2i);
+}
+
+void Debug_glUniform2iv(GLint location, GLsizei count, const GLint* v)
+{
+    glesv2debugger::Message msg;
+    const bool expectResponse = false;
+    struct : public FunctionCall {
+        GLint location;
+        GLsizei count;
+        const GLint* v;
+
+        const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
+            _c->glUniform2iv(location, count, v);
+            return 0;
+        }
+    } caller;
+    caller.location = location;
+    caller.count = count;
+    caller.v = v;
+
+    msg.set_arg0(location);
+    msg.set_arg1(count);
+    msg.set_arg2(ToInt(v));
+
+    // FIXME: check for pointer usage
+    msg.mutable_data()->assign(reinterpret_cast<const char *>(v), 2*count * sizeof(GLint));
+    int * ret = MessageLoop(caller, msg, expectResponse,
+                            glesv2debugger::Message_Function_glUniform2iv);
+}
+
+void Debug_glUniform3f(GLint location, GLfloat x, GLfloat y, GLfloat z)
+{
+    glesv2debugger::Message msg;
+    const bool expectResponse = false;
+    struct : public FunctionCall {
+        GLint location;
+        GLfloat x;
+        GLfloat y;
+        GLfloat z;
+
+        const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
+            _c->glUniform3f(location, x, y, z);
+            return 0;
+        }
+    } caller;
+    caller.location = location;
+    caller.x = x;
+    caller.y = y;
+    caller.z = z;
+
+    msg.set_arg0(location);
+    msg.set_arg1(ToInt(x));
+    msg.set_arg2(ToInt(y));
+    msg.set_arg3(ToInt(z));
+
+    int * ret = MessageLoop(caller, msg, expectResponse,
+                            glesv2debugger::Message_Function_glUniform3f);
+}
+
+void Debug_glUniform3fv(GLint location, GLsizei count, const GLfloat* v)
+{
+    glesv2debugger::Message msg;
+    const bool expectResponse = false;
+    struct : public FunctionCall {
+        GLint location;
+        GLsizei count;
+        const GLfloat* v;
+
+        const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
+            _c->glUniform3fv(location, count, v);
+            return 0;
+        }
+    } caller;
+    caller.location = location;
+    caller.count = count;
+    caller.v = v;
+
+    msg.set_arg0(location);
+    msg.set_arg1(count);
+    msg.set_arg2(ToInt(v));
+
+    // FIXME: check for pointer usage
+    msg.mutable_data()->assign(reinterpret_cast<const char *>(v), 3*count * sizeof(GLfloat));
+    int * ret = MessageLoop(caller, msg, expectResponse,
+                            glesv2debugger::Message_Function_glUniform3fv);
+}
+
+void Debug_glUniform3i(GLint location, GLint x, GLint y, GLint z)
+{
+    glesv2debugger::Message msg;
+    const bool expectResponse = false;
+    struct : public FunctionCall {
+        GLint location;
+        GLint x;
+        GLint y;
+        GLint z;
+
+        const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
+            _c->glUniform3i(location, x, y, z);
+            return 0;
+        }
+    } caller;
+    caller.location = location;
+    caller.x = x;
+    caller.y = y;
+    caller.z = z;
+
+    msg.set_arg0(location);
+    msg.set_arg1(x);
+    msg.set_arg2(y);
+    msg.set_arg3(z);
+
+    int * ret = MessageLoop(caller, msg, expectResponse,
+                            glesv2debugger::Message_Function_glUniform3i);
+}
+
+void Debug_glUniform3iv(GLint location, GLsizei count, const GLint* v)
+{
+    glesv2debugger::Message msg;
+    const bool expectResponse = false;
+    struct : public FunctionCall {
+        GLint location;
+        GLsizei count;
+        const GLint* v;
+
+        const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
+            _c->glUniform3iv(location, count, v);
+            return 0;
+        }
+    } caller;
+    caller.location = location;
+    caller.count = count;
+    caller.v = v;
+
+    msg.set_arg0(location);
+    msg.set_arg1(count);
+    msg.set_arg2(ToInt(v));
+
+    // FIXME: check for pointer usage
+    msg.mutable_data()->assign(reinterpret_cast<const char *>(v), 3*count * sizeof(GLint));
+    int * ret = MessageLoop(caller, msg, expectResponse,
+                            glesv2debugger::Message_Function_glUniform3iv);
+}
+
+void Debug_glUniform4f(GLint location, GLfloat x, GLfloat y, GLfloat z, GLfloat w)
+{
+    glesv2debugger::Message msg;
+    const bool expectResponse = false;
+    struct : public FunctionCall {
+        GLint location;
+        GLfloat x;
+        GLfloat y;
+        GLfloat z;
+        GLfloat w;
+
+        const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
+            _c->glUniform4f(location, x, y, z, w);
+            return 0;
+        }
+    } caller;
+    caller.location = location;
+    caller.x = x;
+    caller.y = y;
+    caller.z = z;
+    caller.w = w;
+
+    msg.set_arg0(location);
+    msg.set_arg1(ToInt(x));
+    msg.set_arg2(ToInt(y));
+    msg.set_arg3(ToInt(z));
+    msg.set_arg4(ToInt(w));
+
+    int * ret = MessageLoop(caller, msg, expectResponse,
+                            glesv2debugger::Message_Function_glUniform4f);
+}
+
+void Debug_glUniform4fv(GLint location, GLsizei count, const GLfloat* v)
+{
+    glesv2debugger::Message msg;
+    const bool expectResponse = false;
+    struct : public FunctionCall {
+        GLint location;
+        GLsizei count;
+        const GLfloat* v;
+
+        const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
+            _c->glUniform4fv(location, count, v);
+            return 0;
+        }
+    } caller;
+    caller.location = location;
+    caller.count = count;
+    caller.v = v;
+
+    msg.set_arg0(location);
+    msg.set_arg1(count);
+    msg.set_arg2(ToInt(v));
+
+    // FIXME: check for pointer usage
+    msg.mutable_data()->assign(reinterpret_cast<const char *>(v), 4*count * sizeof(GLfloat));
+    int * ret = MessageLoop(caller, msg, expectResponse,
+                            glesv2debugger::Message_Function_glUniform4fv);
+}
+
+void Debug_glUniform4i(GLint location, GLint x, GLint y, GLint z, GLint w)
+{
+    glesv2debugger::Message msg;
+    const bool expectResponse = false;
+    struct : public FunctionCall {
+        GLint location;
+        GLint x;
+        GLint y;
+        GLint z;
+        GLint w;
+
+        const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
+            _c->glUniform4i(location, x, y, z, w);
+            return 0;
+        }
+    } caller;
+    caller.location = location;
+    caller.x = x;
+    caller.y = y;
+    caller.z = z;
+    caller.w = w;
+
+    msg.set_arg0(location);
+    msg.set_arg1(x);
+    msg.set_arg2(y);
+    msg.set_arg3(z);
+    msg.set_arg4(w);
+
+    int * ret = MessageLoop(caller, msg, expectResponse,
+                            glesv2debugger::Message_Function_glUniform4i);
+}
+
+void Debug_glUniform4iv(GLint location, GLsizei count, const GLint* v)
+{
+    glesv2debugger::Message msg;
+    const bool expectResponse = false;
+    struct : public FunctionCall {
+        GLint location;
+        GLsizei count;
+        const GLint* v;
+
+        const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
+            _c->glUniform4iv(location, count, v);
+            return 0;
+        }
+    } caller;
+    caller.location = location;
+    caller.count = count;
+    caller.v = v;
+
+    msg.set_arg0(location);
+    msg.set_arg1(count);
+    msg.set_arg2(ToInt(v));
+
+    // FIXME: check for pointer usage
+    msg.mutable_data()->assign(reinterpret_cast<const char *>(v), 4*count * sizeof(GLint));
+    int * ret = MessageLoop(caller, msg, expectResponse,
+                            glesv2debugger::Message_Function_glUniform4iv);
+}
+
+void Debug_glUniformMatrix2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value)
+{
+    glesv2debugger::Message msg;
+    const bool expectResponse = false;
+    struct : public FunctionCall {
+        GLint location;
+        GLsizei count;
+        GLboolean transpose;
+        const GLfloat* value;
+
+        const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
+            _c->glUniformMatrix2fv(location, count, transpose, value);
+            return 0;
+        }
+    } caller;
+    caller.location = location;
+    caller.count = count;
+    caller.transpose = transpose;
+    caller.value = value;
+
+    msg.set_arg0(location);
+    msg.set_arg1(count);
+    msg.set_arg2(transpose);
+    msg.set_arg3(ToInt(value));
+
+    // FIXME: check for pointer usage
+    msg.mutable_data()->assign(reinterpret_cast<const char *>(value), 4*count * sizeof(GLfloat));
+    int * ret = MessageLoop(caller, msg, expectResponse,
+                            glesv2debugger::Message_Function_glUniformMatrix2fv);
+}
+
+void Debug_glUniformMatrix3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value)
+{
+    glesv2debugger::Message msg;
+    const bool expectResponse = false;
+    struct : public FunctionCall {
+        GLint location;
+        GLsizei count;
+        GLboolean transpose;
+        const GLfloat* value;
+
+        const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
+            _c->glUniformMatrix3fv(location, count, transpose, value);
+            return 0;
+        }
+    } caller;
+    caller.location = location;
+    caller.count = count;
+    caller.transpose = transpose;
+    caller.value = value;
+
+    msg.set_arg0(location);
+    msg.set_arg1(count);
+    msg.set_arg2(transpose);
+    msg.set_arg3(ToInt(value));
+
+    // FIXME: check for pointer usage
+    msg.mutable_data()->assign(reinterpret_cast<const char *>(value), 9*count * sizeof(GLfloat));
+    int * ret = MessageLoop(caller, msg, expectResponse,
+                            glesv2debugger::Message_Function_glUniformMatrix3fv);
+}
+
+void Debug_glUniformMatrix4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value)
+{
+    glesv2debugger::Message msg;
+    const bool expectResponse = false;
+    struct : public FunctionCall {
+        GLint location;
+        GLsizei count;
+        GLboolean transpose;
+        const GLfloat* value;
+
+        const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
+            _c->glUniformMatrix4fv(location, count, transpose, value);
+            return 0;
+        }
+    } caller;
+    caller.location = location;
+    caller.count = count;
+    caller.transpose = transpose;
+    caller.value = value;
+
+    msg.set_arg0(location);
+    msg.set_arg1(count);
+    msg.set_arg2(transpose);
+    msg.set_arg3(ToInt(value));
+
+    // FIXME: check for pointer usage
+    msg.mutable_data()->assign(reinterpret_cast<const char *>(value), 16*count * sizeof(GLfloat));
+    int * ret = MessageLoop(caller, msg, expectResponse,
+                            glesv2debugger::Message_Function_glUniformMatrix4fv);
+}
+
+void Debug_glUseProgram(GLuint program)
+{
+    glesv2debugger::Message msg;
+    const bool expectResponse = false;
+    struct : public FunctionCall {
+        GLuint program;
+
+        const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
+            _c->glUseProgram(program);
+            getDbgContextThreadSpecific()->glUseProgram(program);
+            return 0;
+        }
+    } caller;
+    caller.program = program;
+
+    msg.set_arg0(program);
+
+    int * ret = MessageLoop(caller, msg, expectResponse,
+                            glesv2debugger::Message_Function_glUseProgram);
+}
+
+void Debug_glValidateProgram(GLuint program)
+{
+    glesv2debugger::Message msg;
+    const bool expectResponse = false;
+    struct : public FunctionCall {
+        GLuint program;
+
+        const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
+            _c->glValidateProgram(program);
+            return 0;
+        }
+    } caller;
+    caller.program = program;
+
+    msg.set_arg0(program);
+
+    int * ret = MessageLoop(caller, msg, expectResponse,
+                            glesv2debugger::Message_Function_glValidateProgram);
+}
+
+void Debug_glVertexAttrib1f(GLuint indx, GLfloat x)
+{
+    glesv2debugger::Message msg;
+    const bool expectResponse = false;
+    struct : public FunctionCall {
+        GLuint indx;
+        GLfloat x;
+
+        const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
+            _c->glVertexAttrib1f(indx, x);
+            return 0;
+        }
+    } caller;
+    caller.indx = indx;
+    caller.x = x;
+
+    msg.set_arg0(indx);
+    msg.set_arg1(ToInt(x));
+
+    int * ret = MessageLoop(caller, msg, expectResponse,
+                            glesv2debugger::Message_Function_glVertexAttrib1f);
+}
+
+void Debug_glVertexAttrib1fv(GLuint indx, const GLfloat* values)
+{
+    glesv2debugger::Message msg;
+    const bool expectResponse = false;
+    struct : public FunctionCall {
+        GLuint indx;
+        const GLfloat* values;
+
+        const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
+            _c->glVertexAttrib1fv(indx, values);
+            return 0;
+        }
+    } caller;
+    caller.indx = indx;
+    caller.values = values;
+
+    msg.set_arg0(indx);
+    msg.set_arg1(ToInt(values));
+
+    // FIXME: check for pointer usage
+    msg.mutable_data()->assign(reinterpret_cast<const char *>(values), 1 * sizeof(GLfloat));
+    int * ret = MessageLoop(caller, msg, expectResponse,
+                            glesv2debugger::Message_Function_glVertexAttrib1fv);
+}
+
+void Debug_glVertexAttrib2f(GLuint indx, GLfloat x, GLfloat y)
+{
+    glesv2debugger::Message msg;
+    const bool expectResponse = false;
+    struct : public FunctionCall {
+        GLuint indx;
+        GLfloat x;
+        GLfloat y;
+
+        const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
+            _c->glVertexAttrib2f(indx, x, y);
+            return 0;
+        }
+    } caller;
+    caller.indx = indx;
+    caller.x = x;
+    caller.y = y;
+
+    msg.set_arg0(indx);
+    msg.set_arg1(ToInt(x));
+    msg.set_arg2(ToInt(y));
+
+    int * ret = MessageLoop(caller, msg, expectResponse,
+                            glesv2debugger::Message_Function_glVertexAttrib2f);
+}
+
+void Debug_glVertexAttrib2fv(GLuint indx, const GLfloat* values)
+{
+    glesv2debugger::Message msg;
+    const bool expectResponse = false;
+    struct : public FunctionCall {
+        GLuint indx;
+        const GLfloat* values;
+
+        const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
+            _c->glVertexAttrib2fv(indx, values);
+            return 0;
+        }
+    } caller;
+    caller.indx = indx;
+    caller.values = values;
+
+    msg.set_arg0(indx);
+    msg.set_arg1(ToInt(values));
+
+    // FIXME: check for pointer usage
+    msg.mutable_data()->assign(reinterpret_cast<const char *>(values), 2 * sizeof(GLfloat));
+    int * ret = MessageLoop(caller, msg, expectResponse,
+                            glesv2debugger::Message_Function_glVertexAttrib2fv);
+}
+
+void Debug_glVertexAttrib3f(GLuint indx, GLfloat x, GLfloat y, GLfloat z)
+{
+    glesv2debugger::Message msg;
+    const bool expectResponse = false;
+    struct : public FunctionCall {
+        GLuint indx;
+        GLfloat x;
+        GLfloat y;
+        GLfloat z;
+
+        const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
+            _c->glVertexAttrib3f(indx, x, y, z);
+            return 0;
+        }
+    } caller;
+    caller.indx = indx;
+    caller.x = x;
+    caller.y = y;
+    caller.z = z;
+
+    msg.set_arg0(indx);
+    msg.set_arg1(ToInt(x));
+    msg.set_arg2(ToInt(y));
+    msg.set_arg3(ToInt(z));
+
+    int * ret = MessageLoop(caller, msg, expectResponse,
+                            glesv2debugger::Message_Function_glVertexAttrib3f);
+}
+
+void Debug_glVertexAttrib3fv(GLuint indx, const GLfloat* values)
+{
+    glesv2debugger::Message msg;
+    const bool expectResponse = false;
+    struct : public FunctionCall {
+        GLuint indx;
+        const GLfloat* values;
+
+        const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
+            _c->glVertexAttrib3fv(indx, values);
+            return 0;
+        }
+    } caller;
+    caller.indx = indx;
+    caller.values = values;
+
+    msg.set_arg0(indx);
+    msg.set_arg1(ToInt(values));
+
+    // FIXME: check for pointer usage
+    msg.mutable_data()->assign(reinterpret_cast<const char *>(values), 3 * sizeof(GLfloat));
+    int * ret = MessageLoop(caller, msg, expectResponse,
+                            glesv2debugger::Message_Function_glVertexAttrib3fv);
+}
+
+void Debug_glVertexAttrib4f(GLuint indx, GLfloat x, GLfloat y, GLfloat z, GLfloat w)
+{
+    glesv2debugger::Message msg;
+    const bool expectResponse = false;
+    struct : public FunctionCall {
+        GLuint indx;
+        GLfloat x;
+        GLfloat y;
+        GLfloat z;
+        GLfloat w;
+
+        const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
+            _c->glVertexAttrib4f(indx, x, y, z, w);
+            return 0;
+        }
+    } caller;
+    caller.indx = indx;
+    caller.x = x;
+    caller.y = y;
+    caller.z = z;
+    caller.w = w;
+
+    msg.set_arg0(indx);
+    msg.set_arg1(ToInt(x));
+    msg.set_arg2(ToInt(y));
+    msg.set_arg3(ToInt(z));
+    msg.set_arg4(ToInt(w));
+
+    int * ret = MessageLoop(caller, msg, expectResponse,
+                            glesv2debugger::Message_Function_glVertexAttrib4f);
+}
+
+void Debug_glVertexAttrib4fv(GLuint indx, const GLfloat* values)
+{
+    glesv2debugger::Message msg;
+    const bool expectResponse = false;
+    struct : public FunctionCall {
+        GLuint indx;
+        const GLfloat* values;
+
+        const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
+            _c->glVertexAttrib4fv(indx, values);
+            return 0;
+        }
+    } caller;
+    caller.indx = indx;
+    caller.values = values;
+
+    msg.set_arg0(indx);
+    msg.set_arg1(ToInt(values));
+
+    // FIXME: check for pointer usage
+    msg.mutable_data()->assign(reinterpret_cast<const char *>(values), 4 * sizeof(GLfloat));
+    int * ret = MessageLoop(caller, msg, expectResponse,
+                            glesv2debugger::Message_Function_glVertexAttrib4fv);
+}
+
+// FIXME: this function has pointers, it should be hand written
+void Debug_glVertexAttribPointer(GLuint indx, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const GLvoid* ptr)
+{
+    glesv2debugger::Message msg;
+    const bool expectResponse = false;
+    struct : public FunctionCall {
+        GLuint indx;
+        GLint size;
+        GLenum type;
+        GLboolean normalized;
+        GLsizei stride;
+        const GLvoid* ptr;
+
+        const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
+            _c->glVertexAttribPointer(indx, size, type, normalized, stride, ptr);
+            getDbgContextThreadSpecific()->glVertexAttribPointer(indx, size, type, normalized, stride, ptr);
+            return 0;
+        }
+    } caller;
+    caller.indx = indx;
+    caller.size = size;
+    caller.type = type;
+    caller.normalized = normalized;
+    caller.stride = stride;
+    caller.ptr = ptr;
+
+    msg.set_arg0(indx);
+    msg.set_arg1(size);
+    msg.set_arg2(type);
+    msg.set_arg3(normalized);
+    msg.set_arg4(stride);
+    msg.set_arg5(ToInt(ptr));
+
+    // FIXME: check for pointer usage
+    int * ret = MessageLoop(caller, msg, expectResponse,
+                            glesv2debugger::Message_Function_glVertexAttribPointer);
+}
+
+void Debug_glViewport(GLint x, GLint y, GLsizei width, GLsizei height)
+{
+    glesv2debugger::Message msg;
+    const bool expectResponse = false;
+    struct : public FunctionCall {
+        GLint x;
+        GLint y;
+        GLsizei width;
+        GLsizei height;
+
+        const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
+            _c->glViewport(x, y, width, height);
+            return 0;
+        }
+    } caller;
+    caller.x = x;
+    caller.y = y;
+    caller.width = width;
+    caller.height = height;
+
+    msg.set_arg0(x);
+    msg.set_arg1(y);
+    msg.set_arg2(width);
+    msg.set_arg3(height);
+
+    int * ret = MessageLoop(caller, msg, expectResponse,
+                            glesv2debugger::Message_Function_glViewport);
+}
+
+// FIXME: the following functions should be written by hand
+void Debug_glCompressedTexImage2D(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const GLvoid* data);
+void Debug_glCompressedTexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const GLvoid* data);
+void Debug_glGetActiveAttrib(GLuint program, GLuint index, GLsizei bufsize, GLsizei* length, GLint* size, GLenum* type, GLchar* name);
+void Debug_glGetActiveUniform(GLuint program, GLuint index, GLsizei bufsize, GLsizei* length, GLint* size, GLenum* type, GLchar* name);
+void Debug_glGetAttachedShaders(GLuint program, GLsizei maxcount, GLsizei* count, GLuint* shaders);
+void Debug_glGetBooleanv(GLenum pname, GLboolean* params);
+void Debug_glGetBufferParameteriv(GLenum target, GLenum pname, GLint* params);
+void Debug_glGetFloatv(GLenum pname, GLfloat* params);
+void Debug_glGetFramebufferAttachmentParameteriv(GLenum target, GLenum attachment, GLenum pname, GLint* params);
+void Debug_glGetIntegerv(GLenum pname, GLint* params);
+void Debug_glGetProgramInfoLog(GLuint program, GLsizei bufsize, GLsizei* length, GLchar* infolog);
+void Debug_glGetRenderbufferParameteriv(GLenum target, GLenum pname, GLint* params);
+void Debug_glGetShaderInfoLog(GLuint shader, GLsizei bufsize, GLsizei* length, GLchar* infolog);
+void Debug_glGetShaderPrecisionFormat(GLenum shadertype, GLenum precisiontype, GLint* range, GLint* precision);
+void Debug_glGetShaderSource(GLuint shader, GLsizei bufsize, GLsizei* length, GLchar* source);
+const GLubyte* Debug_glGetString(GLenum name);
+void Debug_glGetTexParameterfv(GLenum target, GLenum pname, GLfloat* params);
+void Debug_glGetTexParameteriv(GLenum target, GLenum pname, GLint* params);
+void Debug_glGetUniformfv(GLuint program, GLint location, GLfloat* params);
+void Debug_glGetUniformiv(GLuint program, GLint location, GLint* params);
+void Debug_glGetVertexAttribfv(GLuint index, GLenum pname, GLfloat* params);
+void Debug_glGetVertexAttribiv(GLuint index, GLenum pname, GLint* params);
+void Debug_glGetVertexAttribPointerv(GLuint index, GLenum pname, GLvoid** pointer);
+void Debug_glShaderBinary(GLsizei n, const GLuint* shaders, GLenum binaryformat, const GLvoid* binary, GLsizei length);
+void Debug_glTexParameterfv(GLenum target, GLenum pname, const GLfloat* params);
+void Debug_glTexParameteriv(GLenum target, GLenum pname, const GLint* params);
+void Debug_glVertexAttribPointer(GLuint indx, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const GLvoid* ptr);
diff --git a/opengl/libs/GLES2_dbg/src/api.h b/opengl/libs/GLES2_dbg/src/api.h
new file mode 100644
index 0000000..be94dfc
--- /dev/null
+++ b/opengl/libs/GLES2_dbg/src/api.h
@@ -0,0 +1,31 @@
+/*
+ ** Copyright 2011, The Android Open Source Project
+ **
+ ** Licensed under the Apache License, Version 2.0 (the "License");
+ ** you may not use this file except in compliance with the License.
+ ** You may obtain a copy of the License at
+ **
+ **     http://www.apache.org/licenses/LICENSE-2.0
+ **
+ ** Unless required by applicable law or agreed to in writing, software
+ ** distributed under the License is distributed on an "AS IS" BASIS,
+ ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ** See the License for the specific language governing permissions and
+ ** limitations under the License.
+ */
+
+#define EXTEND_Debug_glCopyTexImage2D \
+    void * pixels = malloc(width * height * 4); \
+    getGLTraceThreadSpecific()->gl.glReadPixels(x, y, width, height, GL_RGBA, GL_UNSIGNED_BYTE, pixels); \
+    msg.set_data(pixels, width * height * 4); \
+    free(pixels);
+    
+#define EXTEND_Debug_glCopyTexSubImage2D EXTEND_Debug_glCopyTexImage2D
+
+#define EXTEND_Debug_glShaderSource \
+    std::string * const data = msg.mutable_data(); \
+    for (unsigned i = 0; i < count; i++) \
+        if (!length || length[i] < 0) \
+            data->append(string[i]); \
+        else \
+            data->append(string[i], length[i]);
\ No newline at end of file
diff --git a/opengl/libs/GLES2_dbg/src/caller.h b/opengl/libs/GLES2_dbg/src/caller.h
new file mode 100644
index 0000000..01bc4ea
--- /dev/null
+++ b/opengl/libs/GLES2_dbg/src/caller.h
@@ -0,0 +1,19 @@
+/*
+ ** Copyright 2011, The Android Open Source Project
+ **
+ ** Licensed under the Apache License, Version 2.0 (the "License");
+ ** you may not use this file except in compliance with the License.
+ ** You may obtain a copy of the License at
+ **
+ **     http://www.apache.org/licenses/LICENSE-2.0
+ **
+ ** Unless required by applicable law or agreed to in writing, software
+ ** distributed under the License is distributed on an "AS IS" BASIS,
+ ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ** See the License for the specific language governing permissions and
+ ** limitations under the License.
+ */
+
+#include "src/header.h"
+
+
diff --git a/opengl/libs/GLES2_dbg/src/dbgcontext.cpp b/opengl/libs/GLES2_dbg/src/dbgcontext.cpp
new file mode 100644
index 0000000..5c418258
--- /dev/null
+++ b/opengl/libs/GLES2_dbg/src/dbgcontext.cpp
@@ -0,0 +1,247 @@
+/*
+ ** Copyright 2011, The Android Open Source Project
+ **
+ ** Licensed under the Apache License, Version 2.0 (the "License");
+ ** you may not use this file except in compliance with the License.
+ ** You may obtain a copy of the License at
+ **
+ **     http://www.apache.org/licenses/LICENSE-2.0
+ **
+ ** Unless required by applicable law or agreed to in writing, software
+ ** distributed under the License is distributed on an "AS IS" BASIS,
+ ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ** See the License for the specific language governing permissions and
+ ** limitations under the License.
+ */
+ 
+#include "header.h"
+
+namespace android
+{
+
+DbgContext::DbgContext(const unsigned version, const gl_hooks_t * const hooks,
+                       const unsigned MAX_VERTEX_ATTRIBS)
+        : version(version), hooks(hooks)
+        , MAX_VERTEX_ATTRIBS(MAX_VERTEX_ATTRIBS)
+        , vertexAttribs(new VertexAttrib[MAX_VERTEX_ATTRIBS])
+        , hasNonVBOAttribs(false), indexBuffers(NULL), indexBuffer(NULL)
+{
+    for (unsigned i = 0; i < MAX_VERTEX_ATTRIBS; i++)
+        vertexAttribs[i] = VertexAttrib();
+}
+
+DbgContext::~DbgContext()
+{
+    delete vertexAttribs;
+}
+
+DbgContext * CreateDbgContext(const unsigned version, const gl_hooks_t * const hooks)
+{
+    assert(version < 2);
+    assert(GL_NO_ERROR == hooks->gl.glGetError());
+    GLint MAX_VERTEX_ATTRIBS = 0;
+    hooks->gl.glGetIntegerv(GL_MAX_VERTEX_ATTRIBS, &MAX_VERTEX_ATTRIBS);
+    return new DbgContext(version, hooks, MAX_VERTEX_ATTRIBS);
+}
+
+void DestroyDbgContext(DbgContext * const dbg)
+{
+    delete dbg;
+}
+
+void DbgContext::Fetch(const unsigned index, std::string * const data) const
+{
+    // VBO data is already on client, just send user pointer data
+    for (unsigned i = 0; i < maxAttrib; i++) {
+        if (!vertexAttribs[i].enabled)
+            continue;
+        if (vertexAttribs[i].buffer > 0)
+            continue;
+        const char * ptr = (const char *)vertexAttribs[i].ptr;
+        ptr += index * vertexAttribs[i].stride;
+        data->append(ptr, vertexAttribs[i].elemSize);
+    }
+}
+
+void DbgContext::glUseProgram(GLuint program)
+{
+    while (GLenum error = hooks->gl.glGetError())
+        LOGD("DbgContext::glUseProgram: before glGetError() = 0x%.4X", error);
+        
+    this->program = program;
+
+    GLint activeAttributes = 0;
+    hooks->gl.glGetProgramiv(program, GL_ACTIVE_ATTRIBUTES, &activeAttributes);
+    maxAttrib = 0;
+    GLint maxNameLen = -1;
+    hooks->gl.glGetProgramiv(program, GL_ACTIVE_ATTRIBUTE_MAX_LENGTH, &maxNameLen);
+    char * name = new char [maxNameLen + 1];
+    name[maxNameLen] = 0;
+    // find total number of attribute slots used
+    for (unsigned i = 0; i < activeAttributes; i++) {
+        GLint size = -1;
+        GLenum type = -1;
+        hooks->gl.glGetActiveAttrib(program, i, maxNameLen + 1, NULL, &size, &type, name);
+        GLint slot = hooks->gl.glGetAttribLocation(program, name);
+        assert(slot >= 0);
+        switch (type) {
+        case GL_FLOAT:
+        case GL_FLOAT_VEC2:
+        case GL_FLOAT_VEC3:
+        case GL_FLOAT_VEC4:
+            slot += size;
+            break;
+        case GL_FLOAT_MAT2:
+            slot += size * 2;
+            break;
+        case GL_FLOAT_MAT3:
+            slot += size * 3;
+            break;
+        case GL_FLOAT_MAT4:
+            slot += size * 4;
+            break;
+        default:
+            assert(0);
+        }
+        if (slot > maxAttrib)
+            maxAttrib = slot;
+    }
+    delete name;
+    
+    while (GLenum error = hooks->gl.glGetError())
+        LOGD("DbgContext::glUseProgram: after glGetError() = 0x%.4X", error);
+}
+
+static bool HasNonVBOAttribs(const DbgContext * const ctx)
+{
+    bool need = false;
+    for (unsigned i = 0; !need && i < ctx->maxAttrib; i++)
+        if (ctx->vertexAttribs[i].enabled && ctx->vertexAttribs[i].buffer == 0)
+            need = true;
+    return need;
+}
+
+void DbgContext::glVertexAttribPointer(GLuint indx, GLint size, GLenum type,
+                                       GLboolean normalized, GLsizei stride, const GLvoid* ptr)
+{
+    assert(GL_NO_ERROR == hooks->gl.glGetError());
+    assert(indx < MAX_VERTEX_ATTRIBS);
+    vertexAttribs[indx].size = size;
+    vertexAttribs[indx].type = type;
+    vertexAttribs[indx].normalized = normalized;
+    switch (type) {
+    case GL_FLOAT:
+        vertexAttribs[indx].elemSize = sizeof(GLfloat) * size;
+        break;
+    case GL_INT:
+    case GL_UNSIGNED_INT:
+        vertexAttribs[indx].elemSize = sizeof(GLint) * size;
+        break;
+    case GL_SHORT:
+    case GL_UNSIGNED_SHORT:
+        vertexAttribs[indx].elemSize = sizeof(GLshort) * size;
+        break;
+    case GL_BYTE:
+    case GL_UNSIGNED_BYTE:
+        vertexAttribs[indx].elemSize = sizeof(GLbyte) * size;
+        break;
+    default:
+        assert(0);
+    }
+    if (0 == stride)
+        stride = vertexAttribs[indx].elemSize;
+    vertexAttribs[indx].stride = stride;
+    vertexAttribs[indx].ptr = ptr;
+    hooks->gl.glGetVertexAttribiv(indx, GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING,
+                                  (GLint *)&vertexAttribs[indx].buffer);
+    hasNonVBOAttribs = HasNonVBOAttribs(this);
+}
+
+void DbgContext::glEnableVertexAttribArray(GLuint index)
+{
+    assert(index < MAX_VERTEX_ATTRIBS);
+    vertexAttribs[index].enabled = true;
+    hasNonVBOAttribs = HasNonVBOAttribs(this);
+}
+
+void DbgContext::glDisableVertexAttribArray(GLuint index)
+{
+    assert(index < MAX_VERTEX_ATTRIBS);
+    vertexAttribs[index].enabled = false;
+    hasNonVBOAttribs = HasNonVBOAttribs(this);
+}
+
+void DbgContext::glBindBuffer(GLenum target, GLuint buffer)
+{
+    if (GL_ELEMENT_ARRAY_BUFFER != target)
+        return;
+    if (0 == buffer) {
+        indexBuffer = NULL;
+        return;
+    }
+    VBO * b = indexBuffers;
+    indexBuffer = NULL;
+    while (b) {
+        if (b->name == buffer) {
+            assert(GL_ELEMENT_ARRAY_BUFFER == b->target);
+            indexBuffer = b;
+            break;
+        }
+        b = b->next;
+    }
+    if (!indexBuffer)
+        indexBuffer = indexBuffers = new VBO(buffer, target, indexBuffers);
+}
+
+void DbgContext::glBufferData(GLenum target, GLsizeiptr size, const GLvoid* data, GLenum usage)
+{
+    if (GL_ELEMENT_ARRAY_BUFFER != target)
+        return;
+    assert(indexBuffer);
+    assert(size >= 0);
+    indexBuffer->size = size;
+    indexBuffer->data = realloc(indexBuffer->data, size);
+    memcpy(indexBuffer->data, data, size);
+}
+
+void DbgContext::glBufferSubData(GLenum target, GLintptr offset, GLsizeiptr size, const GLvoid* data)
+{
+    if (GL_ELEMENT_ARRAY_BUFFER != target)
+        return;
+    assert(indexBuffer);
+    assert(size >= 0);
+    assert(offset >= 0);
+    assert(offset + size <= indexBuffer->size);
+    memcpy((char *)indexBuffer->data + offset, data, size);
+}
+
+void DbgContext::glDeleteBuffers(GLsizei n, const GLuint *buffers)
+{
+    for (unsigned i = 0; i < n; i++) {
+        for (unsigned j = 0; j < MAX_VERTEX_ATTRIBS; j++)
+            if (buffers[i] == vertexAttribs[j].buffer) {
+                vertexAttribs[j].buffer = 0;
+                vertexAttribs[j].enabled = false;
+            }
+        VBO * b = indexBuffers, * previous = NULL;
+        while (b) {
+            if (b->name == buffers[i]) {
+                assert(GL_ELEMENT_ARRAY_BUFFER == b->target);
+                if (indexBuffer == b)
+                    indexBuffer = NULL;
+                if (previous)
+                    previous->next = b->next;
+                else
+                    indexBuffers = b->next;
+                free(b->data);
+                delete b;
+                break;
+            }
+            previous = b;
+            b = b->next;
+        }
+    }
+    hasNonVBOAttribs = HasNonVBOAttribs(this);
+}
+
+}; // namespace android
diff --git a/opengl/libs/GLES2_dbg/src/debugger_message.pb.cpp b/opengl/libs/GLES2_dbg/src/debugger_message.pb.cpp
new file mode 100644
index 0000000..1f404c2
--- /dev/null
+++ b/opengl/libs/GLES2_dbg/src/debugger_message.pb.cpp
@@ -0,0 +1,1250 @@
+// Generated by the protocol buffer compiler.  DO NOT EDIT!
+
+#define INTERNAL_SUPPRESS_PROTOBUF_FIELD_DEPRECATION
+#include "debugger_message.pb.h"
+#include <google/protobuf/stubs/once.h>
+#include <google/protobuf/io/coded_stream.h>
+#include <google/protobuf/wire_format_lite_inl.h>
+// @@protoc_insertion_point(includes)
+
+namespace com {
+namespace android {
+namespace glesv2debugger {
+
+void protobuf_ShutdownFile_debugger_5fmessage_2eproto() {
+  delete Message::default_instance_;
+}
+
+void protobuf_AddDesc_debugger_5fmessage_2eproto() {
+  static bool already_here = false;
+  if (already_here) return;
+  already_here = true;
+  GOOGLE_PROTOBUF_VERIFY_VERSION;
+
+  Message::default_instance_ = new Message();
+  Message::default_instance_->InitAsDefaultInstance();
+  ::google::protobuf::internal::OnShutdown(&protobuf_ShutdownFile_debugger_5fmessage_2eproto);
+}
+
+// Force AddDescriptors() to be called at static initialization time.
+struct StaticDescriptorInitializer_debugger_5fmessage_2eproto {
+  StaticDescriptorInitializer_debugger_5fmessage_2eproto() {
+    protobuf_AddDesc_debugger_5fmessage_2eproto();
+  }
+} static_descriptor_initializer_debugger_5fmessage_2eproto_;
+
+
+// ===================================================================
+
+bool Message_Function_IsValid(int value) {
+  switch(value) {
+    case 0:
+    case 1:
+    case 2:
+    case 3:
+    case 4:
+    case 5:
+    case 6:
+    case 7:
+    case 8:
+    case 9:
+    case 10:
+    case 11:
+    case 12:
+    case 13:
+    case 14:
+    case 15:
+    case 16:
+    case 17:
+    case 18:
+    case 19:
+    case 20:
+    case 21:
+    case 22:
+    case 23:
+    case 24:
+    case 25:
+    case 26:
+    case 27:
+    case 28:
+    case 29:
+    case 30:
+    case 31:
+    case 32:
+    case 33:
+    case 34:
+    case 35:
+    case 36:
+    case 37:
+    case 38:
+    case 39:
+    case 40:
+    case 41:
+    case 42:
+    case 43:
+    case 44:
+    case 45:
+    case 46:
+    case 47:
+    case 48:
+    case 49:
+    case 50:
+    case 51:
+    case 52:
+    case 53:
+    case 54:
+    case 55:
+    case 56:
+    case 57:
+    case 58:
+    case 59:
+    case 60:
+    case 61:
+    case 62:
+    case 63:
+    case 64:
+    case 65:
+    case 66:
+    case 67:
+    case 68:
+    case 69:
+    case 70:
+    case 71:
+    case 72:
+    case 73:
+    case 74:
+    case 75:
+    case 76:
+    case 77:
+    case 78:
+    case 79:
+    case 80:
+    case 81:
+    case 82:
+    case 83:
+    case 84:
+    case 85:
+    case 86:
+    case 87:
+    case 88:
+    case 89:
+    case 90:
+    case 91:
+    case 92:
+    case 93:
+    case 94:
+    case 95:
+    case 96:
+    case 97:
+    case 98:
+    case 99:
+    case 100:
+    case 101:
+    case 102:
+    case 103:
+    case 104:
+    case 105:
+    case 106:
+    case 107:
+    case 108:
+    case 109:
+    case 110:
+    case 111:
+    case 112:
+    case 113:
+    case 114:
+    case 115:
+    case 116:
+    case 117:
+    case 118:
+    case 119:
+    case 120:
+    case 121:
+    case 122:
+    case 123:
+    case 124:
+    case 125:
+    case 126:
+    case 127:
+    case 128:
+    case 129:
+    case 130:
+    case 131:
+    case 132:
+    case 133:
+    case 134:
+    case 135:
+    case 136:
+    case 137:
+    case 138:
+    case 139:
+    case 140:
+    case 141:
+    case 142:
+    case 143:
+    case 144:
+    case 145:
+    case 146:
+    case 147:
+    case 148:
+    case 149:
+    case 150:
+    case 151:
+    case 152:
+    case 153:
+    case 154:
+    case 155:
+    case 156:
+    case 157:
+    case 158:
+    case 159:
+    case 160:
+    case 161:
+    case 162:
+    case 163:
+    case 164:
+    case 165:
+    case 166:
+    case 167:
+    case 168:
+    case 169:
+    case 170:
+    case 171:
+    case 172:
+    case 173:
+    case 174:
+    case 175:
+    case 176:
+    case 177:
+    case 178:
+    case 179:
+    case 180:
+    case 181:
+    case 182:
+    case 183:
+    case 184:
+    case 185:
+    case 186:
+    case 187:
+    case 188:
+    case 189:
+    case 190:
+      return true;
+    default:
+      return false;
+  }
+}
+
+#ifndef _MSC_VER
+const Message_Function Message::glActiveTexture;
+const Message_Function Message::glAttachShader;
+const Message_Function Message::glBindAttribLocation;
+const Message_Function Message::glBindBuffer;
+const Message_Function Message::glBindFramebuffer;
+const Message_Function Message::glBindRenderbuffer;
+const Message_Function Message::glBindTexture;
+const Message_Function Message::glBlendColor;
+const Message_Function Message::glBlendEquation;
+const Message_Function Message::glBlendEquationSeparate;
+const Message_Function Message::glBlendFunc;
+const Message_Function Message::glBlendFuncSeparate;
+const Message_Function Message::glBufferData;
+const Message_Function Message::glBufferSubData;
+const Message_Function Message::glCheckFramebufferStatus;
+const Message_Function Message::glClear;
+const Message_Function Message::glClearColor;
+const Message_Function Message::glClearDepthf;
+const Message_Function Message::glClearStencil;
+const Message_Function Message::glColorMask;
+const Message_Function Message::glCompileShader;
+const Message_Function Message::glCompressedTexImage2D;
+const Message_Function Message::glCompressedTexSubImage2D;
+const Message_Function Message::glCopyTexImage2D;
+const Message_Function Message::glCopyTexSubImage2D;
+const Message_Function Message::glCreateProgram;
+const Message_Function Message::glCreateShader;
+const Message_Function Message::glCullFace;
+const Message_Function Message::glDeleteBuffers;
+const Message_Function Message::glDeleteFramebuffers;
+const Message_Function Message::glDeleteProgram;
+const Message_Function Message::glDeleteRenderbuffers;
+const Message_Function Message::glDeleteShader;
+const Message_Function Message::glDeleteTextures;
+const Message_Function Message::glDepthFunc;
+const Message_Function Message::glDepthMask;
+const Message_Function Message::glDepthRangef;
+const Message_Function Message::glDetachShader;
+const Message_Function Message::glDisable;
+const Message_Function Message::glDisableVertexAttribArray;
+const Message_Function Message::glDrawArrays;
+const Message_Function Message::glDrawElements;
+const Message_Function Message::glEnable;
+const Message_Function Message::glEnableVertexAttribArray;
+const Message_Function Message::glFinish;
+const Message_Function Message::glFlush;
+const Message_Function Message::glFramebufferRenderbuffer;
+const Message_Function Message::glFramebufferTexture2D;
+const Message_Function Message::glFrontFace;
+const Message_Function Message::glGenBuffers;
+const Message_Function Message::glGenerateMipmap;
+const Message_Function Message::glGenFramebuffers;
+const Message_Function Message::glGenRenderbuffers;
+const Message_Function Message::glGenTextures;
+const Message_Function Message::glGetActiveAttrib;
+const Message_Function Message::glGetActiveUniform;
+const Message_Function Message::glGetAttachedShaders;
+const Message_Function Message::glGetAttribLocation;
+const Message_Function Message::glGetBooleanv;
+const Message_Function Message::glGetBufferParameteriv;
+const Message_Function Message::glGetError;
+const Message_Function Message::glGetFloatv;
+const Message_Function Message::glGetFramebufferAttachmentParameteriv;
+const Message_Function Message::glGetIntegerv;
+const Message_Function Message::glGetProgramiv;
+const Message_Function Message::glGetProgramInfoLog;
+const Message_Function Message::glGetRenderbufferParameteriv;
+const Message_Function Message::glGetShaderiv;
+const Message_Function Message::glGetShaderInfoLog;
+const Message_Function Message::glGetShaderPrecisionFormat;
+const Message_Function Message::glGetShaderSource;
+const Message_Function Message::glGetString;
+const Message_Function Message::glGetTexParameterfv;
+const Message_Function Message::glGetTexParameteriv;
+const Message_Function Message::glGetUniformfv;
+const Message_Function Message::glGetUniformiv;
+const Message_Function Message::glGetUniformLocation;
+const Message_Function Message::glGetVertexAttribfv;
+const Message_Function Message::glGetVertexAttribiv;
+const Message_Function Message::glGetVertexAttribPointerv;
+const Message_Function Message::glHint;
+const Message_Function Message::glIsBuffer;
+const Message_Function Message::glIsEnabled;
+const Message_Function Message::glIsFramebuffer;
+const Message_Function Message::glIsProgram;
+const Message_Function Message::glIsRenderbuffer;
+const Message_Function Message::glIsShader;
+const Message_Function Message::glIsTexture;
+const Message_Function Message::glLineWidth;
+const Message_Function Message::glLinkProgram;
+const Message_Function Message::glPixelStorei;
+const Message_Function Message::glPolygonOffset;
+const Message_Function Message::glReadPixels;
+const Message_Function Message::glReleaseShaderCompiler;
+const Message_Function Message::glRenderbufferStorage;
+const Message_Function Message::glSampleCoverage;
+const Message_Function Message::glScissor;
+const Message_Function Message::glShaderBinary;
+const Message_Function Message::glShaderSource;
+const Message_Function Message::glStencilFunc;
+const Message_Function Message::glStencilFuncSeparate;
+const Message_Function Message::glStencilMask;
+const Message_Function Message::glStencilMaskSeparate;
+const Message_Function Message::glStencilOp;
+const Message_Function Message::glStencilOpSeparate;
+const Message_Function Message::glTexImage2D;
+const Message_Function Message::glTexParameterf;
+const Message_Function Message::glTexParameterfv;
+const Message_Function Message::glTexParameteri;
+const Message_Function Message::glTexParameteriv;
+const Message_Function Message::glTexSubImage2D;
+const Message_Function Message::glUniform1f;
+const Message_Function Message::glUniform1fv;
+const Message_Function Message::glUniform1i;
+const Message_Function Message::glUniform1iv;
+const Message_Function Message::glUniform2f;
+const Message_Function Message::glUniform2fv;
+const Message_Function Message::glUniform2i;
+const Message_Function Message::glUniform2iv;
+const Message_Function Message::glUniform3f;
+const Message_Function Message::glUniform3fv;
+const Message_Function Message::glUniform3i;
+const Message_Function Message::glUniform3iv;
+const Message_Function Message::glUniform4f;
+const Message_Function Message::glUniform4fv;
+const Message_Function Message::glUniform4i;
+const Message_Function Message::glUniform4iv;
+const Message_Function Message::glUniformMatrix2fv;
+const Message_Function Message::glUniformMatrix3fv;
+const Message_Function Message::glUniformMatrix4fv;
+const Message_Function Message::glUseProgram;
+const Message_Function Message::glValidateProgram;
+const Message_Function Message::glVertexAttrib1f;
+const Message_Function Message::glVertexAttrib1fv;
+const Message_Function Message::glVertexAttrib2f;
+const Message_Function Message::glVertexAttrib2fv;
+const Message_Function Message::glVertexAttrib3f;
+const Message_Function Message::glVertexAttrib3fv;
+const Message_Function Message::glVertexAttrib4f;
+const Message_Function Message::glVertexAttrib4fv;
+const Message_Function Message::glVertexAttribPointer;
+const Message_Function Message::glViewport;
+const Message_Function Message::eglGetDisplay;
+const Message_Function Message::eglInitialize;
+const Message_Function Message::eglTerminate;
+const Message_Function Message::eglGetConfigs;
+const Message_Function Message::eglChooseConfig;
+const Message_Function Message::eglGetConfigAttrib;
+const Message_Function Message::eglCreateWindowSurface;
+const Message_Function Message::eglCreatePixmapSurface;
+const Message_Function Message::eglCreatePbufferSurface;
+const Message_Function Message::eglDestroySurface;
+const Message_Function Message::eglQuerySurface;
+const Message_Function Message::eglCreateContext;
+const Message_Function Message::eglDestroyContext;
+const Message_Function Message::eglMakeCurrent;
+const Message_Function Message::eglGetCurrentContext;
+const Message_Function Message::eglGetCurrentSurface;
+const Message_Function Message::eglGetCurrentDisplay;
+const Message_Function Message::eglQueryContext;
+const Message_Function Message::eglWaitGL;
+const Message_Function Message::eglWaitNative;
+const Message_Function Message::eglSwapBuffers;
+const Message_Function Message::eglCopyBuffers;
+const Message_Function Message::eglGetError;
+const Message_Function Message::eglQueryString;
+const Message_Function Message::eglGetProcAddress;
+const Message_Function Message::eglSurfaceAttrib;
+const Message_Function Message::eglBindTexImage;
+const Message_Function Message::eglReleaseTexImage;
+const Message_Function Message::eglSwapInterval;
+const Message_Function Message::eglBindAPI;
+const Message_Function Message::eglQueryAPI;
+const Message_Function Message::eglWaitClient;
+const Message_Function Message::eglReleaseThread;
+const Message_Function Message::eglCreatePbufferFromClientBuffer;
+const Message_Function Message::eglLockSurfaceKHR;
+const Message_Function Message::eglUnlockSurfaceKHR;
+const Message_Function Message::eglCreateImageKHR;
+const Message_Function Message::eglDestroyImageKHR;
+const Message_Function Message::eglCreateSyncKHR;
+const Message_Function Message::eglDestroySyncKHR;
+const Message_Function Message::eglClientWaitSyncKHR;
+const Message_Function Message::eglGetSyncAttribKHR;
+const Message_Function Message::eglSetSwapRectangleANDROID;
+const Message_Function Message::eglGetRenderBufferANDROID;
+const Message_Function Message::ACK;
+const Message_Function Message::NEG;
+const Message_Function Message::CONTINUE;
+const Message_Function Message::SKIP;
+const Message_Function Message::SETPROP;
+const Message_Function Message::Function_MIN;
+const Message_Function Message::Function_MAX;
+const int Message::Function_ARRAYSIZE;
+#endif  // _MSC_VER
+bool Message_Type_IsValid(int value) {
+  switch(value) {
+    case 0:
+    case 1:
+    case 2:
+      return true;
+    default:
+      return false;
+  }
+}
+
+#ifndef _MSC_VER
+const Message_Type Message::BeforeCall;
+const Message_Type Message::AfterCall;
+const Message_Type Message::Response;
+const Message_Type Message::Type_MIN;
+const Message_Type Message::Type_MAX;
+const int Message::Type_ARRAYSIZE;
+#endif  // _MSC_VER
+bool Message_Prop_IsValid(int value) {
+  switch(value) {
+    case 0:
+    case 1:
+      return true;
+    default:
+      return false;
+  }
+}
+
+#ifndef _MSC_VER
+const Message_Prop Message::Capture;
+const Message_Prop Message::TimeMode;
+const Message_Prop Message::Prop_MIN;
+const Message_Prop Message::Prop_MAX;
+const int Message::Prop_ARRAYSIZE;
+#endif  // _MSC_VER
+const ::std::string Message::_default_data_;
+#ifndef _MSC_VER
+const int Message::kContextIdFieldNumber;
+const int Message::kFunctionFieldNumber;
+const int Message::kTypeFieldNumber;
+const int Message::kExpectResponseFieldNumber;
+const int Message::kRetFieldNumber;
+const int Message::kArg0FieldNumber;
+const int Message::kArg1FieldNumber;
+const int Message::kArg2FieldNumber;
+const int Message::kArg3FieldNumber;
+const int Message::kArg4FieldNumber;
+const int Message::kArg5FieldNumber;
+const int Message::kArg6FieldNumber;
+const int Message::kArg7FieldNumber;
+const int Message::kArg8FieldNumber;
+const int Message::kDataFieldNumber;
+const int Message::kTimeFieldNumber;
+const int Message::kPropFieldNumber;
+const int Message::kClockFieldNumber;
+#endif  // !_MSC_VER
+
+Message::Message()
+  : ::google::protobuf::MessageLite() {
+  SharedCtor();
+}
+
+void Message::InitAsDefaultInstance() {
+}
+
+Message::Message(const Message& from)
+  : ::google::protobuf::MessageLite() {
+  SharedCtor();
+  MergeFrom(from);
+}
+
+void Message::SharedCtor() {
+  _cached_size_ = 0;
+  context_id_ = 0;
+  function_ = 187;
+  type_ = 0;
+  expect_response_ = false;
+  ret_ = 0;
+  arg0_ = 0;
+  arg1_ = 0;
+  arg2_ = 0;
+  arg3_ = 0;
+  arg4_ = 0;
+  arg5_ = 0;
+  arg6_ = 0;
+  arg7_ = 0;
+  arg8_ = 0;
+  data_ = const_cast< ::std::string*>(&_default_data_);
+  time_ = 0;
+  prop_ = 0;
+  clock_ = 0;
+  ::memset(_has_bits_, 0, sizeof(_has_bits_));
+}
+
+Message::~Message() {
+  SharedDtor();
+}
+
+void Message::SharedDtor() {
+  if (data_ != &_default_data_) {
+    delete data_;
+  }
+  if (this != default_instance_) {
+  }
+}
+
+void Message::SetCachedSize(int size) const {
+  GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
+  _cached_size_ = size;
+  GOOGLE_SAFE_CONCURRENT_WRITES_END();
+}
+const Message& Message::default_instance() {
+  if (default_instance_ == NULL) protobuf_AddDesc_debugger_5fmessage_2eproto();  return *default_instance_;
+}
+
+Message* Message::default_instance_ = NULL;
+
+Message* Message::New() const {
+  return new Message;
+}
+
+void Message::Clear() {
+  if (_has_bits_[0 / 32] & (0xffu << (0 % 32))) {
+    context_id_ = 0;
+    function_ = 187;
+    type_ = 0;
+    expect_response_ = false;
+    ret_ = 0;
+    arg0_ = 0;
+    arg1_ = 0;
+    arg2_ = 0;
+  }
+  if (_has_bits_[8 / 32] & (0xffu << (8 % 32))) {
+    arg3_ = 0;
+    arg4_ = 0;
+    arg5_ = 0;
+    arg6_ = 0;
+    arg7_ = 0;
+    arg8_ = 0;
+    if (_has_bit(14)) {
+      if (data_ != &_default_data_) {
+        data_->clear();
+      }
+    }
+    time_ = 0;
+  }
+  if (_has_bits_[16 / 32] & (0xffu << (16 % 32))) {
+    prop_ = 0;
+    clock_ = 0;
+  }
+  ::memset(_has_bits_, 0, sizeof(_has_bits_));
+}
+
+bool Message::MergePartialFromCodedStream(
+    ::google::protobuf::io::CodedInputStream* input) {
+#define DO_(EXPRESSION) if (!(EXPRESSION)) return false
+  ::google::protobuf::uint32 tag;
+  while ((tag = input->ReadTag()) != 0) {
+    switch (::google::protobuf::internal::WireFormatLite::GetTagFieldNumber(tag)) {
+      // required int32 context_id = 1;
+      case 1: {
+        if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
+            ::google::protobuf::internal::WireFormatLite::WIRETYPE_VARINT) {
+          DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+                   ::google::protobuf::int32, ::google::protobuf::internal::WireFormatLite::TYPE_INT32>(
+                 input, &context_id_)));
+          _set_bit(0);
+        } else {
+          goto handle_uninterpreted;
+        }
+        if (input->ExpectTag(16)) goto parse_function;
+        break;
+      }
+      
+      // required .com.android.glesv2debugger.Message.Function function = 2 [default = NEG];
+      case 2: {
+        if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
+            ::google::protobuf::internal::WireFormatLite::WIRETYPE_VARINT) {
+         parse_function:
+          int value;
+          DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+                   int, ::google::protobuf::internal::WireFormatLite::TYPE_ENUM>(
+                 input, &value)));
+          if (::com::android::glesv2debugger::Message_Function_IsValid(value)) {
+            set_function(static_cast< ::com::android::glesv2debugger::Message_Function >(value));
+          }
+        } else {
+          goto handle_uninterpreted;
+        }
+        if (input->ExpectTag(24)) goto parse_type;
+        break;
+      }
+      
+      // required .com.android.glesv2debugger.Message.Type type = 3;
+      case 3: {
+        if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
+            ::google::protobuf::internal::WireFormatLite::WIRETYPE_VARINT) {
+         parse_type:
+          int value;
+          DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+                   int, ::google::protobuf::internal::WireFormatLite::TYPE_ENUM>(
+                 input, &value)));
+          if (::com::android::glesv2debugger::Message_Type_IsValid(value)) {
+            set_type(static_cast< ::com::android::glesv2debugger::Message_Type >(value));
+          }
+        } else {
+          goto handle_uninterpreted;
+        }
+        if (input->ExpectTag(32)) goto parse_expect_response;
+        break;
+      }
+      
+      // required bool expect_response = 4;
+      case 4: {
+        if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
+            ::google::protobuf::internal::WireFormatLite::WIRETYPE_VARINT) {
+         parse_expect_response:
+          DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+                   bool, ::google::protobuf::internal::WireFormatLite::TYPE_BOOL>(
+                 input, &expect_response_)));
+          _set_bit(3);
+        } else {
+          goto handle_uninterpreted;
+        }
+        if (input->ExpectTag(40)) goto parse_ret;
+        break;
+      }
+      
+      // optional int32 ret = 5;
+      case 5: {
+        if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
+            ::google::protobuf::internal::WireFormatLite::WIRETYPE_VARINT) {
+         parse_ret:
+          DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+                   ::google::protobuf::int32, ::google::protobuf::internal::WireFormatLite::TYPE_INT32>(
+                 input, &ret_)));
+          _set_bit(4);
+        } else {
+          goto handle_uninterpreted;
+        }
+        if (input->ExpectTag(48)) goto parse_arg0;
+        break;
+      }
+      
+      // optional int32 arg0 = 6;
+      case 6: {
+        if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
+            ::google::protobuf::internal::WireFormatLite::WIRETYPE_VARINT) {
+         parse_arg0:
+          DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+                   ::google::protobuf::int32, ::google::protobuf::internal::WireFormatLite::TYPE_INT32>(
+                 input, &arg0_)));
+          _set_bit(5);
+        } else {
+          goto handle_uninterpreted;
+        }
+        if (input->ExpectTag(56)) goto parse_arg1;
+        break;
+      }
+      
+      // optional int32 arg1 = 7;
+      case 7: {
+        if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
+            ::google::protobuf::internal::WireFormatLite::WIRETYPE_VARINT) {
+         parse_arg1:
+          DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+                   ::google::protobuf::int32, ::google::protobuf::internal::WireFormatLite::TYPE_INT32>(
+                 input, &arg1_)));
+          _set_bit(6);
+        } else {
+          goto handle_uninterpreted;
+        }
+        if (input->ExpectTag(64)) goto parse_arg2;
+        break;
+      }
+      
+      // optional int32 arg2 = 8;
+      case 8: {
+        if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
+            ::google::protobuf::internal::WireFormatLite::WIRETYPE_VARINT) {
+         parse_arg2:
+          DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+                   ::google::protobuf::int32, ::google::protobuf::internal::WireFormatLite::TYPE_INT32>(
+                 input, &arg2_)));
+          _set_bit(7);
+        } else {
+          goto handle_uninterpreted;
+        }
+        if (input->ExpectTag(72)) goto parse_arg3;
+        break;
+      }
+      
+      // optional int32 arg3 = 9;
+      case 9: {
+        if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
+            ::google::protobuf::internal::WireFormatLite::WIRETYPE_VARINT) {
+         parse_arg3:
+          DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+                   ::google::protobuf::int32, ::google::protobuf::internal::WireFormatLite::TYPE_INT32>(
+                 input, &arg3_)));
+          _set_bit(8);
+        } else {
+          goto handle_uninterpreted;
+        }
+        if (input->ExpectTag(82)) goto parse_data;
+        break;
+      }
+      
+      // optional bytes data = 10;
+      case 10: {
+        if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
+            ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED) {
+         parse_data:
+          DO_(::google::protobuf::internal::WireFormatLite::ReadBytes(
+                input, this->mutable_data()));
+        } else {
+          goto handle_uninterpreted;
+        }
+        if (input->ExpectTag(93)) goto parse_time;
+        break;
+      }
+      
+      // optional float time = 11;
+      case 11: {
+        if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
+            ::google::protobuf::internal::WireFormatLite::WIRETYPE_FIXED32) {
+         parse_time:
+          DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+                   float, ::google::protobuf::internal::WireFormatLite::TYPE_FLOAT>(
+                 input, &time_)));
+          _set_bit(15);
+        } else {
+          goto handle_uninterpreted;
+        }
+        if (input->ExpectTag(128)) goto parse_arg4;
+        break;
+      }
+      
+      // optional int32 arg4 = 16;
+      case 16: {
+        if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
+            ::google::protobuf::internal::WireFormatLite::WIRETYPE_VARINT) {
+         parse_arg4:
+          DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+                   ::google::protobuf::int32, ::google::protobuf::internal::WireFormatLite::TYPE_INT32>(
+                 input, &arg4_)));
+          _set_bit(9);
+        } else {
+          goto handle_uninterpreted;
+        }
+        if (input->ExpectTag(136)) goto parse_arg5;
+        break;
+      }
+      
+      // optional int32 arg5 = 17;
+      case 17: {
+        if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
+            ::google::protobuf::internal::WireFormatLite::WIRETYPE_VARINT) {
+         parse_arg5:
+          DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+                   ::google::protobuf::int32, ::google::protobuf::internal::WireFormatLite::TYPE_INT32>(
+                 input, &arg5_)));
+          _set_bit(10);
+        } else {
+          goto handle_uninterpreted;
+        }
+        if (input->ExpectTag(144)) goto parse_arg6;
+        break;
+      }
+      
+      // optional int32 arg6 = 18;
+      case 18: {
+        if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
+            ::google::protobuf::internal::WireFormatLite::WIRETYPE_VARINT) {
+         parse_arg6:
+          DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+                   ::google::protobuf::int32, ::google::protobuf::internal::WireFormatLite::TYPE_INT32>(
+                 input, &arg6_)));
+          _set_bit(11);
+        } else {
+          goto handle_uninterpreted;
+        }
+        if (input->ExpectTag(152)) goto parse_arg7;
+        break;
+      }
+      
+      // optional int32 arg7 = 19;
+      case 19: {
+        if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
+            ::google::protobuf::internal::WireFormatLite::WIRETYPE_VARINT) {
+         parse_arg7:
+          DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+                   ::google::protobuf::int32, ::google::protobuf::internal::WireFormatLite::TYPE_INT32>(
+                 input, &arg7_)));
+          _set_bit(12);
+        } else {
+          goto handle_uninterpreted;
+        }
+        if (input->ExpectTag(160)) goto parse_arg8;
+        break;
+      }
+      
+      // optional int32 arg8 = 20;
+      case 20: {
+        if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
+            ::google::protobuf::internal::WireFormatLite::WIRETYPE_VARINT) {
+         parse_arg8:
+          DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+                   ::google::protobuf::int32, ::google::protobuf::internal::WireFormatLite::TYPE_INT32>(
+                 input, &arg8_)));
+          _set_bit(13);
+        } else {
+          goto handle_uninterpreted;
+        }
+        if (input->ExpectTag(168)) goto parse_prop;
+        break;
+      }
+      
+      // optional .com.android.glesv2debugger.Message.Prop prop = 21;
+      case 21: {
+        if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
+            ::google::protobuf::internal::WireFormatLite::WIRETYPE_VARINT) {
+         parse_prop:
+          int value;
+          DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+                   int, ::google::protobuf::internal::WireFormatLite::TYPE_ENUM>(
+                 input, &value)));
+          if (::com::android::glesv2debugger::Message_Prop_IsValid(value)) {
+            set_prop(static_cast< ::com::android::glesv2debugger::Message_Prop >(value));
+          }
+        } else {
+          goto handle_uninterpreted;
+        }
+        if (input->ExpectTag(181)) goto parse_clock;
+        break;
+      }
+      
+      // optional float clock = 22;
+      case 22: {
+        if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
+            ::google::protobuf::internal::WireFormatLite::WIRETYPE_FIXED32) {
+         parse_clock:
+          DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+                   float, ::google::protobuf::internal::WireFormatLite::TYPE_FLOAT>(
+                 input, &clock_)));
+          _set_bit(17);
+        } else {
+          goto handle_uninterpreted;
+        }
+        if (input->ExpectAtEnd()) return true;
+        break;
+      }
+      
+      default: {
+      handle_uninterpreted:
+        if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
+            ::google::protobuf::internal::WireFormatLite::WIRETYPE_END_GROUP) {
+          return true;
+        }
+        DO_(::google::protobuf::internal::WireFormatLite::SkipField(input, tag));
+        break;
+      }
+    }
+  }
+  return true;
+#undef DO_
+}
+
+void Message::SerializeWithCachedSizes(
+    ::google::protobuf::io::CodedOutputStream* output) const {
+  // required int32 context_id = 1;
+  if (_has_bit(0)) {
+    ::google::protobuf::internal::WireFormatLite::WriteInt32(1, this->context_id(), output);
+  }
+  
+  // required .com.android.glesv2debugger.Message.Function function = 2 [default = NEG];
+  if (_has_bit(1)) {
+    ::google::protobuf::internal::WireFormatLite::WriteEnum(
+      2, this->function(), output);
+  }
+  
+  // required .com.android.glesv2debugger.Message.Type type = 3;
+  if (_has_bit(2)) {
+    ::google::protobuf::internal::WireFormatLite::WriteEnum(
+      3, this->type(), output);
+  }
+  
+  // required bool expect_response = 4;
+  if (_has_bit(3)) {
+    ::google::protobuf::internal::WireFormatLite::WriteBool(4, this->expect_response(), output);
+  }
+  
+  // optional int32 ret = 5;
+  if (_has_bit(4)) {
+    ::google::protobuf::internal::WireFormatLite::WriteInt32(5, this->ret(), output);
+  }
+  
+  // optional int32 arg0 = 6;
+  if (_has_bit(5)) {
+    ::google::protobuf::internal::WireFormatLite::WriteInt32(6, this->arg0(), output);
+  }
+  
+  // optional int32 arg1 = 7;
+  if (_has_bit(6)) {
+    ::google::protobuf::internal::WireFormatLite::WriteInt32(7, this->arg1(), output);
+  }
+  
+  // optional int32 arg2 = 8;
+  if (_has_bit(7)) {
+    ::google::protobuf::internal::WireFormatLite::WriteInt32(8, this->arg2(), output);
+  }
+  
+  // optional int32 arg3 = 9;
+  if (_has_bit(8)) {
+    ::google::protobuf::internal::WireFormatLite::WriteInt32(9, this->arg3(), output);
+  }
+  
+  // optional bytes data = 10;
+  if (_has_bit(14)) {
+    ::google::protobuf::internal::WireFormatLite::WriteBytes(
+      10, this->data(), output);
+  }
+  
+  // optional float time = 11;
+  if (_has_bit(15)) {
+    ::google::protobuf::internal::WireFormatLite::WriteFloat(11, this->time(), output);
+  }
+  
+  // optional int32 arg4 = 16;
+  if (_has_bit(9)) {
+    ::google::protobuf::internal::WireFormatLite::WriteInt32(16, this->arg4(), output);
+  }
+  
+  // optional int32 arg5 = 17;
+  if (_has_bit(10)) {
+    ::google::protobuf::internal::WireFormatLite::WriteInt32(17, this->arg5(), output);
+  }
+  
+  // optional int32 arg6 = 18;
+  if (_has_bit(11)) {
+    ::google::protobuf::internal::WireFormatLite::WriteInt32(18, this->arg6(), output);
+  }
+  
+  // optional int32 arg7 = 19;
+  if (_has_bit(12)) {
+    ::google::protobuf::internal::WireFormatLite::WriteInt32(19, this->arg7(), output);
+  }
+  
+  // optional int32 arg8 = 20;
+  if (_has_bit(13)) {
+    ::google::protobuf::internal::WireFormatLite::WriteInt32(20, this->arg8(), output);
+  }
+  
+  // optional .com.android.glesv2debugger.Message.Prop prop = 21;
+  if (_has_bit(16)) {
+    ::google::protobuf::internal::WireFormatLite::WriteEnum(
+      21, this->prop(), output);
+  }
+  
+  // optional float clock = 22;
+  if (_has_bit(17)) {
+    ::google::protobuf::internal::WireFormatLite::WriteFloat(22, this->clock(), output);
+  }
+  
+}
+
+int Message::ByteSize() const {
+  int total_size = 0;
+  
+  if (_has_bits_[0 / 32] & (0xffu << (0 % 32))) {
+    // required int32 context_id = 1;
+    if (has_context_id()) {
+      total_size += 1 +
+        ::google::protobuf::internal::WireFormatLite::Int32Size(
+          this->context_id());
+    }
+    
+    // required .com.android.glesv2debugger.Message.Function function = 2 [default = NEG];
+    if (has_function()) {
+      total_size += 1 +
+        ::google::protobuf::internal::WireFormatLite::EnumSize(this->function());
+    }
+    
+    // required .com.android.glesv2debugger.Message.Type type = 3;
+    if (has_type()) {
+      total_size += 1 +
+        ::google::protobuf::internal::WireFormatLite::EnumSize(this->type());
+    }
+    
+    // required bool expect_response = 4;
+    if (has_expect_response()) {
+      total_size += 1 + 1;
+    }
+    
+    // optional int32 ret = 5;
+    if (has_ret()) {
+      total_size += 1 +
+        ::google::protobuf::internal::WireFormatLite::Int32Size(
+          this->ret());
+    }
+    
+    // optional int32 arg0 = 6;
+    if (has_arg0()) {
+      total_size += 1 +
+        ::google::protobuf::internal::WireFormatLite::Int32Size(
+          this->arg0());
+    }
+    
+    // optional int32 arg1 = 7;
+    if (has_arg1()) {
+      total_size += 1 +
+        ::google::protobuf::internal::WireFormatLite::Int32Size(
+          this->arg1());
+    }
+    
+    // optional int32 arg2 = 8;
+    if (has_arg2()) {
+      total_size += 1 +
+        ::google::protobuf::internal::WireFormatLite::Int32Size(
+          this->arg2());
+    }
+    
+  }
+  if (_has_bits_[8 / 32] & (0xffu << (8 % 32))) {
+    // optional int32 arg3 = 9;
+    if (has_arg3()) {
+      total_size += 1 +
+        ::google::protobuf::internal::WireFormatLite::Int32Size(
+          this->arg3());
+    }
+    
+    // optional int32 arg4 = 16;
+    if (has_arg4()) {
+      total_size += 2 +
+        ::google::protobuf::internal::WireFormatLite::Int32Size(
+          this->arg4());
+    }
+    
+    // optional int32 arg5 = 17;
+    if (has_arg5()) {
+      total_size += 2 +
+        ::google::protobuf::internal::WireFormatLite::Int32Size(
+          this->arg5());
+    }
+    
+    // optional int32 arg6 = 18;
+    if (has_arg6()) {
+      total_size += 2 +
+        ::google::protobuf::internal::WireFormatLite::Int32Size(
+          this->arg6());
+    }
+    
+    // optional int32 arg7 = 19;
+    if (has_arg7()) {
+      total_size += 2 +
+        ::google::protobuf::internal::WireFormatLite::Int32Size(
+          this->arg7());
+    }
+    
+    // optional int32 arg8 = 20;
+    if (has_arg8()) {
+      total_size += 2 +
+        ::google::protobuf::internal::WireFormatLite::Int32Size(
+          this->arg8());
+    }
+    
+    // optional bytes data = 10;
+    if (has_data()) {
+      total_size += 1 +
+        ::google::protobuf::internal::WireFormatLite::BytesSize(
+          this->data());
+    }
+    
+    // optional float time = 11;
+    if (has_time()) {
+      total_size += 1 + 4;
+    }
+    
+  }
+  if (_has_bits_[16 / 32] & (0xffu << (16 % 32))) {
+    // optional .com.android.glesv2debugger.Message.Prop prop = 21;
+    if (has_prop()) {
+      total_size += 2 +
+        ::google::protobuf::internal::WireFormatLite::EnumSize(this->prop());
+    }
+    
+    // optional float clock = 22;
+    if (has_clock()) {
+      total_size += 2 + 4;
+    }
+    
+  }
+  GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
+  _cached_size_ = total_size;
+  GOOGLE_SAFE_CONCURRENT_WRITES_END();
+  return total_size;
+}
+
+void Message::CheckTypeAndMergeFrom(
+    const ::google::protobuf::MessageLite& from) {
+  MergeFrom(*::google::protobuf::down_cast<const Message*>(&from));
+}
+
+void Message::MergeFrom(const Message& from) {
+  GOOGLE_CHECK_NE(&from, this);
+  if (from._has_bits_[0 / 32] & (0xffu << (0 % 32))) {
+    if (from._has_bit(0)) {
+      set_context_id(from.context_id());
+    }
+    if (from._has_bit(1)) {
+      set_function(from.function());
+    }
+    if (from._has_bit(2)) {
+      set_type(from.type());
+    }
+    if (from._has_bit(3)) {
+      set_expect_response(from.expect_response());
+    }
+    if (from._has_bit(4)) {
+      set_ret(from.ret());
+    }
+    if (from._has_bit(5)) {
+      set_arg0(from.arg0());
+    }
+    if (from._has_bit(6)) {
+      set_arg1(from.arg1());
+    }
+    if (from._has_bit(7)) {
+      set_arg2(from.arg2());
+    }
+  }
+  if (from._has_bits_[8 / 32] & (0xffu << (8 % 32))) {
+    if (from._has_bit(8)) {
+      set_arg3(from.arg3());
+    }
+    if (from._has_bit(9)) {
+      set_arg4(from.arg4());
+    }
+    if (from._has_bit(10)) {
+      set_arg5(from.arg5());
+    }
+    if (from._has_bit(11)) {
+      set_arg6(from.arg6());
+    }
+    if (from._has_bit(12)) {
+      set_arg7(from.arg7());
+    }
+    if (from._has_bit(13)) {
+      set_arg8(from.arg8());
+    }
+    if (from._has_bit(14)) {
+      set_data(from.data());
+    }
+    if (from._has_bit(15)) {
+      set_time(from.time());
+    }
+  }
+  if (from._has_bits_[16 / 32] & (0xffu << (16 % 32))) {
+    if (from._has_bit(16)) {
+      set_prop(from.prop());
+    }
+    if (from._has_bit(17)) {
+      set_clock(from.clock());
+    }
+  }
+}
+
+void Message::CopyFrom(const Message& from) {
+  if (&from == this) return;
+  Clear();
+  MergeFrom(from);
+}
+
+bool Message::IsInitialized() const {
+  if ((_has_bits_[0] & 0x0000000f) != 0x0000000f) return false;
+  
+  return true;
+}
+
+void Message::Swap(Message* other) {
+  if (other != this) {
+    std::swap(context_id_, other->context_id_);
+    std::swap(function_, other->function_);
+    std::swap(type_, other->type_);
+    std::swap(expect_response_, other->expect_response_);
+    std::swap(ret_, other->ret_);
+    std::swap(arg0_, other->arg0_);
+    std::swap(arg1_, other->arg1_);
+    std::swap(arg2_, other->arg2_);
+    std::swap(arg3_, other->arg3_);
+    std::swap(arg4_, other->arg4_);
+    std::swap(arg5_, other->arg5_);
+    std::swap(arg6_, other->arg6_);
+    std::swap(arg7_, other->arg7_);
+    std::swap(arg8_, other->arg8_);
+    std::swap(data_, other->data_);
+    std::swap(time_, other->time_);
+    std::swap(prop_, other->prop_);
+    std::swap(clock_, other->clock_);
+    std::swap(_has_bits_[0], other->_has_bits_[0]);
+    std::swap(_cached_size_, other->_cached_size_);
+  }
+}
+
+::std::string Message::GetTypeName() const {
+  return "com.android.glesv2debugger.Message";
+}
+
+
+// @@protoc_insertion_point(namespace_scope)
+
+}  // namespace glesv2debugger
+}  // namespace android
+}  // namespace com
+
+// @@protoc_insertion_point(global_scope)
diff --git a/opengl/libs/GLES2_dbg/src/debugger_message.pb.h b/opengl/libs/GLES2_dbg/src/debugger_message.pb.h
new file mode 100644
index 0000000..59e7bab
--- /dev/null
+++ b/opengl/libs/GLES2_dbg/src/debugger_message.pb.h
@@ -0,0 +1,1034 @@
+// Generated by the protocol buffer compiler.  DO NOT EDIT!
+// source: debugger_message.proto
+
+#ifndef PROTOBUF_debugger_5fmessage_2eproto__INCLUDED
+#define PROTOBUF_debugger_5fmessage_2eproto__INCLUDED
+
+#include <string>
+
+#include <google/protobuf/stubs/common.h>
+
+#if GOOGLE_PROTOBUF_VERSION < 2003000
+#error This file was generated by a newer version of protoc which is
+#error incompatible with your Protocol Buffer headers.  Please update
+#error your headers.
+#endif
+#if 2003000 < GOOGLE_PROTOBUF_MIN_PROTOC_VERSION
+#error This file was generated by an older version of protoc which is
+#error incompatible with your Protocol Buffer headers.  Please
+#error regenerate this file with a newer version of protoc.
+#endif
+
+#include <google/protobuf/generated_message_util.h>
+#include <google/protobuf/repeated_field.h>
+#include <google/protobuf/extension_set.h>
+// @@protoc_insertion_point(includes)
+
+namespace com {
+namespace android {
+namespace glesv2debugger {
+
+// Internal implementation detail -- do not call these.
+void  protobuf_AddDesc_debugger_5fmessage_2eproto();
+void protobuf_AssignDesc_debugger_5fmessage_2eproto();
+void protobuf_ShutdownFile_debugger_5fmessage_2eproto();
+
+class Message;
+
+enum Message_Function {
+  Message_Function_glActiveTexture = 0,
+  Message_Function_glAttachShader = 1,
+  Message_Function_glBindAttribLocation = 2,
+  Message_Function_glBindBuffer = 3,
+  Message_Function_glBindFramebuffer = 4,
+  Message_Function_glBindRenderbuffer = 5,
+  Message_Function_glBindTexture = 6,
+  Message_Function_glBlendColor = 7,
+  Message_Function_glBlendEquation = 8,
+  Message_Function_glBlendEquationSeparate = 9,
+  Message_Function_glBlendFunc = 10,
+  Message_Function_glBlendFuncSeparate = 11,
+  Message_Function_glBufferData = 12,
+  Message_Function_glBufferSubData = 13,
+  Message_Function_glCheckFramebufferStatus = 14,
+  Message_Function_glClear = 15,
+  Message_Function_glClearColor = 16,
+  Message_Function_glClearDepthf = 17,
+  Message_Function_glClearStencil = 18,
+  Message_Function_glColorMask = 19,
+  Message_Function_glCompileShader = 20,
+  Message_Function_glCompressedTexImage2D = 21,
+  Message_Function_glCompressedTexSubImage2D = 22,
+  Message_Function_glCopyTexImage2D = 23,
+  Message_Function_glCopyTexSubImage2D = 24,
+  Message_Function_glCreateProgram = 25,
+  Message_Function_glCreateShader = 26,
+  Message_Function_glCullFace = 27,
+  Message_Function_glDeleteBuffers = 28,
+  Message_Function_glDeleteFramebuffers = 29,
+  Message_Function_glDeleteProgram = 30,
+  Message_Function_glDeleteRenderbuffers = 31,
+  Message_Function_glDeleteShader = 32,
+  Message_Function_glDeleteTextures = 33,
+  Message_Function_glDepthFunc = 34,
+  Message_Function_glDepthMask = 35,
+  Message_Function_glDepthRangef = 36,
+  Message_Function_glDetachShader = 37,
+  Message_Function_glDisable = 38,
+  Message_Function_glDisableVertexAttribArray = 39,
+  Message_Function_glDrawArrays = 40,
+  Message_Function_glDrawElements = 41,
+  Message_Function_glEnable = 42,
+  Message_Function_glEnableVertexAttribArray = 43,
+  Message_Function_glFinish = 44,
+  Message_Function_glFlush = 45,
+  Message_Function_glFramebufferRenderbuffer = 46,
+  Message_Function_glFramebufferTexture2D = 47,
+  Message_Function_glFrontFace = 48,
+  Message_Function_glGenBuffers = 49,
+  Message_Function_glGenerateMipmap = 50,
+  Message_Function_glGenFramebuffers = 51,
+  Message_Function_glGenRenderbuffers = 52,
+  Message_Function_glGenTextures = 53,
+  Message_Function_glGetActiveAttrib = 54,
+  Message_Function_glGetActiveUniform = 55,
+  Message_Function_glGetAttachedShaders = 56,
+  Message_Function_glGetAttribLocation = 57,
+  Message_Function_glGetBooleanv = 58,
+  Message_Function_glGetBufferParameteriv = 59,
+  Message_Function_glGetError = 60,
+  Message_Function_glGetFloatv = 61,
+  Message_Function_glGetFramebufferAttachmentParameteriv = 62,
+  Message_Function_glGetIntegerv = 63,
+  Message_Function_glGetProgramiv = 64,
+  Message_Function_glGetProgramInfoLog = 65,
+  Message_Function_glGetRenderbufferParameteriv = 66,
+  Message_Function_glGetShaderiv = 67,
+  Message_Function_glGetShaderInfoLog = 68,
+  Message_Function_glGetShaderPrecisionFormat = 69,
+  Message_Function_glGetShaderSource = 70,
+  Message_Function_glGetString = 71,
+  Message_Function_glGetTexParameterfv = 72,
+  Message_Function_glGetTexParameteriv = 73,
+  Message_Function_glGetUniformfv = 74,
+  Message_Function_glGetUniformiv = 75,
+  Message_Function_glGetUniformLocation = 76,
+  Message_Function_glGetVertexAttribfv = 77,
+  Message_Function_glGetVertexAttribiv = 78,
+  Message_Function_glGetVertexAttribPointerv = 79,
+  Message_Function_glHint = 80,
+  Message_Function_glIsBuffer = 81,
+  Message_Function_glIsEnabled = 82,
+  Message_Function_glIsFramebuffer = 83,
+  Message_Function_glIsProgram = 84,
+  Message_Function_glIsRenderbuffer = 85,
+  Message_Function_glIsShader = 86,
+  Message_Function_glIsTexture = 87,
+  Message_Function_glLineWidth = 88,
+  Message_Function_glLinkProgram = 89,
+  Message_Function_glPixelStorei = 90,
+  Message_Function_glPolygonOffset = 91,
+  Message_Function_glReadPixels = 92,
+  Message_Function_glReleaseShaderCompiler = 93,
+  Message_Function_glRenderbufferStorage = 94,
+  Message_Function_glSampleCoverage = 95,
+  Message_Function_glScissor = 96,
+  Message_Function_glShaderBinary = 97,
+  Message_Function_glShaderSource = 98,
+  Message_Function_glStencilFunc = 99,
+  Message_Function_glStencilFuncSeparate = 100,
+  Message_Function_glStencilMask = 101,
+  Message_Function_glStencilMaskSeparate = 102,
+  Message_Function_glStencilOp = 103,
+  Message_Function_glStencilOpSeparate = 104,
+  Message_Function_glTexImage2D = 105,
+  Message_Function_glTexParameterf = 106,
+  Message_Function_glTexParameterfv = 107,
+  Message_Function_glTexParameteri = 108,
+  Message_Function_glTexParameteriv = 109,
+  Message_Function_glTexSubImage2D = 110,
+  Message_Function_glUniform1f = 111,
+  Message_Function_glUniform1fv = 112,
+  Message_Function_glUniform1i = 113,
+  Message_Function_glUniform1iv = 114,
+  Message_Function_glUniform2f = 115,
+  Message_Function_glUniform2fv = 116,
+  Message_Function_glUniform2i = 117,
+  Message_Function_glUniform2iv = 118,
+  Message_Function_glUniform3f = 119,
+  Message_Function_glUniform3fv = 120,
+  Message_Function_glUniform3i = 121,
+  Message_Function_glUniform3iv = 122,
+  Message_Function_glUniform4f = 123,
+  Message_Function_glUniform4fv = 124,
+  Message_Function_glUniform4i = 125,
+  Message_Function_glUniform4iv = 126,
+  Message_Function_glUniformMatrix2fv = 127,
+  Message_Function_glUniformMatrix3fv = 128,
+  Message_Function_glUniformMatrix4fv = 129,
+  Message_Function_glUseProgram = 130,
+  Message_Function_glValidateProgram = 131,
+  Message_Function_glVertexAttrib1f = 132,
+  Message_Function_glVertexAttrib1fv = 133,
+  Message_Function_glVertexAttrib2f = 134,
+  Message_Function_glVertexAttrib2fv = 135,
+  Message_Function_glVertexAttrib3f = 136,
+  Message_Function_glVertexAttrib3fv = 137,
+  Message_Function_glVertexAttrib4f = 138,
+  Message_Function_glVertexAttrib4fv = 139,
+  Message_Function_glVertexAttribPointer = 140,
+  Message_Function_glViewport = 141,
+  Message_Function_eglGetDisplay = 142,
+  Message_Function_eglInitialize = 143,
+  Message_Function_eglTerminate = 144,
+  Message_Function_eglGetConfigs = 145,
+  Message_Function_eglChooseConfig = 146,
+  Message_Function_eglGetConfigAttrib = 147,
+  Message_Function_eglCreateWindowSurface = 148,
+  Message_Function_eglCreatePixmapSurface = 149,
+  Message_Function_eglCreatePbufferSurface = 150,
+  Message_Function_eglDestroySurface = 151,
+  Message_Function_eglQuerySurface = 152,
+  Message_Function_eglCreateContext = 153,
+  Message_Function_eglDestroyContext = 154,
+  Message_Function_eglMakeCurrent = 155,
+  Message_Function_eglGetCurrentContext = 156,
+  Message_Function_eglGetCurrentSurface = 157,
+  Message_Function_eglGetCurrentDisplay = 158,
+  Message_Function_eglQueryContext = 159,
+  Message_Function_eglWaitGL = 160,
+  Message_Function_eglWaitNative = 161,
+  Message_Function_eglSwapBuffers = 162,
+  Message_Function_eglCopyBuffers = 163,
+  Message_Function_eglGetError = 164,
+  Message_Function_eglQueryString = 165,
+  Message_Function_eglGetProcAddress = 166,
+  Message_Function_eglSurfaceAttrib = 167,
+  Message_Function_eglBindTexImage = 168,
+  Message_Function_eglReleaseTexImage = 169,
+  Message_Function_eglSwapInterval = 170,
+  Message_Function_eglBindAPI = 171,
+  Message_Function_eglQueryAPI = 172,
+  Message_Function_eglWaitClient = 173,
+  Message_Function_eglReleaseThread = 174,
+  Message_Function_eglCreatePbufferFromClientBuffer = 175,
+  Message_Function_eglLockSurfaceKHR = 176,
+  Message_Function_eglUnlockSurfaceKHR = 177,
+  Message_Function_eglCreateImageKHR = 178,
+  Message_Function_eglDestroyImageKHR = 179,
+  Message_Function_eglCreateSyncKHR = 180,
+  Message_Function_eglDestroySyncKHR = 181,
+  Message_Function_eglClientWaitSyncKHR = 182,
+  Message_Function_eglGetSyncAttribKHR = 183,
+  Message_Function_eglSetSwapRectangleANDROID = 184,
+  Message_Function_eglGetRenderBufferANDROID = 185,
+  Message_Function_ACK = 186,
+  Message_Function_NEG = 187,
+  Message_Function_CONTINUE = 188,
+  Message_Function_SKIP = 189,
+  Message_Function_SETPROP = 190
+};
+bool Message_Function_IsValid(int value);
+const Message_Function Message_Function_Function_MIN = Message_Function_glActiveTexture;
+const Message_Function Message_Function_Function_MAX = Message_Function_SETPROP;
+const int Message_Function_Function_ARRAYSIZE = Message_Function_Function_MAX + 1;
+
+enum Message_Type {
+  Message_Type_BeforeCall = 0,
+  Message_Type_AfterCall = 1,
+  Message_Type_Response = 2
+};
+bool Message_Type_IsValid(int value);
+const Message_Type Message_Type_Type_MIN = Message_Type_BeforeCall;
+const Message_Type Message_Type_Type_MAX = Message_Type_Response;
+const int Message_Type_Type_ARRAYSIZE = Message_Type_Type_MAX + 1;
+
+enum Message_Prop {
+  Message_Prop_Capture = 0,
+  Message_Prop_TimeMode = 1
+};
+bool Message_Prop_IsValid(int value);
+const Message_Prop Message_Prop_Prop_MIN = Message_Prop_Capture;
+const Message_Prop Message_Prop_Prop_MAX = Message_Prop_TimeMode;
+const int Message_Prop_Prop_ARRAYSIZE = Message_Prop_Prop_MAX + 1;
+
+// ===================================================================
+
+class Message : public ::google::protobuf::MessageLite {
+ public:
+  Message();
+  virtual ~Message();
+  
+  Message(const Message& from);
+  
+  inline Message& operator=(const Message& from) {
+    CopyFrom(from);
+    return *this;
+  }
+  
+  static const Message& default_instance();
+  
+  void Swap(Message* other);
+  
+  // implements Message ----------------------------------------------
+  
+  Message* New() const;
+  void CheckTypeAndMergeFrom(const ::google::protobuf::MessageLite& from);
+  void CopyFrom(const Message& from);
+  void MergeFrom(const Message& from);
+  void Clear();
+  bool IsInitialized() const;
+  
+  int ByteSize() const;
+  bool MergePartialFromCodedStream(
+      ::google::protobuf::io::CodedInputStream* input);
+  void SerializeWithCachedSizes(
+      ::google::protobuf::io::CodedOutputStream* output) const;
+  int GetCachedSize() const { return _cached_size_; }
+  private:
+  void SharedCtor();
+  void SharedDtor();
+  void SetCachedSize(int size) const;
+  public:
+  
+  ::std::string GetTypeName() const;
+  
+  // nested types ----------------------------------------------------
+  
+  typedef Message_Function Function;
+  static const Function glActiveTexture = Message_Function_glActiveTexture;
+  static const Function glAttachShader = Message_Function_glAttachShader;
+  static const Function glBindAttribLocation = Message_Function_glBindAttribLocation;
+  static const Function glBindBuffer = Message_Function_glBindBuffer;
+  static const Function glBindFramebuffer = Message_Function_glBindFramebuffer;
+  static const Function glBindRenderbuffer = Message_Function_glBindRenderbuffer;
+  static const Function glBindTexture = Message_Function_glBindTexture;
+  static const Function glBlendColor = Message_Function_glBlendColor;
+  static const Function glBlendEquation = Message_Function_glBlendEquation;
+  static const Function glBlendEquationSeparate = Message_Function_glBlendEquationSeparate;
+  static const Function glBlendFunc = Message_Function_glBlendFunc;
+  static const Function glBlendFuncSeparate = Message_Function_glBlendFuncSeparate;
+  static const Function glBufferData = Message_Function_glBufferData;
+  static const Function glBufferSubData = Message_Function_glBufferSubData;
+  static const Function glCheckFramebufferStatus = Message_Function_glCheckFramebufferStatus;
+  static const Function glClear = Message_Function_glClear;
+  static const Function glClearColor = Message_Function_glClearColor;
+  static const Function glClearDepthf = Message_Function_glClearDepthf;
+  static const Function glClearStencil = Message_Function_glClearStencil;
+  static const Function glColorMask = Message_Function_glColorMask;
+  static const Function glCompileShader = Message_Function_glCompileShader;
+  static const Function glCompressedTexImage2D = Message_Function_glCompressedTexImage2D;
+  static const Function glCompressedTexSubImage2D = Message_Function_glCompressedTexSubImage2D;
+  static const Function glCopyTexImage2D = Message_Function_glCopyTexImage2D;
+  static const Function glCopyTexSubImage2D = Message_Function_glCopyTexSubImage2D;
+  static const Function glCreateProgram = Message_Function_glCreateProgram;
+  static const Function glCreateShader = Message_Function_glCreateShader;
+  static const Function glCullFace = Message_Function_glCullFace;
+  static const Function glDeleteBuffers = Message_Function_glDeleteBuffers;
+  static const Function glDeleteFramebuffers = Message_Function_glDeleteFramebuffers;
+  static const Function glDeleteProgram = Message_Function_glDeleteProgram;
+  static const Function glDeleteRenderbuffers = Message_Function_glDeleteRenderbuffers;
+  static const Function glDeleteShader = Message_Function_glDeleteShader;
+  static const Function glDeleteTextures = Message_Function_glDeleteTextures;
+  static const Function glDepthFunc = Message_Function_glDepthFunc;
+  static const Function glDepthMask = Message_Function_glDepthMask;
+  static const Function glDepthRangef = Message_Function_glDepthRangef;
+  static const Function glDetachShader = Message_Function_glDetachShader;
+  static const Function glDisable = Message_Function_glDisable;
+  static const Function glDisableVertexAttribArray = Message_Function_glDisableVertexAttribArray;
+  static const Function glDrawArrays = Message_Function_glDrawArrays;
+  static const Function glDrawElements = Message_Function_glDrawElements;
+  static const Function glEnable = Message_Function_glEnable;
+  static const Function glEnableVertexAttribArray = Message_Function_glEnableVertexAttribArray;
+  static const Function glFinish = Message_Function_glFinish;
+  static const Function glFlush = Message_Function_glFlush;
+  static const Function glFramebufferRenderbuffer = Message_Function_glFramebufferRenderbuffer;
+  static const Function glFramebufferTexture2D = Message_Function_glFramebufferTexture2D;
+  static const Function glFrontFace = Message_Function_glFrontFace;
+  static const Function glGenBuffers = Message_Function_glGenBuffers;
+  static const Function glGenerateMipmap = Message_Function_glGenerateMipmap;
+  static const Function glGenFramebuffers = Message_Function_glGenFramebuffers;
+  static const Function glGenRenderbuffers = Message_Function_glGenRenderbuffers;
+  static const Function glGenTextures = Message_Function_glGenTextures;
+  static const Function glGetActiveAttrib = Message_Function_glGetActiveAttrib;
+  static const Function glGetActiveUniform = Message_Function_glGetActiveUniform;
+  static const Function glGetAttachedShaders = Message_Function_glGetAttachedShaders;
+  static const Function glGetAttribLocation = Message_Function_glGetAttribLocation;
+  static const Function glGetBooleanv = Message_Function_glGetBooleanv;
+  static const Function glGetBufferParameteriv = Message_Function_glGetBufferParameteriv;
+  static const Function glGetError = Message_Function_glGetError;
+  static const Function glGetFloatv = Message_Function_glGetFloatv;
+  static const Function glGetFramebufferAttachmentParameteriv = Message_Function_glGetFramebufferAttachmentParameteriv;
+  static const Function glGetIntegerv = Message_Function_glGetIntegerv;
+  static const Function glGetProgramiv = Message_Function_glGetProgramiv;
+  static const Function glGetProgramInfoLog = Message_Function_glGetProgramInfoLog;
+  static const Function glGetRenderbufferParameteriv = Message_Function_glGetRenderbufferParameteriv;
+  static const Function glGetShaderiv = Message_Function_glGetShaderiv;
+  static const Function glGetShaderInfoLog = Message_Function_glGetShaderInfoLog;
+  static const Function glGetShaderPrecisionFormat = Message_Function_glGetShaderPrecisionFormat;
+  static const Function glGetShaderSource = Message_Function_glGetShaderSource;
+  static const Function glGetString = Message_Function_glGetString;
+  static const Function glGetTexParameterfv = Message_Function_glGetTexParameterfv;
+  static const Function glGetTexParameteriv = Message_Function_glGetTexParameteriv;
+  static const Function glGetUniformfv = Message_Function_glGetUniformfv;
+  static const Function glGetUniformiv = Message_Function_glGetUniformiv;
+  static const Function glGetUniformLocation = Message_Function_glGetUniformLocation;
+  static const Function glGetVertexAttribfv = Message_Function_glGetVertexAttribfv;
+  static const Function glGetVertexAttribiv = Message_Function_glGetVertexAttribiv;
+  static const Function glGetVertexAttribPointerv = Message_Function_glGetVertexAttribPointerv;
+  static const Function glHint = Message_Function_glHint;
+  static const Function glIsBuffer = Message_Function_glIsBuffer;
+  static const Function glIsEnabled = Message_Function_glIsEnabled;
+  static const Function glIsFramebuffer = Message_Function_glIsFramebuffer;
+  static const Function glIsProgram = Message_Function_glIsProgram;
+  static const Function glIsRenderbuffer = Message_Function_glIsRenderbuffer;
+  static const Function glIsShader = Message_Function_glIsShader;
+  static const Function glIsTexture = Message_Function_glIsTexture;
+  static const Function glLineWidth = Message_Function_glLineWidth;
+  static const Function glLinkProgram = Message_Function_glLinkProgram;
+  static const Function glPixelStorei = Message_Function_glPixelStorei;
+  static const Function glPolygonOffset = Message_Function_glPolygonOffset;
+  static const Function glReadPixels = Message_Function_glReadPixels;
+  static const Function glReleaseShaderCompiler = Message_Function_glReleaseShaderCompiler;
+  static const Function glRenderbufferStorage = Message_Function_glRenderbufferStorage;
+  static const Function glSampleCoverage = Message_Function_glSampleCoverage;
+  static const Function glScissor = Message_Function_glScissor;
+  static const Function glShaderBinary = Message_Function_glShaderBinary;
+  static const Function glShaderSource = Message_Function_glShaderSource;
+  static const Function glStencilFunc = Message_Function_glStencilFunc;
+  static const Function glStencilFuncSeparate = Message_Function_glStencilFuncSeparate;
+  static const Function glStencilMask = Message_Function_glStencilMask;
+  static const Function glStencilMaskSeparate = Message_Function_glStencilMaskSeparate;
+  static const Function glStencilOp = Message_Function_glStencilOp;
+  static const Function glStencilOpSeparate = Message_Function_glStencilOpSeparate;
+  static const Function glTexImage2D = Message_Function_glTexImage2D;
+  static const Function glTexParameterf = Message_Function_glTexParameterf;
+  static const Function glTexParameterfv = Message_Function_glTexParameterfv;
+  static const Function glTexParameteri = Message_Function_glTexParameteri;
+  static const Function glTexParameteriv = Message_Function_glTexParameteriv;
+  static const Function glTexSubImage2D = Message_Function_glTexSubImage2D;
+  static const Function glUniform1f = Message_Function_glUniform1f;
+  static const Function glUniform1fv = Message_Function_glUniform1fv;
+  static const Function glUniform1i = Message_Function_glUniform1i;
+  static const Function glUniform1iv = Message_Function_glUniform1iv;
+  static const Function glUniform2f = Message_Function_glUniform2f;
+  static const Function glUniform2fv = Message_Function_glUniform2fv;
+  static const Function glUniform2i = Message_Function_glUniform2i;
+  static const Function glUniform2iv = Message_Function_glUniform2iv;
+  static const Function glUniform3f = Message_Function_glUniform3f;
+  static const Function glUniform3fv = Message_Function_glUniform3fv;
+  static const Function glUniform3i = Message_Function_glUniform3i;
+  static const Function glUniform3iv = Message_Function_glUniform3iv;
+  static const Function glUniform4f = Message_Function_glUniform4f;
+  static const Function glUniform4fv = Message_Function_glUniform4fv;
+  static const Function glUniform4i = Message_Function_glUniform4i;
+  static const Function glUniform4iv = Message_Function_glUniform4iv;
+  static const Function glUniformMatrix2fv = Message_Function_glUniformMatrix2fv;
+  static const Function glUniformMatrix3fv = Message_Function_glUniformMatrix3fv;
+  static const Function glUniformMatrix4fv = Message_Function_glUniformMatrix4fv;
+  static const Function glUseProgram = Message_Function_glUseProgram;
+  static const Function glValidateProgram = Message_Function_glValidateProgram;
+  static const Function glVertexAttrib1f = Message_Function_glVertexAttrib1f;
+  static const Function glVertexAttrib1fv = Message_Function_glVertexAttrib1fv;
+  static const Function glVertexAttrib2f = Message_Function_glVertexAttrib2f;
+  static const Function glVertexAttrib2fv = Message_Function_glVertexAttrib2fv;
+  static const Function glVertexAttrib3f = Message_Function_glVertexAttrib3f;
+  static const Function glVertexAttrib3fv = Message_Function_glVertexAttrib3fv;
+  static const Function glVertexAttrib4f = Message_Function_glVertexAttrib4f;
+  static const Function glVertexAttrib4fv = Message_Function_glVertexAttrib4fv;
+  static const Function glVertexAttribPointer = Message_Function_glVertexAttribPointer;
+  static const Function glViewport = Message_Function_glViewport;
+  static const Function eglGetDisplay = Message_Function_eglGetDisplay;
+  static const Function eglInitialize = Message_Function_eglInitialize;
+  static const Function eglTerminate = Message_Function_eglTerminate;
+  static const Function eglGetConfigs = Message_Function_eglGetConfigs;
+  static const Function eglChooseConfig = Message_Function_eglChooseConfig;
+  static const Function eglGetConfigAttrib = Message_Function_eglGetConfigAttrib;
+  static const Function eglCreateWindowSurface = Message_Function_eglCreateWindowSurface;
+  static const Function eglCreatePixmapSurface = Message_Function_eglCreatePixmapSurface;
+  static const Function eglCreatePbufferSurface = Message_Function_eglCreatePbufferSurface;
+  static const Function eglDestroySurface = Message_Function_eglDestroySurface;
+  static const Function eglQuerySurface = Message_Function_eglQuerySurface;
+  static const Function eglCreateContext = Message_Function_eglCreateContext;
+  static const Function eglDestroyContext = Message_Function_eglDestroyContext;
+  static const Function eglMakeCurrent = Message_Function_eglMakeCurrent;
+  static const Function eglGetCurrentContext = Message_Function_eglGetCurrentContext;
+  static const Function eglGetCurrentSurface = Message_Function_eglGetCurrentSurface;
+  static const Function eglGetCurrentDisplay = Message_Function_eglGetCurrentDisplay;
+  static const Function eglQueryContext = Message_Function_eglQueryContext;
+  static const Function eglWaitGL = Message_Function_eglWaitGL;
+  static const Function eglWaitNative = Message_Function_eglWaitNative;
+  static const Function eglSwapBuffers = Message_Function_eglSwapBuffers;
+  static const Function eglCopyBuffers = Message_Function_eglCopyBuffers;
+  static const Function eglGetError = Message_Function_eglGetError;
+  static const Function eglQueryString = Message_Function_eglQueryString;
+  static const Function eglGetProcAddress = Message_Function_eglGetProcAddress;
+  static const Function eglSurfaceAttrib = Message_Function_eglSurfaceAttrib;
+  static const Function eglBindTexImage = Message_Function_eglBindTexImage;
+  static const Function eglReleaseTexImage = Message_Function_eglReleaseTexImage;
+  static const Function eglSwapInterval = Message_Function_eglSwapInterval;
+  static const Function eglBindAPI = Message_Function_eglBindAPI;
+  static const Function eglQueryAPI = Message_Function_eglQueryAPI;
+  static const Function eglWaitClient = Message_Function_eglWaitClient;
+  static const Function eglReleaseThread = Message_Function_eglReleaseThread;
+  static const Function eglCreatePbufferFromClientBuffer = Message_Function_eglCreatePbufferFromClientBuffer;
+  static const Function eglLockSurfaceKHR = Message_Function_eglLockSurfaceKHR;
+  static const Function eglUnlockSurfaceKHR = Message_Function_eglUnlockSurfaceKHR;
+  static const Function eglCreateImageKHR = Message_Function_eglCreateImageKHR;
+  static const Function eglDestroyImageKHR = Message_Function_eglDestroyImageKHR;
+  static const Function eglCreateSyncKHR = Message_Function_eglCreateSyncKHR;
+  static const Function eglDestroySyncKHR = Message_Function_eglDestroySyncKHR;
+  static const Function eglClientWaitSyncKHR = Message_Function_eglClientWaitSyncKHR;
+  static const Function eglGetSyncAttribKHR = Message_Function_eglGetSyncAttribKHR;
+  static const Function eglSetSwapRectangleANDROID = Message_Function_eglSetSwapRectangleANDROID;
+  static const Function eglGetRenderBufferANDROID = Message_Function_eglGetRenderBufferANDROID;
+  static const Function ACK = Message_Function_ACK;
+  static const Function NEG = Message_Function_NEG;
+  static const Function CONTINUE = Message_Function_CONTINUE;
+  static const Function SKIP = Message_Function_SKIP;
+  static const Function SETPROP = Message_Function_SETPROP;
+  static inline bool Function_IsValid(int value) {
+    return Message_Function_IsValid(value);
+  }
+  static const Function Function_MIN =
+    Message_Function_Function_MIN;
+  static const Function Function_MAX =
+    Message_Function_Function_MAX;
+  static const int Function_ARRAYSIZE =
+    Message_Function_Function_ARRAYSIZE;
+  
+  typedef Message_Type Type;
+  static const Type BeforeCall = Message_Type_BeforeCall;
+  static const Type AfterCall = Message_Type_AfterCall;
+  static const Type Response = Message_Type_Response;
+  static inline bool Type_IsValid(int value) {
+    return Message_Type_IsValid(value);
+  }
+  static const Type Type_MIN =
+    Message_Type_Type_MIN;
+  static const Type Type_MAX =
+    Message_Type_Type_MAX;
+  static const int Type_ARRAYSIZE =
+    Message_Type_Type_ARRAYSIZE;
+  
+  typedef Message_Prop Prop;
+  static const Prop Capture = Message_Prop_Capture;
+  static const Prop TimeMode = Message_Prop_TimeMode;
+  static inline bool Prop_IsValid(int value) {
+    return Message_Prop_IsValid(value);
+  }
+  static const Prop Prop_MIN =
+    Message_Prop_Prop_MIN;
+  static const Prop Prop_MAX =
+    Message_Prop_Prop_MAX;
+  static const int Prop_ARRAYSIZE =
+    Message_Prop_Prop_ARRAYSIZE;
+  
+  // accessors -------------------------------------------------------
+  
+  // required int32 context_id = 1;
+  inline bool has_context_id() const;
+  inline void clear_context_id();
+  static const int kContextIdFieldNumber = 1;
+  inline ::google::protobuf::int32 context_id() const;
+  inline void set_context_id(::google::protobuf::int32 value);
+  
+  // required .com.android.glesv2debugger.Message.Function function = 2 [default = NEG];
+  inline bool has_function() const;
+  inline void clear_function();
+  static const int kFunctionFieldNumber = 2;
+  inline ::com::android::glesv2debugger::Message_Function function() const;
+  inline void set_function(::com::android::glesv2debugger::Message_Function value);
+  
+  // required .com.android.glesv2debugger.Message.Type type = 3;
+  inline bool has_type() const;
+  inline void clear_type();
+  static const int kTypeFieldNumber = 3;
+  inline ::com::android::glesv2debugger::Message_Type type() const;
+  inline void set_type(::com::android::glesv2debugger::Message_Type value);
+  
+  // required bool expect_response = 4;
+  inline bool has_expect_response() const;
+  inline void clear_expect_response();
+  static const int kExpectResponseFieldNumber = 4;
+  inline bool expect_response() const;
+  inline void set_expect_response(bool value);
+  
+  // optional int32 ret = 5;
+  inline bool has_ret() const;
+  inline void clear_ret();
+  static const int kRetFieldNumber = 5;
+  inline ::google::protobuf::int32 ret() const;
+  inline void set_ret(::google::protobuf::int32 value);
+  
+  // optional int32 arg0 = 6;
+  inline bool has_arg0() const;
+  inline void clear_arg0();
+  static const int kArg0FieldNumber = 6;
+  inline ::google::protobuf::int32 arg0() const;
+  inline void set_arg0(::google::protobuf::int32 value);
+  
+  // optional int32 arg1 = 7;
+  inline bool has_arg1() const;
+  inline void clear_arg1();
+  static const int kArg1FieldNumber = 7;
+  inline ::google::protobuf::int32 arg1() const;
+  inline void set_arg1(::google::protobuf::int32 value);
+  
+  // optional int32 arg2 = 8;
+  inline bool has_arg2() const;
+  inline void clear_arg2();
+  static const int kArg2FieldNumber = 8;
+  inline ::google::protobuf::int32 arg2() const;
+  inline void set_arg2(::google::protobuf::int32 value);
+  
+  // optional int32 arg3 = 9;
+  inline bool has_arg3() const;
+  inline void clear_arg3();
+  static const int kArg3FieldNumber = 9;
+  inline ::google::protobuf::int32 arg3() const;
+  inline void set_arg3(::google::protobuf::int32 value);
+  
+  // optional int32 arg4 = 16;
+  inline bool has_arg4() const;
+  inline void clear_arg4();
+  static const int kArg4FieldNumber = 16;
+  inline ::google::protobuf::int32 arg4() const;
+  inline void set_arg4(::google::protobuf::int32 value);
+  
+  // optional int32 arg5 = 17;
+  inline bool has_arg5() const;
+  inline void clear_arg5();
+  static const int kArg5FieldNumber = 17;
+  inline ::google::protobuf::int32 arg5() const;
+  inline void set_arg5(::google::protobuf::int32 value);
+  
+  // optional int32 arg6 = 18;
+  inline bool has_arg6() const;
+  inline void clear_arg6();
+  static const int kArg6FieldNumber = 18;
+  inline ::google::protobuf::int32 arg6() const;
+  inline void set_arg6(::google::protobuf::int32 value);
+  
+  // optional int32 arg7 = 19;
+  inline bool has_arg7() const;
+  inline void clear_arg7();
+  static const int kArg7FieldNumber = 19;
+  inline ::google::protobuf::int32 arg7() const;
+  inline void set_arg7(::google::protobuf::int32 value);
+  
+  // optional int32 arg8 = 20;
+  inline bool has_arg8() const;
+  inline void clear_arg8();
+  static const int kArg8FieldNumber = 20;
+  inline ::google::protobuf::int32 arg8() const;
+  inline void set_arg8(::google::protobuf::int32 value);
+  
+  // optional bytes data = 10;
+  inline bool has_data() const;
+  inline void clear_data();
+  static const int kDataFieldNumber = 10;
+  inline const ::std::string& data() const;
+  inline void set_data(const ::std::string& value);
+  inline void set_data(const char* value);
+  inline void set_data(const void* value, size_t size);
+  inline ::std::string* mutable_data();
+  
+  // optional float time = 11;
+  inline bool has_time() const;
+  inline void clear_time();
+  static const int kTimeFieldNumber = 11;
+  inline float time() const;
+  inline void set_time(float value);
+  
+  // optional .com.android.glesv2debugger.Message.Prop prop = 21;
+  inline bool has_prop() const;
+  inline void clear_prop();
+  static const int kPropFieldNumber = 21;
+  inline ::com::android::glesv2debugger::Message_Prop prop() const;
+  inline void set_prop(::com::android::glesv2debugger::Message_Prop value);
+  
+  // optional float clock = 22;
+  inline bool has_clock() const;
+  inline void clear_clock();
+  static const int kClockFieldNumber = 22;
+  inline float clock() const;
+  inline void set_clock(float value);
+  
+  // @@protoc_insertion_point(class_scope:com.android.glesv2debugger.Message)
+ private:
+  mutable int _cached_size_;
+  
+  ::google::protobuf::int32 context_id_;
+  int function_;
+  int type_;
+  bool expect_response_;
+  ::google::protobuf::int32 ret_;
+  ::google::protobuf::int32 arg0_;
+  ::google::protobuf::int32 arg1_;
+  ::google::protobuf::int32 arg2_;
+  ::google::protobuf::int32 arg3_;
+  ::google::protobuf::int32 arg4_;
+  ::google::protobuf::int32 arg5_;
+  ::google::protobuf::int32 arg6_;
+  ::google::protobuf::int32 arg7_;
+  ::google::protobuf::int32 arg8_;
+  ::std::string* data_;
+  static const ::std::string _default_data_;
+  float time_;
+  int prop_;
+  float clock_;
+  friend void  protobuf_AddDesc_debugger_5fmessage_2eproto();
+  friend void protobuf_AssignDesc_debugger_5fmessage_2eproto();
+  friend void protobuf_ShutdownFile_debugger_5fmessage_2eproto();
+  
+  ::google::protobuf::uint32 _has_bits_[(18 + 31) / 32];
+  
+  // WHY DOES & HAVE LOWER PRECEDENCE THAN != !?
+  inline bool _has_bit(int index) const {
+    return (_has_bits_[index / 32] & (1u << (index % 32))) != 0;
+  }
+  inline void _set_bit(int index) {
+    _has_bits_[index / 32] |= (1u << (index % 32));
+  }
+  inline void _clear_bit(int index) {
+    _has_bits_[index / 32] &= ~(1u << (index % 32));
+  }
+  
+  void InitAsDefaultInstance();
+  static Message* default_instance_;
+};
+// ===================================================================
+
+
+// ===================================================================
+
+// Message
+
+// required int32 context_id = 1;
+inline bool Message::has_context_id() const {
+  return _has_bit(0);
+}
+inline void Message::clear_context_id() {
+  context_id_ = 0;
+  _clear_bit(0);
+}
+inline ::google::protobuf::int32 Message::context_id() const {
+  return context_id_;
+}
+inline void Message::set_context_id(::google::protobuf::int32 value) {
+  _set_bit(0);
+  context_id_ = value;
+}
+
+// required .com.android.glesv2debugger.Message.Function function = 2 [default = NEG];
+inline bool Message::has_function() const {
+  return _has_bit(1);
+}
+inline void Message::clear_function() {
+  function_ = 187;
+  _clear_bit(1);
+}
+inline ::com::android::glesv2debugger::Message_Function Message::function() const {
+  return static_cast< ::com::android::glesv2debugger::Message_Function >(function_);
+}
+inline void Message::set_function(::com::android::glesv2debugger::Message_Function value) {
+  GOOGLE_DCHECK(::com::android::glesv2debugger::Message_Function_IsValid(value));
+  _set_bit(1);
+  function_ = value;
+}
+
+// required .com.android.glesv2debugger.Message.Type type = 3;
+inline bool Message::has_type() const {
+  return _has_bit(2);
+}
+inline void Message::clear_type() {
+  type_ = 0;
+  _clear_bit(2);
+}
+inline ::com::android::glesv2debugger::Message_Type Message::type() const {
+  return static_cast< ::com::android::glesv2debugger::Message_Type >(type_);
+}
+inline void Message::set_type(::com::android::glesv2debugger::Message_Type value) {
+  GOOGLE_DCHECK(::com::android::glesv2debugger::Message_Type_IsValid(value));
+  _set_bit(2);
+  type_ = value;
+}
+
+// required bool expect_response = 4;
+inline bool Message::has_expect_response() const {
+  return _has_bit(3);
+}
+inline void Message::clear_expect_response() {
+  expect_response_ = false;
+  _clear_bit(3);
+}
+inline bool Message::expect_response() const {
+  return expect_response_;
+}
+inline void Message::set_expect_response(bool value) {
+  _set_bit(3);
+  expect_response_ = value;
+}
+
+// optional int32 ret = 5;
+inline bool Message::has_ret() const {
+  return _has_bit(4);
+}
+inline void Message::clear_ret() {
+  ret_ = 0;
+  _clear_bit(4);
+}
+inline ::google::protobuf::int32 Message::ret() const {
+  return ret_;
+}
+inline void Message::set_ret(::google::protobuf::int32 value) {
+  _set_bit(4);
+  ret_ = value;
+}
+
+// optional int32 arg0 = 6;
+inline bool Message::has_arg0() const {
+  return _has_bit(5);
+}
+inline void Message::clear_arg0() {
+  arg0_ = 0;
+  _clear_bit(5);
+}
+inline ::google::protobuf::int32 Message::arg0() const {
+  return arg0_;
+}
+inline void Message::set_arg0(::google::protobuf::int32 value) {
+  _set_bit(5);
+  arg0_ = value;
+}
+
+// optional int32 arg1 = 7;
+inline bool Message::has_arg1() const {
+  return _has_bit(6);
+}
+inline void Message::clear_arg1() {
+  arg1_ = 0;
+  _clear_bit(6);
+}
+inline ::google::protobuf::int32 Message::arg1() const {
+  return arg1_;
+}
+inline void Message::set_arg1(::google::protobuf::int32 value) {
+  _set_bit(6);
+  arg1_ = value;
+}
+
+// optional int32 arg2 = 8;
+inline bool Message::has_arg2() const {
+  return _has_bit(7);
+}
+inline void Message::clear_arg2() {
+  arg2_ = 0;
+  _clear_bit(7);
+}
+inline ::google::protobuf::int32 Message::arg2() const {
+  return arg2_;
+}
+inline void Message::set_arg2(::google::protobuf::int32 value) {
+  _set_bit(7);
+  arg2_ = value;
+}
+
+// optional int32 arg3 = 9;
+inline bool Message::has_arg3() const {
+  return _has_bit(8);
+}
+inline void Message::clear_arg3() {
+  arg3_ = 0;
+  _clear_bit(8);
+}
+inline ::google::protobuf::int32 Message::arg3() const {
+  return arg3_;
+}
+inline void Message::set_arg3(::google::protobuf::int32 value) {
+  _set_bit(8);
+  arg3_ = value;
+}
+
+// optional int32 arg4 = 16;
+inline bool Message::has_arg4() const {
+  return _has_bit(9);
+}
+inline void Message::clear_arg4() {
+  arg4_ = 0;
+  _clear_bit(9);
+}
+inline ::google::protobuf::int32 Message::arg4() const {
+  return arg4_;
+}
+inline void Message::set_arg4(::google::protobuf::int32 value) {
+  _set_bit(9);
+  arg4_ = value;
+}
+
+// optional int32 arg5 = 17;
+inline bool Message::has_arg5() const {
+  return _has_bit(10);
+}
+inline void Message::clear_arg5() {
+  arg5_ = 0;
+  _clear_bit(10);
+}
+inline ::google::protobuf::int32 Message::arg5() const {
+  return arg5_;
+}
+inline void Message::set_arg5(::google::protobuf::int32 value) {
+  _set_bit(10);
+  arg5_ = value;
+}
+
+// optional int32 arg6 = 18;
+inline bool Message::has_arg6() const {
+  return _has_bit(11);
+}
+inline void Message::clear_arg6() {
+  arg6_ = 0;
+  _clear_bit(11);
+}
+inline ::google::protobuf::int32 Message::arg6() const {
+  return arg6_;
+}
+inline void Message::set_arg6(::google::protobuf::int32 value) {
+  _set_bit(11);
+  arg6_ = value;
+}
+
+// optional int32 arg7 = 19;
+inline bool Message::has_arg7() const {
+  return _has_bit(12);
+}
+inline void Message::clear_arg7() {
+  arg7_ = 0;
+  _clear_bit(12);
+}
+inline ::google::protobuf::int32 Message::arg7() const {
+  return arg7_;
+}
+inline void Message::set_arg7(::google::protobuf::int32 value) {
+  _set_bit(12);
+  arg7_ = value;
+}
+
+// optional int32 arg8 = 20;
+inline bool Message::has_arg8() const {
+  return _has_bit(13);
+}
+inline void Message::clear_arg8() {
+  arg8_ = 0;
+  _clear_bit(13);
+}
+inline ::google::protobuf::int32 Message::arg8() const {
+  return arg8_;
+}
+inline void Message::set_arg8(::google::protobuf::int32 value) {
+  _set_bit(13);
+  arg8_ = value;
+}
+
+// optional bytes data = 10;
+inline bool Message::has_data() const {
+  return _has_bit(14);
+}
+inline void Message::clear_data() {
+  if (data_ != &_default_data_) {
+    data_->clear();
+  }
+  _clear_bit(14);
+}
+inline const ::std::string& Message::data() const {
+  return *data_;
+}
+inline void Message::set_data(const ::std::string& value) {
+  _set_bit(14);
+  if (data_ == &_default_data_) {
+    data_ = new ::std::string;
+  }
+  data_->assign(value);
+}
+inline void Message::set_data(const char* value) {
+  _set_bit(14);
+  if (data_ == &_default_data_) {
+    data_ = new ::std::string;
+  }
+  data_->assign(value);
+}
+inline void Message::set_data(const void* value, size_t size) {
+  _set_bit(14);
+  if (data_ == &_default_data_) {
+    data_ = new ::std::string;
+  }
+  data_->assign(reinterpret_cast<const char*>(value), size);
+}
+inline ::std::string* Message::mutable_data() {
+  _set_bit(14);
+  if (data_ == &_default_data_) {
+    data_ = new ::std::string;
+  }
+  return data_;
+}
+
+// optional float time = 11;
+inline bool Message::has_time() const {
+  return _has_bit(15);
+}
+inline void Message::clear_time() {
+  time_ = 0;
+  _clear_bit(15);
+}
+inline float Message::time() const {
+  return time_;
+}
+inline void Message::set_time(float value) {
+  _set_bit(15);
+  time_ = value;
+}
+
+// optional .com.android.glesv2debugger.Message.Prop prop = 21;
+inline bool Message::has_prop() const {
+  return _has_bit(16);
+}
+inline void Message::clear_prop() {
+  prop_ = 0;
+  _clear_bit(16);
+}
+inline ::com::android::glesv2debugger::Message_Prop Message::prop() const {
+  return static_cast< ::com::android::glesv2debugger::Message_Prop >(prop_);
+}
+inline void Message::set_prop(::com::android::glesv2debugger::Message_Prop value) {
+  GOOGLE_DCHECK(::com::android::glesv2debugger::Message_Prop_IsValid(value));
+  _set_bit(16);
+  prop_ = value;
+}
+
+// optional float clock = 22;
+inline bool Message::has_clock() const {
+  return _has_bit(17);
+}
+inline void Message::clear_clock() {
+  clock_ = 0;
+  _clear_bit(17);
+}
+inline float Message::clock() const {
+  return clock_;
+}
+inline void Message::set_clock(float value) {
+  _set_bit(17);
+  clock_ = value;
+}
+
+
+// @@protoc_insertion_point(namespace_scope)
+
+}  // namespace glesv2debugger
+}  // namespace android
+}  // namespace com
+
+// @@protoc_insertion_point(global_scope)
+
+#endif  // PROTOBUF_debugger_5fmessage_2eproto__INCLUDED
diff --git a/opengl/libs/GLES2_dbg/src/egl.cpp b/opengl/libs/GLES2_dbg/src/egl.cpp
new file mode 100644
index 0000000..27c7f7e
--- /dev/null
+++ b/opengl/libs/GLES2_dbg/src/egl.cpp
@@ -0,0 +1,41 @@
+/*
+ ** Copyright 2011, The Android Open Source Project
+ **
+ ** Licensed under the Apache License, Version 2.0 (the "License");
+ ** you may not use this file except in compliance with the License.
+ ** You may obtain a copy of the License at
+ **
+ **     http://www.apache.org/licenses/LICENSE-2.0
+ **
+ ** Unless required by applicable law or agreed to in writing, software
+ ** distributed under the License is distributed on an "AS IS" BASIS,
+ ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ** See the License for the specific language governing permissions and
+ ** limitations under the License.
+ */
+
+#include "header.h"
+
+EGLBoolean Debug_eglSwapBuffers(EGLDisplay dpy, EGLSurface draw)
+{
+    glesv2debugger::Message msg;
+    const bool expectResponse = false;
+    struct : public FunctionCall {
+        EGLDisplay dpy;
+        EGLSurface draw;
+        
+        const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
+            msg.set_time(-1);
+            return reinterpret_cast<const int *>(true);
+        }
+    } caller;
+    caller.dpy = dpy;
+    caller.draw = draw;
+    
+    msg.set_arg0(reinterpret_cast<int>(dpy));
+    msg.set_arg1(reinterpret_cast<int>(draw));
+    
+    int * ret = MessageLoop(caller, msg, expectResponse,
+                            glesv2debugger::Message_Function_eglSwapBuffers);
+    return static_cast<EGLBoolean>(reinterpret_cast<int>(ret));
+}
diff --git a/opengl/libs/GLES2_dbg/src/header.h b/opengl/libs/GLES2_dbg/src/header.h
new file mode 100644
index 0000000..b79cc0f
--- /dev/null
+++ b/opengl/libs/GLES2_dbg/src/header.h
@@ -0,0 +1,131 @@
+/*
+ ** Copyright 2011, The Android Open Source Project
+ **
+ ** Licensed under the Apache License, Version 2.0 (the "License");
+ ** you may not use this file except in compliance with the License.
+ ** You may obtain a copy of the License at
+ **
+ **     http://www.apache.org/licenses/LICENSE-2.0
+ **
+ ** Unless required by applicable law or agreed to in writing, software
+ ** distributed under the License is distributed on an "AS IS" BASIS,
+ ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ** See the License for the specific language governing permissions and
+ ** limitations under the License.
+ */
+
+#include <stdlib.h>
+#include <ctype.h>
+#include <string.h>
+#include <errno.h>
+
+#include <GLES2/gl2.h>
+#include <GLES2/gl2ext.h>
+
+#include <cutils/log.h>
+#include <utils/Timers.h>
+#include <../../../libcore/include/StaticAssert.h>
+
+#define EGL_TRACE 1
+#include "hooks.h"
+
+#include "glesv2dbg.h"
+
+#define GL_ENTRY(_r, _api, ...) _r Debug_##_api ( __VA_ARGS__ );
+#include "glesv2dbg_functions.h"
+
+#include "debugger_message.pb.h"
+
+using namespace android;
+using namespace com::android;
+
+#define API_ENTRY(_api) Debug_##_api
+
+#ifndef __location__
+#define __HIERALLOC_STRING_0__(s)   #s
+#define __HIERALLOC_STRING_1__(s)   __HIERALLOC_STRING_0__(s)
+#define __HIERALLOC_STRING_2__      __HIERALLOC_STRING_1__(__LINE__)
+#define __location__                __FILE__ ":" __HIERALLOC_STRING_2__
+#endif
+
+#undef assert
+#define assert(expr) if (!(expr)) { LOGD("\n*\n*\n* assert: %s at %s \n*\n*", #expr, __location__); int * x = 0; *x = 5; }
+//#undef LOGD
+//#define LOGD(...)
+
+namespace android
+{
+
+struct DbgContext {
+    const unsigned version; // 0 is GLES1, 1 is GLES2
+    const gl_hooks_t * const hooks;
+    const unsigned MAX_VERTEX_ATTRIBS;
+    
+    struct VertexAttrib {
+        GLenum type; // element data type
+        unsigned size; // number of data per element
+        unsigned stride; // calculated number of bytes between elements
+        const void * ptr;
+        unsigned elemSize; // calculated number of bytes per element
+        GLuint buffer; // buffer name
+        GLboolean normalized : 1;
+        GLboolean enabled : 1;
+        VertexAttrib() : type(0), size(0), stride(0), ptr(NULL), elemSize(0),
+                buffer(0), normalized(0), enabled(0) {}
+    } * vertexAttribs;
+    bool hasNonVBOAttribs; // whether any enabled vertexAttrib is user pointer
+
+    struct VBO {
+        const GLuint name;
+        const GLenum target;
+        VBO * next;
+        void * data; // malloc/free
+        unsigned size; // in bytes
+        VBO(const GLuint name, const GLenum target, VBO * head) : name(name),
+                target(target), next(head), data(NULL), size(0) {}
+    } * indexBuffers; // linked list of all index buffers
+    VBO * indexBuffer; // currently bound index buffer
+
+    GLuint program;
+    unsigned maxAttrib; // number of slots used by program
+
+    DbgContext(const unsigned version, const gl_hooks_t * const hooks, const unsigned MAX_VERTEX_ATTRIBS);
+    ~DbgContext();
+
+    void Fetch(const unsigned index, std::string * const data) const;
+
+    void glUseProgram(GLuint program);
+    void glEnableVertexAttribArray(GLuint index);
+    void glDisableVertexAttribArray(GLuint index);
+    void glVertexAttribPointer(GLuint indx, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const GLvoid* ptr);
+    void glBindBuffer(GLenum target, GLuint buffer);
+    void glBufferData(GLenum target, GLsizeiptr size, const GLvoid* data, GLenum usage);
+    void glBufferSubData(GLenum target, GLintptr offset, GLsizeiptr size, const GLvoid* data);
+    void glDeleteBuffers(GLsizei n, const GLuint *buffers);
+};
+
+
+DbgContext * getDbgContextThreadSpecific();
+#define DBGCONTEXT(ctx) DbgContext * const ctx = getDbgContextThreadSpecific();
+
+struct FunctionCall {
+    virtual const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) = 0;
+    virtual ~FunctionCall() {}
+};
+
+// move these into DbgContext as static
+extern bool capture;
+extern int timeMode; // SYSTEM_TIME_
+
+extern int clientSock, serverSock;
+
+unsigned GetBytesPerPixel(const GLenum format, const GLenum type);
+
+// every Debug_gl* function calls this to send message to client and possibly receive commands
+int * MessageLoop(FunctionCall & functionCall, glesv2debugger::Message & msg,
+                  const bool expectResponse, const glesv2debugger::Message_Function function);
+
+void Receive(glesv2debugger::Message & cmd);
+float Send(const glesv2debugger::Message & msg, glesv2debugger::Message & cmd);
+void SetProp(const glesv2debugger::Message & cmd);
+}; // namespace android {
diff --git a/opengl/libs/GLES2_dbg/src/server.cpp b/opengl/libs/GLES2_dbg/src/server.cpp
new file mode 100644
index 0000000..03c3dae
--- /dev/null
+++ b/opengl/libs/GLES2_dbg/src/server.cpp
@@ -0,0 +1,250 @@
+/*
+ ** Copyright 2011, The Android Open Source Project
+ **
+ ** Licensed under the Apache License, Version 2.0 (the "License");
+ ** you may not use this file except in compliance with the License.
+ ** You may obtain a copy of the License at
+ **
+ **     http://www.apache.org/licenses/LICENSE-2.0
+ **
+ ** Unless required by applicable law or agreed to in writing, software
+ ** distributed under the License is distributed on an "AS IS" BASIS,
+ ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ** See the License for the specific language governing permissions and
+ ** limitations under the License.
+ */
+
+#include <sys/ioctl.h>
+#include <unistd.h>
+#include <sys/socket.h>
+#include <fcntl.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <pthread.h>
+
+#include "header.h"
+
+namespace android
+{
+
+int serverSock = -1, clientSock = -1;
+
+int timeMode = SYSTEM_TIME_THREAD;
+
+static void Die(const char * msg)
+{
+    LOGD("\n*\n*\n* GLESv2_dbg: Die: %s \n*\n*", msg);
+    StopDebugServer();
+    exit(1);
+}
+
+void StartDebugServer(unsigned short port)
+{
+    LOGD("GLESv2_dbg: StartDebugServer");
+    if (serverSock >= 0)
+        return;
+
+    LOGD("GLESv2_dbg: StartDebugServer create socket");
+    struct sockaddr_in server = {}, client = {};
+
+    /* Create the TCP socket */
+    if ((serverSock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0) {
+        Die("Failed to create socket");
+    }
+    /* Construct the server sockaddr_in structure */
+    server.sin_family = AF_INET;                  /* Internet/IP */
+    server.sin_addr.s_addr = htonl(INADDR_LOOPBACK);   /* Incoming addr */
+    server.sin_port = htons(port);       /* server port */
+
+    /* Bind the server socket */
+    socklen_t sizeofSockaddr_in = sizeof(sockaddr_in);
+    if (bind(serverSock, (struct sockaddr *) &server,
+             sizeof(server)) < 0) {
+        Die("Failed to bind the server socket");
+    }
+    /* Listen on the server socket */
+    if (listen(serverSock, 1) < 0) {
+        Die("Failed to listen on server socket");
+    }
+
+    LOGD("server started on %d \n", server.sin_port);
+
+
+    /* Wait for client connection */
+    if ((clientSock =
+                accept(serverSock, (struct sockaddr *) &client,
+                       &sizeofSockaddr_in)) < 0) {
+        Die("Failed to accept client connection");
+    }
+
+    LOGD("Client connected: %s\n", inet_ntoa(client.sin_addr));
+//    fcntl(clientSock, F_SETFL, O_NONBLOCK);
+}
+
+void StopDebugServer()
+{
+    LOGD("GLESv2_dbg: StopDebugServer");
+    if (clientSock > 0) {
+        close(clientSock);
+        clientSock = -1;
+    }
+    if (serverSock > 0) {
+        close(serverSock);
+        serverSock = -1;
+    }
+
+}
+
+void Receive(glesv2debugger::Message & cmd)
+{
+    unsigned len = 0;
+
+    int received = recv(clientSock, &len, 4, MSG_WAITALL);
+    if (received < 0)
+        Die("Failed to receive response length");
+    else if (4 != received) {
+        LOGD("received %dB: %.8X", received, len);
+        Die("Received length mismatch, expected 4");
+    }
+    len = ntohl(len);
+    static void * buffer = NULL;
+    static unsigned bufferSize = 0;
+    if (bufferSize < len) {
+        buffer = realloc(buffer, len);
+        assert(buffer);
+        bufferSize = len;
+    }
+    received = recv(clientSock, buffer, len, MSG_WAITALL);
+    if (received < 0)
+        Die("Failed to receive response");
+    else if (len != received)
+        Die("Received length mismatch");
+    cmd.Clear();
+    cmd.ParseFromArray(buffer, len);
+}
+
+bool TryReceive(glesv2debugger::Message & cmd)
+{
+    fd_set readSet;
+    FD_ZERO(&readSet);
+    FD_SET(clientSock, &readSet);
+    timeval timeout;
+    timeout.tv_sec = timeout.tv_usec = 0;
+
+    int rc = select(clientSock + 1, &readSet, NULL, NULL, &timeout);
+    if (rc < 0)
+        Die("failed to select clientSock");
+
+    bool received = false;
+    if (FD_ISSET(clientSock, &readSet)) {
+        LOGD("TryReceive: avaiable for read");
+        Receive(cmd);
+        return true;
+    }
+    return false;
+}
+
+float Send(const glesv2debugger::Message & msg, glesv2debugger::Message & cmd)
+{
+    static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
+    pthread_mutex_lock(&mutex); // TODO: this is just temporary
+
+    if (msg.function() != glesv2debugger::Message_Function_ACK)
+        assert(msg.has_context_id() && msg.context_id() != 0);
+    static std::string str;
+    msg.SerializeToString(&str);
+    unsigned len = str.length();
+    len = htonl(len);
+    int sent = -1;
+    sent = send(clientSock, (const char *)&len, sizeof(len), 0);
+    if (sent != sizeof(len)) {
+        LOGD("actual sent=%d expected=%d clientSock=%d", sent, sizeof(len), clientSock);
+        Die("Failed to send message length");
+    }
+    nsecs_t c0 = systemTime(timeMode);
+    sent = send(clientSock, str.c_str(), str.length(), 0);
+    float t = (float)ns2ms(systemTime(timeMode) - c0);
+    if (sent != str.length()) {
+        LOGD("actual sent=%d expected=%d clientSock=%d", sent, str.length(), clientSock);
+        Die("Failed to send message");
+    }
+
+    // try to receive commands even though not expecting response,
+    // since client can send SETPROP commands anytime
+    if (!msg.expect_response()) {
+        if (TryReceive(cmd)) {
+            LOGD("Send: TryReceived");
+            if (glesv2debugger::Message_Function_SETPROP == cmd.function())
+                LOGD("Send: received SETPROP");
+            else
+                LOGD("Send: received something else");
+        }
+    } else
+        Receive(cmd);
+
+    //LOGD("Message sent tid=%lu len=%d", pthread_self(), str.length());
+    pthread_mutex_unlock(&mutex);
+    return t;
+}
+
+void SetProp(const glesv2debugger::Message & cmd)
+{
+    switch (cmd.prop()) {
+    case glesv2debugger::Message_Prop_Capture:
+        LOGD("SetProp Message_Prop_Capture %d", cmd.arg0());
+        capture = cmd.arg0();
+        break;
+    case glesv2debugger::Message_Prop_TimeMode:
+        LOGD("SetProp Message_Prop_TimeMode %d", cmd.arg0());
+        timeMode = cmd.arg0();
+        break;
+    default:
+        assert(0);
+    }
+}
+
+int * MessageLoop(FunctionCall & functionCall, glesv2debugger::Message & msg,
+                  const bool expectResponse, const glesv2debugger::Message_Function function)
+{
+    DbgContext * const dbg = getDbgContextThreadSpecific();
+    const int * ret = 0;
+    glesv2debugger::Message cmd;
+    msg.set_context_id(reinterpret_cast<int>(dbg));
+    msg.set_type(glesv2debugger::Message_Type_BeforeCall);
+    msg.set_expect_response(expectResponse);
+    msg.set_function(function);
+    if (!expectResponse)
+        cmd.set_function(glesv2debugger::Message_Function_CONTINUE);
+    Send(msg, cmd);
+    while (true) {
+        msg.Clear();
+        nsecs_t c0 = systemTime(timeMode);
+        switch (cmd.function()) {
+        case glesv2debugger::Message_Function_CONTINUE:
+            ret = functionCall(&dbg->hooks->gl, msg);
+            while (GLenum error = dbg->hooks->gl.glGetError())
+                LOGD("Function=%u glGetError() = 0x%.4X", function, error);
+            if (!msg.has_time()) // some has output data copy, so time inside call
+                msg.set_time((systemTime(timeMode) - c0) * 1e-6f);
+            msg.set_context_id(reinterpret_cast<int>(dbg));
+            msg.set_function(function);
+            msg.set_type(glesv2debugger::Message_Type_AfterCall);
+            msg.set_expect_response(expectResponse);
+            if (!expectResponse)
+                cmd.set_function(glesv2debugger::Message_Function_SKIP);
+            Send(msg, cmd);
+            break;
+        case glesv2debugger::Message_Function_SKIP:
+            return const_cast<int *>(ret);
+        case glesv2debugger::Message_Function_SETPROP:
+            SetProp(cmd);
+            Receive(cmd);
+            break;
+        default:
+            assert(0); //GenerateCall(msg, cmd);
+            break;
+        }
+    }
+    return 0;
+}
+}; // namespace android {
diff --git a/opengl/libs/GLES2_dbg/src/texture.cpp b/opengl/libs/GLES2_dbg/src/texture.cpp
new file mode 100644
index 0000000..3aa0aab
--- /dev/null
+++ b/opengl/libs/GLES2_dbg/src/texture.cpp
@@ -0,0 +1,265 @@
+/*
+ ** Copyright 2011, The Android Open Source Project
+ **
+ ** Licensed under the Apache License, Version 2.0 (the "License");
+ ** you may not use this file except in compliance with the License.
+ ** You may obtain a copy of the License at
+ **
+ **     http://www.apache.org/licenses/LICENSE-2.0
+ **
+ ** Unless required by applicable law or agreed to in writing, software
+ ** distributed under the License is distributed on an "AS IS" BASIS,
+ ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ** See the License for the specific language governing permissions and
+ ** limitations under the License.
+ */
+
+#include "header.h"
+
+namespace android
+{
+unsigned GetBytesPerPixel(const GLenum format, const GLenum type)
+{
+    switch (type) {
+    case GL_UNSIGNED_SHORT_5_6_5:
+        return 2;
+    case GL_UNSIGNED_SHORT_4_4_4_4:
+        return 2;
+    case GL_UNSIGNED_SHORT_5_5_5_1:
+        return 2;
+    case GL_UNSIGNED_BYTE:
+        break;
+    default:
+        assert(0);
+    }
+
+    switch (format) {
+    case GL_ALPHA:
+        return 1;
+    case GL_LUMINANCE:
+        return 1;
+        break;
+    case GL_LUMINANCE_ALPHA:
+        return 2;
+    case GL_RGB:
+        return 3;
+    case GL_RGBA:
+        return 4;
+    default:
+        assert(0);
+        return 0;
+    }
+}
+
+#define USE_RLE 0
+#if USE_RLE
+export template<typename T>
+void * RLEEncode(const void * pixels, unsigned count, unsigned * encodedSize)
+{
+    // first is a byte indicating data size [1,2,4] bytes
+    // then an unsigned indicating decompressed size
+    // then a byte of header: MSB == 1 indicates run, else literal
+    // LSB7 is run or literal length (actual length - 1)
+
+    const T * data = (T *)pixels;
+    unsigned bufferSize = sizeof(T) * count / 2 + 8;
+    unsigned char * buffer = (unsigned char *)malloc(bufferSize);
+    buffer[0] = sizeof(T);
+    unsigned bufferWritten = 1; // number of bytes written
+    *(unsigned *)(buffer + bufferWritten) = count;
+    bufferWritten += sizeof(count);
+    while (count) {
+        unsigned char run = 1;
+        bool repeat = true;
+        for (run = 1; run < count; run++)
+            if (data[0] != data[run]) {
+                repeat = false;
+                break;
+            } else if (run > 126)
+                break;
+        if (!repeat) {
+            // find literal length
+            for (run = 1; run < count; run++)
+                if (data[run - 1] == data[run])
+                    break;
+                else if (run > 126)
+                    break;
+            unsigned bytesToWrite = 1 + sizeof(T) * run;
+            if (bufferWritten + bytesToWrite > bufferSize) {
+                bufferSize += sizeof(T) * run + 256;
+                buffer = (unsigned char *)realloc(buffer, bufferSize);
+            }
+            buffer[bufferWritten++] = run - 1;
+            for (unsigned i = 0; i < run; i++) {
+                *(T *)(buffer + bufferWritten) = *data;
+                bufferWritten += sizeof(T);
+                data++;
+            }
+            count -= run;
+        } else {
+            unsigned bytesToWrite = 1 + sizeof(T);
+            if (bufferWritten + bytesToWrite > bufferSize) {
+                bufferSize += 256;
+                buffer = (unsigned char *)realloc(buffer, bufferSize);
+            }
+            buffer[bufferWritten++] = (run - 1) | 0x80;
+            *(T *)(buffer + bufferWritten) = data[0];
+            bufferWritten += sizeof(T);
+            data += run;
+            count -= run;
+        }
+    }
+    if (encodedSize)
+        *encodedSize = bufferWritten;
+    return buffer;
+}
+
+void * RLEEncode(const void * pixels, const unsigned bytesPerPixel, const unsigned count, unsigned * encodedSize)
+{
+    switch (bytesPerPixel) {
+    case 4:
+        return RLEEncode<int>(pixels, count, encodedSize);
+    case 2:
+        return RLEEncode<short>(pixels, count, encodedSize);
+    case 1:
+        return RLEEncode<char>(pixels, count, encodedSize);
+    default:
+        assert(0);
+        return NULL;
+    }
+}
+#endif
+}; // namespace android
+
+void Debug_glTexImage2D(GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const GLvoid* pixels)
+{
+    glesv2debugger::Message msg;
+    const bool expectResponse = false;
+    struct : public FunctionCall {
+        GLenum target;
+        GLint level;
+        GLint internalformat;
+        GLsizei width;
+        GLsizei height;
+        GLint border;
+        GLenum format;
+        GLenum type;
+        const GLvoid* pixels;
+
+        const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
+            nsecs_t c0 = systemTime(timeMode);
+            _c->glTexImage2D(target, level, internalformat, width, height, border, format, type, pixels);
+            msg.set_time((systemTime(timeMode) - c0) * 1e-6f);
+            return 0;
+        }
+    } caller;
+    caller.target = target;
+    caller.level = level;
+    caller.internalformat = internalformat;
+    caller.width = width;
+    caller.height = height;
+    caller.border = border;
+    caller.format = format;
+    caller.type = type;
+    caller.pixels = pixels;
+
+    msg.set_arg0(target);
+    msg.set_arg1(level);
+    msg.set_arg2(internalformat);
+    msg.set_arg3(width);
+    msg.set_arg4(height);
+    msg.set_arg5(border);
+    msg.set_arg6(format);
+    msg.set_arg7(type);
+    msg.set_arg8(reinterpret_cast<int>(pixels));
+
+    if (pixels) {
+        assert(internalformat == format);
+        assert(0 == border);
+
+        unsigned bytesPerPixel = GetBytesPerPixel(format, type);
+        assert(0 < bytesPerPixel);
+
+//        LOGD("GLESv2_dbg: glTexImage2D width=%d height=%d level=%d bytesPerPixel=%d",
+//             width, height, level, bytesPerPixel);
+#if USE_RLE
+        unsigned encodedSize = 0;
+        void * data = RLEEncode(pixels, bytesPerPixel, width * height, &encodedSize);
+        msg.set_data(data, encodedSize);
+        free(data);
+        if (encodedSize > bytesPerPixel * width * height)
+            LOGD("GLESv2_dbg: glTexImage2D sending data encodedSize=%d size=%d", encodedSize, bytesPerPixel * width * height);
+#else
+        msg.set_data(pixels, bytesPerPixel * width * height);
+#endif
+    }
+    
+    int * ret = MessageLoop(caller, msg, expectResponse,
+                            glesv2debugger::Message_Function_glTexImage2D);
+}
+
+void Debug_glTexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid* pixels)
+{
+    glesv2debugger::Message msg;
+    const bool expectResponse = false;
+    struct : public FunctionCall {
+        GLenum target;
+        GLint level;
+        GLint xoffset;
+        GLint yoffset;
+        GLsizei width;
+        GLsizei height;
+        GLenum format;
+        GLenum type;
+        const GLvoid* pixels;
+
+        const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
+            nsecs_t c0 = systemTime(timeMode);
+            _c->glTexSubImage2D(target, level, xoffset, yoffset, width, height, format, type, pixels);
+            msg.set_time((systemTime(timeMode) - c0) * 1e-6f);
+            return 0;
+        }
+    } caller;
+    caller.target = target;
+    caller.level = level;
+    caller.xoffset = xoffset;
+    caller.yoffset = yoffset;
+    caller.width = width;
+    caller.height = height;
+    caller.format = format;
+    caller.type = type;
+    caller.pixels = pixels;
+
+    msg.set_arg0(target);
+    msg.set_arg1(level);
+    msg.set_arg2(xoffset);
+    msg.set_arg3(yoffset);
+    msg.set_arg4(width);
+    msg.set_arg5(height);
+    msg.set_arg6(format);
+    msg.set_arg7(type);
+    msg.set_arg8(reinterpret_cast<int>(pixels));
+
+    assert(pixels);
+    if (pixels) {
+        unsigned bytesPerPixel = GetBytesPerPixel(format, type);
+        assert(0 < bytesPerPixel);
+
+//        LOGD("GLESv2_dbg: glTexSubImage2D width=%d height=%d level=%d bytesPerPixel=%d",
+//             width, height, level, bytesPerPixel);
+
+#if USE_RLE
+        unsigned encodedSize = 0;
+        void * data = RLEEncode(pixels, bytesPerPixel, width * height, &encodedSize);
+        msg.set_data(data, encodedSize);
+        free(data);
+        if (encodedSize > bytesPerPixel * width * height)
+            LOGD("GLESv2_dbg: glTexImage2D sending data encodedSize=%d size=%d", encodedSize, bytesPerPixel * width * height);
+#else
+        msg.set_data(pixels, bytesPerPixel * width * height);
+#endif
+    }
+    
+    int * ret = MessageLoop(caller, msg, expectResponse,
+                            glesv2debugger::Message_Function_glTexSubImage2D);
+}
\ No newline at end of file
diff --git a/opengl/libs/GLES2_dbg/src/vertex.cpp b/opengl/libs/GLES2_dbg/src/vertex.cpp
new file mode 100644
index 0000000..a73967f
--- /dev/null
+++ b/opengl/libs/GLES2_dbg/src/vertex.cpp
@@ -0,0 +1,237 @@
+/*
+ ** Copyright 2011, The Android Open Source Project
+ **
+ ** Licensed under the Apache License, Version 2.0 (the "License");
+ ** you may not use this file except in compliance with the License.
+ ** You may obtain a copy of the License at
+ **
+ **     http://www.apache.org/licenses/LICENSE-2.0
+ **
+ ** Unless required by applicable law or agreed to in writing, software
+ ** distributed under the License is distributed on an "AS IS" BASIS,
+ ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ** See the License for the specific language governing permissions and
+ ** limitations under the License.
+ */
+
+#include "header.h"
+
+namespace android
+{
+bool capture; // capture after each glDraw*
+
+void * RLEEncode(const void * pixels, const unsigned bytesPerPixel, const unsigned count, unsigned * encodedSize);
+}
+
+void Debug_glReadPixels(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLvoid* pixels)
+{
+    DbgContext * const dbg = getDbgContextThreadSpecific();
+    glesv2debugger::Message msg, cmd;
+    msg.set_context_id(reinterpret_cast<int>(dbg));
+    msg.set_type(glesv2debugger::Message_Type_BeforeCall);
+    const bool expectResponse = false;
+    msg.set_expect_response(expectResponse);
+    msg.set_function(glesv2debugger::Message_Function_glReadPixels);
+    msg.set_arg0(x);
+    msg.set_arg1(y);
+    msg.set_arg2(width);
+    msg.set_arg3(height);
+    msg.set_arg4(format);
+    msg.set_arg5(type);
+    msg.set_arg6(reinterpret_cast<int>(pixels));
+    //void * data = NULL;
+    //unsigned encodedSize = 0;
+    if (!expectResponse)
+        cmd.set_function(glesv2debugger::Message_Function_CONTINUE);
+    Send(msg, cmd);
+    float t = 0;
+    while (true) {
+        msg.Clear();
+        nsecs_t c0 = systemTime(timeMode);
+        switch (cmd.function()) {
+        case glesv2debugger::Message_Function_CONTINUE:
+            dbg->hooks->gl.glReadPixels(x, y, width, height, format, type, pixels);
+            msg.set_time((systemTime(timeMode) - c0) * 1e-6f);
+            msg.set_context_id(reinterpret_cast<int>(dbg));
+            msg.set_function(glesv2debugger::Message_Function_glReadPixels);
+            msg.set_type(glesv2debugger::Message_Type_AfterCall);
+            msg.set_expect_response(expectResponse);
+            //data = RLEEncode(pixels, GetBytesPerPixel(format, type), width * height, &encodedSize);
+            msg.set_data(pixels, width * height * GetBytesPerPixel(format, type));
+            //msg.set_data(data, encodedSize);
+            //free(data);
+            c0 = systemTime(timeMode);
+            if (!expectResponse)
+                cmd.set_function(glesv2debugger::Message_Function_SKIP);
+            t = Send(msg, cmd);
+            msg.set_time((systemTime(timeMode) - c0) * 1e-6f);
+            msg.set_clock(t);
+            // time is total send time in seconds, clock is msg serialization time in seconds
+            msg.clear_data();
+            msg.set_expect_response(false);
+            msg.set_type(glesv2debugger::Message_Type_AfterCall);
+            //Send(msg, cmd);
+            break;
+        case glesv2debugger::Message_Function_SKIP:
+            return;
+        case glesv2debugger::Message_Function_SETPROP:
+            SetProp(cmd);
+            Receive(cmd);
+            break;
+        default:
+            assert(0); //GenerateCall(msg, cmd);
+            break;
+        }
+    }
+}
+
+void Debug_glDrawArrays(GLenum mode, GLint first, GLsizei count)
+{
+    DbgContext * const dbg = getDbgContextThreadSpecific();
+    glesv2debugger::Message msg, cmd;
+    msg.set_context_id(reinterpret_cast<int>(dbg));
+    msg.set_type(glesv2debugger::Message_Type_BeforeCall);
+    const bool expectResponse = false;
+    msg.set_expect_response(expectResponse);
+    msg.set_function(glesv2debugger::Message_Function_glDrawArrays);
+    msg.set_arg0(mode);
+    msg.set_arg1(first);
+    msg.set_arg2(count);
+
+    msg.set_arg7(dbg->maxAttrib); // indicate capturing vertex data
+    if (dbg->hasNonVBOAttribs) {
+        std::string * const data = msg.mutable_data();
+        for (unsigned i = 0; i < count; i++)
+            dbg->Fetch(i + first, data);
+    }
+
+    void * pixels = NULL;
+    GLint readFormat = 0, readType = 0;
+    int viewport[4] = {};
+    if (!expectResponse)
+        cmd.set_function(glesv2debugger::Message_Function_CONTINUE);
+    Send(msg, cmd);
+    while (true) {
+        msg.Clear();
+        nsecs_t c0 = systemTime(timeMode);
+        switch (cmd.function()) {
+        case glesv2debugger::Message_Function_CONTINUE:
+            dbg->hooks->gl.glDrawArrays(mode, first, count);
+            msg.set_time((systemTime(timeMode) - c0) * 1e-6f);
+            msg.set_context_id(reinterpret_cast<int>(dbg));
+            msg.set_function(glesv2debugger::Message_Function_glDrawArrays);
+            msg.set_type(glesv2debugger::Message_Type_AfterCall);
+            msg.set_expect_response(expectResponse);
+            if (!expectResponse)
+                cmd.set_function(glesv2debugger::Message_Function_SKIP);
+            Send(msg, cmd);
+            if (capture) {
+                dbg->hooks->gl.glGetIntegerv(GL_VIEWPORT, viewport);
+                dbg->hooks->gl.glGetIntegerv(GL_IMPLEMENTATION_COLOR_READ_FORMAT, &readFormat);
+                dbg->hooks->gl.glGetIntegerv(GL_IMPLEMENTATION_COLOR_READ_TYPE, &readType);
+                LOGD("glDrawArrays CAPTURE: x=%d y=%d width=%d height=%d format=0x%.4X type=0x%.4X",
+                     viewport[0], viewport[1], viewport[2], viewport[3], readFormat, readType);
+                pixels = malloc(viewport[2] * viewport[3] * 4);
+                Debug_glReadPixels(viewport[0], viewport[1], viewport[2], viewport[3],
+                                   readFormat, readType, pixels);
+                free(pixels);
+            }
+            break;
+        case glesv2debugger::Message_Function_SKIP:
+            return;
+        case glesv2debugger::Message_Function_SETPROP:
+            SetProp(cmd);
+            Receive(cmd);
+            break;
+        default:
+            assert(0); //GenerateCall(msg, cmd);
+            break;
+        }
+    }
+}
+
+template<typename T>
+static inline void FetchIndexed(const unsigned count, const T * indices,
+                                std::string * const data, const DbgContext * const ctx)
+{
+    for (unsigned i = 0; i < count; i++) {
+        if (!ctx->indexBuffer)
+            data->append((const char *)(indices + i), sizeof(*indices));
+        if (ctx->hasNonVBOAttribs)
+            ctx->Fetch(indices[i], data);
+    }
+}
+
+void Debug_glDrawElements(GLenum mode, GLsizei count, GLenum type, const GLvoid* indices)
+{
+    DbgContext * const dbg = getDbgContextThreadSpecific();
+    glesv2debugger::Message msg, cmd;
+    msg.set_context_id(reinterpret_cast<int>(dbg));
+    msg.set_type(glesv2debugger::Message_Type_BeforeCall);
+    const bool expectResponse = false;
+    msg.set_expect_response(expectResponse);
+    msg.set_function(glesv2debugger::Message_Function_glDrawElements);
+    msg.set_arg0(mode);
+    msg.set_arg1(count);
+    msg.set_arg2(type);
+    msg.set_arg3(reinterpret_cast<int>(indices));
+
+    msg.set_arg7(dbg->maxAttrib); // indicate capturing vertex data
+    std::string * const data = msg.mutable_data();
+    if (GL_UNSIGNED_BYTE == type) {
+        if (dbg->indexBuffer)
+            FetchIndexed(count, (unsigned char *)dbg->indexBuffer->data + (unsigned long)indices, data, dbg);
+        else
+            FetchIndexed(count, (unsigned char *)indices, data, dbg);
+    } else if (GL_UNSIGNED_SHORT == type) {
+        if (dbg->indexBuffer)
+            FetchIndexed(count, (unsigned short *)((char *)dbg->indexBuffer->data + (unsigned long)indices), data, dbg);
+        else
+            FetchIndexed(count, (unsigned short *)indices, data, dbg);
+    } else
+        assert(0);
+
+    void * pixels = NULL;
+    GLint readFormat = 0, readType = 0;
+    int viewport[4] = {};
+    if (!expectResponse)
+        cmd.set_function(glesv2debugger::Message_Function_CONTINUE);
+    Send(msg, cmd);
+    while (true) {
+        msg.Clear();
+        nsecs_t c0 = systemTime(timeMode);
+        switch (cmd.function()) {
+        case glesv2debugger::Message_Function_CONTINUE:
+            dbg->hooks->gl.glDrawElements(mode, count, type, indices);
+            msg.set_time((systemTime(timeMode) - c0) * 1e-6f);
+            msg.set_context_id(reinterpret_cast<int>(dbg));
+            msg.set_function(glesv2debugger::Message_Function_glDrawElements);
+            msg.set_type(glesv2debugger::Message_Type_AfterCall);
+            msg.set_expect_response(expectResponse);
+            if (!expectResponse)
+                cmd.set_function(glesv2debugger::Message_Function_SKIP);
+            Send(msg, cmd);
+            if (capture) {
+                dbg->hooks->gl.glGetIntegerv(GL_VIEWPORT, viewport);
+                dbg->hooks->gl.glGetIntegerv(GL_IMPLEMENTATION_COLOR_READ_FORMAT, &readFormat);
+                dbg->hooks->gl.glGetIntegerv(GL_IMPLEMENTATION_COLOR_READ_TYPE, &readType);
+                LOGD("glDrawArrays CAPTURE: x=%d y=%d width=%d height=%d format=0x%.4X type=0x%.4X",
+                     viewport[0], viewport[1], viewport[2], viewport[3], readFormat, readType);
+                pixels = malloc(viewport[2] * viewport[3] * 4);
+                Debug_glReadPixels(viewport[0], viewport[1], viewport[2], viewport[3],
+                                   readFormat, readType, pixels);
+                free(pixels);
+            }
+            break;
+        case glesv2debugger::Message_Function_SKIP:
+            return;
+        case glesv2debugger::Message_Function_SETPROP:
+            SetProp(cmd);
+            Receive(cmd);
+            break;
+        default:
+            assert(0); //GenerateCall(msg, cmd);
+            break;
+        }
+    }
+}
diff --git a/opengl/libs/debug.in b/opengl/libs/debug.in
new file mode 100644
index 0000000..882b2da
--- /dev/null
+++ b/opengl/libs/debug.in
@@ -0,0 +1,235 @@
+// the following functions are not defined in GLESv2_dbg
+TRACE_GL_VOID(glAlphaFunc, (GLenum func, GLclampf ref), (func, ref), 2, "GLenum", func, "GLclampf", ref)
+TRACE_GL_VOID(glAlphaFuncx, (GLenum func, GLclampx ref), (func, ref), 2, "GLenum", func, "GLclampx", ref)
+TRACE_GL_VOID(glAlphaFuncxOES, (GLenum func, GLclampx ref), (func, ref), 2, "GLenum", func, "GLclampx", ref)
+TRACE_GL_VOID(glBeginPerfMonitorAMD, (GLuint monitor), (monitor), 1, "GLuint", monitor)
+TRACE_GL_VOID(glBindFramebufferOES, (GLenum target, GLuint framebuffer), (target, framebuffer), 2, "GLenum", target, "GLuint", framebuffer)
+TRACE_GL_VOID(glBindRenderbufferOES, (GLenum target, GLuint renderbuffer), (target, renderbuffer), 2, "GLenum", target, "GLuint", renderbuffer)
+TRACE_GL_VOID(glBindVertexArrayOES, (GLuint array), (array), 1, "GLuint", array)
+TRACE_GL_VOID(glBlendEquationOES, (GLenum mode), (mode), 1, "GLenum", mode)
+TRACE_GL_VOID(glBlendEquationSeparateOES, (GLenum modeRGB, GLenum modeAlpha), (modeRGB, modeAlpha), 2, "GLenum", modeRGB, "GLenum", modeAlpha)
+TRACE_GL_VOID(glBlendFuncSeparateOES, (GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha), (srcRGB, dstRGB, srcAlpha, dstAlpha), 4, "GLenum", srcRGB, "GLenum", dstRGB, "GLenum", srcAlpha, "GLenum", dstAlpha)
+TRACE_GL(GLenum, glCheckFramebufferStatusOES, (GLenum target), (target), 1, "GLenum", target)
+TRACE_GL_VOID(glClearColorx, (GLclampx red, GLclampx green, GLclampx blue, GLclampx alpha), (red, green, blue, alpha), 4, "GLclampx", red, "GLclampx", green, "GLclampx", blue, "GLclampx", alpha)
+TRACE_GL_VOID(glClearColorxOES, (GLclampx red, GLclampx green, GLclampx blue, GLclampx alpha), (red, green, blue, alpha), 4, "GLclampx", red, "GLclampx", green, "GLclampx", blue, "GLclampx", alpha)
+TRACE_GL_VOID(glClearDepthfOES, (GLclampf depth), (depth), 1, "GLclampf", depth)
+TRACE_GL_VOID(glClearDepthx, (GLclampx depth), (depth), 1, "GLclampx", depth)
+TRACE_GL_VOID(glClearDepthxOES, (GLclampx depth), (depth), 1, "GLclampx", depth)
+TRACE_GL_VOID(glClientActiveTexture, (GLenum texture), (texture), 1, "GLenum", texture)
+TRACE_GL_VOID(glClipPlanef, (GLenum plane, const GLfloat *equation), (plane, equation), 2, "GLenum", plane, "const GLfloat *", equation)
+TRACE_GL_VOID(glClipPlanefIMG, (GLenum p, const GLfloat *eqn), (p, eqn), 2, "GLenum", p, "const GLfloat *", eqn)
+TRACE_GL_VOID(glClipPlanefOES, (GLenum plane, const GLfloat *equation), (plane, equation), 2, "GLenum", plane, "const GLfloat *", equation)
+TRACE_GL_VOID(glClipPlanex, (GLenum plane, const GLfixed *equation), (plane, equation), 2, "GLenum", plane, "const GLfixed *", equation)
+TRACE_GL_VOID(glClipPlanexIMG, (GLenum p, const GLfixed *eqn), (p, eqn), 2, "GLenum", p, "const GLfixed *", eqn)
+TRACE_GL_VOID(glClipPlanexOES, (GLenum plane, const GLfixed *equation), (plane, equation), 2, "GLenum", plane, "const GLfixed *", equation)
+TRACE_GL_VOID(glColor4f, (GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha), (red, green, blue, alpha), 4, "GLfloat", red, "GLfloat", green, "GLfloat", blue, "GLfloat", alpha)
+TRACE_GL_VOID(glColor4ub, (GLubyte red, GLubyte green, GLubyte blue, GLubyte alpha), (red, green, blue, alpha), 4, "GLubyte", red, "GLubyte", green, "GLubyte", blue, "GLubyte", alpha)
+TRACE_GL_VOID(glColor4x, (GLfixed red, GLfixed green, GLfixed blue, GLfixed alpha), (red, green, blue, alpha), 4, "GLfixed", red, "GLfixed", green, "GLfixed", blue, "GLfixed", alpha)
+TRACE_GL_VOID(glColor4xOES, (GLfixed red, GLfixed green, GLfixed blue, GLfixed alpha), (red, green, blue, alpha), 4, "GLfixed", red, "GLfixed", green, "GLfixed", blue, "GLfixed", alpha)
+TRACE_GL_VOID(glColorPointer, (GLint size, GLenum type, GLsizei stride, const GLvoid *pointer), (size, type, stride, pointer), 4, "GLint", size, "GLenum", type, "GLsizei", stride, "const GLvoid *", pointer)
+TRACE_GL_VOID(glCompressedTexImage3DOES, (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, const GLvoid* data), (target, level, internalformat, width, height, depth, border, imageSize, data), 9, "GLenum", target, "GLint", level, "GLenum", internalformat, "GLsizei", width, "GLsizei", height, "GLsizei", depth, "GLint", border, "GLsizei", imageSize, "const GLvoid*", data)
+TRACE_GL_VOID(glCompressedTexSubImage3DOES, (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const GLvoid* data), (target, level, xoffset, yoffset, zoffset, width, height, depth, format, imageSize, data), 11, "GLenum", target, "GLint", level, "GLint", xoffset, "GLint", yoffset, "GLint", zoffset, "GLsizei", width, "GLsizei", height, "GLsizei", depth, "GLenum", format, "GLsizei", imageSize, "const GLvoid*", data)
+TRACE_GL_VOID(glCopyTexSubImage3DOES, (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height), (target, level, xoffset, yoffset, zoffset, x, y, width, height), 9, "GLenum", target, "GLint", level, "GLint", xoffset, "GLint", yoffset, "GLint", zoffset, "GLint", x, "GLint", y, "GLsizei", width, "GLsizei", height)
+TRACE_GL_VOID(glCoverageMaskNV, (GLboolean mask), (mask), 1, "GLboolean", mask)
+TRACE_GL_VOID(glCoverageOperationNV, (GLenum operation), (operation), 1, "GLenum", operation)
+TRACE_GL_VOID(glCurrentPaletteMatrixOES, (GLuint matrixpaletteindex), (matrixpaletteindex), 1, "GLuint", matrixpaletteindex)
+TRACE_GL_VOID(glDeleteFencesNV, (GLsizei n, const GLuint *fences), (n, fences), 2, "GLsizei", n, "const GLuint *", fences)
+TRACE_GL_VOID(glDeleteFramebuffersOES, (GLsizei n, const GLuint* framebuffers), (n, framebuffers), 2, "GLsizei", n, "const GLuint*", framebuffers)
+TRACE_GL_VOID(glDeletePerfMonitorsAMD, (GLsizei n, GLuint *monitors), (n, monitors), 2, "GLsizei", n, "GLuint *", monitors)
+TRACE_GL_VOID(glDeleteRenderbuffersOES, (GLsizei n, const GLuint* renderbuffers), (n, renderbuffers), 2, "GLsizei", n, "const GLuint*", renderbuffers)
+TRACE_GL_VOID(glDeleteVertexArraysOES, (GLsizei n, const GLuint *arrays), (n, arrays), 2, "GLsizei", n, "const GLuint *", arrays)
+TRACE_GL_VOID(glDepthRangefOES, (GLclampf zNear, GLclampf zFar), (zNear, zFar), 2, "GLclampf", zNear, "GLclampf", zFar)
+TRACE_GL_VOID(glDepthRangex, (GLclampx zNear, GLclampx zFar), (zNear, zFar), 2, "GLclampx", zNear, "GLclampx", zFar)
+TRACE_GL_VOID(glDepthRangexOES, (GLclampx zNear, GLclampx zFar), (zNear, zFar), 2, "GLclampx", zNear, "GLclampx", zFar)
+TRACE_GL_VOID(glDisableClientState, (GLenum array), (array), 1, "GLenum", array)
+TRACE_GL_VOID(glDisableDriverControlQCOM, (GLuint driverControl), (driverControl), 1, "GLuint", driverControl)
+TRACE_GL_VOID(glDiscardFramebufferEXT, (GLenum target, GLsizei numAttachments, const GLenum *attachments), (target, numAttachments, attachments), 3, "GLenum", target, "GLsizei", numAttachments, "const GLenum *", attachments)
+TRACE_GL_VOID(glDrawTexfOES, (GLfloat x, GLfloat y, GLfloat z, GLfloat width, GLfloat height), (x, y, z, width, height), 5, "GLfloat", x, "GLfloat", y, "GLfloat", z, "GLfloat", width, "GLfloat", height)
+TRACE_GL_VOID(glDrawTexfvOES, (const GLfloat *coords), (coords), 1, "const GLfloat *", coords)
+TRACE_GL_VOID(glDrawTexiOES, (GLint x, GLint y, GLint z, GLint width, GLint height), (x, y, z, width, height), 5, "GLint", x, "GLint", y, "GLint", z, "GLint", width, "GLint", height)
+TRACE_GL_VOID(glDrawTexivOES, (const GLint *coords), (coords), 1, "const GLint *", coords)
+TRACE_GL_VOID(glDrawTexsOES, (GLshort x, GLshort y, GLshort z, GLshort width, GLshort height), (x, y, z, width, height), 5, "GLshort", x, "GLshort", y, "GLshort", z, "GLshort", width, "GLshort", height)
+TRACE_GL_VOID(glDrawTexsvOES, (const GLshort *coords), (coords), 1, "const GLshort *", coords)
+TRACE_GL_VOID(glDrawTexxOES, (GLfixed x, GLfixed y, GLfixed z, GLfixed width, GLfixed height), (x, y, z, width, height), 5, "GLfixed", x, "GLfixed", y, "GLfixed", z, "GLfixed", width, "GLfixed", height)
+TRACE_GL_VOID(glDrawTexxvOES, (const GLfixed *coords), (coords), 1, "const GLfixed *", coords)
+TRACE_GL_VOID(glEGLImageTargetRenderbufferStorageOES, (GLenum target, GLeglImageOES image), (target, image), 2, "GLenum", target, "GLeglImageOES", image)
+TRACE_GL_VOID(glEGLImageTargetTexture2DOES, (GLenum target, GLeglImageOES image), (target, image), 2, "GLenum", target, "GLeglImageOES", image)
+TRACE_GL_VOID(glEnableClientState, (GLenum array), (array), 1, "GLenum", array)
+TRACE_GL_VOID(glEnableDriverControlQCOM, (GLuint driverControl), (driverControl), 1, "GLuint", driverControl)
+TRACE_GL_VOID(glEndPerfMonitorAMD, (GLuint monitor), (monitor), 1, "GLuint", monitor)
+TRACE_GL_VOID(glEndTilingQCOM, (GLbitfield preserveMask), (preserveMask), 1, "GLbitfield", preserveMask)
+TRACE_GL_VOID(glExtGetBufferPointervQCOM, (GLenum target, GLvoid **params), (target, params), 2, "GLenum", target, "GLvoid **", params)
+TRACE_GL_VOID(glExtGetBuffersQCOM, (GLuint *buffers, GLint maxBuffers, GLint *numBuffers), (buffers, maxBuffers, numBuffers), 3, "GLuint *", buffers, "GLint", maxBuffers, "GLint *", numBuffers)
+TRACE_GL_VOID(glExtGetFramebuffersQCOM, (GLuint *framebuffers, GLint maxFramebuffers, GLint *numFramebuffers), (framebuffers, maxFramebuffers, numFramebuffers), 3, "GLuint *", framebuffers, "GLint", maxFramebuffers, "GLint *", numFramebuffers)
+TRACE_GL_VOID(glExtGetProgramBinarySourceQCOM, (GLuint program, GLenum shadertype, GLchar *source, GLint *length), (program, shadertype, source, length), 4, "GLuint", program, "GLenum", shadertype, "GLchar *", source, "GLint *", length)
+TRACE_GL_VOID(glExtGetProgramsQCOM, (GLuint *programs, GLint maxPrograms, GLint *numPrograms), (programs, maxPrograms, numPrograms), 3, "GLuint *", programs, "GLint", maxPrograms, "GLint *", numPrograms)
+TRACE_GL_VOID(glExtGetRenderbuffersQCOM, (GLuint *renderbuffers, GLint maxRenderbuffers, GLint *numRenderbuffers), (renderbuffers, maxRenderbuffers, numRenderbuffers), 3, "GLuint *", renderbuffers, "GLint", maxRenderbuffers, "GLint *", numRenderbuffers)
+TRACE_GL_VOID(glExtGetShadersQCOM, (GLuint *shaders, GLint maxShaders, GLint *numShaders), (shaders, maxShaders, numShaders), 3, "GLuint *", shaders, "GLint", maxShaders, "GLint *", numShaders)
+TRACE_GL_VOID(glExtGetTexLevelParameterivQCOM, (GLuint texture, GLenum face, GLint level, GLenum pname, GLint *params), (texture, face, level, pname, params), 5, "GLuint", texture, "GLenum", face, "GLint", level, "GLenum", pname, "GLint *", params)
+TRACE_GL_VOID(glExtGetTexSubImageQCOM, (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, GLvoid *texels), (target, level, xoffset, yoffset, zoffset, width, height, depth, format, type, texels), 11, "GLenum", target, "GLint", level, "GLint", xoffset, "GLint", yoffset, "GLint", zoffset, "GLsizei", width, "GLsizei", height, "GLsizei", depth, "GLenum", format, "GLenum", type, "GLvoid *", texels)
+TRACE_GL_VOID(glExtGetTexturesQCOM, (GLuint *textures, GLint maxTextures, GLint *numTextures), (textures, maxTextures, numTextures), 3, "GLuint *", textures, "GLint", maxTextures, "GLint *", numTextures)
+TRACE_GL(GLboolean, glExtIsProgramBinaryQCOM, (GLuint program), (program), 1, "GLuint", program)
+TRACE_GL_VOID(glExtTexObjectStateOverrideiQCOM, (GLenum target, GLenum pname, GLint param), (target, pname, param), 3, "GLenum", target, "GLenum", pname, "GLint", param)
+TRACE_GL_VOID(glFinishFenceNV, (GLuint fence), (fence), 1, "GLuint", fence)
+TRACE_GL_VOID(glFogf, (GLenum pname, GLfloat param), (pname, param), 2, "GLenum", pname, "GLfloat", param)
+TRACE_GL_VOID(glFogfv, (GLenum pname, const GLfloat *params), (pname, params), 2, "GLenum", pname, "const GLfloat *", params)
+TRACE_GL_VOID(glFogx, (GLenum pname, GLfixed param), (pname, param), 2, "GLenum", pname, "GLfixed", param)
+TRACE_GL_VOID(glFogxOES, (GLenum pname, GLfixed param), (pname, param), 2, "GLenum", pname, "GLfixed", param)
+TRACE_GL_VOID(glFogxv, (GLenum pname, const GLfixed *params), (pname, params), 2, "GLenum", pname, "const GLfixed *", params)
+TRACE_GL_VOID(glFogxvOES, (GLenum pname, const GLfixed *params), (pname, params), 2, "GLenum", pname, "const GLfixed *", params)
+TRACE_GL_VOID(glFramebufferRenderbufferOES, (GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer), (target, attachment, renderbuffertarget, renderbuffer), 4, "GLenum", target, "GLenum", attachment, "GLenum", renderbuffertarget, "GLuint", renderbuffer)
+TRACE_GL_VOID(glFramebufferTexture2DMultisampleIMG, (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level, GLsizei samples), (target, attachment, textarget, texture, level, samples), 6, "GLenum", target, "GLenum", attachment, "GLenum", textarget, "GLuint", texture, "GLint", level, "GLsizei", samples)
+TRACE_GL_VOID(glFramebufferTexture2DOES, (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level), (target, attachment, textarget, texture, level), 5, "GLenum", target, "GLenum", attachment, "GLenum", textarget, "GLuint", texture, "GLint", level)
+TRACE_GL_VOID(glFramebufferTexture3DOES, (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level, GLint zoffset), (target, attachment, textarget, texture, level, zoffset), 6, "GLenum", target, "GLenum", attachment, "GLenum", textarget, "GLuint", texture, "GLint", level, "GLint", zoffset)
+TRACE_GL_VOID(glFrustumf, (GLfloat left, GLfloat right, GLfloat bottom, GLfloat top, GLfloat zNear, GLfloat zFar), (left, right, bottom, top, zNear, zFar), 6, "GLfloat", left, "GLfloat", right, "GLfloat", bottom, "GLfloat", top, "GLfloat", zNear, "GLfloat", zFar)
+TRACE_GL_VOID(glFrustumfOES, (GLfloat left, GLfloat right, GLfloat bottom, GLfloat top, GLfloat zNear, GLfloat zFar), (left, right, bottom, top, zNear, zFar), 6, "GLfloat", left, "GLfloat", right, "GLfloat", bottom, "GLfloat", top, "GLfloat", zNear, "GLfloat", zFar)
+TRACE_GL_VOID(glFrustumx, (GLfixed left, GLfixed right, GLfixed bottom, GLfixed top, GLfixed zNear, GLfixed zFar), (left, right, bottom, top, zNear, zFar), 6, "GLfixed", left, "GLfixed", right, "GLfixed", bottom, "GLfixed", top, "GLfixed", zNear, "GLfixed", zFar)
+TRACE_GL_VOID(glFrustumxOES, (GLfixed left, GLfixed right, GLfixed bottom, GLfixed top, GLfixed zNear, GLfixed zFar), (left, right, bottom, top, zNear, zFar), 6, "GLfixed", left, "GLfixed", right, "GLfixed", bottom, "GLfixed", top, "GLfixed", zNear, "GLfixed", zFar)
+TRACE_GL_VOID(glGenFencesNV, (GLsizei n, GLuint *fences), (n, fences), 2, "GLsizei", n, "GLuint *", fences)
+TRACE_GL_VOID(glGenFramebuffersOES, (GLsizei n, GLuint* framebuffers), (n, framebuffers), 2, "GLsizei", n, "GLuint*", framebuffers)
+TRACE_GL_VOID(glGenPerfMonitorsAMD, (GLsizei n, GLuint *monitors), (n, monitors), 2, "GLsizei", n, "GLuint *", monitors)
+TRACE_GL_VOID(glGenRenderbuffersOES, (GLsizei n, GLuint* renderbuffers), (n, renderbuffers), 2, "GLsizei", n, "GLuint*", renderbuffers)
+TRACE_GL_VOID(glGenVertexArraysOES, (GLsizei n, GLuint *arrays), (n, arrays), 2, "GLsizei", n, "GLuint *", arrays)
+TRACE_GL_VOID(glGenerateMipmapOES, (GLenum target), (target), 1, "GLenum", target)
+TRACE_GL_VOID(glGetBufferPointervOES, (GLenum target, GLenum pname, GLvoid ** params), (target, pname, params), 3, "GLenum", target, "GLenum", pname, "GLvoid **", params)
+TRACE_GL_VOID(glGetClipPlanef, (GLenum pname, GLfloat eqn[4]), (pname, eqn), 2, "GLenum", pname, "GLfloat", eqn)
+TRACE_GL_VOID(glGetClipPlanefOES, (GLenum pname, GLfloat eqn[4]), (pname, eqn), 2, "GLenum", pname, "GLfloat", eqn)
+TRACE_GL_VOID(glGetClipPlanex, (GLenum pname, GLfixed eqn[4]), (pname, eqn), 2, "GLenum", pname, "GLfixed", eqn)
+TRACE_GL_VOID(glGetClipPlanexOES, (GLenum pname, GLfixed eqn[4]), (pname, eqn), 2, "GLenum", pname, "GLfixed", eqn)
+TRACE_GL_VOID(glGetDriverControlStringQCOM, (GLuint driverControl, GLsizei bufSize, GLsizei *length, GLchar *driverControlString), (driverControl, bufSize, length, driverControlString), 4, "GLuint", driverControl, "GLsizei", bufSize, "GLsizei *", length, "GLchar *", driverControlString)
+TRACE_GL_VOID(glGetDriverControlsQCOM, (GLint *num, GLsizei size, GLuint *driverControls), (num, size, driverControls), 3, "GLint *", num, "GLsizei", size, "GLuint *", driverControls)
+TRACE_GL_VOID(glGetFenceivNV, (GLuint fence, GLenum pname, GLint *params), (fence, pname, params), 3, "GLuint", fence, "GLenum", pname, "GLint *", params)
+TRACE_GL_VOID(glGetFixedv, (GLenum pname, GLfixed *params), (pname, params), 2, "GLenum", pname, "GLfixed *", params)
+TRACE_GL_VOID(glGetFixedvOES, (GLenum pname, GLfixed *params), (pname, params), 2, "GLenum", pname, "GLfixed *", params)
+TRACE_GL_VOID(glGetFramebufferAttachmentParameterivOES, (GLenum target, GLenum attachment, GLenum pname, GLint* params), (target, attachment, pname, params), 4, "GLenum", target, "GLenum", attachment, "GLenum", pname, "GLint*", params)
+TRACE_GL_VOID(glGetLightfv, (GLenum light, GLenum pname, GLfloat *params), (light, pname, params), 3, "GLenum", light, "GLenum", pname, "GLfloat *", params)
+TRACE_GL_VOID(glGetLightxv, (GLenum light, GLenum pname, GLfixed *params), (light, pname, params), 3, "GLenum", light, "GLenum", pname, "GLfixed *", params)
+TRACE_GL_VOID(glGetLightxvOES, (GLenum light, GLenum pname, GLfixed *params), (light, pname, params), 3, "GLenum", light, "GLenum", pname, "GLfixed *", params)
+TRACE_GL_VOID(glGetMaterialfv, (GLenum face, GLenum pname, GLfloat *params), (face, pname, params), 3, "GLenum", face, "GLenum", pname, "GLfloat *", params)
+TRACE_GL_VOID(glGetMaterialxv, (GLenum face, GLenum pname, GLfixed *params), (face, pname, params), 3, "GLenum", face, "GLenum", pname, "GLfixed *", params)
+TRACE_GL_VOID(glGetMaterialxvOES, (GLenum face, GLenum pname, GLfixed *params), (face, pname, params), 3, "GLenum", face, "GLenum", pname, "GLfixed *", params)
+TRACE_GL_VOID(glGetPerfMonitorCounterDataAMD, (GLuint monitor, GLenum pname, GLsizei dataSize, GLuint *data, GLint *bytesWritten), (monitor, pname, dataSize, data, bytesWritten), 5, "GLuint", monitor, "GLenum", pname, "GLsizei", dataSize, "GLuint *", data, "GLint *", bytesWritten)
+TRACE_GL_VOID(glGetPerfMonitorCounterInfoAMD, (GLuint group, GLuint counter, GLenum pname, GLvoid *data), (group, counter, pname, data), 4, "GLuint", group, "GLuint", counter, "GLenum", pname, "GLvoid *", data)
+TRACE_GL_VOID(glGetPerfMonitorCounterStringAMD, (GLuint group, GLuint counter, GLsizei bufSize, GLsizei *length, GLchar *counterString), (group, counter, bufSize, length, counterString), 5, "GLuint", group, "GLuint", counter, "GLsizei", bufSize, "GLsizei *", length, "GLchar *", counterString)
+TRACE_GL_VOID(glGetPerfMonitorCountersAMD, (GLuint group, GLint *numCounters, GLint *maxActiveCounters, GLsizei counterSize, GLuint *counters), (group, numCounters, maxActiveCounters, counterSize, counters), 5, "GLuint", group, "GLint *", numCounters, "GLint *", maxActiveCounters, "GLsizei", counterSize, "GLuint *", counters)
+TRACE_GL_VOID(glGetPerfMonitorGroupStringAMD, (GLuint group, GLsizei bufSize, GLsizei *length, GLchar *groupString), (group, bufSize, length, groupString), 4, "GLuint", group, "GLsizei", bufSize, "GLsizei *", length, "GLchar *", groupString)
+TRACE_GL_VOID(glGetPerfMonitorGroupsAMD, (GLint *numGroups, GLsizei groupsSize, GLuint *groups), (numGroups, groupsSize, groups), 3, "GLint *", numGroups, "GLsizei", groupsSize, "GLuint *", groups)
+TRACE_GL_VOID(glGetPointerv, (GLenum pname, GLvoid **params), (pname, params), 2, "GLenum", pname, "GLvoid **", params)
+TRACE_GL_VOID(glGetProgramBinaryOES, (GLuint program, GLsizei bufSize, GLsizei *length, GLenum *binaryFormat, GLvoid *binary), (program, bufSize, length, binaryFormat, binary), 5, "GLuint", program, "GLsizei", bufSize, "GLsizei *", length, "GLenum *", binaryFormat, "GLvoid *", binary)
+TRACE_GL_VOID(glGetRenderbufferParameterivOES, (GLenum target, GLenum pname, GLint* params), (target, pname, params), 3, "GLenum", target, "GLenum", pname, "GLint*", params)
+TRACE_GL_VOID(glGetTexEnvfv, (GLenum env, GLenum pname, GLfloat *params), (env, pname, params), 3, "GLenum", env, "GLenum", pname, "GLfloat *", params)
+TRACE_GL_VOID(glGetTexEnviv, (GLenum env, GLenum pname, GLint *params), (env, pname, params), 3, "GLenum", env, "GLenum", pname, "GLint *", params)
+TRACE_GL_VOID(glGetTexEnvxv, (GLenum env, GLenum pname, GLfixed *params), (env, pname, params), 3, "GLenum", env, "GLenum", pname, "GLfixed *", params)
+TRACE_GL_VOID(glGetTexEnvxvOES, (GLenum env, GLenum pname, GLfixed *params), (env, pname, params), 3, "GLenum", env, "GLenum", pname, "GLfixed *", params)
+TRACE_GL_VOID(glGetTexGenfvOES, (GLenum coord, GLenum pname, GLfloat *params), (coord, pname, params), 3, "GLenum", coord, "GLenum", pname, "GLfloat *", params)
+TRACE_GL_VOID(glGetTexGenivOES, (GLenum coord, GLenum pname, GLint *params), (coord, pname, params), 3, "GLenum", coord, "GLenum", pname, "GLint *", params)
+TRACE_GL_VOID(glGetTexGenxvOES, (GLenum coord, GLenum pname, GLfixed *params), (coord, pname, params), 3, "GLenum", coord, "GLenum", pname, "GLfixed *", params)
+TRACE_GL_VOID(glGetTexParameterxv, (GLenum target, GLenum pname, GLfixed *params), (target, pname, params), 3, "GLenum", target, "GLenum", pname, "GLfixed *", params)
+TRACE_GL_VOID(glGetTexParameterxvOES, (GLenum target, GLenum pname, GLfixed *params), (target, pname, params), 3, "GLenum", target, "GLenum", pname, "GLfixed *", params)
+TRACE_GL(GLboolean, glIsFenceNV, (GLuint fence), (fence), 1, "GLuint", fence)
+TRACE_GL(GLboolean, glIsFramebufferOES, (GLuint framebuffer), (framebuffer), 1, "GLuint", framebuffer)
+TRACE_GL(GLboolean, glIsRenderbufferOES, (GLuint renderbuffer), (renderbuffer), 1, "GLuint", renderbuffer)
+TRACE_GL(GLboolean, glIsVertexArrayOES, (GLuint array), (array), 1, "GLuint", array)
+TRACE_GL_VOID(glLightModelf, (GLenum pname, GLfloat param), (pname, param), 2, "GLenum", pname, "GLfloat", param)
+TRACE_GL_VOID(glLightModelfv, (GLenum pname, const GLfloat *params), (pname, params), 2, "GLenum", pname, "const GLfloat *", params)
+TRACE_GL_VOID(glLightModelx, (GLenum pname, GLfixed param), (pname, param), 2, "GLenum", pname, "GLfixed", param)
+TRACE_GL_VOID(glLightModelxOES, (GLenum pname, GLfixed param), (pname, param), 2, "GLenum", pname, "GLfixed", param)
+TRACE_GL_VOID(glLightModelxv, (GLenum pname, const GLfixed *params), (pname, params), 2, "GLenum", pname, "const GLfixed *", params)
+TRACE_GL_VOID(glLightModelxvOES, (GLenum pname, const GLfixed *params), (pname, params), 2, "GLenum", pname, "const GLfixed *", params)
+TRACE_GL_VOID(glLightf, (GLenum light, GLenum pname, GLfloat param), (light, pname, param), 3, "GLenum", light, "GLenum", pname, "GLfloat", param)
+TRACE_GL_VOID(glLightfv, (GLenum light, GLenum pname, const GLfloat *params), (light, pname, params), 3, "GLenum", light, "GLenum", pname, "const GLfloat *", params)
+TRACE_GL_VOID(glLightx, (GLenum light, GLenum pname, GLfixed param), (light, pname, param), 3, "GLenum", light, "GLenum", pname, "GLfixed", param)
+TRACE_GL_VOID(glLightxOES, (GLenum light, GLenum pname, GLfixed param), (light, pname, param), 3, "GLenum", light, "GLenum", pname, "GLfixed", param)
+TRACE_GL_VOID(glLightxv, (GLenum light, GLenum pname, const GLfixed *params), (light, pname, params), 3, "GLenum", light, "GLenum", pname, "const GLfixed *", params)
+TRACE_GL_VOID(glLightxvOES, (GLenum light, GLenum pname, const GLfixed *params), (light, pname, params), 3, "GLenum", light, "GLenum", pname, "const GLfixed *", params)
+TRACE_GL_VOID(glLineWidthx, (GLfixed width), (width), 1, "GLfixed", width)
+TRACE_GL_VOID(glLineWidthxOES, (GLfixed width), (width), 1, "GLfixed", width)
+TRACE_GL_VOID(glLoadIdentity, (void), (), 0)
+TRACE_GL_VOID(glLoadMatrixf, (const GLfloat *m), (m), 1, "const GLfloat *", m)
+TRACE_GL_VOID(glLoadMatrixx, (const GLfixed *m), (m), 1, "const GLfixed *", m)
+TRACE_GL_VOID(glLoadMatrixxOES, (const GLfixed *m), (m), 1, "const GLfixed *", m)
+TRACE_GL_VOID(glLoadPaletteFromModelViewMatrixOES, (void), (), 0)
+TRACE_GL_VOID(glLogicOp, (GLenum opcode), (opcode), 1, "GLenum", opcode)
+TRACE_GL(void*, glMapBufferOES, (GLenum target, GLenum access), (target, access), 2, "GLenum", target, "GLenum", access)
+TRACE_GL_VOID(glMaterialf, (GLenum face, GLenum pname, GLfloat param), (face, pname, param), 3, "GLenum", face, "GLenum", pname, "GLfloat", param)
+TRACE_GL_VOID(glMaterialfv, (GLenum face, GLenum pname, const GLfloat *params), (face, pname, params), 3, "GLenum", face, "GLenum", pname, "const GLfloat *", params)
+TRACE_GL_VOID(glMaterialx, (GLenum face, GLenum pname, GLfixed param), (face, pname, param), 3, "GLenum", face, "GLenum", pname, "GLfixed", param)
+TRACE_GL_VOID(glMaterialxOES, (GLenum face, GLenum pname, GLfixed param), (face, pname, param), 3, "GLenum", face, "GLenum", pname, "GLfixed", param)
+TRACE_GL_VOID(glMaterialxv, (GLenum face, GLenum pname, const GLfixed *params), (face, pname, params), 3, "GLenum", face, "GLenum", pname, "const GLfixed *", params)
+TRACE_GL_VOID(glMaterialxvOES, (GLenum face, GLenum pname, const GLfixed *params), (face, pname, params), 3, "GLenum", face, "GLenum", pname, "const GLfixed *", params)
+TRACE_GL_VOID(glMatrixIndexPointerOES, (GLint size, GLenum type, GLsizei stride, const GLvoid *pointer), (size, type, stride, pointer), 4, "GLint", size, "GLenum", type, "GLsizei", stride, "const GLvoid *", pointer)
+TRACE_GL_VOID(glMatrixMode, (GLenum mode), (mode), 1, "GLenum", mode)
+TRACE_GL_VOID(glMultMatrixf, (const GLfloat *m), (m), 1, "const GLfloat *", m)
+TRACE_GL_VOID(glMultMatrixx, (const GLfixed *m), (m), 1, "const GLfixed *", m)
+TRACE_GL_VOID(glMultMatrixxOES, (const GLfixed *m), (m), 1, "const GLfixed *", m)
+TRACE_GL_VOID(glMultiDrawArraysEXT, (GLenum mode, GLint *first, GLsizei *count, GLsizei primcount), (mode, first, count, primcount), 4, "GLenum", mode, "GLint *", first, "GLsizei *", count, "GLsizei", primcount)
+TRACE_GL_VOID(glMultiDrawElementsEXT, (GLenum mode, const GLsizei *count, GLenum type, const GLvoid* *indices, GLsizei primcount), (mode, count, type, indices, primcount), 5, "GLenum", mode, "const GLsizei *", count, "GLenum", type, "const GLvoid* *", indices, "GLsizei", primcount)
+TRACE_GL_VOID(glMultiTexCoord4f, (GLenum target, GLfloat s, GLfloat t, GLfloat r, GLfloat q), (target, s, t, r, q), 5, "GLenum", target, "GLfloat", s, "GLfloat", t, "GLfloat", r, "GLfloat", q)
+TRACE_GL_VOID(glMultiTexCoord4x, (GLenum target, GLfixed s, GLfixed t, GLfixed r, GLfixed q), (target, s, t, r, q), 5, "GLenum", target, "GLfixed", s, "GLfixed", t, "GLfixed", r, "GLfixed", q)
+TRACE_GL_VOID(glMultiTexCoord4xOES, (GLenum target, GLfixed s, GLfixed t, GLfixed r, GLfixed q), (target, s, t, r, q), 5, "GLenum", target, "GLfixed", s, "GLfixed", t, "GLfixed", r, "GLfixed", q)
+TRACE_GL_VOID(glNormal3f, (GLfloat nx, GLfloat ny, GLfloat nz), (nx, ny, nz), 3, "GLfloat", nx, "GLfloat", ny, "GLfloat", nz)
+TRACE_GL_VOID(glNormal3x, (GLfixed nx, GLfixed ny, GLfixed nz), (nx, ny, nz), 3, "GLfixed", nx, "GLfixed", ny, "GLfixed", nz)
+TRACE_GL_VOID(glNormal3xOES, (GLfixed nx, GLfixed ny, GLfixed nz), (nx, ny, nz), 3, "GLfixed", nx, "GLfixed", ny, "GLfixed", nz)
+TRACE_GL_VOID(glNormalPointer, (GLenum type, GLsizei stride, const GLvoid *pointer), (type, stride, pointer), 3, "GLenum", type, "GLsizei", stride, "const GLvoid *", pointer)
+TRACE_GL_VOID(glOrthof, (GLfloat left, GLfloat right, GLfloat bottom, GLfloat top, GLfloat zNear, GLfloat zFar), (left, right, bottom, top, zNear, zFar), 6, "GLfloat", left, "GLfloat", right, "GLfloat", bottom, "GLfloat", top, "GLfloat", zNear, "GLfloat", zFar)
+TRACE_GL_VOID(glOrthofOES, (GLfloat left, GLfloat right, GLfloat bottom, GLfloat top, GLfloat zNear, GLfloat zFar), (left, right, bottom, top, zNear, zFar), 6, "GLfloat", left, "GLfloat", right, "GLfloat", bottom, "GLfloat", top, "GLfloat", zNear, "GLfloat", zFar)
+TRACE_GL_VOID(glOrthox, (GLfixed left, GLfixed right, GLfixed bottom, GLfixed top, GLfixed zNear, GLfixed zFar), (left, right, bottom, top, zNear, zFar), 6, "GLfixed", left, "GLfixed", right, "GLfixed", bottom, "GLfixed", top, "GLfixed", zNear, "GLfixed", zFar)
+TRACE_GL_VOID(glOrthoxOES, (GLfixed left, GLfixed right, GLfixed bottom, GLfixed top, GLfixed zNear, GLfixed zFar), (left, right, bottom, top, zNear, zFar), 6, "GLfixed", left, "GLfixed", right, "GLfixed", bottom, "GLfixed", top, "GLfixed", zNear, "GLfixed", zFar)
+TRACE_GL_VOID(glPointParameterf, (GLenum pname, GLfloat param), (pname, param), 2, "GLenum", pname, "GLfloat", param)
+TRACE_GL_VOID(glPointParameterfv, (GLenum pname, const GLfloat *params), (pname, params), 2, "GLenum", pname, "const GLfloat *", params)
+TRACE_GL_VOID(glPointParameterx, (GLenum pname, GLfixed param), (pname, param), 2, "GLenum", pname, "GLfixed", param)
+TRACE_GL_VOID(glPointParameterxOES, (GLenum pname, GLfixed param), (pname, param), 2, "GLenum", pname, "GLfixed", param)
+TRACE_GL_VOID(glPointParameterxv, (GLenum pname, const GLfixed *params), (pname, params), 2, "GLenum", pname, "const GLfixed *", params)
+TRACE_GL_VOID(glPointParameterxvOES, (GLenum pname, const GLfixed *params), (pname, params), 2, "GLenum", pname, "const GLfixed *", params)
+TRACE_GL_VOID(glPointSize, (GLfloat size), (size), 1, "GLfloat", size)
+TRACE_GL_VOID(glPointSizePointerOES, (GLenum type, GLsizei stride, const GLvoid *pointer), (type, stride, pointer), 3, "GLenum", type, "GLsizei", stride, "const GLvoid *", pointer)
+TRACE_GL_VOID(glPointSizex, (GLfixed size), (size), 1, "GLfixed", size)
+TRACE_GL_VOID(glPointSizexOES, (GLfixed size), (size), 1, "GLfixed", size)
+TRACE_GL_VOID(glPolygonOffsetx, (GLfixed factor, GLfixed units), (factor, units), 2, "GLfixed", factor, "GLfixed", units)
+TRACE_GL_VOID(glPolygonOffsetxOES, (GLfixed factor, GLfixed units), (factor, units), 2, "GLfixed", factor, "GLfixed", units)
+TRACE_GL_VOID(glPopMatrix, (void), (), 0)
+TRACE_GL_VOID(glProgramBinaryOES, (GLuint program, GLenum binaryFormat, const GLvoid *binary, GLint length), (program, binaryFormat, binary, length), 4, "GLuint", program, "GLenum", binaryFormat, "const GLvoid *", binary, "GLint", length)
+TRACE_GL_VOID(glPushMatrix, (void), (), 0)
+TRACE_GL(GLbitfield, glQueryMatrixxOES, (GLfixed mantissa[16], GLint exponent[16]), (mantissa, exponent), 2, "GLfixed", mantissa, "GLint", exponent)
+TRACE_GL_VOID(glRenderbufferStorageMultisampleIMG, (GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height), (target, samples, internalformat, width, height), 5, "GLenum", target, "GLsizei", samples, "GLenum", internalformat, "GLsizei", width, "GLsizei", height)
+TRACE_GL_VOID(glRenderbufferStorageOES, (GLenum target, GLenum internalformat, GLsizei width, GLsizei height), (target, internalformat, width, height), 4, "GLenum", target, "GLenum", internalformat, "GLsizei", width, "GLsizei", height)
+TRACE_GL_VOID(glRotatef, (GLfloat angle, GLfloat x, GLfloat y, GLfloat z), (angle, x, y, z), 4, "GLfloat", angle, "GLfloat", x, "GLfloat", y, "GLfloat", z)
+TRACE_GL_VOID(glRotatex, (GLfixed angle, GLfixed x, GLfixed y, GLfixed z), (angle, x, y, z), 4, "GLfixed", angle, "GLfixed", x, "GLfixed", y, "GLfixed", z)
+TRACE_GL_VOID(glRotatexOES, (GLfixed angle, GLfixed x, GLfixed y, GLfixed z), (angle, x, y, z), 4, "GLfixed", angle, "GLfixed", x, "GLfixed", y, "GLfixed", z)
+TRACE_GL_VOID(glSampleCoveragex, (GLclampx value, GLboolean invert), (value, invert), 2, "GLclampx", value, "GLboolean", invert)
+TRACE_GL_VOID(glSampleCoveragexOES, (GLclampx value, GLboolean invert), (value, invert), 2, "GLclampx", value, "GLboolean", invert)
+TRACE_GL_VOID(glScalef, (GLfloat x, GLfloat y, GLfloat z), (x, y, z), 3, "GLfloat", x, "GLfloat", y, "GLfloat", z)
+TRACE_GL_VOID(glScalex, (GLfixed x, GLfixed y, GLfixed z), (x, y, z), 3, "GLfixed", x, "GLfixed", y, "GLfixed", z)
+TRACE_GL_VOID(glScalexOES, (GLfixed x, GLfixed y, GLfixed z), (x, y, z), 3, "GLfixed", x, "GLfixed", y, "GLfixed", z)
+TRACE_GL_VOID(glSelectPerfMonitorCountersAMD, (GLuint monitor, GLboolean enable, GLuint group, GLint numCounters, GLuint *countersList), (monitor, enable, group, numCounters, countersList), 5, "GLuint", monitor, "GLboolean", enable, "GLuint", group, "GLint", numCounters, "GLuint *", countersList)
+TRACE_GL_VOID(glSetFenceNV, (GLuint fence, GLenum condition), (fence, condition), 2, "GLuint", fence, "GLenum", condition)
+TRACE_GL_VOID(glShadeModel, (GLenum mode), (mode), 1, "GLenum", mode)
+TRACE_GL_VOID(glStartTilingQCOM, (GLuint x, GLuint y, GLuint width, GLuint height, GLbitfield preserveMask), (x, y, width, height, preserveMask), 5, "GLuint", x, "GLuint", y, "GLuint", width, "GLuint", height, "GLbitfield", preserveMask)
+TRACE_GL(GLboolean, glTestFenceNV, (GLuint fence), (fence), 1, "GLuint", fence)
+TRACE_GL_VOID(glTexCoordPointer, (GLint size, GLenum type, GLsizei stride, const GLvoid *pointer), (size, type, stride, pointer), 4, "GLint", size, "GLenum", type, "GLsizei", stride, "const GLvoid *", pointer)
+TRACE_GL_VOID(glTexEnvf, (GLenum target, GLenum pname, GLfloat param), (target, pname, param), 3, "GLenum", target, "GLenum", pname, "GLfloat", param)
+TRACE_GL_VOID(glTexEnvfv, (GLenum target, GLenum pname, const GLfloat *params), (target, pname, params), 3, "GLenum", target, "GLenum", pname, "const GLfloat *", params)
+TRACE_GL_VOID(glTexEnvi, (GLenum target, GLenum pname, GLint param), (target, pname, param), 3, "GLenum", target, "GLenum", pname, "GLint", param)
+TRACE_GL_VOID(glTexEnviv, (GLenum target, GLenum pname, const GLint *params), (target, pname, params), 3, "GLenum", target, "GLenum", pname, "const GLint *", params)
+TRACE_GL_VOID(glTexEnvx, (GLenum target, GLenum pname, GLfixed param), (target, pname, param), 3, "GLenum", target, "GLenum", pname, "GLfixed", param)
+TRACE_GL_VOID(glTexEnvxOES, (GLenum target, GLenum pname, GLfixed param), (target, pname, param), 3, "GLenum", target, "GLenum", pname, "GLfixed", param)
+TRACE_GL_VOID(glTexEnvxv, (GLenum target, GLenum pname, const GLfixed *params), (target, pname, params), 3, "GLenum", target, "GLenum", pname, "const GLfixed *", params)
+TRACE_GL_VOID(glTexEnvxvOES, (GLenum target, GLenum pname, const GLfixed *params), (target, pname, params), 3, "GLenum", target, "GLenum", pname, "const GLfixed *", params)
+TRACE_GL_VOID(glTexGenfOES, (GLenum coord, GLenum pname, GLfloat param), (coord, pname, param), 3, "GLenum", coord, "GLenum", pname, "GLfloat", param)
+TRACE_GL_VOID(glTexGenfvOES, (GLenum coord, GLenum pname, const GLfloat *params), (coord, pname, params), 3, "GLenum", coord, "GLenum", pname, "const GLfloat *", params)
+TRACE_GL_VOID(glTexGeniOES, (GLenum coord, GLenum pname, GLint param), (coord, pname, param), 3, "GLenum", coord, "GLenum", pname, "GLint", param)
+TRACE_GL_VOID(glTexGenivOES, (GLenum coord, GLenum pname, const GLint *params), (coord, pname, params), 3, "GLenum", coord, "GLenum", pname, "const GLint *", params)
+TRACE_GL_VOID(glTexGenxOES, (GLenum coord, GLenum pname, GLfixed param), (coord, pname, param), 3, "GLenum", coord, "GLenum", pname, "GLfixed", param)
+TRACE_GL_VOID(glTexGenxvOES, (GLenum coord, GLenum pname, const GLfixed *params), (coord, pname, params), 3, "GLenum", coord, "GLenum", pname, "const GLfixed *", params)
+TRACE_GL_VOID(glTexImage3DOES, (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const GLvoid* pixels), (target, level, internalformat, width, height, depth, border, format, type, pixels), 10, "GLenum", target, "GLint", level, "GLenum", internalformat, "GLsizei", width, "GLsizei", height, "GLsizei", depth, "GLint", border, "GLenum", format, "GLenum", type, "const GLvoid*", pixels)
+TRACE_GL_VOID(glTexParameterx, (GLenum target, GLenum pname, GLfixed param), (target, pname, param), 3, "GLenum", target, "GLenum", pname, "GLfixed", param)
+TRACE_GL_VOID(glTexParameterxOES, (GLenum target, GLenum pname, GLfixed param), (target, pname, param), 3, "GLenum", target, "GLenum", pname, "GLfixed", param)
+TRACE_GL_VOID(glTexParameterxv, (GLenum target, GLenum pname, const GLfixed *params), (target, pname, params), 3, "GLenum", target, "GLenum", pname, "const GLfixed *", params)
+TRACE_GL_VOID(glTexParameterxvOES, (GLenum target, GLenum pname, const GLfixed *params), (target, pname, params), 3, "GLenum", target, "GLenum", pname, "const GLfixed *", params)
+TRACE_GL_VOID(glTexSubImage3DOES, (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const GLvoid* pixels), (target, level, xoffset, yoffset, zoffset, width, height, depth, format, type, pixels), 11, "GLenum", target, "GLint", level, "GLint", xoffset, "GLint", yoffset, "GLint", zoffset, "GLsizei", width, "GLsizei", height, "GLsizei", depth, "GLenum", format, "GLenum", type, "const GLvoid*", pixels)
+TRACE_GL_VOID(glTranslatef, (GLfloat x, GLfloat y, GLfloat z), (x, y, z), 3, "GLfloat", x, "GLfloat", y, "GLfloat", z)
+TRACE_GL_VOID(glTranslatex, (GLfixed x, GLfixed y, GLfixed z), (x, y, z), 3, "GLfixed", x, "GLfixed", y, "GLfixed", z)
+TRACE_GL_VOID(glTranslatexOES, (GLfixed x, GLfixed y, GLfixed z), (x, y, z), 3, "GLfixed", x, "GLfixed", y, "GLfixed", z)
+TRACE_GL(GLboolean, glUnmapBufferOES, (GLenum target), (target), 1, "GLenum", target)
+TRACE_GL_VOID(glVertexPointer, (GLint size, GLenum type, GLsizei stride, const GLvoid *pointer), (size, type, stride, pointer), 4, "GLint", size, "GLenum", type, "GLsizei", stride, "const GLvoid *", pointer)
+TRACE_GL_VOID(glWeightPointerOES, (GLint size, GLenum type, GLsizei stride, const GLvoid *pointer), (size, type, stride, pointer), 4, "GLint", size, "GLenum", type, "GLsizei", stride, "const GLvoid *", pointer)
diff --git a/opengl/libs/glesv2dbg.h b/opengl/libs/glesv2dbg.h
new file mode 100644
index 0000000..8029dce
--- /dev/null
+++ b/opengl/libs/glesv2dbg.h
@@ -0,0 +1,32 @@
+/*
+ ** Copyright 2011, The Android Open Source Project
+ **
+ ** Licensed under the Apache License, Version 2.0 (the "License");
+ ** you may not use this file except in compliance with the License.
+ ** You may obtain a copy of the License at
+ **
+ **     http://www.apache.org/licenses/LICENSE-2.0
+ **
+ ** Unless required by applicable law or agreed to in writing, software
+ ** distributed under the License is distributed on an "AS IS" BASIS,
+ ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ** See the License for the specific language governing permissions and
+ ** limitations under the License.
+ */
+ 
+#ifndef _GLESV2_DBG_H_
+#define _GLESV2_DBG_H_
+
+namespace android
+{
+    struct DbgContext;
+    
+    DbgContext * CreateDbgContext(const unsigned version, const gl_hooks_t * const hooks);
+    void DestroyDbgContext(DbgContext * const dbg);
+    
+    void StartDebugServer(unsigned short port); // create and bind socket if haven't already
+    void StopDebugServer(); // close socket if open
+    
+}; // namespace android
+
+#endif // #ifndef _GLESV2_DBG_H_
diff --git a/opengl/libs/glesv2dbg_functions.h b/opengl/libs/glesv2dbg_functions.h
new file mode 100644
index 0000000..2d70032
--- /dev/null
+++ b/opengl/libs/glesv2dbg_functions.h
@@ -0,0 +1,381 @@
+extern "C"
+{
+GL_ENTRY(void, glActiveTexture, GLenum texture)
+GL_ENTRY(void, glAlphaFunc, GLenum func, GLclampf ref)
+GL_ENTRY(void, glAlphaFuncx, GLenum func, GLclampx ref)
+GL_ENTRY(void, glAlphaFuncxOES, GLenum func, GLclampx ref)
+GL_ENTRY(void, glAttachShader, GLuint program, GLuint shader)
+GL_ENTRY(void, glBeginPerfMonitorAMD, GLuint monitor)
+GL_ENTRY(void, glBindAttribLocation, GLuint program, GLuint index, const GLchar* name)
+GL_ENTRY(void, glBindBuffer, GLenum target, GLuint buffer)
+GL_ENTRY(void, glBindFramebuffer, GLenum target, GLuint framebuffer)
+GL_ENTRY(void, glBindFramebufferOES, GLenum target, GLuint framebuffer)
+GL_ENTRY(void, glBindRenderbuffer, GLenum target, GLuint renderbuffer)
+GL_ENTRY(void, glBindRenderbufferOES, GLenum target, GLuint renderbuffer)
+GL_ENTRY(void, glBindTexture, GLenum target, GLuint texture)
+GL_ENTRY(void, glBindVertexArrayOES, GLuint array)
+GL_ENTRY(void, glBlendColor, GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha)
+GL_ENTRY(void, glBlendEquation,  GLenum mode )
+GL_ENTRY(void, glBlendEquationOES, GLenum mode)
+GL_ENTRY(void, glBlendEquationSeparate, GLenum modeRGB, GLenum modeAlpha)
+GL_ENTRY(void, glBlendEquationSeparateOES, GLenum modeRGB, GLenum modeAlpha)
+GL_ENTRY(void, glBlendFunc, GLenum sfactor, GLenum dfactor)
+GL_ENTRY(void, glBlendFuncSeparate, GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha)
+GL_ENTRY(void, glBlendFuncSeparateOES, GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha)
+GL_ENTRY(void, glBufferData, GLenum target, GLsizeiptr size, const GLvoid *data, GLenum usage)
+GL_ENTRY(void, glBufferSubData, GLenum target, GLintptr offset, GLsizeiptr size, const GLvoid *data)
+GL_ENTRY(GLenum, glCheckFramebufferStatus, GLenum target)
+GL_ENTRY(GLenum, glCheckFramebufferStatusOES, GLenum target)
+GL_ENTRY(void, glClear, GLbitfield mask)
+GL_ENTRY(void, glClearColor, GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha)
+GL_ENTRY(void, glClearColorx, GLclampx red, GLclampx green, GLclampx blue, GLclampx alpha)
+GL_ENTRY(void, glClearColorxOES, GLclampx red, GLclampx green, GLclampx blue, GLclampx alpha)
+GL_ENTRY(void, glClearDepthf, GLclampf depth)
+GL_ENTRY(void, glClearDepthfOES, GLclampf depth)
+GL_ENTRY(void, glClearDepthx, GLclampx depth)
+GL_ENTRY(void, glClearDepthxOES, GLclampx depth)
+GL_ENTRY(void, glClearStencil, GLint s)
+GL_ENTRY(void, glClientActiveTexture, GLenum texture)
+GL_ENTRY(void, glClipPlanef, GLenum plane, const GLfloat *equation)
+GL_ENTRY(void, glClipPlanefIMG, GLenum p, const GLfloat *eqn)
+GL_ENTRY(void, glClipPlanefOES, GLenum plane, const GLfloat *equation)
+GL_ENTRY(void, glClipPlanex, GLenum plane, const GLfixed *equation)
+GL_ENTRY(void, glClipPlanexIMG, GLenum p, const GLfixed *eqn)
+GL_ENTRY(void, glClipPlanexOES, GLenum plane, const GLfixed *equation)
+GL_ENTRY(void, glColor4f, GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha)
+GL_ENTRY(void, glColor4ub, GLubyte red, GLubyte green, GLubyte blue, GLubyte alpha)
+GL_ENTRY(void, glColor4x, GLfixed red, GLfixed green, GLfixed blue, GLfixed alpha)
+GL_ENTRY(void, glColor4xOES, GLfixed red, GLfixed green, GLfixed blue, GLfixed alpha)
+GL_ENTRY(void, glColorMask, GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha)
+GL_ENTRY(void, glColorPointer, GLint size, GLenum type, GLsizei stride, const GLvoid *pointer)
+GL_ENTRY(void, glCompileShader, GLuint shader)
+GL_ENTRY(void, glCompressedTexImage2D, GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const GLvoid *data)
+GL_ENTRY(void, glCompressedTexImage3DOES, GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, const GLvoid* data)
+GL_ENTRY(void, glCompressedTexSubImage2D, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const GLvoid *data)
+GL_ENTRY(void, glCompressedTexSubImage3DOES, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const GLvoid* data)
+GL_ENTRY(void, glCopyTexImage2D, GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border)
+GL_ENTRY(void, glCopyTexSubImage2D, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height)
+GL_ENTRY(void, glCopyTexSubImage3DOES, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height)
+GL_ENTRY(void, glCoverageMaskNV, GLboolean mask)
+GL_ENTRY(void, glCoverageOperationNV, GLenum operation)
+GL_ENTRY(GLuint, glCreateProgram, void)
+GL_ENTRY(GLuint, glCreateShader, GLenum type)
+GL_ENTRY(void, glCullFace, GLenum mode)
+GL_ENTRY(void, glCurrentPaletteMatrixOES, GLuint matrixpaletteindex)
+GL_ENTRY(void, glDeleteBuffers, GLsizei n, const GLuint *buffers)
+GL_ENTRY(void, glDeleteFencesNV, GLsizei n, const GLuint *fences)
+GL_ENTRY(void, glDeleteFramebuffers, GLsizei n, const GLuint* framebuffers)
+GL_ENTRY(void, glDeleteFramebuffersOES, GLsizei n, const GLuint* framebuffers)
+GL_ENTRY(void, glDeletePerfMonitorsAMD, GLsizei n, GLuint *monitors)
+GL_ENTRY(void, glDeleteProgram, GLuint program)
+GL_ENTRY(void, glDeleteRenderbuffers, GLsizei n, const GLuint* renderbuffers)
+GL_ENTRY(void, glDeleteRenderbuffersOES, GLsizei n, const GLuint* renderbuffers)
+GL_ENTRY(void, glDeleteShader, GLuint shader)
+GL_ENTRY(void, glDeleteTextures, GLsizei n, const GLuint *textures)
+GL_ENTRY(void, glDeleteVertexArraysOES, GLsizei n, const GLuint *arrays)
+GL_ENTRY(void, glDepthFunc, GLenum func)
+GL_ENTRY(void, glDepthMask, GLboolean flag)
+GL_ENTRY(void, glDepthRangef, GLclampf zNear, GLclampf zFar)
+GL_ENTRY(void, glDepthRangefOES, GLclampf zNear, GLclampf zFar)
+GL_ENTRY(void, glDepthRangex, GLclampx zNear, GLclampx zFar)
+GL_ENTRY(void, glDepthRangexOES, GLclampx zNear, GLclampx zFar)
+GL_ENTRY(void, glDetachShader, GLuint program, GLuint shader)
+GL_ENTRY(void, glDisable, GLenum cap)
+GL_ENTRY(void, glDisableClientState, GLenum array)
+GL_ENTRY(void, glDisableDriverControlQCOM, GLuint driverControl)
+GL_ENTRY(void, glDisableVertexAttribArray, GLuint index)
+GL_ENTRY(void, glDiscardFramebufferEXT, GLenum target, GLsizei numAttachments, const GLenum *attachments)
+GL_ENTRY(void, glDrawArrays, GLenum mode, GLint first, GLsizei count)
+GL_ENTRY(void, glDrawElements, GLenum mode, GLsizei count, GLenum type, const GLvoid *indices)
+GL_ENTRY(void, glDrawTexfOES, GLfloat x, GLfloat y, GLfloat z, GLfloat width, GLfloat height)
+GL_ENTRY(void, glDrawTexfvOES, const GLfloat *coords)
+GL_ENTRY(void, glDrawTexiOES, GLint x, GLint y, GLint z, GLint width, GLint height)
+GL_ENTRY(void, glDrawTexivOES, const GLint *coords)
+GL_ENTRY(void, glDrawTexsOES, GLshort x, GLshort y, GLshort z, GLshort width, GLshort height)
+GL_ENTRY(void, glDrawTexsvOES, const GLshort *coords)
+GL_ENTRY(void, glDrawTexxOES, GLfixed x, GLfixed y, GLfixed z, GLfixed width, GLfixed height)
+GL_ENTRY(void, glDrawTexxvOES, const GLfixed *coords)
+GL_ENTRY(void, glEGLImageTargetRenderbufferStorageOES, GLenum target, GLeglImageOES image)
+GL_ENTRY(void, glEGLImageTargetTexture2DOES, GLenum target, GLeglImageOES image)
+GL_ENTRY(void, glEnable, GLenum cap)
+GL_ENTRY(void, glEnableClientState, GLenum array)
+GL_ENTRY(void, glEnableDriverControlQCOM, GLuint driverControl)
+GL_ENTRY(void, glEnableVertexAttribArray, GLuint index)
+GL_ENTRY(void, glEndPerfMonitorAMD, GLuint monitor)
+GL_ENTRY(void, glEndTilingQCOM, GLbitfield preserveMask)
+GL_ENTRY(void, glExtGetBufferPointervQCOM, GLenum target, GLvoid **params)
+GL_ENTRY(void, glExtGetBuffersQCOM, GLuint *buffers, GLint maxBuffers, GLint *numBuffers)
+GL_ENTRY(void, glExtGetFramebuffersQCOM, GLuint *framebuffers, GLint maxFramebuffers, GLint *numFramebuffers)
+GL_ENTRY(void, glExtGetProgramBinarySourceQCOM, GLuint program, GLenum shadertype, GLchar *source, GLint *length)
+GL_ENTRY(void, glExtGetProgramsQCOM, GLuint *programs, GLint maxPrograms, GLint *numPrograms)
+GL_ENTRY(void, glExtGetRenderbuffersQCOM, GLuint *renderbuffers, GLint maxRenderbuffers, GLint *numRenderbuffers)
+GL_ENTRY(void, glExtGetShadersQCOM, GLuint *shaders, GLint maxShaders, GLint *numShaders)
+GL_ENTRY(void, glExtGetTexLevelParameterivQCOM, GLuint texture, GLenum face, GLint level, GLenum pname, GLint *params)
+GL_ENTRY(void, glExtGetTexSubImageQCOM, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, GLvoid *texels)
+GL_ENTRY(void, glExtGetTexturesQCOM, GLuint *textures, GLint maxTextures, GLint *numTextures)
+GL_ENTRY(GLboolean, glExtIsProgramBinaryQCOM, GLuint program)
+GL_ENTRY(void, glExtTexObjectStateOverrideiQCOM, GLenum target, GLenum pname, GLint param)
+GL_ENTRY(void, glFinish, void)
+GL_ENTRY(void, glFinishFenceNV, GLuint fence)
+GL_ENTRY(void, glFlush, void)
+GL_ENTRY(void, glFogf, GLenum pname, GLfloat param)
+GL_ENTRY(void, glFogfv, GLenum pname, const GLfloat *params)
+GL_ENTRY(void, glFogx, GLenum pname, GLfixed param)
+GL_ENTRY(void, glFogxOES, GLenum pname, GLfixed param)
+GL_ENTRY(void, glFogxv, GLenum pname, const GLfixed *params)
+GL_ENTRY(void, glFogxvOES, GLenum pname, const GLfixed *params)
+GL_ENTRY(void, glFramebufferRenderbuffer, GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer)
+GL_ENTRY(void, glFramebufferRenderbufferOES, GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer)
+GL_ENTRY(void, glFramebufferTexture2D, GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level)
+GL_ENTRY(void, glFramebufferTexture2DMultisampleIMG, GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level, GLsizei samples)
+GL_ENTRY(void, glFramebufferTexture2DOES, GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level)
+GL_ENTRY(void, glFramebufferTexture3DOES, GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level, GLint zoffset)
+GL_ENTRY(void, glFrontFace, GLenum mode)
+GL_ENTRY(void, glFrustumf, GLfloat left, GLfloat right, GLfloat bottom, GLfloat top, GLfloat zNear, GLfloat zFar)
+GL_ENTRY(void, glFrustumfOES, GLfloat left, GLfloat right, GLfloat bottom, GLfloat top, GLfloat zNear, GLfloat zFar)
+GL_ENTRY(void, glFrustumx, GLfixed left, GLfixed right, GLfixed bottom, GLfixed top, GLfixed zNear, GLfixed zFar)
+GL_ENTRY(void, glFrustumxOES, GLfixed left, GLfixed right, GLfixed bottom, GLfixed top, GLfixed zNear, GLfixed zFar)
+GL_ENTRY(void, glGenBuffers, GLsizei n, GLuint *buffers)
+GL_ENTRY(void, glGenFencesNV, GLsizei n, GLuint *fences)
+GL_ENTRY(void, glGenFramebuffers, GLsizei n, GLuint* framebuffers)
+GL_ENTRY(void, glGenFramebuffersOES, GLsizei n, GLuint* framebuffers)
+GL_ENTRY(void, glGenPerfMonitorsAMD, GLsizei n, GLuint *monitors)
+GL_ENTRY(void, glGenRenderbuffers, GLsizei n, GLuint* renderbuffers)
+GL_ENTRY(void, glGenRenderbuffersOES, GLsizei n, GLuint* renderbuffers)
+GL_ENTRY(void, glGenTextures, GLsizei n, GLuint *textures)
+GL_ENTRY(void, glGenVertexArraysOES, GLsizei n, GLuint *arrays)
+GL_ENTRY(void, glGenerateMipmap, GLenum target)
+GL_ENTRY(void, glGenerateMipmapOES, GLenum target)
+GL_ENTRY(void, glGetActiveAttrib, GLuint program, GLuint index, GLsizei bufsize, GLsizei* length, GLint* size, GLenum* type, GLchar* name)
+GL_ENTRY(void, glGetActiveUniform, GLuint program, GLuint index, GLsizei bufsize, GLsizei* length, GLint* size, GLenum* type, GLchar* name)
+GL_ENTRY(void, glGetAttachedShaders, GLuint program, GLsizei maxcount, GLsizei* count, GLuint* shaders)
+GL_ENTRY(int, glGetAttribLocation, GLuint program, const GLchar* name)
+GL_ENTRY(void, glGetBooleanv, GLenum pname, GLboolean *params)
+GL_ENTRY(void, glGetBufferParameteriv, GLenum target, GLenum pname, GLint *params)
+GL_ENTRY(void, glGetBufferPointervOES, GLenum target, GLenum pname, GLvoid ** params)
+GL_ENTRY(void, glGetClipPlanef, GLenum pname, GLfloat eqn[4])
+GL_ENTRY(void, glGetClipPlanefOES, GLenum pname, GLfloat eqn[4])
+GL_ENTRY(void, glGetClipPlanex, GLenum pname, GLfixed eqn[4])
+GL_ENTRY(void, glGetClipPlanexOES, GLenum pname, GLfixed eqn[4])
+GL_ENTRY(void, glGetDriverControlStringQCOM, GLuint driverControl, GLsizei bufSize, GLsizei *length, GLchar *driverControlString)
+GL_ENTRY(void, glGetDriverControlsQCOM, GLint *num, GLsizei size, GLuint *driverControls)
+GL_ENTRY(GLenum, glGetError, void)
+GL_ENTRY(void, glGetFenceivNV, GLuint fence, GLenum pname, GLint *params)
+GL_ENTRY(void, glGetFixedv, GLenum pname, GLfixed *params)
+GL_ENTRY(void, glGetFixedvOES, GLenum pname, GLfixed *params)
+GL_ENTRY(void, glGetFloatv, GLenum pname, GLfloat *params)
+GL_ENTRY(void, glGetFramebufferAttachmentParameteriv, GLenum target, GLenum attachment, GLenum pname, GLint* params)
+GL_ENTRY(void, glGetFramebufferAttachmentParameterivOES, GLenum target, GLenum attachment, GLenum pname, GLint* params)
+GL_ENTRY(void, glGetIntegerv, GLenum pname, GLint *params)
+GL_ENTRY(void, glGetLightfv, GLenum light, GLenum pname, GLfloat *params)
+GL_ENTRY(void, glGetLightxv, GLenum light, GLenum pname, GLfixed *params)
+GL_ENTRY(void, glGetLightxvOES, GLenum light, GLenum pname, GLfixed *params)
+GL_ENTRY(void, glGetMaterialfv, GLenum face, GLenum pname, GLfloat *params)
+GL_ENTRY(void, glGetMaterialxv, GLenum face, GLenum pname, GLfixed *params)
+GL_ENTRY(void, glGetMaterialxvOES, GLenum face, GLenum pname, GLfixed *params)
+GL_ENTRY(void, glGetPerfMonitorCounterDataAMD, GLuint monitor, GLenum pname, GLsizei dataSize, GLuint *data, GLint *bytesWritten)
+GL_ENTRY(void, glGetPerfMonitorCounterInfoAMD, GLuint group, GLuint counter, GLenum pname, GLvoid *data)
+GL_ENTRY(void, glGetPerfMonitorCounterStringAMD, GLuint group, GLuint counter, GLsizei bufSize, GLsizei *length, GLchar *counterString)
+GL_ENTRY(void, glGetPerfMonitorCountersAMD, GLuint group, GLint *numCounters, GLint *maxActiveCounters, GLsizei counterSize, GLuint *counters)
+GL_ENTRY(void, glGetPerfMonitorGroupStringAMD, GLuint group, GLsizei bufSize, GLsizei *length, GLchar *groupString)
+GL_ENTRY(void, glGetPerfMonitorGroupsAMD, GLint *numGroups, GLsizei groupsSize, GLuint *groups)
+GL_ENTRY(void, glGetPointerv, GLenum pname, GLvoid **params)
+GL_ENTRY(void, glGetProgramBinaryOES, GLuint program, GLsizei bufSize, GLsizei *length, GLenum *binaryFormat, GLvoid *binary)
+GL_ENTRY(void, glGetProgramInfoLog, GLuint program, GLsizei bufsize, GLsizei* length, GLchar* infolog)
+GL_ENTRY(void, glGetProgramiv, GLuint program, GLenum pname, GLint* params)
+GL_ENTRY(void, glGetRenderbufferParameteriv, GLenum target, GLenum pname, GLint* params)
+GL_ENTRY(void, glGetRenderbufferParameterivOES, GLenum target, GLenum pname, GLint* params)
+GL_ENTRY(void, glGetShaderInfoLog, GLuint shader, GLsizei bufsize, GLsizei* length, GLchar* infolog)
+GL_ENTRY(void, glGetShaderPrecisionFormat, GLenum shadertype, GLenum precisiontype, GLint* range, GLint* precision)
+GL_ENTRY(void, glGetShaderSource, GLuint shader, GLsizei bufsize, GLsizei* length, GLchar* source)
+GL_ENTRY(void, glGetShaderiv, GLuint shader, GLenum pname, GLint* params)
+GL_ENTRY(const GLubyte *, glGetString, GLenum name)
+GL_ENTRY(void, glGetTexEnvfv, GLenum env, GLenum pname, GLfloat *params)
+GL_ENTRY(void, glGetTexEnviv, GLenum env, GLenum pname, GLint *params)
+GL_ENTRY(void, glGetTexEnvxv, GLenum env, GLenum pname, GLfixed *params)
+GL_ENTRY(void, glGetTexEnvxvOES, GLenum env, GLenum pname, GLfixed *params)
+GL_ENTRY(void, glGetTexGenfvOES, GLenum coord, GLenum pname, GLfloat *params)
+GL_ENTRY(void, glGetTexGenivOES, GLenum coord, GLenum pname, GLint *params)
+GL_ENTRY(void, glGetTexGenxvOES, GLenum coord, GLenum pname, GLfixed *params)
+GL_ENTRY(void, glGetTexParameterfv, GLenum target, GLenum pname, GLfloat *params)
+GL_ENTRY(void, glGetTexParameteriv, GLenum target, GLenum pname, GLint *params)
+GL_ENTRY(void, glGetTexParameterxv, GLenum target, GLenum pname, GLfixed *params)
+GL_ENTRY(void, glGetTexParameterxvOES, GLenum target, GLenum pname, GLfixed *params)
+GL_ENTRY(int, glGetUniformLocation, GLuint program, const GLchar* name)
+GL_ENTRY(void, glGetUniformfv, GLuint program, GLint location, GLfloat* params)
+GL_ENTRY(void, glGetUniformiv, GLuint program, GLint location, GLint* params)
+GL_ENTRY(void, glGetVertexAttribPointerv, GLuint index, GLenum pname, GLvoid** pointer)
+GL_ENTRY(void, glGetVertexAttribfv, GLuint index, GLenum pname, GLfloat* params)
+GL_ENTRY(void, glGetVertexAttribiv, GLuint index, GLenum pname, GLint* params)
+GL_ENTRY(void, glHint, GLenum target, GLenum mode)
+GL_ENTRY(GLboolean, glIsBuffer, GLuint buffer)
+GL_ENTRY(GLboolean, glIsEnabled, GLenum cap)
+GL_ENTRY(GLboolean, glIsFenceNV, GLuint fence)
+GL_ENTRY(GLboolean, glIsFramebuffer, GLuint framebuffer)
+GL_ENTRY(GLboolean, glIsFramebufferOES, GLuint framebuffer)
+GL_ENTRY(GLboolean, glIsProgram, GLuint program)
+GL_ENTRY(GLboolean, glIsRenderbuffer, GLuint renderbuffer)
+GL_ENTRY(GLboolean, glIsRenderbufferOES, GLuint renderbuffer)
+GL_ENTRY(GLboolean, glIsShader, GLuint shader)
+GL_ENTRY(GLboolean, glIsTexture, GLuint texture)
+GL_ENTRY(GLboolean, glIsVertexArrayOES, GLuint array)
+GL_ENTRY(void, glLightModelf, GLenum pname, GLfloat param)
+GL_ENTRY(void, glLightModelfv, GLenum pname, const GLfloat *params)
+GL_ENTRY(void, glLightModelx, GLenum pname, GLfixed param)
+GL_ENTRY(void, glLightModelxOES, GLenum pname, GLfixed param)
+GL_ENTRY(void, glLightModelxv, GLenum pname, const GLfixed *params)
+GL_ENTRY(void, glLightModelxvOES, GLenum pname, const GLfixed *params)
+GL_ENTRY(void, glLightf, GLenum light, GLenum pname, GLfloat param)
+GL_ENTRY(void, glLightfv, GLenum light, GLenum pname, const GLfloat *params)
+GL_ENTRY(void, glLightx, GLenum light, GLenum pname, GLfixed param)
+GL_ENTRY(void, glLightxOES, GLenum light, GLenum pname, GLfixed param)
+GL_ENTRY(void, glLightxv, GLenum light, GLenum pname, const GLfixed *params)
+GL_ENTRY(void, glLightxvOES, GLenum light, GLenum pname, const GLfixed *params)
+GL_ENTRY(void, glLineWidth, GLfloat width)
+GL_ENTRY(void, glLineWidthx, GLfixed width)
+GL_ENTRY(void, glLineWidthxOES, GLfixed width)
+GL_ENTRY(void, glLinkProgram, GLuint program)
+GL_ENTRY(void, glLoadIdentity, void)
+GL_ENTRY(void, glLoadMatrixf, const GLfloat *m)
+GL_ENTRY(void, glLoadMatrixx, const GLfixed *m)
+GL_ENTRY(void, glLoadMatrixxOES, const GLfixed *m)
+GL_ENTRY(void, glLoadPaletteFromModelViewMatrixOES, void)
+GL_ENTRY(void, glLogicOp, GLenum opcode)
+GL_ENTRY(void*, glMapBufferOES, GLenum target, GLenum access)
+GL_ENTRY(void, glMaterialf, GLenum face, GLenum pname, GLfloat param)
+GL_ENTRY(void, glMaterialfv, GLenum face, GLenum pname, const GLfloat *params)
+GL_ENTRY(void, glMaterialx, GLenum face, GLenum pname, GLfixed param)
+GL_ENTRY(void, glMaterialxOES, GLenum face, GLenum pname, GLfixed param)
+GL_ENTRY(void, glMaterialxv, GLenum face, GLenum pname, const GLfixed *params)
+GL_ENTRY(void, glMaterialxvOES, GLenum face, GLenum pname, const GLfixed *params)
+GL_ENTRY(void, glMatrixIndexPointerOES, GLint size, GLenum type, GLsizei stride, const GLvoid *pointer)
+GL_ENTRY(void, glMatrixMode, GLenum mode)
+GL_ENTRY(void, glMultMatrixf, const GLfloat *m)
+GL_ENTRY(void, glMultMatrixx, const GLfixed *m)
+GL_ENTRY(void, glMultMatrixxOES, const GLfixed *m)
+GL_ENTRY(void, glMultiDrawArraysEXT, GLenum mode, GLint *first, GLsizei *count, GLsizei primcount)
+GL_ENTRY(void, glMultiDrawElementsEXT, GLenum mode, const GLsizei *count, GLenum type, const GLvoid* *indices, GLsizei primcount)
+GL_ENTRY(void, glMultiTexCoord4f, GLenum target, GLfloat s, GLfloat t, GLfloat r, GLfloat q)
+GL_ENTRY(void, glMultiTexCoord4x, GLenum target, GLfixed s, GLfixed t, GLfixed r, GLfixed q)
+GL_ENTRY(void, glMultiTexCoord4xOES, GLenum target, GLfixed s, GLfixed t, GLfixed r, GLfixed q)
+GL_ENTRY(void, glNormal3f, GLfloat nx, GLfloat ny, GLfloat nz)
+GL_ENTRY(void, glNormal3x, GLfixed nx, GLfixed ny, GLfixed nz)
+GL_ENTRY(void, glNormal3xOES, GLfixed nx, GLfixed ny, GLfixed nz)
+GL_ENTRY(void, glNormalPointer, GLenum type, GLsizei stride, const GLvoid *pointer)
+GL_ENTRY(void, glOrthof, GLfloat left, GLfloat right, GLfloat bottom, GLfloat top, GLfloat zNear, GLfloat zFar)
+GL_ENTRY(void, glOrthofOES, GLfloat left, GLfloat right, GLfloat bottom, GLfloat top, GLfloat zNear, GLfloat zFar)
+GL_ENTRY(void, glOrthox, GLfixed left, GLfixed right, GLfixed bottom, GLfixed top, GLfixed zNear, GLfixed zFar)
+GL_ENTRY(void, glOrthoxOES, GLfixed left, GLfixed right, GLfixed bottom, GLfixed top, GLfixed zNear, GLfixed zFar)
+GL_ENTRY(void, glPixelStorei, GLenum pname, GLint param)
+GL_ENTRY(void, glPointParameterf, GLenum pname, GLfloat param)
+GL_ENTRY(void, glPointParameterfv, GLenum pname, const GLfloat *params)
+GL_ENTRY(void, glPointParameterx, GLenum pname, GLfixed param)
+GL_ENTRY(void, glPointParameterxOES, GLenum pname, GLfixed param)
+GL_ENTRY(void, glPointParameterxv, GLenum pname, const GLfixed *params)
+GL_ENTRY(void, glPointParameterxvOES, GLenum pname, const GLfixed *params)
+GL_ENTRY(void, glPointSize, GLfloat size)
+GL_ENTRY(void, glPointSizePointerOES, GLenum type, GLsizei stride, const GLvoid *pointer)
+GL_ENTRY(void, glPointSizex, GLfixed size)
+GL_ENTRY(void, glPointSizexOES, GLfixed size)
+GL_ENTRY(void, glPolygonOffset, GLfloat factor, GLfloat units)
+GL_ENTRY(void, glPolygonOffsetx, GLfixed factor, GLfixed units)
+GL_ENTRY(void, glPolygonOffsetxOES, GLfixed factor, GLfixed units)
+GL_ENTRY(void, glPopMatrix, void)
+GL_ENTRY(void, glProgramBinaryOES, GLuint program, GLenum binaryFormat, const GLvoid *binary, GLint length)
+GL_ENTRY(void, glPushMatrix, void)
+GL_ENTRY(GLbitfield, glQueryMatrixxOES, GLfixed mantissa[16], GLint exponent[16])
+GL_ENTRY(void, glReadPixels, GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLvoid *pixels)
+GL_ENTRY(void, glReleaseShaderCompiler, void)
+GL_ENTRY(void, glRenderbufferStorage, GLenum target, GLenum internalformat, GLsizei width, GLsizei height)
+GL_ENTRY(void, glRenderbufferStorageMultisampleIMG, GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height)
+GL_ENTRY(void, glRenderbufferStorageOES, GLenum target, GLenum internalformat, GLsizei width, GLsizei height)
+GL_ENTRY(void, glRotatef, GLfloat angle, GLfloat x, GLfloat y, GLfloat z)
+GL_ENTRY(void, glRotatex, GLfixed angle, GLfixed x, GLfixed y, GLfixed z)
+GL_ENTRY(void, glRotatexOES, GLfixed angle, GLfixed x, GLfixed y, GLfixed z)
+GL_ENTRY(void, glSampleCoverage, GLclampf value, GLboolean invert)
+GL_ENTRY(void, glSampleCoveragex, GLclampx value, GLboolean invert)
+GL_ENTRY(void, glSampleCoveragexOES, GLclampx value, GLboolean invert)
+GL_ENTRY(void, glScalef, GLfloat x, GLfloat y, GLfloat z)
+GL_ENTRY(void, glScalex, GLfixed x, GLfixed y, GLfixed z)
+GL_ENTRY(void, glScalexOES, GLfixed x, GLfixed y, GLfixed z)
+GL_ENTRY(void, glScissor, GLint x, GLint y, GLsizei width, GLsizei height)
+GL_ENTRY(void, glSelectPerfMonitorCountersAMD, GLuint monitor, GLboolean enable, GLuint group, GLint numCounters, GLuint *countersList)
+GL_ENTRY(void, glSetFenceNV, GLuint fence, GLenum condition)
+GL_ENTRY(void, glShadeModel, GLenum mode)
+GL_ENTRY(void, glShaderBinary, GLsizei n, const GLuint* shaders, GLenum binaryformat, const GLvoid* binary, GLsizei length)
+GL_ENTRY(void, glShaderSource, GLuint shader, GLsizei count, const GLchar** string, const GLint* length)
+GL_ENTRY(void, glStartTilingQCOM, GLuint x, GLuint y, GLuint width, GLuint height, GLbitfield preserveMask)
+GL_ENTRY(void, glStencilFunc, GLenum func, GLint ref, GLuint mask)
+GL_ENTRY(void, glStencilFuncSeparate, GLenum face, GLenum func, GLint ref, GLuint mask)
+GL_ENTRY(void, glStencilMask, GLuint mask)
+GL_ENTRY(void, glStencilMaskSeparate, GLenum face, GLuint mask)
+GL_ENTRY(void, glStencilOp, GLenum fail, GLenum zfail, GLenum zpass)
+GL_ENTRY(void, glStencilOpSeparate, GLenum face, GLenum fail, GLenum zfail, GLenum zpass)
+GL_ENTRY(GLboolean, glTestFenceNV, GLuint fence)
+GL_ENTRY(void, glTexCoordPointer, GLint size, GLenum type, GLsizei stride, const GLvoid *pointer)
+GL_ENTRY(void, glTexEnvf, GLenum target, GLenum pname, GLfloat param)
+GL_ENTRY(void, glTexEnvfv, GLenum target, GLenum pname, const GLfloat *params)
+GL_ENTRY(void, glTexEnvi, GLenum target, GLenum pname, GLint param)
+GL_ENTRY(void, glTexEnviv, GLenum target, GLenum pname, const GLint *params)
+GL_ENTRY(void, glTexEnvx, GLenum target, GLenum pname, GLfixed param)
+GL_ENTRY(void, glTexEnvxOES, GLenum target, GLenum pname, GLfixed param)
+GL_ENTRY(void, glTexEnvxv, GLenum target, GLenum pname, const GLfixed *params)
+GL_ENTRY(void, glTexEnvxvOES, GLenum target, GLenum pname, const GLfixed *params)
+GL_ENTRY(void, glTexGenfOES, GLenum coord, GLenum pname, GLfloat param)
+GL_ENTRY(void, glTexGenfvOES, GLenum coord, GLenum pname, const GLfloat *params)
+GL_ENTRY(void, glTexGeniOES, GLenum coord, GLenum pname, GLint param)
+GL_ENTRY(void, glTexGenivOES, GLenum coord, GLenum pname, const GLint *params)
+GL_ENTRY(void, glTexGenxOES, GLenum coord, GLenum pname, GLfixed param)
+GL_ENTRY(void, glTexGenxvOES, GLenum coord, GLenum pname, const GLfixed *params)
+GL_ENTRY(void, glTexImage2D, GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const GLvoid *pixels)
+GL_ENTRY(void, glTexImage3DOES, GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const GLvoid* pixels)
+GL_ENTRY(void, glTexParameterf, GLenum target, GLenum pname, GLfloat param)
+GL_ENTRY(void, glTexParameterfv, GLenum target, GLenum pname, const GLfloat *params)
+GL_ENTRY(void, glTexParameteri, GLenum target, GLenum pname, GLint param)
+GL_ENTRY(void, glTexParameteriv, GLenum target, GLenum pname, const GLint *params)
+GL_ENTRY(void, glTexParameterx, GLenum target, GLenum pname, GLfixed param)
+GL_ENTRY(void, glTexParameterxOES, GLenum target, GLenum pname, GLfixed param)
+GL_ENTRY(void, glTexParameterxv, GLenum target, GLenum pname, const GLfixed *params)
+GL_ENTRY(void, glTexParameterxvOES, GLenum target, GLenum pname, const GLfixed *params)
+GL_ENTRY(void, glTexSubImage2D, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *pixels)
+GL_ENTRY(void, glTexSubImage3DOES, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const GLvoid* pixels)
+GL_ENTRY(void, glTranslatef, GLfloat x, GLfloat y, GLfloat z)
+GL_ENTRY(void, glTranslatex, GLfixed x, GLfixed y, GLfixed z)
+GL_ENTRY(void, glTranslatexOES, GLfixed x, GLfixed y, GLfixed z)
+GL_ENTRY(void, glUniform1f, GLint location, GLfloat x)
+GL_ENTRY(void, glUniform1fv, GLint location, GLsizei count, const GLfloat* v)
+GL_ENTRY(void, glUniform1i, GLint location, GLint x)
+GL_ENTRY(void, glUniform1iv, GLint location, GLsizei count, const GLint* v)
+GL_ENTRY(void, glUniform2f, GLint location, GLfloat x, GLfloat y)
+GL_ENTRY(void, glUniform2fv, GLint location, GLsizei count, const GLfloat* v)
+GL_ENTRY(void, glUniform2i, GLint location, GLint x, GLint y)
+GL_ENTRY(void, glUniform2iv, GLint location, GLsizei count, const GLint* v)
+GL_ENTRY(void, glUniform3f, GLint location, GLfloat x, GLfloat y, GLfloat z)
+GL_ENTRY(void, glUniform3fv, GLint location, GLsizei count, const GLfloat* v)
+GL_ENTRY(void, glUniform3i, GLint location, GLint x, GLint y, GLint z)
+GL_ENTRY(void, glUniform3iv, GLint location, GLsizei count, const GLint* v)
+GL_ENTRY(void, glUniform4f, GLint location, GLfloat x, GLfloat y, GLfloat z, GLfloat w)
+GL_ENTRY(void, glUniform4fv, GLint location, GLsizei count, const GLfloat* v)
+GL_ENTRY(void, glUniform4i, GLint location, GLint x, GLint y, GLint z, GLint w)
+GL_ENTRY(void, glUniform4iv, GLint location, GLsizei count, const GLint* v)
+GL_ENTRY(void, glUniformMatrix2fv, GLint location, GLsizei count, GLboolean transpose, const GLfloat* value)
+GL_ENTRY(void, glUniformMatrix3fv, GLint location, GLsizei count, GLboolean transpose, const GLfloat* value)
+GL_ENTRY(void, glUniformMatrix4fv, GLint location, GLsizei count, GLboolean transpose, const GLfloat* value)
+GL_ENTRY(GLboolean, glUnmapBufferOES, GLenum target)
+GL_ENTRY(void, glUseProgram, GLuint program)
+GL_ENTRY(void, glValidateProgram, GLuint program)
+GL_ENTRY(void, glVertexAttrib1f, GLuint indx, GLfloat x)
+GL_ENTRY(void, glVertexAttrib1fv, GLuint indx, const GLfloat* values)
+GL_ENTRY(void, glVertexAttrib2f, GLuint indx, GLfloat x, GLfloat y)
+GL_ENTRY(void, glVertexAttrib2fv, GLuint indx, const GLfloat* values)
+GL_ENTRY(void, glVertexAttrib3f, GLuint indx, GLfloat x, GLfloat y, GLfloat z)
+GL_ENTRY(void, glVertexAttrib3fv, GLuint indx, const GLfloat* values)
+GL_ENTRY(void, glVertexAttrib4f, GLuint indx, GLfloat x, GLfloat y, GLfloat z, GLfloat w)
+GL_ENTRY(void, glVertexAttrib4fv, GLuint indx, const GLfloat* values)
+GL_ENTRY(void, glVertexAttribPointer, GLuint indx, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const GLvoid* ptr)
+GL_ENTRY(void, glVertexPointer, GLint size, GLenum type, GLsizei stride, const GLvoid *pointer)
+GL_ENTRY(void, glViewport, GLint x, GLint y, GLsizei width, GLsizei height)
+GL_ENTRY(void, glWeightPointerOES, GLint size, GLenum type, GLsizei stride, const GLvoid *pointer)
+
+
+}
diff --git a/opengl/tests/gl2_jni/Android.mk b/opengl/tests/gl2_jni/Android.mk
index 384966c..e8b6c57 100644
--- a/opengl/tests/gl2_jni/Android.mk
+++ b/opengl/tests/gl2_jni/Android.mk
@@ -44,7 +44,7 @@
 
 LOCAL_MODULE := libgl2jni
 
-LOCAL_PRELINK_MODULE := false
+
 
 include $(BUILD_SHARED_LIBRARY)
 
diff --git a/opengl/tests/gl2_yuvtex/gl2_yuvtex.cpp b/opengl/tests/gl2_yuvtex/gl2_yuvtex.cpp
index 602ea1a..f0b8d12 100644
--- a/opengl/tests/gl2_yuvtex/gl2_yuvtex.cpp
+++ b/opengl/tests/gl2_yuvtex/gl2_yuvtex.cpp
@@ -186,11 +186,6 @@
         GraphicBuffer::USAGE_SW_WRITE_RARELY;
 const int yuvTexFormat = HAL_PIXEL_FORMAT_YV12;
 const int yuvTexOffsetY = 0;
-const int yuvTexStrideY = (yuvTexWidth + 0xf) & ~0xf;
-const int yuvTexOffsetV = yuvTexStrideY * yuvTexHeight;
-const int yuvTexStrideV = (yuvTexStrideY/2 + 0xf) & ~0xf; 
-const int yuvTexOffsetU = yuvTexOffsetV + yuvTexStrideV * yuvTexHeight/2;
-const int yuvTexStrideU = yuvTexStrideV;
 const bool yuvTexSameUV = false;
 static sp<GraphicBuffer> yuvTexBuffer;
 static GLuint yuvTex;
@@ -200,6 +195,11 @@
     int blockHeight = yuvTexHeight > 16 ? yuvTexHeight / 16 : 1;
     yuvTexBuffer = new GraphicBuffer(yuvTexWidth, yuvTexHeight, yuvTexFormat,
             yuvTexUsage);
+    int yuvTexStrideY = yuvTexBuffer->getStride();
+    int yuvTexOffsetV = yuvTexStrideY * yuvTexHeight;
+    int yuvTexStrideV = (yuvTexStrideY/2 + 0xf) & ~0xf;
+    int yuvTexOffsetU = yuvTexOffsetV + yuvTexStrideV * yuvTexHeight/2;
+    int yuvTexStrideU = yuvTexStrideV;
     char* buf = NULL;
     status_t err = yuvTexBuffer->lock(GRALLOC_USAGE_SW_WRITE_OFTEN, (void**)(&buf));
     if (err != 0) {
diff --git a/opengl/tests/gl_jni/Android.mk b/opengl/tests/gl_jni/Android.mk
index f1bd31d..4acd91f 100644
--- a/opengl/tests/gl_jni/Android.mk
+++ b/opengl/tests/gl_jni/Android.mk
@@ -46,7 +46,7 @@
 
 LOCAL_ARM_MODE := arm
 
-LOCAL_PRELINK_MODULE := false
+
 
 include $(BUILD_SHARED_LIBRARY)
 
diff --git a/opengl/tests/gl_perfapp/Android.mk b/opengl/tests/gl_perfapp/Android.mk
index dd75a74..4b79569 100644
--- a/opengl/tests/gl_perfapp/Android.mk
+++ b/opengl/tests/gl_perfapp/Android.mk
@@ -47,7 +47,7 @@
 
 LOCAL_MODULE := libglperf
 
-LOCAL_PRELINK_MODULE := false
+
 
 include $(BUILD_SHARED_LIBRARY)
 
diff --git a/opengl/tests/gldual/Android.mk b/opengl/tests/gldual/Android.mk
index 995a5d7..f1a998a 100644
--- a/opengl/tests/gldual/Android.mk
+++ b/opengl/tests/gldual/Android.mk
@@ -44,7 +44,7 @@
 
 LOCAL_MODULE := libgldualjni
 
-LOCAL_PRELINK_MODULE := false
+
 
 include $(BUILD_SHARED_LIBRARY)
 
diff --git a/opengl/tests/hwc/Android.mk b/opengl/tests/hwc/Android.mk
index 6312970..e4d7e28 100644
--- a/opengl/tests/hwc/Android.mk
+++ b/opengl/tests/hwc/Android.mk
@@ -29,7 +29,7 @@
 
 LOCAL_SHARED_LIBRARIES += libcutils libutils libstlport
 LOCAL_STATIC_LIBRARIES += libglTest
-LOCAL_PRELINK_MODULE := false
+
 
 include $(BUILD_STATIC_LIBRARY)
 
diff --git a/opengl/tests/lib/Android.mk b/opengl/tests/lib/Android.mk
index 7542ac4..ac1e183 100644
--- a/opengl/tests/lib/Android.mk
+++ b/opengl/tests/lib/Android.mk
@@ -27,6 +27,6 @@
 LOCAL_CFLAGS := -DGL_GLEXT_PROTOTYPES -DEGL_EGLEXT_PROTOTYPES
 
 LOCAL_SHARED_LIBRARIES += libcutils libutils libstlport
-LOCAL_PRELINK_MODULE := false
+
 
 include $(BUILD_STATIC_LIBRARY)
diff --git a/packages/DefaultContainerService/jni/Android.mk b/packages/DefaultContainerService/jni/Android.mk
index a2febec..79ff451 100644
--- a/packages/DefaultContainerService/jni/Android.mk
+++ b/packages/DefaultContainerService/jni/Android.mk
@@ -18,7 +18,7 @@
 
 include $(CLEAR_VARS)
 
-LOCAL_PRELINK_MODULE := false
+
 
 LOCAL_SRC_FILES := \
     com_android_defcontainer_MeasurementUtils.cpp
diff --git a/packages/DefaultContainerService/src/com/android/defcontainer/DefaultContainerService.java b/packages/DefaultContainerService/src/com/android/defcontainer/DefaultContainerService.java
index 21f77e3..15c1653 100644
--- a/packages/DefaultContainerService/src/com/android/defcontainer/DefaultContainerService.java
+++ b/packages/DefaultContainerService/src/com/android/defcontainer/DefaultContainerService.java
@@ -47,7 +47,7 @@
 import java.io.FileOutputStream;
 import java.io.IOException;
 import java.io.InputStream;
-import java.util.LinkedList;
+import java.util.ArrayList;
 import java.util.List;
 import java.util.zip.ZipEntry;
 import java.util.zip.ZipException;
@@ -117,7 +117,7 @@
          * @return Returns PackageInfoLite object containing
          * the package info and recommended app location.
          */
-        public PackageInfoLite getMinimalPackageInfo(final Uri fileUri, int flags) {
+        public PackageInfoLite getMinimalPackageInfo(final Uri fileUri, int flags, long threshold) {
             PackageInfoLite ret = new PackageInfoLite();
             if (fileUri == null) {
                 Log.i(TAG, "Invalid package uri " + fileUri);
@@ -131,15 +131,9 @@
                 return ret;
             }
             String archiveFilePath = fileUri.getPath();
-            PackageParser packageParser = new PackageParser(archiveFilePath);
-            File sourceFile = new File(archiveFilePath);
             DisplayMetrics metrics = new DisplayMetrics();
             metrics.setToDefaults();
-            PackageParser.PackageLite pkg = packageParser.parsePackageLite(
-                    archiveFilePath, 0);
-            // Nuke the parser reference right away and force a gc
-            packageParser = null;
-            Runtime.getRuntime().gc();
+            PackageParser.PackageLite pkg = PackageParser.parsePackageLite(archiveFilePath, 0);
             if (pkg == null) {
                 Log.w(TAG, "Failed to parse package");
                 ret.recommendedInstallLocation = PackageHelper.RECOMMEND_FAILED_INVALID_APK;
@@ -147,12 +141,22 @@
             }
             ret.packageName = pkg.packageName;
             ret.installLocation = pkg.installLocation;
-            ret.recommendedInstallLocation = recommendAppInstallLocation(pkg.installLocation, archiveFilePath, flags);
+            ret.recommendedInstallLocation = recommendAppInstallLocation(pkg.installLocation,
+                    archiveFilePath, flags, threshold);
             return ret;
         }
 
-        public boolean checkFreeStorage(boolean external, Uri fileUri) {
-            return checkFreeStorageInner(external, fileUri);
+        @Override
+        public boolean checkInternalFreeStorage(Uri packageUri, long threshold)
+                throws RemoteException {
+            final File apkFile = new File(packageUri.getPath());
+            return isUnderInternalThreshold(apkFile, threshold);
+        }
+
+        @Override
+        public boolean checkExternalFreeStorage(Uri packageUri) throws RemoteException {
+            final File apkFile = new File(packageUri.getPath());
+            return isUnderExternalThreshold(apkFile);
         }
 
         public ObbInfo getObbInfo(String filename) {
@@ -225,41 +229,15 @@
         String codePath = packageURI.getPath();
         File codeFile = new File(codePath);
 
+        // Native files we need to copy to the container.
+        List<Pair<ZipEntry, String>> nativeFiles = new ArrayList<Pair<ZipEntry, String>>();
+
         // Calculate size of container needed to hold base APK.
-        long sizeBytes = codeFile.length();
-
-        // Check all the native files that need to be copied and add that to the container size.
-        ZipFile zipFile;
-        List<Pair<ZipEntry, String>> nativeFiles;
-        try {
-            zipFile = new ZipFile(codeFile);
-
-            nativeFiles = new LinkedList<Pair<ZipEntry, String>>();
-
-            NativeLibraryHelper.listPackageNativeBinariesLI(zipFile, nativeFiles);
-
-            final int N = nativeFiles.size();
-            for (int i = 0; i < N; i++) {
-                final Pair<ZipEntry, String> entry = nativeFiles.get(i);
-
-                /*
-                 * Note that PackageHelper.createSdDir adds a 1MB padding on
-                 * our claimed size, so we don't have to worry about block
-                 * alignment here.
-                 */
-                sizeBytes += entry.first.getSize();
-            }
-        } catch (ZipException e) {
-            Log.w(TAG, "Failed to extract data from package file", e);
-            return null;
-        } catch (IOException e) {
-            Log.w(TAG, "Failed to cache package shared libs", e);
-            return null;
-        }
+        final int sizeMb = calculateContainerSize(codeFile, nativeFiles);
 
         // Create new container
         String newCachePath = null;
-        if ((newCachePath = PackageHelper.createSdDir(sizeBytes, newCid, key, Process.myUid())) == null) {
+        if ((newCachePath = PackageHelper.createSdDir(sizeMb, newCid, key, Process.myUid())) == null) {
             Log.e(TAG, "Failed to create container " + newCid);
             return null;
         }
@@ -274,6 +252,8 @@
         }
 
         try {
+            ZipFile zipFile = new ZipFile(codeFile);
+
             File sharedLibraryDir = new File(newCachePath, LIB_DIR_NAME);
             sharedLibraryDir.mkdir();
 
@@ -386,159 +366,196 @@
         return true;
     }
 
-    // Constants related to app heuristics
-    // No-installation limit for internal flash: 10% or less space available
-    private static final double LOW_NAND_FLASH_TRESHOLD = 0.1;
+    private static final int PREFER_INTERNAL = 1;
+    private static final int PREFER_EXTERNAL = 2;
 
-    // SD-to-internal app size threshold: currently set to 1 MB
-    private static final long INSTALL_ON_SD_THRESHOLD = (1024 * 1024);
-    private static final int ERR_LOC = -1;
-
-    private int recommendAppInstallLocation(int installLocation,
-            String archiveFilePath, int flags) {
-        boolean checkInt = false;
-        boolean checkExt = false;
+    private int recommendAppInstallLocation(int installLocation, String archiveFilePath, int flags,
+            long threshold) {
+        int prefer;
         boolean checkBoth = false;
+
         check_inner : {
-            // Check flags.
+            /*
+             * Explicit install flags should override the manifest settings.
+             */
             if ((flags & PackageManager.INSTALL_FORWARD_LOCK) != 0) {
-                // Check for forward locked app
-                checkInt = true;
+                /*
+                 * Forward-locked applications cannot be installed on SD card,
+                 * so only allow checking internal storage.
+                 */
+                prefer = PREFER_INTERNAL;
                 break check_inner;
             } else if ((flags & PackageManager.INSTALL_INTERNAL) != 0) {
-                // Explicit flag to install internally.
-                // Check internal storage and return
-                checkInt = true;
+                prefer = PREFER_INTERNAL;
                 break check_inner;
             } else if ((flags & PackageManager.INSTALL_EXTERNAL) != 0) {
-                // Explicit flag to install externally.
-                // Check external storage and return
-                checkExt = true;
+                prefer = PREFER_EXTERNAL;
                 break check_inner;
             }
-            // Check for manifest option
+
+            /* No install flags. Check for manifest option. */
             if (installLocation == PackageInfo.INSTALL_LOCATION_INTERNAL_ONLY) {
-                checkInt = true;
+                prefer = PREFER_INTERNAL;
                 break check_inner;
             } else if (installLocation == PackageInfo.INSTALL_LOCATION_PREFER_EXTERNAL) {
-                checkExt = true;
+                prefer = PREFER_EXTERNAL;
                 checkBoth = true;
                 break check_inner;
             } else if (installLocation == PackageInfo.INSTALL_LOCATION_AUTO) {
-                checkInt = true;
+                // We default to preferring internal storage.
+                prefer = PREFER_INTERNAL;
                 checkBoth = true;
                 break check_inner;
             }
+
             // Pick user preference
             int installPreference = Settings.System.getInt(getApplicationContext()
                     .getContentResolver(),
                     Settings.Secure.DEFAULT_INSTALL_LOCATION,
                     PackageHelper.APP_INSTALL_AUTO);
             if (installPreference == PackageHelper.APP_INSTALL_INTERNAL) {
-                checkInt = true;
+                prefer = PREFER_INTERNAL;
                 break check_inner;
             } else if (installPreference == PackageHelper.APP_INSTALL_EXTERNAL) {
-                checkExt = true;
+                prefer = PREFER_EXTERNAL;
                 break check_inner;
             }
-            // Fall back to default policy if nothing else is specified.
-            checkInt = true;
+
+            /*
+             * Fall back to default policy of internal-only if nothing else is
+             * specified.
+             */
+            prefer = PREFER_INTERNAL;
         }
 
-        // Package size = code size + cache size + data size
-        // If code size > 1 MB, install on SD card.
-        // Else install on internal NAND flash, unless space on NAND is less than 10%
-        String status = Environment.getExternalStorageState();
-        long availSDSize = -1;
-        boolean mediaAvailable = false;
-        if (!Environment.isExternalStorageEmulated() && status.equals(Environment.MEDIA_MOUNTED)) {
-            StatFs sdStats = new StatFs(
-                    Environment.getExternalStorageDirectory().getPath());
-            availSDSize = (long)sdStats.getAvailableBlocks() *
-                    (long)sdStats.getBlockSize();
-            mediaAvailable = true;
+        final boolean emulated = Environment.isExternalStorageEmulated();
+
+        final File apkFile = new File(archiveFilePath);
+
+        boolean fitsOnInternal = false;
+        if (checkBoth || prefer == PREFER_INTERNAL) {
+            fitsOnInternal = isUnderInternalThreshold(apkFile, threshold);
         }
-        StatFs internalStats = new StatFs(Environment.getDataDirectory().getPath());
-        long totalInternalSize = (long)internalStats.getBlockCount() *
-                (long)internalStats.getBlockSize();
-        long availInternalSize = (long)internalStats.getAvailableBlocks() *
-                (long)internalStats.getBlockSize();
 
-        double pctNandFree = (double)availInternalSize / (double)totalInternalSize;
-
-        File apkFile = new File(archiveFilePath);
-        long pkgLen = apkFile.length();
-        
-        // To make final copy
-        long reqInstallSize = pkgLen;
-        // For dex files. Just ignore and fail when extracting. Max limit of 2Gig for now.
-        long reqInternalSize = 0;
-        boolean intThresholdOk = (pctNandFree >= LOW_NAND_FLASH_TRESHOLD);
-        boolean intAvailOk = ((reqInstallSize + reqInternalSize) < availInternalSize);
         boolean fitsOnSd = false;
-        if (mediaAvailable && (reqInstallSize < availSDSize)) {
-            // If we do not have an internal size requirement
-            // don't do a threshold check.
-            if (reqInternalSize == 0) {
-                fitsOnSd = true;
-            } else if ((reqInternalSize < availInternalSize) && intThresholdOk) {
-                fitsOnSd = true;
-            }
+        if (!emulated && (checkBoth || prefer == PREFER_EXTERNAL)) {
+            fitsOnSd = isUnderExternalThreshold(apkFile);
         }
-        boolean fitsOnInt = intThresholdOk && intAvailOk;
-        if (checkInt) {
-            // Check for internal memory availability
-            if (fitsOnInt) {
+
+        if (prefer == PREFER_INTERNAL) {
+            if (fitsOnInternal) {
                 return PackageHelper.RECOMMEND_INSTALL_INTERNAL;
             }
-        } else if (checkExt) {
+        } else if (!emulated && prefer == PREFER_EXTERNAL) {
             if (fitsOnSd) {
                 return PackageHelper.RECOMMEND_INSTALL_EXTERNAL;
             }
         }
+
         if (checkBoth) {
-            // Check for internal first
-            if (fitsOnInt) {
+            if (fitsOnInternal) {
                 return PackageHelper.RECOMMEND_INSTALL_INTERNAL;
-            }
-            // Check for external next
-            if (fitsOnSd) {
+            } else if (!emulated && fitsOnSd) {
                 return PackageHelper.RECOMMEND_INSTALL_EXTERNAL;
             }
         }
-        if ((checkExt || checkBoth) && !mediaAvailable) {
+
+        /*
+         * If they requested to be on the external media by default, return that
+         * the media was unavailable. Otherwise, indicate there was insufficient
+         * storage space available.
+         */
+        if (!emulated && (checkBoth || prefer == PREFER_EXTERNAL)
+                && !Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState())) {
             return PackageHelper.RECOMMEND_MEDIA_UNAVAILABLE;
+        } else {
+            return PackageHelper.RECOMMEND_FAILED_INSUFFICIENT_STORAGE;
         }
-        return PackageHelper.RECOMMEND_FAILED_INSUFFICIENT_STORAGE;
     }
 
-    private boolean checkFreeStorageInner(boolean external, Uri packageURI) {
-        File apkFile = new File(packageURI.getPath());
-        long size = apkFile.length();
-        if (external) {
-            String status = Environment.getExternalStorageState();
-            long availSDSize = -1;
-            if (status.equals(Environment.MEDIA_MOUNTED)) {
-                StatFs sdStats = new StatFs(
-                        Environment.getExternalStorageDirectory().getPath());
-                availSDSize = (long)sdStats.getAvailableBlocks() *
-                (long)sdStats.getBlockSize();
-            }
-            return availSDSize > size;
-        }
-        StatFs internalStats = new StatFs(Environment.getDataDirectory().getPath());
-        long totalInternalSize = (long)internalStats.getBlockCount() *
-        (long)internalStats.getBlockSize();
-        long availInternalSize = (long)internalStats.getAvailableBlocks() *
-        (long)internalStats.getBlockSize();
+    private boolean isUnderInternalThreshold(File apkFile, long threshold) {
+        final long size = apkFile.length();
 
-        double pctNandFree = (double)availInternalSize / (double)totalInternalSize;
-        // To make final copy
-        long reqInstallSize = size;
-        // For dex files. Just ignore and fail when extracting. Max limit of 2Gig for now.
-        long reqInternalSize = 0;
-        boolean intThresholdOk = (pctNandFree >= LOW_NAND_FLASH_TRESHOLD);
-        boolean intAvailOk = ((reqInstallSize + reqInternalSize) < availInternalSize);
-        return intThresholdOk && intAvailOk;
+        final StatFs internalStats = new StatFs(Environment.getDataDirectory().getPath());
+        final long availInternalSize = (long) internalStats.getAvailableBlocks()
+                * (long) internalStats.getBlockSize();
+
+        return (availInternalSize - size) > threshold;
+    }
+
+
+    private boolean isUnderExternalThreshold(File apkFile) {
+        if (Environment.isExternalStorageEmulated()) {
+            return false;
+        }
+
+        final int sizeMb = calculateContainerSize(apkFile, null);
+
+        final int availSdMb;
+        if (Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState())) {
+            StatFs sdStats = new StatFs(Environment.getExternalStorageDirectory().getPath());
+            long availSdSize = (long) (sdStats.getAvailableBlocks() * sdStats.getBlockSize());
+            availSdMb = (int) (availSdSize >> 20);
+        } else {
+            availSdMb = -1;
+        }
+
+        return availSdMb > sizeMb;
+    }
+
+    /**
+     * Calculate the container size for an APK. Takes into account the
+     * 
+     * @param apkFile file from which to calculate size
+     * @return size in megabytes (2^20 bytes)
+     */
+    private int calculateContainerSize(File apkFile, List<Pair<ZipEntry, String>> outFiles) {
+        // Calculate size of container needed to hold base APK.
+        long sizeBytes = apkFile.length();
+
+        // Check all the native files that need to be copied and add that to the
+        // container size.
+        ZipFile zipFile;
+        final List<Pair<ZipEntry, String>> nativeFiles;
+        try {
+            zipFile = new ZipFile(apkFile);
+
+            if (outFiles != null) {
+                nativeFiles = outFiles;
+            } else {
+                nativeFiles = new ArrayList<Pair<ZipEntry, String>>();
+            }
+
+            NativeLibraryHelper.listPackageNativeBinariesLI(zipFile, nativeFiles);
+
+            final int N = nativeFiles.size();
+            for (int i = 0; i < N; i++) {
+                final Pair<ZipEntry, String> entry = nativeFiles.get(i);
+
+                /*
+                 * Note a 1MB padding is added to the claimed size, so we don't
+                 * have to worry about block alignment here.
+                 */
+                sizeBytes += entry.first.getSize();
+            }
+        } catch (ZipException e) {
+            Log.w(TAG, "Failed to extract data from package file", e);
+        } catch (IOException e) {
+            Log.w(TAG, "Failed to cache package shared libs", e);
+        }
+
+        int sizeMb = (int) (sizeBytes >> 20);
+        if ((sizeBytes - (sizeMb * 1024 * 1024)) > 0) {
+            sizeMb++;
+        }
+
+        /*
+         * Add buffer size because we don't have a good way to determine the
+         * real FAT size. Your FAT size varies with how many directory entries
+         * you need, how big the whole filesystem is, and other such headaches.
+         */
+        sizeMb++;
+
+        return sizeMb;
     }
 }
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java
index fa63edb..744798e 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java
@@ -27,6 +27,7 @@
 import java.io.FileOutputStream;
 import java.io.FileReader;
 import java.io.FileWriter;
+import java.io.InputStream;
 import java.io.IOException;
 import java.io.OutputStream;
 import java.util.Arrays;
@@ -58,15 +59,20 @@
     private static final String KEY_SECURE = "secure";
     private static final String KEY_LOCALE = "locale";
 
+    //Version 2 adds STATE_WIFI_CONFIG
+    private static final int STATE_VERSION_1       = 1;
+    private static final int STATE_VERSION_1_SIZE  = 4;
+
     // Versioning of the state file.  Increment this version
     // number any time the set of state items is altered.
-    private static final int STATE_VERSION = 1;
+    private static final int STATE_VERSION = 2;
 
-    private static final int STATE_SYSTEM = 0;
-    private static final int STATE_SECURE = 1;
-    private static final int STATE_LOCALE = 2;
-    private static final int STATE_WIFI   = 3;
-    private static final int STATE_SIZE   = 4; // The number of state items
+    private static final int STATE_SYSTEM          = 0;
+    private static final int STATE_SECURE          = 1;
+    private static final int STATE_LOCALE          = 2;
+    private static final int STATE_WIFI_SUPPLICANT = 3;
+    private static final int STATE_WIFI_CONFIG     = 4;
+    private static final int STATE_SIZE            = 5; // The number of state items
 
     private static String[] sortedSystemKeys = null;
     private static String[] sortedSecureKeys = null;
@@ -91,12 +97,18 @@
     // the key to store the WIFI data under, should be sorted as last, so restore happens last.
     // use very late unicode character to quasi-guarantee last sort position.
     private static final String KEY_WIFI_SUPPLICANT = "\uffedWIFI";
+    private static final String KEY_WIFI_CONFIG = "\uffedCONFIG_WIFI";
 
     private SettingsHelper mSettingsHelper;
+    private WifiManager mWfm;
+    private static String mWifiConfigFile;
 
     public void onCreate() {
         mSettingsHelper = new SettingsHelper(this);
         super.onCreate();
+
+        WifiManager mWfm = (WifiManager) getSystemService(Context.WIFI_SERVICE);
+        if (mWfm != null) mWifiConfigFile = mWfm.getConfigFile();
     }
 
     @Override
@@ -106,7 +118,8 @@
         byte[] systemSettingsData = getSystemSettings();
         byte[] secureSettingsData = getSecureSettings();
         byte[] locale = mSettingsHelper.getLocaleData();
-        byte[] wifiData = getWifiSupplicant(FILE_WIFI_SUPPLICANT);
+        byte[] wifiSupplicantData = getWifiSupplicant(FILE_WIFI_SUPPLICANT);
+        byte[] wifiConfigData = getFileData(mWifiConfigFile);
 
         long[] stateChecksums = readOldChecksums(oldState);
 
@@ -116,8 +129,12 @@
                 writeIfChanged(stateChecksums[STATE_SECURE], KEY_SECURE, secureSettingsData, data);
         stateChecksums[STATE_LOCALE] =
                 writeIfChanged(stateChecksums[STATE_LOCALE], KEY_LOCALE, locale, data);
-        stateChecksums[STATE_WIFI] =
-                writeIfChanged(stateChecksums[STATE_WIFI], KEY_WIFI_SUPPLICANT, wifiData, data);
+        stateChecksums[STATE_WIFI_SUPPLICANT] =
+                writeIfChanged(stateChecksums[STATE_WIFI_SUPPLICANT], KEY_WIFI_SUPPLICANT,
+                wifiSupplicantData, data);
+        stateChecksums[STATE_WIFI_CONFIG] =
+                writeIfChanged(stateChecksums[STATE_WIFI_CONFIG], KEY_WIFI_CONFIG, wifiConfigData,
+                data);
 
         writeNewChecksums(stateChecksums, newState);
     }
@@ -148,7 +165,9 @@
                 byte[] localeData = new byte[size];
                 data.readEntityData(localeData, 0, size);
                 mSettingsHelper.setLocaleData(localeData);
-            } else {
+            } else if (KEY_WIFI_CONFIG.equals(key)) {
+                restoreFileData(mWifiConfigFile, data);
+             } else {
                 data.skipEntityData();
             }
         }
@@ -162,7 +181,11 @@
 
         try {
             int stateVersion = dataInput.readInt();
-            if (stateVersion == STATE_VERSION) {
+            if (stateVersion == STATE_VERSION_1) {
+                for (int i = 0; i < STATE_VERSION_1_SIZE; i++) {
+                    stateChecksums[i] = dataInput.readLong();
+                }
+            } else if (stateVersion == STATE_VERSION) {
                 for (int i = 0; i < STATE_SIZE; i++) {
                     stateChecksums[i] = dataInput.readLong();
                 }
@@ -353,6 +376,60 @@
         return result;
     }
 
+    private byte[] getFileData(String filename) {
+        InputStream is = null;
+        try {
+            File file = new File(filename);
+            is = new FileInputStream(file);
+
+            //Will truncate read on a very long file,
+            //should not happen for a config file
+            byte[] bytes = new byte[(int)file.length()];
+
+            int offset = 0;
+            int numRead = 0;
+            while (offset < bytes.length
+                    && (numRead=is.read(bytes, offset, bytes.length-offset)) >= 0) {
+                offset += numRead;
+            }
+
+            //read failure
+            if (offset < bytes.length) {
+                Log.w(TAG, "Couldn't backup " + filename);
+                return EMPTY_DATA;
+            }
+            return bytes;
+        } catch (IOException ioe) {
+            Log.w(TAG, "Couldn't backup " + filename);
+            return EMPTY_DATA;
+        } finally {
+            if (is != null) {
+                try {
+                    is.close();
+                } catch (IOException e) {
+                }
+            }
+        }
+
+    }
+
+    private void restoreFileData(String filename, BackupDataInput data) {
+        byte[] bytes = new byte[data.getDataSize()];
+        if (bytes.length <= 0) return;
+        try {
+            data.readEntityData(bytes, 0, bytes.length);
+            File file = new File(filename);
+            if (file.exists()) file.delete();
+
+            OutputStream os = new BufferedOutputStream(new FileOutputStream(filename, true));
+            os.write(bytes);
+            os.close();
+        } catch (IOException ioe) {
+            Log.w(TAG, "Couldn't restore " + filename);
+        }
+    }
+
+
     private byte[] getWifiSupplicant(String filename) {
         BufferedReader br = null;
         try {
@@ -455,10 +532,9 @@
     }
 
     private int enableWifi(boolean enable) {
-        WifiManager wfm = (WifiManager) getSystemService(Context.WIFI_SERVICE);
-        if (wfm != null) {
-            int state = wfm.getWifiState();
-            wfm.setWifiEnabled(enable);
+        if (mWfm != null) {
+            int state = mWfm.getWifiState();
+            mWfm.setWifiEnabled(enable);
             return state;
         }
         return WifiManager.WIFI_STATE_UNKNOWN;
diff --git a/packages/SystemUI/AndroidManifest.xml b/packages/SystemUI/AndroidManifest.xml
index d3d1750..bbe146d6 100644
--- a/packages/SystemUI/AndroidManifest.xml
+++ b/packages/SystemUI/AndroidManifest.xml
@@ -8,6 +8,7 @@
     <uses-permission android:name="android.permission.BLUETOOTH" />
     <uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
     <uses-permission android:name="android.permission.GET_TASKS" />
+    <uses-permission android:name="android.permission.MANAGE_USB" />
 
     <application
         android:persistent="true"
@@ -39,5 +40,40 @@
             android:exported="true">
         </activity>
 
+        <!-- started from UsbDeviceSettingsManager -->
+        <activity android:name=".usb.UsbConfirmActivity"
+            android:exported="true"
+            android:permission="android.permission.MANAGE_USB"
+            android:theme="@*android:style/Theme.Holo.Dialog.Alert"
+            android:finishOnCloseSystemDialogs="true"
+            android:excludeFromRecents="true">
+        </activity>
+
+        <!-- started from UsbDeviceSettingsManager -->
+        <activity android:name=".usb.UsbPermissionActivity"
+            android:exported="true"
+            android:permission="android.permission.MANAGE_USB"
+            android:theme="@*android:style/Theme.Holo.Dialog.Alert"
+            android:finishOnCloseSystemDialogs="true"
+            android:excludeFromRecents="true">
+        </activity>
+
+        <!-- started from UsbDeviceSettingsManager -->
+        <activity android:name=".usb.UsbResolverActivity"
+            android:exported="true"
+            android:permission="android.permission.MANAGE_USB"
+            android:theme="@*android:style/Theme.Holo.Dialog.Alert"
+            android:finishOnCloseSystemDialogs="true"
+            android:excludeFromRecents="true">
+        </activity>
+
+        <!-- started from UsbDeviceSettingsManager -->
+        <activity android:name=".usb.UsbAccessoryUriActivity"
+            android:exported="true"
+            android:permission="android.permission.MANAGE_USB"
+            android:theme="@*android:style/Theme.Holo.Dialog.Alert"
+            android:finishOnCloseSystemDialogs="true"
+            android:excludeFromRecents="true">
+        </activity>
     </application>
 </manifest>
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_notification_dnd.png b/packages/SystemUI/res/drawable-hdpi/ic_notification_dnd.png
new file mode 100644
index 0000000..eb783df
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/ic_notification_dnd.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/notify_panel_clock_bg_pressed.9.png b/packages/SystemUI/res/drawable-hdpi/notify_panel_clock_bg_pressed.9.png
new file mode 100644
index 0000000..0c40c73
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/notify_panel_clock_bg_pressed.9.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_notify_alarm.png b/packages/SystemUI/res/drawable-hdpi/stat_notify_alarm.png
index 51b4f3f..4ec771a 100644
--- a/packages/SystemUI/res/drawable-hdpi/stat_notify_alarm.png
+++ b/packages/SystemUI/res/drawable-hdpi/stat_notify_alarm.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_notify_more.png b/packages/SystemUI/res/drawable-hdpi/stat_notify_more.png
index 170178c..2ea2609 100755
--- a/packages/SystemUI/res/drawable-hdpi/stat_notify_more.png
+++ b/packages/SystemUI/res/drawable-hdpi/stat_notify_more.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_gps_acquiring.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_gps_acquiring.png
index 61f65bf..765cdd7 100644
--- a/packages/SystemUI/res/drawable-hdpi/stat_sys_gps_acquiring.png
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_gps_acquiring.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_0.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_0.png
index ff74c35..d17771e 100644
--- a/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_0.png
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_0.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_1.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_1.png
index 6375b1b..b595b60 100644
--- a/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_1.png
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_1.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_1_fully.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_1_fully.png
index ef886b8..0bd3ba3 100644
--- a/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_1_fully.png
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_1_fully.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_2.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_2.png
index 92882bd..473c74a 100644
--- a/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_2.png
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_2.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_2_fully.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_2_fully.png
index cf5c4c3..ccd32fe 100644
--- a/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_2_fully.png
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_2_fully.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_3.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_3.png
index 24b6d25..047e888 100644
--- a/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_3.png
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_3.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_3_fully.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_3_fully.png
index b147583..80f5701 100644
--- a/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_3_fully.png
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_3_fully.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_4.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_4.png
index 594ad6a..3b8fb13 100644
--- a/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_4.png
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_4.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_4_fully.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_4_fully.png
index 2879550..9a6532a 100644
--- a/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_4_fully.png
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_4_fully.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_flightmode.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_flightmode.png
index c763976..52e8a8e 100644
--- a/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_flightmode.png
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_flightmode.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_in.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_in.png
index 883808a..a7a3623 100644
--- a/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_in.png
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_in.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_inout.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_inout.png
new file mode 100644
index 0000000..6429ffc6
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_inout.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_out.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_out.png
index 8ea42c7..9416793 100644
--- a/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_out.png
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_out.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_wifi_in.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_wifi_in.png
index 71429ae..c8cba34 100644
--- a/packages/SystemUI/res/drawable-hdpi/stat_sys_wifi_in.png
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_wifi_in.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_wifi_inout.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_wifi_inout.png
index 5c34554..c0de67d 100644
--- a/packages/SystemUI/res/drawable-hdpi/stat_sys_wifi_inout.png
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_wifi_inout.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_wifi_out.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_wifi_out.png
index 44e7072..1647b21 100644
--- a/packages/SystemUI/res/drawable-hdpi/stat_sys_wifi_out.png
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_wifi_out.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_wifi_signal_0.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_wifi_signal_0.png
index 7cd2893..f5b07e6 100644
--- a/packages/SystemUI/res/drawable-hdpi/stat_sys_wifi_signal_0.png
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_wifi_signal_0.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_wifi_signal_1.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_wifi_signal_1.png
index 23eb1d6..fbb31b8 100644
--- a/packages/SystemUI/res/drawable-hdpi/stat_sys_wifi_signal_1.png
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_wifi_signal_1.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_wifi_signal_1_fully.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_wifi_signal_1_fully.png
index ad28667..c1f2f97 100644
--- a/packages/SystemUI/res/drawable-hdpi/stat_sys_wifi_signal_1_fully.png
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_wifi_signal_1_fully.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_wifi_signal_2.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_wifi_signal_2.png
index 048dfd1..8721d5c 100644
--- a/packages/SystemUI/res/drawable-hdpi/stat_sys_wifi_signal_2.png
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_wifi_signal_2.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_wifi_signal_2_fully.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_wifi_signal_2_fully.png
index 224ae1f..b8feac6 100755
--- a/packages/SystemUI/res/drawable-hdpi/stat_sys_wifi_signal_2_fully.png
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_wifi_signal_2_fully.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_wifi_signal_3.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_wifi_signal_3.png
index b85859b..6854a2b 100644
--- a/packages/SystemUI/res/drawable-hdpi/stat_sys_wifi_signal_3.png
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_wifi_signal_3.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_wifi_signal_3_fully.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_wifi_signal_3_fully.png
index d7f3960..efff76c 100755
--- a/packages/SystemUI/res/drawable-hdpi/stat_sys_wifi_signal_3_fully.png
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_wifi_signal_3_fully.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_wifi_signal_4.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_wifi_signal_4.png
index 54915b9..3a5c7e2 100644
--- a/packages/SystemUI/res/drawable-hdpi/stat_sys_wifi_signal_4.png
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_wifi_signal_4.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_wifi_signal_4_fully.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_wifi_signal_4_fully.png
index bd44b52..dc1ce8e 100755
--- a/packages/SystemUI/res/drawable-hdpi/stat_sys_wifi_signal_4_fully.png
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_wifi_signal_4_fully.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_notification_dnd.png b/packages/SystemUI/res/drawable-mdpi/ic_notification_dnd.png
index 6d4da7f..3f88968 100644
--- a/packages/SystemUI/res/drawable-mdpi/ic_notification_dnd.png
+++ b/packages/SystemUI/res/drawable-mdpi/ic_notification_dnd.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/notify_panel_clock_bg_pressed.9.png b/packages/SystemUI/res/drawable-mdpi/notify_panel_clock_bg_pressed.9.png
index 4fc6b46..4fb1cf1 100644
--- a/packages/SystemUI/res/drawable-mdpi/notify_panel_clock_bg_pressed.9.png
+++ b/packages/SystemUI/res/drawable-mdpi/notify_panel_clock_bg_pressed.9.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_notify_alarm.png b/packages/SystemUI/res/drawable-mdpi/stat_notify_alarm.png
index d846afe..3a50987 100644
--- a/packages/SystemUI/res/drawable-mdpi/stat_notify_alarm.png
+++ b/packages/SystemUI/res/drawable-mdpi/stat_notify_alarm.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_notify_more.png b/packages/SystemUI/res/drawable-mdpi/stat_notify_more.png
index 9b28252..5bde4e5 100644
--- a/packages/SystemUI/res/drawable-mdpi/stat_notify_more.png
+++ b/packages/SystemUI/res/drawable-mdpi/stat_notify_more.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_gps_acquiring.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_gps_acquiring.png
index 3a0fce0..c9da7b9 100644
--- a/packages/SystemUI/res/drawable-mdpi/stat_sys_gps_acquiring.png
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_gps_acquiring.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_0.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_0.png
index 8654aa0..3aa22f5 100644
--- a/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_0.png
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_0.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_1.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_1.png
index c10629f..1afd107 100644
--- a/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_1.png
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_1.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_1_fully.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_1_fully.png
index 753c9f9..3af5991 100644
--- a/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_1_fully.png
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_1_fully.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_2.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_2.png
index 65a886a..49b0175 100644
--- a/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_2.png
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_2.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_2_fully.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_2_fully.png
index 6e90ce4..496df52 100644
--- a/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_2_fully.png
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_2_fully.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_3.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_3.png
index cce7d9b..fab2e10 100644
--- a/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_3.png
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_3.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_3_fully.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_3_fully.png
index c4e33bd..ff474b6 100644
--- a/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_3_fully.png
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_3_fully.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_4.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_4.png
index 433a2c5..409bb31 100644
--- a/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_4.png
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_4.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_4_fully.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_4_fully.png
index 81401b2..38c7f07 100644
--- a/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_4_fully.png
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_4_fully.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_flightmode.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_flightmode.png
index a1a9794..174d65c 100644
--- a/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_flightmode.png
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_flightmode.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_in.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_in.png
index e429ea1..5799ad2 100644
--- a/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_in.png
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_in.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_inout.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_inout.png
index e3bcaf9..ec617d7 100644
--- a/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_inout.png
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_inout.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_out.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_out.png
index 26db91e..1260c59 100644
--- a/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_out.png
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_out.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_wifi_in.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_wifi_in.png
index 957c5ba..0ec4c64 100644
--- a/packages/SystemUI/res/drawable-mdpi/stat_sys_wifi_in.png
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_wifi_in.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_wifi_inout.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_wifi_inout.png
index aec6050..60dc8a6 100644
--- a/packages/SystemUI/res/drawable-mdpi/stat_sys_wifi_inout.png
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_wifi_inout.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_wifi_out.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_wifi_out.png
index bb8eea0..fe2ba7a 100644
--- a/packages/SystemUI/res/drawable-mdpi/stat_sys_wifi_out.png
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_wifi_out.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_wifi_signal_0.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_wifi_signal_0.png
index 75906a2..150a6c7 100644
--- a/packages/SystemUI/res/drawable-mdpi/stat_sys_wifi_signal_0.png
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_wifi_signal_0.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_wifi_signal_1.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_wifi_signal_1.png
index 528e4ce..76f86dc 100644
--- a/packages/SystemUI/res/drawable-mdpi/stat_sys_wifi_signal_1.png
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_wifi_signal_1.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_wifi_signal_1_fully.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_wifi_signal_1_fully.png
index 1eb5aad..1f0dd89 100644
--- a/packages/SystemUI/res/drawable-mdpi/stat_sys_wifi_signal_1_fully.png
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_wifi_signal_1_fully.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_wifi_signal_2.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_wifi_signal_2.png
index 5f2c230..5e7ae35 100644
--- a/packages/SystemUI/res/drawable-mdpi/stat_sys_wifi_signal_2.png
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_wifi_signal_2.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_wifi_signal_2_fully.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_wifi_signal_2_fully.png
index 2c27620..b861bc9 100644
--- a/packages/SystemUI/res/drawable-mdpi/stat_sys_wifi_signal_2_fully.png
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_wifi_signal_2_fully.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_wifi_signal_3.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_wifi_signal_3.png
index 4cb06be..8f16376 100644
--- a/packages/SystemUI/res/drawable-mdpi/stat_sys_wifi_signal_3.png
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_wifi_signal_3.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_wifi_signal_3_fully.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_wifi_signal_3_fully.png
index fd9c350..67f46d3 100644
--- a/packages/SystemUI/res/drawable-mdpi/stat_sys_wifi_signal_3_fully.png
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_wifi_signal_3_fully.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_wifi_signal_4.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_wifi_signal_4.png
index e8aed95..165348c 100644
--- a/packages/SystemUI/res/drawable-mdpi/stat_sys_wifi_signal_4.png
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_wifi_signal_4.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_wifi_signal_4_fully.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_wifi_signal_4_fully.png
index c629387..d53d3bc 100644
--- a/packages/SystemUI/res/drawable-mdpi/stat_sys_wifi_signal_4_fully.png
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_wifi_signal_4_fully.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xlarge-hdpi/stat_sys_data_connected_1x.png b/packages/SystemUI/res/drawable-xlarge-hdpi/stat_sys_data_connected_1x.png
index 8e039ce..1629575 100644
--- a/packages/SystemUI/res/drawable-xlarge-hdpi/stat_sys_data_connected_1x.png
+++ b/packages/SystemUI/res/drawable-xlarge-hdpi/stat_sys_data_connected_1x.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xlarge-hdpi/stat_sys_data_connected_3g.png b/packages/SystemUI/res/drawable-xlarge-hdpi/stat_sys_data_connected_3g.png
index 0cb0a08..e87bcec 100644
--- a/packages/SystemUI/res/drawable-xlarge-hdpi/stat_sys_data_connected_3g.png
+++ b/packages/SystemUI/res/drawable-xlarge-hdpi/stat_sys_data_connected_3g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xlarge-hdpi/stat_sys_data_connected_4g.png b/packages/SystemUI/res/drawable-xlarge-hdpi/stat_sys_data_connected_4g.png
index c3cd10b..fd44002 100644
--- a/packages/SystemUI/res/drawable-xlarge-hdpi/stat_sys_data_connected_4g.png
+++ b/packages/SystemUI/res/drawable-xlarge-hdpi/stat_sys_data_connected_4g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xlarge-hdpi/stat_sys_data_connected_e.png b/packages/SystemUI/res/drawable-xlarge-hdpi/stat_sys_data_connected_e.png
index 650f67b..e455ad6 100644
--- a/packages/SystemUI/res/drawable-xlarge-hdpi/stat_sys_data_connected_e.png
+++ b/packages/SystemUI/res/drawable-xlarge-hdpi/stat_sys_data_connected_e.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xlarge-hdpi/stat_sys_data_connected_g.png b/packages/SystemUI/res/drawable-xlarge-hdpi/stat_sys_data_connected_g.png
index f5b1618..6613585 100644
--- a/packages/SystemUI/res/drawable-xlarge-hdpi/stat_sys_data_connected_g.png
+++ b/packages/SystemUI/res/drawable-xlarge-hdpi/stat_sys_data_connected_g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xlarge-hdpi/stat_sys_data_connected_h.png b/packages/SystemUI/res/drawable-xlarge-hdpi/stat_sys_data_connected_h.png
index eddc487..7502a54 100644
--- a/packages/SystemUI/res/drawable-xlarge-hdpi/stat_sys_data_connected_h.png
+++ b/packages/SystemUI/res/drawable-xlarge-hdpi/stat_sys_data_connected_h.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xlarge-hdpi/stat_sys_data_connected_roam.png b/packages/SystemUI/res/drawable-xlarge-hdpi/stat_sys_data_connected_roam.png
index 1eb0142..1309176 100644
--- a/packages/SystemUI/res/drawable-xlarge-hdpi/stat_sys_data_connected_roam.png
+++ b/packages/SystemUI/res/drawable-xlarge-hdpi/stat_sys_data_connected_roam.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xlarge-hdpi/stat_sys_data_fully_connected_1x.png b/packages/SystemUI/res/drawable-xlarge-hdpi/stat_sys_data_fully_connected_1x.png
index 4c8e7c3..810714e 100644
--- a/packages/SystemUI/res/drawable-xlarge-hdpi/stat_sys_data_fully_connected_1x.png
+++ b/packages/SystemUI/res/drawable-xlarge-hdpi/stat_sys_data_fully_connected_1x.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xlarge-hdpi/stat_sys_data_fully_connected_3g.png b/packages/SystemUI/res/drawable-xlarge-hdpi/stat_sys_data_fully_connected_3g.png
index 657dc04..72176ba 100644
--- a/packages/SystemUI/res/drawable-xlarge-hdpi/stat_sys_data_fully_connected_3g.png
+++ b/packages/SystemUI/res/drawable-xlarge-hdpi/stat_sys_data_fully_connected_3g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xlarge-hdpi/stat_sys_data_fully_connected_4g.png b/packages/SystemUI/res/drawable-xlarge-hdpi/stat_sys_data_fully_connected_4g.png
index 359e8f8..82a2bf0 100644
--- a/packages/SystemUI/res/drawable-xlarge-hdpi/stat_sys_data_fully_connected_4g.png
+++ b/packages/SystemUI/res/drawable-xlarge-hdpi/stat_sys_data_fully_connected_4g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xlarge-hdpi/stat_sys_data_fully_connected_e.png b/packages/SystemUI/res/drawable-xlarge-hdpi/stat_sys_data_fully_connected_e.png
index e5b0841..1e6c604 100644
--- a/packages/SystemUI/res/drawable-xlarge-hdpi/stat_sys_data_fully_connected_e.png
+++ b/packages/SystemUI/res/drawable-xlarge-hdpi/stat_sys_data_fully_connected_e.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xlarge-hdpi/stat_sys_data_fully_connected_g.png b/packages/SystemUI/res/drawable-xlarge-hdpi/stat_sys_data_fully_connected_g.png
index 4fe8df3..13aee06 100644
--- a/packages/SystemUI/res/drawable-xlarge-hdpi/stat_sys_data_fully_connected_g.png
+++ b/packages/SystemUI/res/drawable-xlarge-hdpi/stat_sys_data_fully_connected_g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xlarge-hdpi/stat_sys_data_fully_connected_h.png b/packages/SystemUI/res/drawable-xlarge-hdpi/stat_sys_data_fully_connected_h.png
index a7a7bea..76c48a8 100644
--- a/packages/SystemUI/res/drawable-xlarge-hdpi/stat_sys_data_fully_connected_h.png
+++ b/packages/SystemUI/res/drawable-xlarge-hdpi/stat_sys_data_fully_connected_h.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xlarge-mdpi/stat_sys_data_connected_1x.png b/packages/SystemUI/res/drawable-xlarge-mdpi/stat_sys_data_connected_1x.png
index 2cbec7b..73cdabe 100644
--- a/packages/SystemUI/res/drawable-xlarge-mdpi/stat_sys_data_connected_1x.png
+++ b/packages/SystemUI/res/drawable-xlarge-mdpi/stat_sys_data_connected_1x.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xlarge-mdpi/stat_sys_data_connected_3g.png b/packages/SystemUI/res/drawable-xlarge-mdpi/stat_sys_data_connected_3g.png
index 0efb9c9..b5a39cc 100644
--- a/packages/SystemUI/res/drawable-xlarge-mdpi/stat_sys_data_connected_3g.png
+++ b/packages/SystemUI/res/drawable-xlarge-mdpi/stat_sys_data_connected_3g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xlarge-mdpi/stat_sys_data_connected_4g.png b/packages/SystemUI/res/drawable-xlarge-mdpi/stat_sys_data_connected_4g.png
index 2eae1e1..6de880c 100644
--- a/packages/SystemUI/res/drawable-xlarge-mdpi/stat_sys_data_connected_4g.png
+++ b/packages/SystemUI/res/drawable-xlarge-mdpi/stat_sys_data_connected_4g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xlarge-mdpi/stat_sys_data_connected_e.png b/packages/SystemUI/res/drawable-xlarge-mdpi/stat_sys_data_connected_e.png
index 7e82c4c..2dbbfc0 100644
--- a/packages/SystemUI/res/drawable-xlarge-mdpi/stat_sys_data_connected_e.png
+++ b/packages/SystemUI/res/drawable-xlarge-mdpi/stat_sys_data_connected_e.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xlarge-mdpi/stat_sys_data_connected_g.png b/packages/SystemUI/res/drawable-xlarge-mdpi/stat_sys_data_connected_g.png
index d37f1e5..a45f011 100644
--- a/packages/SystemUI/res/drawable-xlarge-mdpi/stat_sys_data_connected_g.png
+++ b/packages/SystemUI/res/drawable-xlarge-mdpi/stat_sys_data_connected_g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xlarge-mdpi/stat_sys_data_connected_h.png b/packages/SystemUI/res/drawable-xlarge-mdpi/stat_sys_data_connected_h.png
index 5f7349e..517a6bb 100644
--- a/packages/SystemUI/res/drawable-xlarge-mdpi/stat_sys_data_connected_h.png
+++ b/packages/SystemUI/res/drawable-xlarge-mdpi/stat_sys_data_connected_h.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xlarge-mdpi/stat_sys_data_connected_roam.png b/packages/SystemUI/res/drawable-xlarge-mdpi/stat_sys_data_connected_roam.png
index 31358ec..5226c1c 100644
--- a/packages/SystemUI/res/drawable-xlarge-mdpi/stat_sys_data_connected_roam.png
+++ b/packages/SystemUI/res/drawable-xlarge-mdpi/stat_sys_data_connected_roam.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xlarge-mdpi/stat_sys_data_fully_connected_1x.png b/packages/SystemUI/res/drawable-xlarge-mdpi/stat_sys_data_fully_connected_1x.png
index e5a3484..a845648 100644
--- a/packages/SystemUI/res/drawable-xlarge-mdpi/stat_sys_data_fully_connected_1x.png
+++ b/packages/SystemUI/res/drawable-xlarge-mdpi/stat_sys_data_fully_connected_1x.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xlarge-mdpi/stat_sys_data_fully_connected_3g.png b/packages/SystemUI/res/drawable-xlarge-mdpi/stat_sys_data_fully_connected_3g.png
index 2a3a5dc..1d15587 100644
--- a/packages/SystemUI/res/drawable-xlarge-mdpi/stat_sys_data_fully_connected_3g.png
+++ b/packages/SystemUI/res/drawable-xlarge-mdpi/stat_sys_data_fully_connected_3g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xlarge-mdpi/stat_sys_data_fully_connected_4g.png b/packages/SystemUI/res/drawable-xlarge-mdpi/stat_sys_data_fully_connected_4g.png
index 5dbd1ab..52d5736 100644
--- a/packages/SystemUI/res/drawable-xlarge-mdpi/stat_sys_data_fully_connected_4g.png
+++ b/packages/SystemUI/res/drawable-xlarge-mdpi/stat_sys_data_fully_connected_4g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xlarge-mdpi/stat_sys_data_fully_connected_e.png b/packages/SystemUI/res/drawable-xlarge-mdpi/stat_sys_data_fully_connected_e.png
index 51d1f76..79a2a05 100644
--- a/packages/SystemUI/res/drawable-xlarge-mdpi/stat_sys_data_fully_connected_e.png
+++ b/packages/SystemUI/res/drawable-xlarge-mdpi/stat_sys_data_fully_connected_e.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xlarge-mdpi/stat_sys_data_fully_connected_g.png b/packages/SystemUI/res/drawable-xlarge-mdpi/stat_sys_data_fully_connected_g.png
index 10d81ca..b032594 100644
--- a/packages/SystemUI/res/drawable-xlarge-mdpi/stat_sys_data_fully_connected_g.png
+++ b/packages/SystemUI/res/drawable-xlarge-mdpi/stat_sys_data_fully_connected_g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xlarge-mdpi/stat_sys_data_fully_connected_h.png b/packages/SystemUI/res/drawable-xlarge-mdpi/stat_sys_data_fully_connected_h.png
index 1d9bda0..c4abcc9 100644
--- a/packages/SystemUI/res/drawable-xlarge-mdpi/stat_sys_data_fully_connected_h.png
+++ b/packages/SystemUI/res/drawable-xlarge-mdpi/stat_sys_data_fully_connected_h.png
Binary files differ
diff --git a/packages/SystemUI/res/layout-xlarge/status_bar_notification_panel_title.xml b/packages/SystemUI/res/layout-xlarge/status_bar_notification_panel_title.xml
index 1afb2e3..543f4ed 100644
--- a/packages/SystemUI/res/layout-xlarge/status_bar_notification_panel_title.xml
+++ b/packages/SystemUI/res/layout-xlarge/status_bar_notification_panel_title.xml
@@ -22,7 +22,6 @@
     android:layout_height="0dp"
     android:orientation="vertical"
     android:background="@drawable/notify_panel_clock_bg"
-    android:clickable="true"
     >
     <LinearLayout
         android:id="@+id/icons"
diff --git a/packages/SystemUI/res/layout-xlarge/status_bar_recent_item.xml b/packages/SystemUI/res/layout-xlarge/status_bar_recent_item.xml
index bfa6c36..3f172e6 100644
--- a/packages/SystemUI/res/layout-xlarge/status_bar_recent_item.xml
+++ b/packages/SystemUI/res/layout-xlarge/status_bar_recent_item.xml
@@ -38,8 +38,8 @@
         android:layout_height="wrap_content"
         android:layout_alignParentLeft="true"
         android:layout_alignParentTop="true"
-        android:layout_marginLeft="123dip"
-        android:layout_marginTop="16dip"
+        android:layout_marginLeft="131dip"
+        android:layout_marginTop="13dip"
         android:maxWidth="@dimen/status_bar_recents_thumbnail_max_width"
         android:maxHeight="@dimen/status_bar_recents_thumbnail_max_height"
         android:adjustViewBounds="true"
diff --git a/packages/SystemUI/res/layout-xlarge/status_bar_recent_panel.xml b/packages/SystemUI/res/layout-xlarge/status_bar_recent_panel.xml
index eda19b7..42940be 100644
--- a/packages/SystemUI/res/layout-xlarge/status_bar_recent_panel.xml
+++ b/packages/SystemUI/res/layout-xlarge/status_bar_recent_panel.xml
@@ -51,7 +51,7 @@
                 android:stackFromBottom="true"
                 android:fadingEdge="vertical"
                 android:scrollbars="none"
-                android:fadingEdgeLength="30dip"
+                android:fadingEdgeLength="20dip"
                 android:listSelector="@drawable/recents_thumbnail_bg_selector"
             />
 
diff --git a/packages/SystemUI/res/values-ar-xlarge/strings.xml b/packages/SystemUI/res/values-ar-xlarge/strings.xml
index af0eed0..d4fb873 100644
--- a/packages/SystemUI/res/values-ar-xlarge/strings.xml
+++ b/packages/SystemUI/res/values-ar-xlarge/strings.xml
@@ -24,8 +24,6 @@
     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="1456658018593445677">"Wi-Fi متصل"</string>
     <string name="gps_notification_searching_text" msgid="894185519046488403">"جارٍ البحث عن GPS"</string>
     <string name="gps_notification_found_text" msgid="5306445324124275852">"تم تعيين الموقع بواسطة GPS"</string>
-    <!-- no translation found for notifications_off_title (2297252328026582111) -->
-    <skip />
-    <!-- no translation found for notifications_off_text (3754847213329718358) -->
-    <skip />
+    <string name="notifications_off_title" msgid="2297252328026582111">"إيقاف التنبيهات"</string>
+    <string name="notifications_off_text" msgid="3754847213329718358">"انقر هنا لإعادة تشغيل التنبيهات."</string>
 </resources>
diff --git a/packages/SystemUI/res/values-ar/strings.xml b/packages/SystemUI/res/values-ar/strings.xml
index 486dacc..0660a17 100644
--- a/packages/SystemUI/res/values-ar/strings.xml
+++ b/packages/SystemUI/res/values-ar/strings.xml
@@ -34,7 +34,7 @@
     <string name="status_bar_settings_settings_button" msgid="3023889916699270224">"الإعدادات"</string>
     <string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"Wi-Fi"</string>
     <string name="status_bar_settings_airplane" msgid="4879879698500955300">"وضع الطائرة"</string>
-    <string name="status_bar_settings_rotation_lock" msgid="8361452930058000609">"تأمين اتجاه الشاشة"</string>
+    <string name="status_bar_settings_auto_rotation" msgid="3790482541357798421">"التدوير التلقائي للشاشة"</string>
     <string name="status_bar_settings_mute_label" msgid="554682549917429396">"كتم"</string>
     <string name="status_bar_settings_auto_brightness_label" msgid="511453614962324674">"تلقائي"</string>
     <string name="status_bar_settings_notifications" msgid="397146176280905137">"التنبيهات"</string>
@@ -44,4 +44,22 @@
     <string name="bluetooth_tethered" msgid="7094101612161133267">"تم إنشاء الاتصال بالإنترنت عن طريق البلوتوث."</string>
     <string name="status_bar_input_method_settings_configure_input_methods" msgid="737483394044014246">"تهيئة طرق الإدخال"</string>
     <string name="status_bar_use_physical_keyboard" msgid="3695516942412442936">"استخدام لوحة المفاتيح الفعلية"</string>
+    <!-- no translation found for usb_device_permission_prompt (3816016361969816903) -->
+    <skip />
+    <!-- no translation found for usb_accessory_permission_prompt (6888598803988889959) -->
+    <skip />
+    <!-- no translation found for usb_device_confirm_prompt (5161205258635253206) -->
+    <skip />
+    <!-- no translation found for usb_accessory_confirm_prompt (3808984931830229888) -->
+    <skip />
+    <!-- no translation found for usb_accessory_uri_prompt (6332150684964235705) -->
+    <skip />
+    <!-- no translation found for title_usb_accessory (4966265263465181372) -->
+    <skip />
+    <!-- no translation found for label_view (6304565553218192990) -->
+    <skip />
+    <!-- no translation found for always_use_device (1450287437017315906) -->
+    <skip />
+    <!-- no translation found for always_use_accessory (1210954576979621596) -->
+    <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-bg-xlarge/strings.xml b/packages/SystemUI/res/values-bg-xlarge/strings.xml
index d44366d..4e730ae 100644
--- a/packages/SystemUI/res/values-bg-xlarge/strings.xml
+++ b/packages/SystemUI/res/values-bg-xlarge/strings.xml
@@ -24,8 +24,6 @@
     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="1456658018593445677">"Wi-Fi: има връзка"</string>
     <string name="gps_notification_searching_text" msgid="894185519046488403">"Търси се GPS"</string>
     <string name="gps_notification_found_text" msgid="5306445324124275852">"Местоположението е зададено от GPS"</string>
-    <!-- no translation found for notifications_off_title (2297252328026582111) -->
-    <skip />
-    <!-- no translation found for notifications_off_text (3754847213329718358) -->
-    <skip />
+    <string name="notifications_off_title" msgid="2297252328026582111">"Известията са изключени"</string>
+    <string name="notifications_off_text" msgid="3754847213329718358">"Докоснете тук, за да включите отново известията."</string>
 </resources>
diff --git a/packages/SystemUI/res/values-bg/strings.xml b/packages/SystemUI/res/values-bg/strings.xml
index df6ef71..4c9ecfc 100644
--- a/packages/SystemUI/res/values-bg/strings.xml
+++ b/packages/SystemUI/res/values-bg/strings.xml
@@ -34,7 +34,7 @@
     <string name="status_bar_settings_settings_button" msgid="3023889916699270224">"Настройки"</string>
     <string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"Wi-Fi"</string>
     <string name="status_bar_settings_airplane" msgid="4879879698500955300">"Самолетен режим"</string>
-    <string name="status_bar_settings_rotation_lock" msgid="8361452930058000609">"Заключване на ориентацията"</string>
+    <string name="status_bar_settings_auto_rotation" msgid="3790482541357798421">"Авт. завъртане на екрана"</string>
     <string name="status_bar_settings_mute_label" msgid="554682549917429396">"БЕЗ"</string>
     <string name="status_bar_settings_auto_brightness_label" msgid="511453614962324674">"АВТ."</string>
     <string name="status_bar_settings_notifications" msgid="397146176280905137">"Известия"</string>
@@ -44,4 +44,22 @@
     <string name="bluetooth_tethered" msgid="7094101612161133267">"Bluetooth има връзка с тетъринг"</string>
     <string name="status_bar_input_method_settings_configure_input_methods" msgid="737483394044014246">"Конфигуриране на въвеждането"</string>
     <string name="status_bar_use_physical_keyboard" msgid="3695516942412442936">"Използване на физ. клав."</string>
+    <!-- no translation found for usb_device_permission_prompt (3816016361969816903) -->
+    <skip />
+    <!-- no translation found for usb_accessory_permission_prompt (6888598803988889959) -->
+    <skip />
+    <!-- no translation found for usb_device_confirm_prompt (5161205258635253206) -->
+    <skip />
+    <!-- no translation found for usb_accessory_confirm_prompt (3808984931830229888) -->
+    <skip />
+    <!-- no translation found for usb_accessory_uri_prompt (6332150684964235705) -->
+    <skip />
+    <!-- no translation found for title_usb_accessory (4966265263465181372) -->
+    <skip />
+    <!-- no translation found for label_view (6304565553218192990) -->
+    <skip />
+    <!-- no translation found for always_use_device (1450287437017315906) -->
+    <skip />
+    <!-- no translation found for always_use_accessory (1210954576979621596) -->
+    <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-ca-xlarge/strings.xml b/packages/SystemUI/res/values-ca-xlarge/strings.xml
index a0ace2c..9fc74d0 100644
--- a/packages/SystemUI/res/values-ca-xlarge/strings.xml
+++ b/packages/SystemUI/res/values-ca-xlarge/strings.xml
@@ -24,8 +24,6 @@
     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="1456658018593445677">"Wi-Fi: connectat"</string>
     <string name="gps_notification_searching_text" msgid="894185519046488403">"S\'està cercant un GPS"</string>
     <string name="gps_notification_found_text" msgid="5306445324124275852">"S\'ha establert la ubicació per GPS"</string>
-    <!-- no translation found for notifications_off_title (2297252328026582111) -->
-    <skip />
-    <!-- no translation found for notifications_off_text (3754847213329718358) -->
-    <skip />
+    <string name="notifications_off_title" msgid="2297252328026582111">"Notificacions desactivades"</string>
+    <string name="notifications_off_text" msgid="3754847213329718358">"Pica aquí per tornar a activar les notificacions."</string>
 </resources>
diff --git a/packages/SystemUI/res/values-ca/strings.xml b/packages/SystemUI/res/values-ca/strings.xml
index 2993e8b..9a4a360 100644
--- a/packages/SystemUI/res/values-ca/strings.xml
+++ b/packages/SystemUI/res/values-ca/strings.xml
@@ -34,7 +34,7 @@
     <string name="status_bar_settings_settings_button" msgid="3023889916699270224">"Configuració"</string>
     <string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"Wi-Fi"</string>
     <string name="status_bar_settings_airplane" msgid="4879879698500955300">"Mode d\'avió"</string>
-    <string name="status_bar_settings_rotation_lock" msgid="8361452930058000609">"Bloquejar orientació pantalla"</string>
+    <string name="status_bar_settings_auto_rotation" msgid="3790482541357798421">"Gira pantalla automàticament"</string>
     <string name="status_bar_settings_mute_label" msgid="554682549917429396">"Silen."</string>
     <string name="status_bar_settings_auto_brightness_label" msgid="511453614962324674">"AUTOM."</string>
     <string name="status_bar_settings_notifications" msgid="397146176280905137">"Notificacions"</string>
@@ -44,4 +44,22 @@
     <string name="bluetooth_tethered" msgid="7094101612161133267">"Bluetooth sense fil"</string>
     <string name="status_bar_input_method_settings_configure_input_methods" msgid="737483394044014246">"Configura mètodes d\'entrada"</string>
     <string name="status_bar_use_physical_keyboard" msgid="3695516942412442936">"Utilitza un teclat físic"</string>
+    <!-- no translation found for usb_device_permission_prompt (3816016361969816903) -->
+    <skip />
+    <!-- no translation found for usb_accessory_permission_prompt (6888598803988889959) -->
+    <skip />
+    <!-- no translation found for usb_device_confirm_prompt (5161205258635253206) -->
+    <skip />
+    <!-- no translation found for usb_accessory_confirm_prompt (3808984931830229888) -->
+    <skip />
+    <!-- no translation found for usb_accessory_uri_prompt (6332150684964235705) -->
+    <skip />
+    <!-- no translation found for title_usb_accessory (4966265263465181372) -->
+    <skip />
+    <!-- no translation found for label_view (6304565553218192990) -->
+    <skip />
+    <!-- no translation found for always_use_device (1450287437017315906) -->
+    <skip />
+    <!-- no translation found for always_use_accessory (1210954576979621596) -->
+    <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-cs-xlarge/strings.xml b/packages/SystemUI/res/values-cs-xlarge/strings.xml
index 5fe365c..05b1248 100644
--- a/packages/SystemUI/res/values-cs-xlarge/strings.xml
+++ b/packages/SystemUI/res/values-cs-xlarge/strings.xml
@@ -24,8 +24,6 @@
     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="1456658018593445677">"Wi-Fi: připojeno"</string>
     <string name="gps_notification_searching_text" msgid="894185519046488403">"Vyhledávání satelitů GPS"</string>
     <string name="gps_notification_found_text" msgid="5306445324124275852">"Poloha nastavena pomocí GPS"</string>
-    <!-- no translation found for notifications_off_title (2297252328026582111) -->
-    <skip />
-    <!-- no translation found for notifications_off_text (3754847213329718358) -->
-    <skip />
+    <string name="notifications_off_title" msgid="2297252328026582111">"Oznámení jsou vypnuta"</string>
+    <string name="notifications_off_text" msgid="3754847213329718358">"Chcete-li oznámení znovu zapnout, klepněte sem."</string>
 </resources>
diff --git a/packages/SystemUI/res/values-cs/strings.xml b/packages/SystemUI/res/values-cs/strings.xml
index 29ab1a7..31aa1a7 100644
--- a/packages/SystemUI/res/values-cs/strings.xml
+++ b/packages/SystemUI/res/values-cs/strings.xml
@@ -34,7 +34,7 @@
     <string name="status_bar_settings_settings_button" msgid="3023889916699270224">"Nastavení"</string>
     <string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"Wi-Fi"</string>
     <string name="status_bar_settings_airplane" msgid="4879879698500955300">"Režim V letadle"</string>
-    <string name="status_bar_settings_rotation_lock" msgid="8361452930058000609">"Uzamknout orientaci obrazovky"</string>
+    <string name="status_bar_settings_auto_rotation" msgid="3790482541357798421">"Automatické otočení obrazovky"</string>
     <string name="status_bar_settings_mute_label" msgid="554682549917429396">"ZTLUM."</string>
     <string name="status_bar_settings_auto_brightness_label" msgid="511453614962324674">"AUTOM."</string>
     <string name="status_bar_settings_notifications" msgid="397146176280905137">"Oznámení"</string>
@@ -44,4 +44,22 @@
     <string name="bluetooth_tethered" msgid="7094101612161133267">"Datové připojení Bluetooth se sdílí"</string>
     <string name="status_bar_input_method_settings_configure_input_methods" msgid="737483394044014246">"Nakonfigurovat metody vstupu"</string>
     <string name="status_bar_use_physical_keyboard" msgid="3695516942412442936">"Použít fyz. klávesnici"</string>
+    <!-- no translation found for usb_device_permission_prompt (3816016361969816903) -->
+    <skip />
+    <!-- no translation found for usb_accessory_permission_prompt (6888598803988889959) -->
+    <skip />
+    <!-- no translation found for usb_device_confirm_prompt (5161205258635253206) -->
+    <skip />
+    <!-- no translation found for usb_accessory_confirm_prompt (3808984931830229888) -->
+    <skip />
+    <!-- no translation found for usb_accessory_uri_prompt (6332150684964235705) -->
+    <skip />
+    <!-- no translation found for title_usb_accessory (4966265263465181372) -->
+    <skip />
+    <!-- no translation found for label_view (6304565553218192990) -->
+    <skip />
+    <!-- no translation found for always_use_device (1450287437017315906) -->
+    <skip />
+    <!-- no translation found for always_use_accessory (1210954576979621596) -->
+    <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-da-xlarge/strings.xml b/packages/SystemUI/res/values-da-xlarge/strings.xml
index ae430b3..dd20e64 100644
--- a/packages/SystemUI/res/values-da-xlarge/strings.xml
+++ b/packages/SystemUI/res/values-da-xlarge/strings.xml
@@ -24,8 +24,6 @@
     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="1456658018593445677">"Wi-Fi er forbundet"</string>
     <string name="gps_notification_searching_text" msgid="894185519046488403">"Søger efter GPS"</string>
     <string name="gps_notification_found_text" msgid="5306445324124275852">"Placeringen er angivet ved hjælp af GPS"</string>
-    <!-- no translation found for notifications_off_title (2297252328026582111) -->
-    <skip />
-    <!-- no translation found for notifications_off_text (3754847213329718358) -->
-    <skip />
+    <string name="notifications_off_title" msgid="2297252328026582111">"Meddelelser: Fra"</string>
+    <string name="notifications_off_text" msgid="3754847213329718358">"Tryk her for at slå meddelelser til igen."</string>
 </resources>
diff --git a/packages/SystemUI/res/values-da/strings.xml b/packages/SystemUI/res/values-da/strings.xml
index 81122a8..ddbcf25 100644
--- a/packages/SystemUI/res/values-da/strings.xml
+++ b/packages/SystemUI/res/values-da/strings.xml
@@ -34,7 +34,7 @@
     <string name="status_bar_settings_settings_button" msgid="3023889916699270224">"Indstillinger"</string>
     <string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"Wi-Fi"</string>
     <string name="status_bar_settings_airplane" msgid="4879879698500955300">"Flytilstand"</string>
-    <string name="status_bar_settings_rotation_lock" msgid="8361452930058000609">"Lås skærmretning"</string>
+    <string name="status_bar_settings_auto_rotation" msgid="3790482541357798421">"Automatisk skærmrotation"</string>
     <string name="status_bar_settings_mute_label" msgid="554682549917429396">"LYDLØS"</string>
     <string name="status_bar_settings_auto_brightness_label" msgid="511453614962324674">"AUTO"</string>
     <string name="status_bar_settings_notifications" msgid="397146176280905137">"Meddelelser"</string>
@@ -44,4 +44,22 @@
     <string name="bluetooth_tethered" msgid="7094101612161133267">"Bluetooth-tethering anvendt"</string>
     <string name="status_bar_input_method_settings_configure_input_methods" msgid="737483394044014246">"Konfigurer inputmetoder"</string>
     <string name="status_bar_use_physical_keyboard" msgid="3695516942412442936">"Brug fysisk tastatur"</string>
+    <!-- no translation found for usb_device_permission_prompt (3816016361969816903) -->
+    <skip />
+    <!-- no translation found for usb_accessory_permission_prompt (6888598803988889959) -->
+    <skip />
+    <!-- no translation found for usb_device_confirm_prompt (5161205258635253206) -->
+    <skip />
+    <!-- no translation found for usb_accessory_confirm_prompt (3808984931830229888) -->
+    <skip />
+    <!-- no translation found for usb_accessory_uri_prompt (6332150684964235705) -->
+    <skip />
+    <!-- no translation found for title_usb_accessory (4966265263465181372) -->
+    <skip />
+    <!-- no translation found for label_view (6304565553218192990) -->
+    <skip />
+    <!-- no translation found for always_use_device (1450287437017315906) -->
+    <skip />
+    <!-- no translation found for always_use_accessory (1210954576979621596) -->
+    <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-de-xlarge/strings.xml b/packages/SystemUI/res/values-de-xlarge/strings.xml
index 825cd0d..cc782da 100644
--- a/packages/SystemUI/res/values-de-xlarge/strings.xml
+++ b/packages/SystemUI/res/values-de-xlarge/strings.xml
@@ -24,8 +24,6 @@
     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="1456658018593445677">"Mit WLAN verbunden"</string>
     <string name="gps_notification_searching_text" msgid="894185519046488403">"Suche nach GPS"</string>
     <string name="gps_notification_found_text" msgid="5306445324124275852">"Standort durch GPS festgelegt"</string>
-    <!-- no translation found for notifications_off_title (2297252328026582111) -->
-    <skip />
-    <!-- no translation found for notifications_off_text (3754847213329718358) -->
-    <skip />
+    <string name="notifications_off_title" msgid="2297252328026582111">"Benachrichtigungen aus"</string>
+    <string name="notifications_off_text" msgid="3754847213329718358">"Tippen Sie hier, um Benachrichtigungen wieder einzuschalten."</string>
 </resources>
diff --git a/packages/SystemUI/res/values-de/strings.xml b/packages/SystemUI/res/values-de/strings.xml
index 1ea87e8..c7d9502 100644
--- a/packages/SystemUI/res/values-de/strings.xml
+++ b/packages/SystemUI/res/values-de/strings.xml
@@ -34,14 +34,32 @@
     <string name="status_bar_settings_settings_button" msgid="3023889916699270224">"Einstellungen"</string>
     <string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"WLAN"</string>
     <string name="status_bar_settings_airplane" msgid="4879879698500955300">"Flugmodus"</string>
-    <string name="status_bar_settings_rotation_lock" msgid="8361452930058000609">"Bildschirmausrichtung sperren"</string>
+    <string name="status_bar_settings_auto_rotation" msgid="3790482541357798421">"Bildschirm automatisch drehen"</string>
     <string name="status_bar_settings_mute_label" msgid="554682549917429396">"STUMM"</string>
     <string name="status_bar_settings_auto_brightness_label" msgid="511453614962324674">"AUTO"</string>
     <string name="status_bar_settings_notifications" msgid="397146176280905137">"Benachrichtigungen"</string>
     <string name="recent_tasks_title" msgid="3691764623638127888">"Zuletzt verwendet"</string>
-    <string name="recent_tasks_empty" msgid="1905484479067697884">"Keine neuen Anwendungen"</string>
+    <string name="recent_tasks_empty" msgid="1905484479067697884">"Keine zuletzt verwendeten Anwendungen"</string>
     <string name="recent_tasks_app_label" msgid="3796483981246752469">"Google Apps"</string>
     <string name="bluetooth_tethered" msgid="7094101612161133267">"Bluetooth-Tethering aktiv"</string>
     <string name="status_bar_input_method_settings_configure_input_methods" msgid="737483394044014246">"Eingabemethoden konfigurieren"</string>
     <string name="status_bar_use_physical_keyboard" msgid="3695516942412442936">"Physische Tastatur"</string>
+    <!-- no translation found for usb_device_permission_prompt (3816016361969816903) -->
+    <skip />
+    <!-- no translation found for usb_accessory_permission_prompt (6888598803988889959) -->
+    <skip />
+    <!-- no translation found for usb_device_confirm_prompt (5161205258635253206) -->
+    <skip />
+    <!-- no translation found for usb_accessory_confirm_prompt (3808984931830229888) -->
+    <skip />
+    <!-- no translation found for usb_accessory_uri_prompt (6332150684964235705) -->
+    <skip />
+    <!-- no translation found for title_usb_accessory (4966265263465181372) -->
+    <skip />
+    <!-- no translation found for label_view (6304565553218192990) -->
+    <skip />
+    <!-- no translation found for always_use_device (1450287437017315906) -->
+    <skip />
+    <!-- no translation found for always_use_accessory (1210954576979621596) -->
+    <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-el-xlarge/strings.xml b/packages/SystemUI/res/values-el-xlarge/strings.xml
index 4902bb5..4f7814a 100644
--- a/packages/SystemUI/res/values-el-xlarge/strings.xml
+++ b/packages/SystemUI/res/values-el-xlarge/strings.xml
@@ -24,8 +24,6 @@
     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="1456658018593445677">"Wi-Fi: συνδέθηκε"</string>
     <string name="gps_notification_searching_text" msgid="894185519046488403">"Αναζήτηση για GPS"</string>
     <string name="gps_notification_found_text" msgid="5306445324124275852">"Ρύθμιση τοποθεσίας με GPS"</string>
-    <!-- no translation found for notifications_off_title (2297252328026582111) -->
-    <skip />
-    <!-- no translation found for notifications_off_text (3754847213329718358) -->
-    <skip />
+    <string name="notifications_off_title" msgid="2297252328026582111">"Ειδοποιήσεις ανενεργές"</string>
+    <string name="notifications_off_text" msgid="3754847213329718358">"Πατήστε εδώ για να ενεργοποιήσετε τις ειδοποιήσεις"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-el/strings.xml b/packages/SystemUI/res/values-el/strings.xml
index cd412f4..7e15f7f 100644
--- a/packages/SystemUI/res/values-el/strings.xml
+++ b/packages/SystemUI/res/values-el/strings.xml
@@ -34,7 +34,7 @@
     <string name="status_bar_settings_settings_button" msgid="3023889916699270224">"Ρυθμίσεις"</string>
     <string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"Wi-Fi"</string>
     <string name="status_bar_settings_airplane" msgid="4879879698500955300">"Λειτουργία πτήσης"</string>
-    <string name="status_bar_settings_rotation_lock" msgid="8361452930058000609">"Κλείδωμα προσανατολ. οθόνης"</string>
+    <string name="status_bar_settings_auto_rotation" msgid="3790482541357798421">"Αυτόματη περιστροφή οθόνης"</string>
     <string name="status_bar_settings_mute_label" msgid="554682549917429396">"ΣΙΓΑΣΗ"</string>
     <string name="status_bar_settings_auto_brightness_label" msgid="511453614962324674">"ΑΥΤΟΜ."</string>
     <string name="status_bar_settings_notifications" msgid="397146176280905137">"Ειδοποιήσεις"</string>
@@ -44,4 +44,22 @@
     <string name="bluetooth_tethered" msgid="7094101612161133267">"Έγινε σύνδεση μέσω Bluetooth"</string>
     <string name="status_bar_input_method_settings_configure_input_methods" msgid="737483394044014246">"Διαμόρφωση μεθόδων εισαγωγής"</string>
     <string name="status_bar_use_physical_keyboard" msgid="3695516942412442936">"Χρήση κανονικού πληκτρολ."</string>
+    <!-- no translation found for usb_device_permission_prompt (3816016361969816903) -->
+    <skip />
+    <!-- no translation found for usb_accessory_permission_prompt (6888598803988889959) -->
+    <skip />
+    <!-- no translation found for usb_device_confirm_prompt (5161205258635253206) -->
+    <skip />
+    <!-- no translation found for usb_accessory_confirm_prompt (3808984931830229888) -->
+    <skip />
+    <!-- no translation found for usb_accessory_uri_prompt (6332150684964235705) -->
+    <skip />
+    <!-- no translation found for title_usb_accessory (4966265263465181372) -->
+    <skip />
+    <!-- no translation found for label_view (6304565553218192990) -->
+    <skip />
+    <!-- no translation found for always_use_device (1450287437017315906) -->
+    <skip />
+    <!-- no translation found for always_use_accessory (1210954576979621596) -->
+    <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-en-rGB-xlarge/strings.xml b/packages/SystemUI/res/values-en-rGB-xlarge/strings.xml
index de1eb52..68986f0 100644
--- a/packages/SystemUI/res/values-en-rGB-xlarge/strings.xml
+++ b/packages/SystemUI/res/values-en-rGB-xlarge/strings.xml
@@ -24,8 +24,6 @@
     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="1456658018593445677">"Wi-Fi connected"</string>
     <string name="gps_notification_searching_text" msgid="894185519046488403">"Searching for GPS"</string>
     <string name="gps_notification_found_text" msgid="5306445324124275852">"Location set by GPS"</string>
-    <!-- no translation found for notifications_off_title (2297252328026582111) -->
-    <skip />
-    <!-- no translation found for notifications_off_text (3754847213329718358) -->
-    <skip />
+    <string name="notifications_off_title" msgid="2297252328026582111">"Notifications off"</string>
+    <string name="notifications_off_text" msgid="3754847213329718358">"Tap here to turn notifications back on."</string>
 </resources>
diff --git a/packages/SystemUI/res/values-en-rGB/strings.xml b/packages/SystemUI/res/values-en-rGB/strings.xml
index 2bd662b..350913a 100644
--- a/packages/SystemUI/res/values-en-rGB/strings.xml
+++ b/packages/SystemUI/res/values-en-rGB/strings.xml
@@ -34,7 +34,7 @@
     <string name="status_bar_settings_settings_button" msgid="3023889916699270224">"Settings"</string>
     <string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"Wi-Fi"</string>
     <string name="status_bar_settings_airplane" msgid="4879879698500955300">"Airplane mode"</string>
-    <string name="status_bar_settings_rotation_lock" msgid="8361452930058000609">"Lock screen orientation"</string>
+    <string name="status_bar_settings_auto_rotation" msgid="3790482541357798421">"Auto-rotate screen"</string>
     <string name="status_bar_settings_mute_label" msgid="554682549917429396">"MUTE"</string>
     <string name="status_bar_settings_auto_brightness_label" msgid="511453614962324674">"AUTO"</string>
     <string name="status_bar_settings_notifications" msgid="397146176280905137">"Notifications"</string>
@@ -44,4 +44,22 @@
     <string name="bluetooth_tethered" msgid="7094101612161133267">"Bluetooth tethered"</string>
     <string name="status_bar_input_method_settings_configure_input_methods" msgid="737483394044014246">"Configure input methods"</string>
     <string name="status_bar_use_physical_keyboard" msgid="3695516942412442936">"Use physical keyboard"</string>
+    <!-- no translation found for usb_device_permission_prompt (3816016361969816903) -->
+    <skip />
+    <!-- no translation found for usb_accessory_permission_prompt (6888598803988889959) -->
+    <skip />
+    <!-- no translation found for usb_device_confirm_prompt (5161205258635253206) -->
+    <skip />
+    <!-- no translation found for usb_accessory_confirm_prompt (3808984931830229888) -->
+    <skip />
+    <!-- no translation found for usb_accessory_uri_prompt (6332150684964235705) -->
+    <skip />
+    <!-- no translation found for title_usb_accessory (4966265263465181372) -->
+    <skip />
+    <!-- no translation found for label_view (6304565553218192990) -->
+    <skip />
+    <!-- no translation found for always_use_device (1450287437017315906) -->
+    <skip />
+    <!-- no translation found for always_use_accessory (1210954576979621596) -->
+    <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-es-rUS-xlarge-land/strings.xml b/packages/SystemUI/res/values-es-rUS-xlarge-land/strings.xml
deleted file mode 100644
index 78a4c18..0000000
--- a/packages/SystemUI/res/values-es-rUS-xlarge-land/strings.xml
+++ /dev/null
@@ -1,6 +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">
-    <!-- XL -->
-    <string name="toast_rotation_locked" msgid="2686639138967158852">"La pantalla está bloqueada en orientación paisaje."</string>
-</resources>
diff --git a/packages/SystemUI/res/values-es-rUS-xlarge-port/strings.xml b/packages/SystemUI/res/values-es-rUS-xlarge-port/strings.xml
deleted file mode 100644
index 9daef6a..0000000
--- a/packages/SystemUI/res/values-es-rUS-xlarge-port/strings.xml
+++ /dev/null
@@ -1,6 +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">
-    <!-- XL -->
-    <string name="toast_rotation_locked" msgid="4297721709987511908">"La pantalla está bloqueada en orientación retrato."</string>
-</resources>
diff --git a/packages/SystemUI/res/values-es-rUS-xlarge/strings.xml b/packages/SystemUI/res/values-es-rUS-xlarge/strings.xml
index 2ace144..fa9b762 100644
--- a/packages/SystemUI/res/values-es-rUS-xlarge/strings.xml
+++ b/packages/SystemUI/res/values-es-rUS-xlarge/strings.xml
@@ -24,8 +24,6 @@
     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="1456658018593445677">"WiFi conectado"</string>
     <string name="gps_notification_searching_text" msgid="894185519046488403">"Buscando GPS"</string>
     <string name="gps_notification_found_text" msgid="5306445324124275852">"La ubicación se estableció por GPS."</string>
-    <!-- no translation found for notifications_off_title (2297252328026582111) -->
-    <skip />
-    <!-- no translation found for notifications_off_text (3754847213329718358) -->
-    <skip />
+    <string name="notifications_off_title" msgid="2297252328026582111">"Notificaciones desactivadas"</string>
+    <string name="notifications_off_text" msgid="3754847213329718358">"Presiona aquí para volver a activar las notificaciones."</string>
 </resources>
diff --git a/packages/SystemUI/res/values-es-rUS/strings.xml b/packages/SystemUI/res/values-es-rUS/strings.xml
index 2c50160..43d9337 100644
--- a/packages/SystemUI/res/values-es-rUS/strings.xml
+++ b/packages/SystemUI/res/values-es-rUS/strings.xml
@@ -19,7 +19,7 @@
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="app_label" msgid="7164937344850004466">"Sistema UI"</string>
+    <string name="app_label" msgid="7164937344850004466">"IU del sistema"</string>
     <string name="status_bar_clear_all_button" msgid="7774721344716731603">"Borrar"</string>
     <string name="status_bar_do_not_disturb_button" msgid="5812628897510997853">"No molestar"</string>
     <string name="status_bar_please_disturb_button" msgid="3345398298841572813">"Mostrar notificaciones"</string>
@@ -34,7 +34,7 @@
     <string name="status_bar_settings_settings_button" msgid="3023889916699270224">"Configuración"</string>
     <string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"Wi-Fi"</string>
     <string name="status_bar_settings_airplane" msgid="4879879698500955300">"Modo avión"</string>
-    <string name="status_bar_settings_rotation_lock" msgid="8361452930058000609">"Bloq orient de pant"</string>
+    <string name="status_bar_settings_auto_rotation" msgid="3790482541357798421">"Girar la pantalla automáticamente"</string>
     <string name="status_bar_settings_mute_label" msgid="554682549917429396">"SILENC"</string>
     <string name="status_bar_settings_auto_brightness_label" msgid="511453614962324674">"AUTO"</string>
     <string name="status_bar_settings_notifications" msgid="397146176280905137">"Notificaciones"</string>
@@ -44,4 +44,22 @@
     <string name="bluetooth_tethered" msgid="7094101612161133267">"Bluetooth anclado"</string>
     <string name="status_bar_input_method_settings_configure_input_methods" msgid="737483394044014246">"Configurar métodos de entrada"</string>
     <string name="status_bar_use_physical_keyboard" msgid="3695516942412442936">"Usar teclado físico"</string>
+    <!-- no translation found for usb_device_permission_prompt (3816016361969816903) -->
+    <skip />
+    <!-- no translation found for usb_accessory_permission_prompt (6888598803988889959) -->
+    <skip />
+    <!-- no translation found for usb_device_confirm_prompt (5161205258635253206) -->
+    <skip />
+    <!-- no translation found for usb_accessory_confirm_prompt (3808984931830229888) -->
+    <skip />
+    <!-- no translation found for usb_accessory_uri_prompt (6332150684964235705) -->
+    <skip />
+    <!-- no translation found for title_usb_accessory (4966265263465181372) -->
+    <skip />
+    <!-- no translation found for label_view (6304565553218192990) -->
+    <skip />
+    <!-- no translation found for always_use_device (1450287437017315906) -->
+    <skip />
+    <!-- no translation found for always_use_accessory (1210954576979621596) -->
+    <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-es-xlarge/strings.xml b/packages/SystemUI/res/values-es-xlarge/strings.xml
index dd490fb..a7588da 100644
--- a/packages/SystemUI/res/values-es-xlarge/strings.xml
+++ b/packages/SystemUI/res/values-es-xlarge/strings.xml
@@ -24,8 +24,6 @@
     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="1456658018593445677">"Con conexión WiFi"</string>
     <string name="gps_notification_searching_text" msgid="894185519046488403">"Buscando GPS"</string>
     <string name="gps_notification_found_text" msgid="5306445324124275852">"Ubicación definida por GPS"</string>
-    <!-- no translation found for notifications_off_title (2297252328026582111) -->
-    <skip />
-    <!-- no translation found for notifications_off_text (3754847213329718358) -->
-    <skip />
+    <string name="notifications_off_title" msgid="2297252328026582111">"Notificaciones desactivadas"</string>
+    <string name="notifications_off_text" msgid="3754847213329718358">"Toca aquí para volver a activar las notificaciones."</string>
 </resources>
diff --git a/packages/SystemUI/res/values-es/strings.xml b/packages/SystemUI/res/values-es/strings.xml
index 8d9cc5c..e6c1ce2 100644
--- a/packages/SystemUI/res/values-es/strings.xml
+++ b/packages/SystemUI/res/values-es/strings.xml
@@ -34,7 +34,7 @@
     <string name="status_bar_settings_settings_button" msgid="3023889916699270224">"Ajustes"</string>
     <string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"Wi-Fi"</string>
     <string name="status_bar_settings_airplane" msgid="4879879698500955300">"Modo avión"</string>
-    <string name="status_bar_settings_rotation_lock" msgid="8361452930058000609">"Bloquear orientación pantalla"</string>
+    <string name="status_bar_settings_auto_rotation" msgid="3790482541357798421">"Girar pantalla automáticamente"</string>
     <string name="status_bar_settings_mute_label" msgid="554682549917429396">"SILENC"</string>
     <string name="status_bar_settings_auto_brightness_label" msgid="511453614962324674">"AUTO"</string>
     <string name="status_bar_settings_notifications" msgid="397146176280905137">"Notificaciones"</string>
@@ -44,4 +44,22 @@
     <string name="bluetooth_tethered" msgid="7094101612161133267">"Bluetooth anclado"</string>
     <string name="status_bar_input_method_settings_configure_input_methods" msgid="737483394044014246">"Configurar métodos de introducción"</string>
     <string name="status_bar_use_physical_keyboard" msgid="3695516942412442936">"Utilizar teclado físico"</string>
+    <!-- no translation found for usb_device_permission_prompt (3816016361969816903) -->
+    <skip />
+    <!-- no translation found for usb_accessory_permission_prompt (6888598803988889959) -->
+    <skip />
+    <!-- no translation found for usb_device_confirm_prompt (5161205258635253206) -->
+    <skip />
+    <!-- no translation found for usb_accessory_confirm_prompt (3808984931830229888) -->
+    <skip />
+    <!-- no translation found for usb_accessory_uri_prompt (6332150684964235705) -->
+    <skip />
+    <!-- no translation found for title_usb_accessory (4966265263465181372) -->
+    <skip />
+    <!-- no translation found for label_view (6304565553218192990) -->
+    <skip />
+    <!-- no translation found for always_use_device (1450287437017315906) -->
+    <skip />
+    <!-- no translation found for always_use_accessory (1210954576979621596) -->
+    <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-fa-xlarge/strings.xml b/packages/SystemUI/res/values-fa-xlarge/strings.xml
index 6e0654d..a8e2543 100644
--- a/packages/SystemUI/res/values-fa-xlarge/strings.xml
+++ b/packages/SystemUI/res/values-fa-xlarge/strings.xml
@@ -24,8 +24,6 @@
     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="1456658018593445677">"Wi-Fi متصل شد"</string>
     <string name="gps_notification_searching_text" msgid="894185519046488403">"جستجوی GPS"</string>
     <string name="gps_notification_found_text" msgid="5306445324124275852">"مکان تنظیم شده توسط GPS"</string>
-    <!-- no translation found for notifications_off_title (2297252328026582111) -->
-    <skip />
-    <!-- no translation found for notifications_off_text (3754847213329718358) -->
-    <skip />
+    <string name="notifications_off_title" msgid="2297252328026582111">"اعلان ها خاموش"</string>
+    <string name="notifications_off_text" msgid="3754847213329718358">"برای روشن کردن مجدد اعلان ها، اینجا را ضربه بزنید."</string>
 </resources>
diff --git a/packages/SystemUI/res/values-fa/strings.xml b/packages/SystemUI/res/values-fa/strings.xml
index 1e0f1e9..9e70d5a 100644
--- a/packages/SystemUI/res/values-fa/strings.xml
+++ b/packages/SystemUI/res/values-fa/strings.xml
@@ -34,7 +34,7 @@
     <string name="status_bar_settings_settings_button" msgid="3023889916699270224">"تنظیمات"</string>
     <string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"Wi-Fi"</string>
     <string name="status_bar_settings_airplane" msgid="4879879698500955300">"حالت هواپیما"</string>
-    <string name="status_bar_settings_rotation_lock" msgid="8361452930058000609">"قفل جهت صفحه"</string>
+    <string name="status_bar_settings_auto_rotation" msgid="3790482541357798421">"چرخش خودکار صفحه"</string>
     <string name="status_bar_settings_mute_label" msgid="554682549917429396">"بیصدا"</string>
     <string name="status_bar_settings_auto_brightness_label" msgid="511453614962324674">"خودکار"</string>
     <string name="status_bar_settings_notifications" msgid="397146176280905137">"اعلان ها"</string>
@@ -44,4 +44,22 @@
     <string name="bluetooth_tethered" msgid="7094101612161133267">"اتصال اینترنتی با بلوتوث تلفن همراه"</string>
     <string name="status_bar_input_method_settings_configure_input_methods" msgid="737483394044014246">"پیکربندی روش های ورودی"</string>
     <string name="status_bar_use_physical_keyboard" msgid="3695516942412442936">"از صفحه کلید فیزیکی استفاده کنید"</string>
+    <!-- no translation found for usb_device_permission_prompt (3816016361969816903) -->
+    <skip />
+    <!-- no translation found for usb_accessory_permission_prompt (6888598803988889959) -->
+    <skip />
+    <!-- no translation found for usb_device_confirm_prompt (5161205258635253206) -->
+    <skip />
+    <!-- no translation found for usb_accessory_confirm_prompt (3808984931830229888) -->
+    <skip />
+    <!-- no translation found for usb_accessory_uri_prompt (6332150684964235705) -->
+    <skip />
+    <!-- no translation found for title_usb_accessory (4966265263465181372) -->
+    <skip />
+    <!-- no translation found for label_view (6304565553218192990) -->
+    <skip />
+    <!-- no translation found for always_use_device (1450287437017315906) -->
+    <skip />
+    <!-- no translation found for always_use_accessory (1210954576979621596) -->
+    <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-fi-xlarge/strings.xml b/packages/SystemUI/res/values-fi-xlarge/strings.xml
index 7d49e9b..754c577 100644
--- a/packages/SystemUI/res/values-fi-xlarge/strings.xml
+++ b/packages/SystemUI/res/values-fi-xlarge/strings.xml
@@ -24,8 +24,6 @@
     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="1456658018593445677">"Wifi yhdistetty"</string>
     <string name="gps_notification_searching_text" msgid="894185519046488403">"Haetaan GPS-yhteyttä"</string>
     <string name="gps_notification_found_text" msgid="5306445324124275852">"Sijainti määritetty GPS:n avulla"</string>
-    <!-- no translation found for notifications_off_title (2297252328026582111) -->
-    <skip />
-    <!-- no translation found for notifications_off_text (3754847213329718358) -->
-    <skip />
+    <string name="notifications_off_title" msgid="2297252328026582111">"Ilmoitukset pois käytöstä"</string>
+    <string name="notifications_off_text" msgid="3754847213329718358">"Ota ilmoitukset uudelleen käyttöön napauttamalla tätä."</string>
 </resources>
diff --git a/packages/SystemUI/res/values-fi/strings.xml b/packages/SystemUI/res/values-fi/strings.xml
index e2f935a..47b3220 100644
--- a/packages/SystemUI/res/values-fi/strings.xml
+++ b/packages/SystemUI/res/values-fi/strings.xml
@@ -34,7 +34,7 @@
     <string name="status_bar_settings_settings_button" msgid="3023889916699270224">"Asetukset"</string>
     <string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"WiFi"</string>
     <string name="status_bar_settings_airplane" msgid="4879879698500955300">"Lentokonetila"</string>
-    <string name="status_bar_settings_rotation_lock" msgid="8361452930058000609">"Lukitse ruudun suunta"</string>
+    <string name="status_bar_settings_auto_rotation" msgid="3790482541357798421">"Kierrä näyttöä automaattisesti"</string>
     <string name="status_bar_settings_mute_label" msgid="554682549917429396">"ÄÄNET."</string>
     <string name="status_bar_settings_auto_brightness_label" msgid="511453614962324674">"AUTO"</string>
     <string name="status_bar_settings_notifications" msgid="397146176280905137">"Ilmoitukset"</string>
@@ -44,4 +44,22 @@
     <string name="bluetooth_tethered" msgid="7094101612161133267">"Bluetooth yhdistetty"</string>
     <string name="status_bar_input_method_settings_configure_input_methods" msgid="737483394044014246">"Määritä syöttötavat"</string>
     <string name="status_bar_use_physical_keyboard" msgid="3695516942412442936">"Käytä fyysistä näppäimistöä"</string>
+    <!-- no translation found for usb_device_permission_prompt (3816016361969816903) -->
+    <skip />
+    <!-- no translation found for usb_accessory_permission_prompt (6888598803988889959) -->
+    <skip />
+    <!-- no translation found for usb_device_confirm_prompt (5161205258635253206) -->
+    <skip />
+    <!-- no translation found for usb_accessory_confirm_prompt (3808984931830229888) -->
+    <skip />
+    <!-- no translation found for usb_accessory_uri_prompt (6332150684964235705) -->
+    <skip />
+    <!-- no translation found for title_usb_accessory (4966265263465181372) -->
+    <skip />
+    <!-- no translation found for label_view (6304565553218192990) -->
+    <skip />
+    <!-- no translation found for always_use_device (1450287437017315906) -->
+    <skip />
+    <!-- no translation found for always_use_accessory (1210954576979621596) -->
+    <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-fr-xlarge/strings.xml b/packages/SystemUI/res/values-fr-xlarge/strings.xml
index 98dc6c0..08f673d 100644
--- a/packages/SystemUI/res/values-fr-xlarge/strings.xml
+++ b/packages/SystemUI/res/values-fr-xlarge/strings.xml
@@ -24,8 +24,6 @@
     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="1456658018593445677">"Connecté au Wi-Fi"</string>
     <string name="gps_notification_searching_text" msgid="894185519046488403">"Recherche de GPS en cours"</string>
     <string name="gps_notification_found_text" msgid="5306445324124275852">"Position définie par GPS"</string>
-    <!-- no translation found for notifications_off_title (2297252328026582111) -->
-    <skip />
-    <!-- no translation found for notifications_off_text (3754847213329718358) -->
-    <skip />
+    <string name="notifications_off_title" msgid="2297252328026582111">"Notifications désactivées"</string>
+    <string name="notifications_off_text" msgid="3754847213329718358">"Appuyez ici pour réactiver les notifications."</string>
 </resources>
diff --git a/packages/SystemUI/res/values-fr/strings.xml b/packages/SystemUI/res/values-fr/strings.xml
index 9bd1886..a4a287e 100644
--- a/packages/SystemUI/res/values-fr/strings.xml
+++ b/packages/SystemUI/res/values-fr/strings.xml
@@ -34,7 +34,7 @@
     <string name="status_bar_settings_settings_button" msgid="3023889916699270224">"Paramètres"</string>
     <string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"Wi-Fi"</string>
     <string name="status_bar_settings_airplane" msgid="4879879698500955300">"Mode Avion"</string>
-    <string name="status_bar_settings_rotation_lock" msgid="8361452930058000609">"Verrouiller orientation écran"</string>
+    <string name="status_bar_settings_auto_rotation" msgid="3790482541357798421">"Rotation automatique de l\'écran"</string>
     <string name="status_bar_settings_mute_label" msgid="554682549917429396">"MUET"</string>
     <string name="status_bar_settings_auto_brightness_label" msgid="511453614962324674">"AUTO"</string>
     <string name="status_bar_settings_notifications" msgid="397146176280905137">"Notifications"</string>
@@ -44,4 +44,22 @@
     <string name="bluetooth_tethered" msgid="7094101612161133267">"Connexion Bluetooth partagée"</string>
     <string name="status_bar_input_method_settings_configure_input_methods" msgid="737483394044014246">"Configurer les modes de saisie"</string>
     <string name="status_bar_use_physical_keyboard" msgid="3695516942412442936">"Utiliser clavier physique"</string>
+    <!-- no translation found for usb_device_permission_prompt (3816016361969816903) -->
+    <skip />
+    <!-- no translation found for usb_accessory_permission_prompt (6888598803988889959) -->
+    <skip />
+    <!-- no translation found for usb_device_confirm_prompt (5161205258635253206) -->
+    <skip />
+    <!-- no translation found for usb_accessory_confirm_prompt (3808984931830229888) -->
+    <skip />
+    <!-- no translation found for usb_accessory_uri_prompt (6332150684964235705) -->
+    <skip />
+    <!-- no translation found for title_usb_accessory (4966265263465181372) -->
+    <skip />
+    <!-- no translation found for label_view (6304565553218192990) -->
+    <skip />
+    <!-- no translation found for always_use_device (1450287437017315906) -->
+    <skip />
+    <!-- no translation found for always_use_accessory (1210954576979621596) -->
+    <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-hr-xlarge/strings.xml b/packages/SystemUI/res/values-hr-xlarge/strings.xml
index 08adaf0..b6e15dc 100644
--- a/packages/SystemUI/res/values-hr-xlarge/strings.xml
+++ b/packages/SystemUI/res/values-hr-xlarge/strings.xml
@@ -24,8 +24,6 @@
     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="1456658018593445677">"Wi-Fi: povezano"</string>
     <string name="gps_notification_searching_text" msgid="894185519046488403">"Pretraživanje GPS-a"</string>
     <string name="gps_notification_found_text" msgid="5306445324124275852">"Lokaciju utvrdio GPS"</string>
-    <!-- no translation found for notifications_off_title (2297252328026582111) -->
-    <skip />
-    <!-- no translation found for notifications_off_text (3754847213329718358) -->
-    <skip />
+    <string name="notifications_off_title" msgid="2297252328026582111">"Obavijesti isključene"</string>
+    <string name="notifications_off_text" msgid="3754847213329718358">"Dotaknite ovdje da biste ponovo uključili obavijesti."</string>
 </resources>
diff --git a/packages/SystemUI/res/values-hr/strings.xml b/packages/SystemUI/res/values-hr/strings.xml
index 8034eb7..680a3e3 100644
--- a/packages/SystemUI/res/values-hr/strings.xml
+++ b/packages/SystemUI/res/values-hr/strings.xml
@@ -34,7 +34,7 @@
     <string name="status_bar_settings_settings_button" msgid="3023889916699270224">"Postavke"</string>
     <string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"Wi-Fi"</string>
     <string name="status_bar_settings_airplane" msgid="4879879698500955300">"Način rada u zrakoplovu"</string>
-    <string name="status_bar_settings_rotation_lock" msgid="8361452930058000609">"Zaključaj orijentaciju zaslona"</string>
+    <string name="status_bar_settings_auto_rotation" msgid="3790482541357798421">"Automatski zakreni zaslon"</string>
     <string name="status_bar_settings_mute_label" msgid="554682549917429396">"Bez zv."</string>
     <string name="status_bar_settings_auto_brightness_label" msgid="511453614962324674">"AUTOM."</string>
     <string name="status_bar_settings_notifications" msgid="397146176280905137">"Obavijesti"</string>
@@ -44,4 +44,22 @@
     <string name="bluetooth_tethered" msgid="7094101612161133267">"Bluetooth posredno povezan"</string>
     <string name="status_bar_input_method_settings_configure_input_methods" msgid="737483394044014246">"Konfiguriraj načine ulaza"</string>
     <string name="status_bar_use_physical_keyboard" msgid="3695516942412442936">"Rabi fizičku tipkovnicu"</string>
+    <!-- no translation found for usb_device_permission_prompt (3816016361969816903) -->
+    <skip />
+    <!-- no translation found for usb_accessory_permission_prompt (6888598803988889959) -->
+    <skip />
+    <!-- no translation found for usb_device_confirm_prompt (5161205258635253206) -->
+    <skip />
+    <!-- no translation found for usb_accessory_confirm_prompt (3808984931830229888) -->
+    <skip />
+    <!-- no translation found for usb_accessory_uri_prompt (6332150684964235705) -->
+    <skip />
+    <!-- no translation found for title_usb_accessory (4966265263465181372) -->
+    <skip />
+    <!-- no translation found for label_view (6304565553218192990) -->
+    <skip />
+    <!-- no translation found for always_use_device (1450287437017315906) -->
+    <skip />
+    <!-- no translation found for always_use_accessory (1210954576979621596) -->
+    <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-hu-xlarge/strings.xml b/packages/SystemUI/res/values-hu-xlarge/strings.xml
index 41d60fc..fe2e5ee 100644
--- a/packages/SystemUI/res/values-hu-xlarge/strings.xml
+++ b/packages/SystemUI/res/values-hu-xlarge/strings.xml
@@ -24,8 +24,6 @@
     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="1456658018593445677">"Wi-Fi csatlakozva"</string>
     <string name="gps_notification_searching_text" msgid="894185519046488403">"GPS keresése"</string>
     <string name="gps_notification_found_text" msgid="5306445324124275852">"A GPS beállította a helyet"</string>
-    <!-- no translation found for notifications_off_title (2297252328026582111) -->
-    <skip />
-    <!-- no translation found for notifications_off_text (3754847213329718358) -->
-    <skip />
+    <string name="notifications_off_title" msgid="2297252328026582111">"Értesítések kikapcsolva"</string>
+    <string name="notifications_off_text" msgid="3754847213329718358">"Itt érintse meg az értesítések bekapcsolásához."</string>
 </resources>
diff --git a/packages/SystemUI/res/values-hu/strings.xml b/packages/SystemUI/res/values-hu/strings.xml
index 9a91b13..9a103f7 100644
--- a/packages/SystemUI/res/values-hu/strings.xml
+++ b/packages/SystemUI/res/values-hu/strings.xml
@@ -34,7 +34,7 @@
     <string name="status_bar_settings_settings_button" msgid="3023889916699270224">"Beállítások"</string>
     <string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"Wi-Fi"</string>
     <string name="status_bar_settings_airplane" msgid="4879879698500955300">"Repülőgép üzemmód"</string>
-    <string name="status_bar_settings_rotation_lock" msgid="8361452930058000609">"Telefon tájolásának zárolása"</string>
+    <string name="status_bar_settings_auto_rotation" msgid="3790482541357798421">"Képernyő automatikus forgatása"</string>
     <string name="status_bar_settings_mute_label" msgid="554682549917429396">"NÉMÍT"</string>
     <string name="status_bar_settings_auto_brightness_label" msgid="511453614962324674">"AUTO"</string>
     <string name="status_bar_settings_notifications" msgid="397146176280905137">"Értesítések"</string>
@@ -44,4 +44,22 @@
     <string name="bluetooth_tethered" msgid="7094101612161133267">"Bluetooth megosztva"</string>
     <string name="status_bar_input_method_settings_configure_input_methods" msgid="737483394044014246">"Beviteli módok konfigurálása"</string>
     <string name="status_bar_use_physical_keyboard" msgid="3695516942412442936">"Valódi bill. használata"</string>
+    <!-- no translation found for usb_device_permission_prompt (3816016361969816903) -->
+    <skip />
+    <!-- no translation found for usb_accessory_permission_prompt (6888598803988889959) -->
+    <skip />
+    <!-- no translation found for usb_device_confirm_prompt (5161205258635253206) -->
+    <skip />
+    <!-- no translation found for usb_accessory_confirm_prompt (3808984931830229888) -->
+    <skip />
+    <!-- no translation found for usb_accessory_uri_prompt (6332150684964235705) -->
+    <skip />
+    <!-- no translation found for title_usb_accessory (4966265263465181372) -->
+    <skip />
+    <!-- no translation found for label_view (6304565553218192990) -->
+    <skip />
+    <!-- no translation found for always_use_device (1450287437017315906) -->
+    <skip />
+    <!-- no translation found for always_use_accessory (1210954576979621596) -->
+    <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-in-xlarge/strings.xml b/packages/SystemUI/res/values-in-xlarge/strings.xml
index 8d95060..a4ca341 100644
--- a/packages/SystemUI/res/values-in-xlarge/strings.xml
+++ b/packages/SystemUI/res/values-in-xlarge/strings.xml
@@ -24,8 +24,6 @@
     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="1456658018593445677">"Wi-Fi tersambung"</string>
     <string name="gps_notification_searching_text" msgid="894185519046488403">"Menelusuri GPS"</string>
     <string name="gps_notification_found_text" msgid="5306445324124275852">"Lokasi yang disetel oleh GPS"</string>
-    <!-- no translation found for notifications_off_title (2297252328026582111) -->
-    <skip />
-    <!-- no translation found for notifications_off_text (3754847213329718358) -->
-    <skip />
+    <string name="notifications_off_title" msgid="2297252328026582111">"Pemberitahuan mati"</string>
+    <string name="notifications_off_text" msgid="3754847213329718358">"Ketuk di sini untuk menghidupkan lagi pemberitahuan."</string>
 </resources>
diff --git a/packages/SystemUI/res/values-in/strings.xml b/packages/SystemUI/res/values-in/strings.xml
index 8d3cfb1..e7fbbbe 100644
--- a/packages/SystemUI/res/values-in/strings.xml
+++ b/packages/SystemUI/res/values-in/strings.xml
@@ -34,7 +34,7 @@
     <string name="status_bar_settings_settings_button" msgid="3023889916699270224">"Setelan"</string>
     <string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"Wi-Fi"</string>
     <string name="status_bar_settings_airplane" msgid="4879879698500955300">"Mode pesawat"</string>
-    <string name="status_bar_settings_rotation_lock" msgid="8361452930058000609">"Kunci orientasi layar"</string>
+    <string name="status_bar_settings_auto_rotation" msgid="3790482541357798421">"Putar layar secara otomatis"</string>
     <string name="status_bar_settings_mute_label" msgid="554682549917429396">"BISUKAN"</string>
     <string name="status_bar_settings_auto_brightness_label" msgid="511453614962324674">"AUTO"</string>
     <string name="status_bar_settings_notifications" msgid="397146176280905137">"Pemberitahuan"</string>
@@ -44,4 +44,22 @@
     <string name="bluetooth_tethered" msgid="7094101612161133267">"Bluetooth tertambat"</string>
     <string name="status_bar_input_method_settings_configure_input_methods" msgid="737483394044014246">"Konfigurasikan metode masukan"</string>
     <string name="status_bar_use_physical_keyboard" msgid="3695516942412442936">"Gunakan keyboard fisik"</string>
+    <!-- no translation found for usb_device_permission_prompt (3816016361969816903) -->
+    <skip />
+    <!-- no translation found for usb_accessory_permission_prompt (6888598803988889959) -->
+    <skip />
+    <!-- no translation found for usb_device_confirm_prompt (5161205258635253206) -->
+    <skip />
+    <!-- no translation found for usb_accessory_confirm_prompt (3808984931830229888) -->
+    <skip />
+    <!-- no translation found for usb_accessory_uri_prompt (6332150684964235705) -->
+    <skip />
+    <!-- no translation found for title_usb_accessory (4966265263465181372) -->
+    <skip />
+    <!-- no translation found for label_view (6304565553218192990) -->
+    <skip />
+    <!-- no translation found for always_use_device (1450287437017315906) -->
+    <skip />
+    <!-- no translation found for always_use_accessory (1210954576979621596) -->
+    <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-it-xlarge/strings.xml b/packages/SystemUI/res/values-it-xlarge/strings.xml
index 68393fb..24d88744 100644
--- a/packages/SystemUI/res/values-it-xlarge/strings.xml
+++ b/packages/SystemUI/res/values-it-xlarge/strings.xml
@@ -24,8 +24,6 @@
     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="1456658018593445677">"Wi-Fi: connesso"</string>
     <string name="gps_notification_searching_text" msgid="894185519046488403">"Ricerca del GPS"</string>
     <string name="gps_notification_found_text" msgid="5306445324124275852">"Posizione stabilita dal GPS"</string>
-    <!-- no translation found for notifications_off_title (2297252328026582111) -->
-    <skip />
-    <!-- no translation found for notifications_off_text (3754847213329718358) -->
-    <skip />
+    <string name="notifications_off_title" msgid="2297252328026582111">"Notifiche disattivate"</string>
+    <string name="notifications_off_text" msgid="3754847213329718358">"Tocca qui per riattivare le notifiche."</string>
 </resources>
diff --git a/packages/SystemUI/res/values-it/strings.xml b/packages/SystemUI/res/values-it/strings.xml
index 9e7f53a..b541374 100644
--- a/packages/SystemUI/res/values-it/strings.xml
+++ b/packages/SystemUI/res/values-it/strings.xml
@@ -34,7 +34,7 @@
     <string name="status_bar_settings_settings_button" msgid="3023889916699270224">"Impostazioni"</string>
     <string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"Wi-Fi"</string>
     <string name="status_bar_settings_airplane" msgid="4879879698500955300">"Modalità aereo"</string>
-    <string name="status_bar_settings_rotation_lock" msgid="8361452930058000609">"Blocca orientamento schermo"</string>
+    <string name="status_bar_settings_auto_rotation" msgid="3790482541357798421">"Rotazione automatica schermo"</string>
     <string name="status_bar_settings_mute_label" msgid="554682549917429396">"MUTE"</string>
     <string name="status_bar_settings_auto_brightness_label" msgid="511453614962324674">"AUTO"</string>
     <string name="status_bar_settings_notifications" msgid="397146176280905137">"Notifiche"</string>
@@ -44,4 +44,22 @@
     <string name="bluetooth_tethered" msgid="7094101612161133267">"Bluetooth con tethering"</string>
     <string name="status_bar_input_method_settings_configure_input_methods" msgid="737483394044014246">"Configura metodi di input"</string>
     <string name="status_bar_use_physical_keyboard" msgid="3695516942412442936">"Utilizza tastiera fisica"</string>
+    <!-- no translation found for usb_device_permission_prompt (3816016361969816903) -->
+    <skip />
+    <!-- no translation found for usb_accessory_permission_prompt (6888598803988889959) -->
+    <skip />
+    <!-- no translation found for usb_device_confirm_prompt (5161205258635253206) -->
+    <skip />
+    <!-- no translation found for usb_accessory_confirm_prompt (3808984931830229888) -->
+    <skip />
+    <!-- no translation found for usb_accessory_uri_prompt (6332150684964235705) -->
+    <skip />
+    <!-- no translation found for title_usb_accessory (4966265263465181372) -->
+    <skip />
+    <!-- no translation found for label_view (6304565553218192990) -->
+    <skip />
+    <!-- no translation found for always_use_device (1450287437017315906) -->
+    <skip />
+    <!-- no translation found for always_use_accessory (1210954576979621596) -->
+    <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-iw-xlarge/strings.xml b/packages/SystemUI/res/values-iw-xlarge/strings.xml
index fd3ce0e..97172b8 100644
--- a/packages/SystemUI/res/values-iw-xlarge/strings.xml
+++ b/packages/SystemUI/res/values-iw-xlarge/strings.xml
@@ -24,8 +24,6 @@
     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="1456658018593445677">"Wi-Fi מחובר"</string>
     <string name="gps_notification_searching_text" msgid="894185519046488403">"מחפש GPS"</string>
     <string name="gps_notification_found_text" msgid="5306445324124275852">"מיקום מוגדר על ידי GPS"</string>
-    <!-- no translation found for notifications_off_title (2297252328026582111) -->
-    <skip />
-    <!-- no translation found for notifications_off_text (3754847213329718358) -->
-    <skip />
+    <string name="notifications_off_title" msgid="2297252328026582111">"מצב התראות כבוי"</string>
+    <string name="notifications_off_text" msgid="3754847213329718358">"הקש כאן כדי להפעיל מחדש את ההתראות."</string>
 </resources>
diff --git a/packages/SystemUI/res/values-iw/strings.xml b/packages/SystemUI/res/values-iw/strings.xml
index a242d04..3194cf5 100644
--- a/packages/SystemUI/res/values-iw/strings.xml
+++ b/packages/SystemUI/res/values-iw/strings.xml
@@ -34,7 +34,7 @@
     <string name="status_bar_settings_settings_button" msgid="3023889916699270224">"הגדרות"</string>
     <string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"Wi-Fi"</string>
     <string name="status_bar_settings_airplane" msgid="4879879698500955300">"מצב טיסה"</string>
-    <string name="status_bar_settings_rotation_lock" msgid="8361452930058000609">"נעל כיוון מסך"</string>
+    <string name="status_bar_settings_auto_rotation" msgid="3790482541357798421">"סיבוב אוטומטי של המסך"</string>
     <string name="status_bar_settings_mute_label" msgid="554682549917429396">"השתק"</string>
     <string name="status_bar_settings_auto_brightness_label" msgid="511453614962324674">"אוטומטי"</string>
     <string name="status_bar_settings_notifications" msgid="397146176280905137">"התראות"</string>
@@ -44,4 +44,22 @@
     <string name="bluetooth_tethered" msgid="7094101612161133267">"Bluetooth קשור"</string>
     <string name="status_bar_input_method_settings_configure_input_methods" msgid="737483394044014246">"הגדר שיטות קלט"</string>
     <string name="status_bar_use_physical_keyboard" msgid="3695516942412442936">"השתמש במקלדת הפיזית"</string>
+    <!-- no translation found for usb_device_permission_prompt (3816016361969816903) -->
+    <skip />
+    <!-- no translation found for usb_accessory_permission_prompt (6888598803988889959) -->
+    <skip />
+    <!-- no translation found for usb_device_confirm_prompt (5161205258635253206) -->
+    <skip />
+    <!-- no translation found for usb_accessory_confirm_prompt (3808984931830229888) -->
+    <skip />
+    <!-- no translation found for usb_accessory_uri_prompt (6332150684964235705) -->
+    <skip />
+    <!-- no translation found for title_usb_accessory (4966265263465181372) -->
+    <skip />
+    <!-- no translation found for label_view (6304565553218192990) -->
+    <skip />
+    <!-- no translation found for always_use_device (1450287437017315906) -->
+    <skip />
+    <!-- no translation found for always_use_accessory (1210954576979621596) -->
+    <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-ja-xlarge/strings.xml b/packages/SystemUI/res/values-ja-xlarge/strings.xml
index c7c0824..e67e0e1 100644
--- a/packages/SystemUI/res/values-ja-xlarge/strings.xml
+++ b/packages/SystemUI/res/values-ja-xlarge/strings.xml
@@ -24,8 +24,6 @@
     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="1456658018593445677">"Wi-Fi接続済み"</string>
     <string name="gps_notification_searching_text" msgid="894185519046488403">"GPSで検索中"</string>
     <string name="gps_notification_found_text" msgid="5306445324124275852">"GPSにより現在地が設定されました"</string>
-    <!-- no translation found for notifications_off_title (2297252328026582111) -->
-    <skip />
-    <!-- no translation found for notifications_off_text (3754847213329718358) -->
-    <skip />
+    <string name="notifications_off_title" msgid="2297252328026582111">"通知OFF"</string>
+    <string name="notifications_off_text" msgid="3754847213329718358">"通知を有効にするにはここをタップします。"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-ja/strings.xml b/packages/SystemUI/res/values-ja/strings.xml
index 869688c..ac82ed4 100644
--- a/packages/SystemUI/res/values-ja/strings.xml
+++ b/packages/SystemUI/res/values-ja/strings.xml
@@ -34,7 +34,7 @@
     <string name="status_bar_settings_settings_button" msgid="3023889916699270224">"設定"</string>
     <string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"Wi-Fi"</string>
     <string name="status_bar_settings_airplane" msgid="4879879698500955300">"機内モード"</string>
-    <string name="status_bar_settings_rotation_lock" msgid="8361452930058000609">"画面の向きをロック"</string>
+    <string name="status_bar_settings_auto_rotation" msgid="3790482541357798421">"自動回転画面"</string>
     <string name="status_bar_settings_mute_label" msgid="554682549917429396">"ミュート"</string>
     <string name="status_bar_settings_auto_brightness_label" msgid="511453614962324674">"オート"</string>
     <string name="status_bar_settings_notifications" msgid="397146176280905137">"通知"</string>
@@ -44,4 +44,22 @@
     <string name="bluetooth_tethered" msgid="7094101612161133267">"Bluetoothテザリング接続"</string>
     <string name="status_bar_input_method_settings_configure_input_methods" msgid="737483394044014246">"入力方法の設定"</string>
     <string name="status_bar_use_physical_keyboard" msgid="3695516942412442936">"物理キーボードを使用"</string>
+    <!-- no translation found for usb_device_permission_prompt (3816016361969816903) -->
+    <skip />
+    <!-- no translation found for usb_accessory_permission_prompt (6888598803988889959) -->
+    <skip />
+    <!-- no translation found for usb_device_confirm_prompt (5161205258635253206) -->
+    <skip />
+    <!-- no translation found for usb_accessory_confirm_prompt (3808984931830229888) -->
+    <skip />
+    <!-- no translation found for usb_accessory_uri_prompt (6332150684964235705) -->
+    <skip />
+    <!-- no translation found for title_usb_accessory (4966265263465181372) -->
+    <skip />
+    <!-- no translation found for label_view (6304565553218192990) -->
+    <skip />
+    <!-- no translation found for always_use_device (1450287437017315906) -->
+    <skip />
+    <!-- no translation found for always_use_accessory (1210954576979621596) -->
+    <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-ko-xlarge/strings.xml b/packages/SystemUI/res/values-ko-xlarge/strings.xml
index 3777154..e28ac63 100644
--- a/packages/SystemUI/res/values-ko-xlarge/strings.xml
+++ b/packages/SystemUI/res/values-ko-xlarge/strings.xml
@@ -24,8 +24,6 @@
     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="1456658018593445677">"Wi-Fi 연결됨"</string>
     <string name="gps_notification_searching_text" msgid="894185519046488403">"GPS 검색"</string>
     <string name="gps_notification_found_text" msgid="5306445324124275852">"GPS에서 설정한 위치"</string>
-    <!-- no translation found for notifications_off_title (2297252328026582111) -->
-    <skip />
-    <!-- no translation found for notifications_off_text (3754847213329718358) -->
-    <skip />
+    <string name="notifications_off_title" msgid="2297252328026582111">"알림 사용 안함"</string>
+    <string name="notifications_off_text" msgid="3754847213329718358">"알림을 다시 사용하려면 여기를 누르세요."</string>
 </resources>
diff --git a/packages/SystemUI/res/values-ko/strings.xml b/packages/SystemUI/res/values-ko/strings.xml
index 32ae7e7..2d4786d 100644
--- a/packages/SystemUI/res/values-ko/strings.xml
+++ b/packages/SystemUI/res/values-ko/strings.xml
@@ -34,7 +34,7 @@
     <string name="status_bar_settings_settings_button" msgid="3023889916699270224">"설정"</string>
     <string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"Wi-Fi"</string>
     <string name="status_bar_settings_airplane" msgid="4879879698500955300">"비행기 모드"</string>
-    <string name="status_bar_settings_rotation_lock" msgid="8361452930058000609">"화면 방향 잠금"</string>
+    <string name="status_bar_settings_auto_rotation" msgid="3790482541357798421">"자동 화면 회전"</string>
     <string name="status_bar_settings_mute_label" msgid="554682549917429396">"무시"</string>
     <string name="status_bar_settings_auto_brightness_label" msgid="511453614962324674">"자동"</string>
     <string name="status_bar_settings_notifications" msgid="397146176280905137">"알림"</string>
@@ -44,4 +44,22 @@
     <string name="bluetooth_tethered" msgid="7094101612161133267">"블루투스 테더링됨"</string>
     <string name="status_bar_input_method_settings_configure_input_methods" msgid="737483394044014246">"입력 방법 구성"</string>
     <string name="status_bar_use_physical_keyboard" msgid="3695516942412442936">"물리적 키보드 사용"</string>
+    <!-- no translation found for usb_device_permission_prompt (3816016361969816903) -->
+    <skip />
+    <!-- no translation found for usb_accessory_permission_prompt (6888598803988889959) -->
+    <skip />
+    <!-- no translation found for usb_device_confirm_prompt (5161205258635253206) -->
+    <skip />
+    <!-- no translation found for usb_accessory_confirm_prompt (3808984931830229888) -->
+    <skip />
+    <!-- no translation found for usb_accessory_uri_prompt (6332150684964235705) -->
+    <skip />
+    <!-- no translation found for title_usb_accessory (4966265263465181372) -->
+    <skip />
+    <!-- no translation found for label_view (6304565553218192990) -->
+    <skip />
+    <!-- no translation found for always_use_device (1450287437017315906) -->
+    <skip />
+    <!-- no translation found for always_use_accessory (1210954576979621596) -->
+    <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-lt-xlarge/strings.xml b/packages/SystemUI/res/values-lt-xlarge/strings.xml
index 90dd501..12e8bb3 100644
--- a/packages/SystemUI/res/values-lt-xlarge/strings.xml
+++ b/packages/SystemUI/res/values-lt-xlarge/strings.xml
@@ -24,8 +24,6 @@
     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="1456658018593445677">"Prisijungta prie „Wi-Fi“"</string>
     <string name="gps_notification_searching_text" msgid="894185519046488403">"Ieškoma GPS"</string>
     <string name="gps_notification_found_text" msgid="5306445324124275852">"GPS nustatyta vieta"</string>
-    <!-- no translation found for notifications_off_title (2297252328026582111) -->
-    <skip />
-    <!-- no translation found for notifications_off_text (3754847213329718358) -->
-    <skip />
+    <string name="notifications_off_title" msgid="2297252328026582111">"Pranešimai išjungti"</string>
+    <string name="notifications_off_text" msgid="3754847213329718358">"Palieskite čia, kad vėl įjungtumėte pranešimus."</string>
 </resources>
diff --git a/packages/SystemUI/res/values-lt/strings.xml b/packages/SystemUI/res/values-lt/strings.xml
index 01cdffd..db06596 100644
--- a/packages/SystemUI/res/values-lt/strings.xml
+++ b/packages/SystemUI/res/values-lt/strings.xml
@@ -34,7 +34,7 @@
     <string name="status_bar_settings_settings_button" msgid="3023889916699270224">"Nustatymai"</string>
     <string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"Wi-Fi"</string>
     <string name="status_bar_settings_airplane" msgid="4879879698500955300">"Lėktuvo režimas"</string>
-    <string name="status_bar_settings_rotation_lock" msgid="8361452930058000609">"Užfiksuoti ekrano orientaciją"</string>
+    <string name="status_bar_settings_auto_rotation" msgid="3790482541357798421">"Automatiškai sukti ekraną"</string>
     <string name="status_bar_settings_mute_label" msgid="554682549917429396">"NUTILD."</string>
     <string name="status_bar_settings_auto_brightness_label" msgid="511453614962324674">"AUTOM."</string>
     <string name="status_bar_settings_notifications" msgid="397146176280905137">"Pranešimai"</string>
@@ -44,4 +44,22 @@
     <string name="bluetooth_tethered" msgid="7094101612161133267">"„Bluetooth“ susieta"</string>
     <string name="status_bar_input_method_settings_configure_input_methods" msgid="737483394044014246">"Konfigūruoti įvesties metodus"</string>
     <string name="status_bar_use_physical_keyboard" msgid="3695516942412442936">"Naudoti fizinę klaviatūrą"</string>
+    <!-- no translation found for usb_device_permission_prompt (3816016361969816903) -->
+    <skip />
+    <!-- no translation found for usb_accessory_permission_prompt (6888598803988889959) -->
+    <skip />
+    <!-- no translation found for usb_device_confirm_prompt (5161205258635253206) -->
+    <skip />
+    <!-- no translation found for usb_accessory_confirm_prompt (3808984931830229888) -->
+    <skip />
+    <!-- no translation found for usb_accessory_uri_prompt (6332150684964235705) -->
+    <skip />
+    <!-- no translation found for title_usb_accessory (4966265263465181372) -->
+    <skip />
+    <!-- no translation found for label_view (6304565553218192990) -->
+    <skip />
+    <!-- no translation found for always_use_device (1450287437017315906) -->
+    <skip />
+    <!-- no translation found for always_use_accessory (1210954576979621596) -->
+    <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-lv-xlarge/strings.xml b/packages/SystemUI/res/values-lv-xlarge/strings.xml
index c533ecb..aecb471 100644
--- a/packages/SystemUI/res/values-lv-xlarge/strings.xml
+++ b/packages/SystemUI/res/values-lv-xlarge/strings.xml
@@ -24,8 +24,6 @@
     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="1456658018593445677">"Izv. sav. ar Wi-Fi"</string>
     <string name="gps_notification_searching_text" msgid="894185519046488403">"Notiek GPS meklēšana..."</string>
     <string name="gps_notification_found_text" msgid="5306445324124275852">"GPS iestatītā atrašanās vieta"</string>
-    <!-- no translation found for notifications_off_title (2297252328026582111) -->
-    <skip />
-    <!-- no translation found for notifications_off_text (3754847213329718358) -->
-    <skip />
+    <string name="notifications_off_title" msgid="2297252328026582111">"Paziņojumi ir izslēgti."</string>
+    <string name="notifications_off_text" msgid="3754847213329718358">"Pieskarieties šeit, lai vēlreiz ieslēgtu paziņojumus."</string>
 </resources>
diff --git a/packages/SystemUI/res/values-lv/strings.xml b/packages/SystemUI/res/values-lv/strings.xml
index 817e1d5..079591e 100644
--- a/packages/SystemUI/res/values-lv/strings.xml
+++ b/packages/SystemUI/res/values-lv/strings.xml
@@ -34,7 +34,7 @@
     <string name="status_bar_settings_settings_button" msgid="3023889916699270224">"Iestatījumi"</string>
     <string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"Wi-Fi"</string>
     <string name="status_bar_settings_airplane" msgid="4879879698500955300">"Lidmašīnas režīms"</string>
-    <string name="status_bar_settings_rotation_lock" msgid="8361452930058000609">"Bloķēt ekrāna orientāciju"</string>
+    <string name="status_bar_settings_auto_rotation" msgid="3790482541357798421">"Ekrāna automātiska pagriešana"</string>
     <string name="status_bar_settings_mute_label" msgid="554682549917429396">"IZ. SK."</string>
     <string name="status_bar_settings_auto_brightness_label" msgid="511453614962324674">"AUTOM."</string>
     <string name="status_bar_settings_notifications" msgid="397146176280905137">"Paziņojumi"</string>
@@ -44,4 +44,22 @@
     <string name="bluetooth_tethered" msgid="7094101612161133267">"Bluetooth piesaiste"</string>
     <string name="status_bar_input_method_settings_configure_input_methods" msgid="737483394044014246">"Konfigurēt ievades metodes"</string>
     <string name="status_bar_use_physical_keyboard" msgid="3695516942412442936">"Izmantot fizisku tastatūru"</string>
+    <!-- no translation found for usb_device_permission_prompt (3816016361969816903) -->
+    <skip />
+    <!-- no translation found for usb_accessory_permission_prompt (6888598803988889959) -->
+    <skip />
+    <!-- no translation found for usb_device_confirm_prompt (5161205258635253206) -->
+    <skip />
+    <!-- no translation found for usb_accessory_confirm_prompt (3808984931830229888) -->
+    <skip />
+    <!-- no translation found for usb_accessory_uri_prompt (6332150684964235705) -->
+    <skip />
+    <!-- no translation found for title_usb_accessory (4966265263465181372) -->
+    <skip />
+    <!-- no translation found for label_view (6304565553218192990) -->
+    <skip />
+    <!-- no translation found for always_use_device (1450287437017315906) -->
+    <skip />
+    <!-- no translation found for always_use_accessory (1210954576979621596) -->
+    <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-nb-xlarge/strings.xml b/packages/SystemUI/res/values-nb-xlarge/strings.xml
index 2bf63e8..717ee79 100644
--- a/packages/SystemUI/res/values-nb-xlarge/strings.xml
+++ b/packages/SystemUI/res/values-nb-xlarge/strings.xml
@@ -24,8 +24,6 @@
     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="1456658018593445677">"Wi-Fi: tilkoblet"</string>
     <string name="gps_notification_searching_text" msgid="894185519046488403">"Søker etter GPS"</string>
     <string name="gps_notification_found_text" msgid="5306445324124275852">"Posisjon angitt av GPS"</string>
-    <!-- no translation found for notifications_off_title (2297252328026582111) -->
-    <skip />
-    <!-- no translation found for notifications_off_text (3754847213329718358) -->
-    <skip />
+    <string name="notifications_off_title" msgid="2297252328026582111">"Varslinger er slått av"</string>
+    <string name="notifications_off_text" msgid="3754847213329718358">"Trykk her for å slå på varslinger igjen."</string>
 </resources>
diff --git a/packages/SystemUI/res/values-nb/strings.xml b/packages/SystemUI/res/values-nb/strings.xml
index bb96483..b7e7711 100644
--- a/packages/SystemUI/res/values-nb/strings.xml
+++ b/packages/SystemUI/res/values-nb/strings.xml
@@ -34,7 +34,7 @@
     <string name="status_bar_settings_settings_button" msgid="3023889916699270224">"Innstillinger"</string>
     <string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"Trådløse nettverk"</string>
     <string name="status_bar_settings_airplane" msgid="4879879698500955300">"Flymodus"</string>
-    <string name="status_bar_settings_rotation_lock" msgid="8361452930058000609">"Lås skjermretning"</string>
+    <string name="status_bar_settings_auto_rotation" msgid="3790482541357798421">"Roter skjerm automatisk"</string>
     <string name="status_bar_settings_mute_label" msgid="554682549917429396">"DEMPET"</string>
     <string name="status_bar_settings_auto_brightness_label" msgid="511453614962324674">"AUTO"</string>
     <string name="status_bar_settings_notifications" msgid="397146176280905137">"Varslinger"</string>
@@ -44,4 +44,22 @@
     <string name="bluetooth_tethered" msgid="7094101612161133267">"Bluetooth tilknyttet"</string>
     <string name="status_bar_input_method_settings_configure_input_methods" msgid="737483394044014246">"Konfigurer inndatametoder"</string>
     <string name="status_bar_use_physical_keyboard" msgid="3695516942412442936">"Bruk fysisk tastatur"</string>
+    <!-- no translation found for usb_device_permission_prompt (3816016361969816903) -->
+    <skip />
+    <!-- no translation found for usb_accessory_permission_prompt (6888598803988889959) -->
+    <skip />
+    <!-- no translation found for usb_device_confirm_prompt (5161205258635253206) -->
+    <skip />
+    <!-- no translation found for usb_accessory_confirm_prompt (3808984931830229888) -->
+    <skip />
+    <!-- no translation found for usb_accessory_uri_prompt (6332150684964235705) -->
+    <skip />
+    <!-- no translation found for title_usb_accessory (4966265263465181372) -->
+    <skip />
+    <!-- no translation found for label_view (6304565553218192990) -->
+    <skip />
+    <!-- no translation found for always_use_device (1450287437017315906) -->
+    <skip />
+    <!-- no translation found for always_use_accessory (1210954576979621596) -->
+    <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-nl-xlarge/strings.xml b/packages/SystemUI/res/values-nl-xlarge/strings.xml
index 7a63401..7c84a7a 100644
--- a/packages/SystemUI/res/values-nl-xlarge/strings.xml
+++ b/packages/SystemUI/res/values-nl-xlarge/strings.xml
@@ -24,8 +24,6 @@
     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="1456658018593445677">"Verbonden via Wi-Fi"</string>
     <string name="gps_notification_searching_text" msgid="894185519046488403">"Zoeken naar GPS"</string>
     <string name="gps_notification_found_text" msgid="5306445324124275852">"Locatie bepaald met GPS"</string>
-    <!-- no translation found for notifications_off_title (2297252328026582111) -->
-    <skip />
-    <!-- no translation found for notifications_off_text (3754847213329718358) -->
-    <skip />
+    <string name="notifications_off_title" msgid="2297252328026582111">"Meldingen uit"</string>
+    <string name="notifications_off_text" msgid="3754847213329718358">"Tik hier om meldingen weer in te schakelen."</string>
 </resources>
diff --git a/packages/SystemUI/res/values-nl/strings.xml b/packages/SystemUI/res/values-nl/strings.xml
index faf3f32..cc9e7a3 100644
--- a/packages/SystemUI/res/values-nl/strings.xml
+++ b/packages/SystemUI/res/values-nl/strings.xml
@@ -34,7 +34,7 @@
     <string name="status_bar_settings_settings_button" msgid="3023889916699270224">"Instellingen"</string>
     <string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"Wi-Fi"</string>
     <string name="status_bar_settings_airplane" msgid="4879879698500955300">"Vliegmodus"</string>
-    <string name="status_bar_settings_rotation_lock" msgid="8361452930058000609">"Schermstand vergrendelen"</string>
+    <string name="status_bar_settings_auto_rotation" msgid="3790482541357798421">"Scherm automatisch draaien"</string>
     <string name="status_bar_settings_mute_label" msgid="554682549917429396">"DEMPEN"</string>
     <string name="status_bar_settings_auto_brightness_label" msgid="511453614962324674">"AUTO"</string>
     <string name="status_bar_settings_notifications" msgid="397146176280905137">"Meldingen"</string>
@@ -44,4 +44,22 @@
     <string name="bluetooth_tethered" msgid="7094101612161133267">"Bluetooth getetherd"</string>
     <string name="status_bar_input_method_settings_configure_input_methods" msgid="737483394044014246">"Invoermethoden configureren"</string>
     <string name="status_bar_use_physical_keyboard" msgid="3695516942412442936">"Fysiek toetsenbord gebruiken"</string>
+    <!-- no translation found for usb_device_permission_prompt (3816016361969816903) -->
+    <skip />
+    <!-- no translation found for usb_accessory_permission_prompt (6888598803988889959) -->
+    <skip />
+    <!-- no translation found for usb_device_confirm_prompt (5161205258635253206) -->
+    <skip />
+    <!-- no translation found for usb_accessory_confirm_prompt (3808984931830229888) -->
+    <skip />
+    <!-- no translation found for usb_accessory_uri_prompt (6332150684964235705) -->
+    <skip />
+    <!-- no translation found for title_usb_accessory (4966265263465181372) -->
+    <skip />
+    <!-- no translation found for label_view (6304565553218192990) -->
+    <skip />
+    <!-- no translation found for always_use_device (1450287437017315906) -->
+    <skip />
+    <!-- no translation found for always_use_accessory (1210954576979621596) -->
+    <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-pl-xlarge/strings.xml b/packages/SystemUI/res/values-pl-xlarge/strings.xml
index 1334b70..9db1cab 100644
--- a/packages/SystemUI/res/values-pl-xlarge/strings.xml
+++ b/packages/SystemUI/res/values-pl-xlarge/strings.xml
@@ -24,8 +24,6 @@
     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="1456658018593445677">"Wi-Fi: połączono"</string>
     <string name="gps_notification_searching_text" msgid="894185519046488403">"Wyszukiwanie sygnału GPS"</string>
     <string name="gps_notification_found_text" msgid="5306445324124275852">"Lokalizacja ustawiona wg GPS"</string>
-    <!-- no translation found for notifications_off_title (2297252328026582111) -->
-    <skip />
-    <!-- no translation found for notifications_off_text (3754847213329718358) -->
-    <skip />
+    <string name="notifications_off_title" msgid="2297252328026582111">"Powiadomienia wyłączone"</string>
+    <string name="notifications_off_text" msgid="3754847213329718358">"Dotknij tutaj, aby z powrotem włączyć powiadomienia."</string>
 </resources>
diff --git a/packages/SystemUI/res/values-pl/strings.xml b/packages/SystemUI/res/values-pl/strings.xml
index 77ae7e7..67d9cc1 100644
--- a/packages/SystemUI/res/values-pl/strings.xml
+++ b/packages/SystemUI/res/values-pl/strings.xml
@@ -34,7 +34,7 @@
     <string name="status_bar_settings_settings_button" msgid="3023889916699270224">"Ustawienia"</string>
     <string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"Wi-Fi"</string>
     <string name="status_bar_settings_airplane" msgid="4879879698500955300">"Tryb samolotowy"</string>
-    <string name="status_bar_settings_rotation_lock" msgid="8361452930058000609">"Zablokuj orientację ekranu"</string>
+    <string name="status_bar_settings_auto_rotation" msgid="3790482541357798421">"Autoobracanie ekranu"</string>
     <string name="status_bar_settings_mute_label" msgid="554682549917429396">"WYGAŚ"</string>
     <string name="status_bar_settings_auto_brightness_label" msgid="511453614962324674">"AUTOM."</string>
     <string name="status_bar_settings_notifications" msgid="397146176280905137">"Powiadomienia"</string>
@@ -44,4 +44,22 @@
     <string name="bluetooth_tethered" msgid="7094101612161133267">"Bluetooth – podłączono"</string>
     <string name="status_bar_input_method_settings_configure_input_methods" msgid="737483394044014246">"Konfiguruj metody wprowadzania"</string>
     <string name="status_bar_use_physical_keyboard" msgid="3695516942412442936">"Używaj klawiatury fizycznej"</string>
+    <!-- no translation found for usb_device_permission_prompt (3816016361969816903) -->
+    <skip />
+    <!-- no translation found for usb_accessory_permission_prompt (6888598803988889959) -->
+    <skip />
+    <!-- no translation found for usb_device_confirm_prompt (5161205258635253206) -->
+    <skip />
+    <!-- no translation found for usb_accessory_confirm_prompt (3808984931830229888) -->
+    <skip />
+    <!-- no translation found for usb_accessory_uri_prompt (6332150684964235705) -->
+    <skip />
+    <!-- no translation found for title_usb_accessory (4966265263465181372) -->
+    <skip />
+    <!-- no translation found for label_view (6304565553218192990) -->
+    <skip />
+    <!-- no translation found for always_use_device (1450287437017315906) -->
+    <skip />
+    <!-- no translation found for always_use_accessory (1210954576979621596) -->
+    <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-pt-rPT-xlarge/strings.xml b/packages/SystemUI/res/values-pt-rPT-xlarge/strings.xml
index a5d6bac..7860208 100644
--- a/packages/SystemUI/res/values-pt-rPT-xlarge/strings.xml
+++ b/packages/SystemUI/res/values-pt-rPT-xlarge/strings.xml
@@ -24,8 +24,6 @@
     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="1456658018593445677">"Wi-Fi ligado"</string>
     <string name="gps_notification_searching_text" msgid="894185519046488403">"A procurar GPS"</string>
     <string name="gps_notification_found_text" msgid="5306445324124275852">"Localização definida por GPS"</string>
-    <!-- no translation found for notifications_off_title (2297252328026582111) -->
-    <skip />
-    <!-- no translation found for notifications_off_text (3754847213329718358) -->
-    <skip />
+    <string name="notifications_off_title" msgid="2297252328026582111">"Notificações desativadas"</string>
+    <string name="notifications_off_text" msgid="3754847213329718358">"Toque aqui para voltar a ativar as notificações."</string>
 </resources>
diff --git a/packages/SystemUI/res/values-pt-rPT/strings.xml b/packages/SystemUI/res/values-pt-rPT/strings.xml
index 1215415..5ee79a0 100644
--- a/packages/SystemUI/res/values-pt-rPT/strings.xml
+++ b/packages/SystemUI/res/values-pt-rPT/strings.xml
@@ -34,7 +34,7 @@
     <string name="status_bar_settings_settings_button" msgid="3023889916699270224">"Definições"</string>
     <string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"Wi-Fi"</string>
     <string name="status_bar_settings_airplane" msgid="4879879698500955300">"Modo de avião"</string>
-    <string name="status_bar_settings_rotation_lock" msgid="8361452930058000609">"Bloquear orientação do ecrã"</string>
+    <string name="status_bar_settings_auto_rotation" msgid="3790482541357798421">"Rodar ecrã automaticamente"</string>
     <string name="status_bar_settings_mute_label" msgid="554682549917429396">"D. SOM"</string>
     <string name="status_bar_settings_auto_brightness_label" msgid="511453614962324674">"AUTO"</string>
     <string name="status_bar_settings_notifications" msgid="397146176280905137">"Notificações"</string>
@@ -44,4 +44,22 @@
     <string name="bluetooth_tethered" msgid="7094101612161133267">"Bluetooth ligado"</string>
     <string name="status_bar_input_method_settings_configure_input_methods" msgid="737483394044014246">"Configurar métodos de entrada"</string>
     <string name="status_bar_use_physical_keyboard" msgid="3695516942412442936">"Utilizar teclado físico"</string>
+    <!-- no translation found for usb_device_permission_prompt (3816016361969816903) -->
+    <skip />
+    <!-- no translation found for usb_accessory_permission_prompt (6888598803988889959) -->
+    <skip />
+    <!-- no translation found for usb_device_confirm_prompt (5161205258635253206) -->
+    <skip />
+    <!-- no translation found for usb_accessory_confirm_prompt (3808984931830229888) -->
+    <skip />
+    <!-- no translation found for usb_accessory_uri_prompt (6332150684964235705) -->
+    <skip />
+    <!-- no translation found for title_usb_accessory (4966265263465181372) -->
+    <skip />
+    <!-- no translation found for label_view (6304565553218192990) -->
+    <skip />
+    <!-- no translation found for always_use_device (1450287437017315906) -->
+    <skip />
+    <!-- no translation found for always_use_accessory (1210954576979621596) -->
+    <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-pt-xlarge/strings.xml b/packages/SystemUI/res/values-pt-xlarge/strings.xml
index 5209ab9..2a1786d 100644
--- a/packages/SystemUI/res/values-pt-xlarge/strings.xml
+++ b/packages/SystemUI/res/values-pt-xlarge/strings.xml
@@ -24,8 +24,6 @@
     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="1456658018593445677">"Wi-Fi conectado"</string>
     <string name="gps_notification_searching_text" msgid="894185519046488403">"Procurando GPS"</string>
     <string name="gps_notification_found_text" msgid="5306445324124275852">"Localização definida por GPS"</string>
-    <!-- no translation found for notifications_off_title (2297252328026582111) -->
-    <skip />
-    <!-- no translation found for notifications_off_text (3754847213329718358) -->
-    <skip />
+    <string name="notifications_off_title" msgid="2297252328026582111">"Notificações desativadas"</string>
+    <string name="notifications_off_text" msgid="3754847213329718358">"Toque aqui para ativar novamente as notificações."</string>
 </resources>
diff --git a/packages/SystemUI/res/values-pt/strings.xml b/packages/SystemUI/res/values-pt/strings.xml
index 1f4afb7..a91d406 100644
--- a/packages/SystemUI/res/values-pt/strings.xml
+++ b/packages/SystemUI/res/values-pt/strings.xml
@@ -34,7 +34,7 @@
     <string name="status_bar_settings_settings_button" msgid="3023889916699270224">"Configurações"</string>
     <string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"Wi-Fi"</string>
     <string name="status_bar_settings_airplane" msgid="4879879698500955300">"Modo para avião"</string>
-    <string name="status_bar_settings_rotation_lock" msgid="8361452930058000609">"Bloquear orientação de tela"</string>
+    <string name="status_bar_settings_auto_rotation" msgid="3790482541357798421">"Girar automaticamente a tela"</string>
     <string name="status_bar_settings_mute_label" msgid="554682549917429396">"MUDO"</string>
     <string name="status_bar_settings_auto_brightness_label" msgid="511453614962324674">"AUTO"</string>
     <string name="status_bar_settings_notifications" msgid="397146176280905137">"Notificações"</string>
@@ -44,4 +44,22 @@
     <string name="bluetooth_tethered" msgid="7094101612161133267">"Bluetooth vinculado"</string>
     <string name="status_bar_input_method_settings_configure_input_methods" msgid="737483394044014246">"Configurar métodos de entrada"</string>
     <string name="status_bar_use_physical_keyboard" msgid="3695516942412442936">"Usar o teclado físico"</string>
+    <!-- no translation found for usb_device_permission_prompt (3816016361969816903) -->
+    <skip />
+    <!-- no translation found for usb_accessory_permission_prompt (6888598803988889959) -->
+    <skip />
+    <!-- no translation found for usb_device_confirm_prompt (5161205258635253206) -->
+    <skip />
+    <!-- no translation found for usb_accessory_confirm_prompt (3808984931830229888) -->
+    <skip />
+    <!-- no translation found for usb_accessory_uri_prompt (6332150684964235705) -->
+    <skip />
+    <!-- no translation found for title_usb_accessory (4966265263465181372) -->
+    <skip />
+    <!-- no translation found for label_view (6304565553218192990) -->
+    <skip />
+    <!-- no translation found for always_use_device (1450287437017315906) -->
+    <skip />
+    <!-- no translation found for always_use_accessory (1210954576979621596) -->
+    <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-rm/strings.xml b/packages/SystemUI/res/values-rm/strings.xml
index d4d4600..b41b9bd 100644
--- a/packages/SystemUI/res/values-rm/strings.xml
+++ b/packages/SystemUI/res/values-rm/strings.xml
@@ -42,7 +42,7 @@
     <skip />
     <!-- no translation found for status_bar_settings_airplane (4879879698500955300) -->
     <skip />
-    <!-- no translation found for status_bar_settings_rotation_lock (8361452930058000609) -->
+    <!-- no translation found for status_bar_settings_auto_rotation (3790482541357798421) -->
     <skip />
     <!-- no translation found for status_bar_settings_mute_label (554682549917429396) -->
     <skip />
@@ -61,4 +61,22 @@
     <skip />
     <!-- no translation found for status_bar_use_physical_keyboard (3695516942412442936) -->
     <skip />
+    <!-- no translation found for usb_device_permission_prompt (3816016361969816903) -->
+    <skip />
+    <!-- no translation found for usb_accessory_permission_prompt (6888598803988889959) -->
+    <skip />
+    <!-- no translation found for usb_device_confirm_prompt (5161205258635253206) -->
+    <skip />
+    <!-- no translation found for usb_accessory_confirm_prompt (3808984931830229888) -->
+    <skip />
+    <!-- no translation found for usb_accessory_uri_prompt (6332150684964235705) -->
+    <skip />
+    <!-- no translation found for title_usb_accessory (4966265263465181372) -->
+    <skip />
+    <!-- no translation found for label_view (6304565553218192990) -->
+    <skip />
+    <!-- no translation found for always_use_device (1450287437017315906) -->
+    <skip />
+    <!-- no translation found for always_use_accessory (1210954576979621596) -->
+    <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-ro-xlarge/strings.xml b/packages/SystemUI/res/values-ro-xlarge/strings.xml
index 2dedd3b..21fd0ad 100644
--- a/packages/SystemUI/res/values-ro-xlarge/strings.xml
+++ b/packages/SystemUI/res/values-ro-xlarge/strings.xml
@@ -24,8 +24,6 @@
     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="1456658018593445677">"Wi-Fi conectat"</string>
     <string name="gps_notification_searching_text" msgid="894185519046488403">"Se caută dispozitivul GPS"</string>
     <string name="gps_notification_found_text" msgid="5306445324124275852">"Locaţie setată prin GPS"</string>
-    <!-- no translation found for notifications_off_title (2297252328026582111) -->
-    <skip />
-    <!-- no translation found for notifications_off_text (3754847213329718358) -->
-    <skip />
+    <string name="notifications_off_title" msgid="2297252328026582111">"Notificările sunt dezactivate"</string>
+    <string name="notifications_off_text" msgid="3754847213329718358">"Apăsaţi aici pentru a reactiva notificările."</string>
 </resources>
diff --git a/packages/SystemUI/res/values-ro/strings.xml b/packages/SystemUI/res/values-ro/strings.xml
index c3bcc97..36628aa 100644
--- a/packages/SystemUI/res/values-ro/strings.xml
+++ b/packages/SystemUI/res/values-ro/strings.xml
@@ -34,7 +34,7 @@
     <string name="status_bar_settings_settings_button" msgid="3023889916699270224">"Setări"</string>
     <string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"Wi-Fi"</string>
     <string name="status_bar_settings_airplane" msgid="4879879698500955300">"Mod Avion"</string>
-    <string name="status_bar_settings_rotation_lock" msgid="8361452930058000609">"Blocaţi orientarea ecranului"</string>
+    <string name="status_bar_settings_auto_rotation" msgid="3790482541357798421">"Rotire automată a ecranului"</string>
     <string name="status_bar_settings_mute_label" msgid="554682549917429396">"DEZAC."</string>
     <string name="status_bar_settings_auto_brightness_label" msgid="511453614962324674">"AUTOM."</string>
     <string name="status_bar_settings_notifications" msgid="397146176280905137">"Notificări"</string>
@@ -44,4 +44,22 @@
     <string name="bluetooth_tethered" msgid="7094101612161133267">"Conectat prin tethering prin Bluetooth"</string>
     <string name="status_bar_input_method_settings_configure_input_methods" msgid="737483394044014246">"Configuraţi metode de intrare"</string>
     <string name="status_bar_use_physical_keyboard" msgid="3695516942412442936">"Utilizaţi tastat. fizică"</string>
+    <!-- no translation found for usb_device_permission_prompt (3816016361969816903) -->
+    <skip />
+    <!-- no translation found for usb_accessory_permission_prompt (6888598803988889959) -->
+    <skip />
+    <!-- no translation found for usb_device_confirm_prompt (5161205258635253206) -->
+    <skip />
+    <!-- no translation found for usb_accessory_confirm_prompt (3808984931830229888) -->
+    <skip />
+    <!-- no translation found for usb_accessory_uri_prompt (6332150684964235705) -->
+    <skip />
+    <!-- no translation found for title_usb_accessory (4966265263465181372) -->
+    <skip />
+    <!-- no translation found for label_view (6304565553218192990) -->
+    <skip />
+    <!-- no translation found for always_use_device (1450287437017315906) -->
+    <skip />
+    <!-- no translation found for always_use_accessory (1210954576979621596) -->
+    <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-ru-xlarge/strings.xml b/packages/SystemUI/res/values-ru-xlarge/strings.xml
index 212fa83..bc31fb1 100644
--- a/packages/SystemUI/res/values-ru-xlarge/strings.xml
+++ b/packages/SystemUI/res/values-ru-xlarge/strings.xml
@@ -24,8 +24,6 @@
     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="1456658018593445677">"Wi-Fi подкл."</string>
     <string name="gps_notification_searching_text" msgid="894185519046488403">"Выполняется поиск при помощи GPS"</string>
     <string name="gps_notification_found_text" msgid="5306445324124275852">"Местоположение установлено при помощи GPS"</string>
-    <!-- no translation found for notifications_off_title (2297252328026582111) -->
-    <skip />
-    <!-- no translation found for notifications_off_text (3754847213329718358) -->
-    <skip />
+    <string name="notifications_off_title" msgid="2297252328026582111">"Показ уведомлений отключен"</string>
+    <string name="notifications_off_text" msgid="3754847213329718358">"Нажмите здесь, чтобы снова включить показ уведомлений."</string>
 </resources>
diff --git a/packages/SystemUI/res/values-ru/strings.xml b/packages/SystemUI/res/values-ru/strings.xml
index e53fbd2..13da8a3 100644
--- a/packages/SystemUI/res/values-ru/strings.xml
+++ b/packages/SystemUI/res/values-ru/strings.xml
@@ -34,7 +34,7 @@
     <string name="status_bar_settings_settings_button" msgid="3023889916699270224">"Настройки"</string>
     <string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"Wi-Fi"</string>
     <string name="status_bar_settings_airplane" msgid="4879879698500955300">"Режим полета"</string>
-    <string name="status_bar_settings_rotation_lock" msgid="8361452930058000609">"Закрепить ориентацию экрана"</string>
+    <string name="status_bar_settings_auto_rotation" msgid="3790482541357798421">"Автоповорот экрана"</string>
     <string name="status_bar_settings_mute_label" msgid="554682549917429396">"ВЫКЛ."</string>
     <string name="status_bar_settings_auto_brightness_label" msgid="511453614962324674">"АВТО"</string>
     <string name="status_bar_settings_notifications" msgid="397146176280905137">"Уведомления"</string>
@@ -44,4 +44,22 @@
     <string name="bluetooth_tethered" msgid="7094101612161133267">"Общий модем доступен через Bluetooth"</string>
     <string name="status_bar_input_method_settings_configure_input_methods" msgid="737483394044014246">"Настроить способ ввода"</string>
     <string name="status_bar_use_physical_keyboard" msgid="3695516942412442936">"Использовать физическую клавиатуру"</string>
+    <!-- no translation found for usb_device_permission_prompt (3816016361969816903) -->
+    <skip />
+    <!-- no translation found for usb_accessory_permission_prompt (6888598803988889959) -->
+    <skip />
+    <!-- no translation found for usb_device_confirm_prompt (5161205258635253206) -->
+    <skip />
+    <!-- no translation found for usb_accessory_confirm_prompt (3808984931830229888) -->
+    <skip />
+    <!-- no translation found for usb_accessory_uri_prompt (6332150684964235705) -->
+    <skip />
+    <!-- no translation found for title_usb_accessory (4966265263465181372) -->
+    <skip />
+    <!-- no translation found for label_view (6304565553218192990) -->
+    <skip />
+    <!-- no translation found for always_use_device (1450287437017315906) -->
+    <skip />
+    <!-- no translation found for always_use_accessory (1210954576979621596) -->
+    <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-sk-xlarge/strings.xml b/packages/SystemUI/res/values-sk-xlarge/strings.xml
index 0fcdd4a..ee9e613 100644
--- a/packages/SystemUI/res/values-sk-xlarge/strings.xml
+++ b/packages/SystemUI/res/values-sk-xlarge/strings.xml
@@ -24,8 +24,6 @@
     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="1456658018593445677">"Wi-Fi: pripojené"</string>
     <string name="gps_notification_searching_text" msgid="894185519046488403">"Hľadanie signálu GPS"</string>
     <string name="gps_notification_found_text" msgid="5306445324124275852">"Poloha určená pomocou GPS"</string>
-    <!-- no translation found for notifications_off_title (2297252328026582111) -->
-    <skip />
-    <!-- no translation found for notifications_off_text (3754847213329718358) -->
-    <skip />
+    <string name="notifications_off_title" msgid="2297252328026582111">"Upozornenia sú vypnuté"</string>
+    <string name="notifications_off_text" msgid="3754847213329718358">"Klepnutím tu upozornenia znova povolíte."</string>
 </resources>
diff --git a/packages/SystemUI/res/values-sk/strings.xml b/packages/SystemUI/res/values-sk/strings.xml
index bf316cc..c08eb21 100644
--- a/packages/SystemUI/res/values-sk/strings.xml
+++ b/packages/SystemUI/res/values-sk/strings.xml
@@ -34,7 +34,7 @@
     <string name="status_bar_settings_settings_button" msgid="3023889916699270224">"Nastavenia"</string>
     <string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"Wi-Fi"</string>
     <string name="status_bar_settings_airplane" msgid="4879879698500955300">"Režim V lietadle"</string>
-    <string name="status_bar_settings_rotation_lock" msgid="8361452930058000609">"Uzamknúť orientáciu obrazovky"</string>
+    <string name="status_bar_settings_auto_rotation" msgid="3790482541357798421">"Automatické otočenie obrazovky"</string>
     <string name="status_bar_settings_mute_label" msgid="554682549917429396">"STLMIŤ"</string>
     <string name="status_bar_settings_auto_brightness_label" msgid="511453614962324674">"AUTO"</string>
     <string name="status_bar_settings_notifications" msgid="397146176280905137">"Upozornenia"</string>
@@ -44,4 +44,22 @@
     <string name="bluetooth_tethered" msgid="7094101612161133267">"Zdieľané dátové pripojenie cez Bluetooth"</string>
     <string name="status_bar_input_method_settings_configure_input_methods" msgid="737483394044014246">"Konfigurovať metódy vstupu"</string>
     <string name="status_bar_use_physical_keyboard" msgid="3695516942412442936">"Použiť fyzickú klávesnicu"</string>
+    <!-- no translation found for usb_device_permission_prompt (3816016361969816903) -->
+    <skip />
+    <!-- no translation found for usb_accessory_permission_prompt (6888598803988889959) -->
+    <skip />
+    <!-- no translation found for usb_device_confirm_prompt (5161205258635253206) -->
+    <skip />
+    <!-- no translation found for usb_accessory_confirm_prompt (3808984931830229888) -->
+    <skip />
+    <!-- no translation found for usb_accessory_uri_prompt (6332150684964235705) -->
+    <skip />
+    <!-- no translation found for title_usb_accessory (4966265263465181372) -->
+    <skip />
+    <!-- no translation found for label_view (6304565553218192990) -->
+    <skip />
+    <!-- no translation found for always_use_device (1450287437017315906) -->
+    <skip />
+    <!-- no translation found for always_use_accessory (1210954576979621596) -->
+    <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-sl-xlarge/strings.xml b/packages/SystemUI/res/values-sl-xlarge/strings.xml
index 615c565..57ed9a7 100644
--- a/packages/SystemUI/res/values-sl-xlarge/strings.xml
+++ b/packages/SystemUI/res/values-sl-xlarge/strings.xml
@@ -24,8 +24,6 @@
     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="1456658018593445677">"Wi-Fi – povezano"</string>
     <string name="gps_notification_searching_text" msgid="894185519046488403">"Iskanje GPS-a"</string>
     <string name="gps_notification_found_text" msgid="5306445324124275852">"Lokacija nastavljena z GPS-om"</string>
-    <!-- no translation found for notifications_off_title (2297252328026582111) -->
-    <skip />
-    <!-- no translation found for notifications_off_text (3754847213329718358) -->
-    <skip />
+    <string name="notifications_off_title" msgid="2297252328026582111">"Obvestila izklopljena"</string>
+    <string name="notifications_off_text" msgid="3754847213329718358">"Tapnite tukaj, da spet vklopite obvestila."</string>
 </resources>
diff --git a/packages/SystemUI/res/values-sl/strings.xml b/packages/SystemUI/res/values-sl/strings.xml
index c0a7f04..d7cb726 100644
--- a/packages/SystemUI/res/values-sl/strings.xml
+++ b/packages/SystemUI/res/values-sl/strings.xml
@@ -34,7 +34,7 @@
     <string name="status_bar_settings_settings_button" msgid="3023889916699270224">"Nastavitve"</string>
     <string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"Wi-Fi"</string>
     <string name="status_bar_settings_airplane" msgid="4879879698500955300">"Način za letalo"</string>
-    <string name="status_bar_settings_rotation_lock" msgid="8361452930058000609">"Zakleni usmerjenost zaslona"</string>
+    <string name="status_bar_settings_auto_rotation" msgid="3790482541357798421">"Samodejno zasukaj zaslon"</string>
     <string name="status_bar_settings_mute_label" msgid="554682549917429396">"TIHO"</string>
     <string name="status_bar_settings_auto_brightness_label" msgid="511453614962324674">"SAMOD."</string>
     <string name="status_bar_settings_notifications" msgid="397146176280905137">"Obvestila"</string>
@@ -44,4 +44,22 @@
     <string name="bluetooth_tethered" msgid="7094101612161133267">"Internetna povezava prek Bluetootha"</string>
     <string name="status_bar_input_method_settings_configure_input_methods" msgid="737483394044014246">"Nastavitev načinov vnosa"</string>
     <string name="status_bar_use_physical_keyboard" msgid="3695516942412442936">"Uporabi fizično tipkovn."</string>
+    <!-- no translation found for usb_device_permission_prompt (3816016361969816903) -->
+    <skip />
+    <!-- no translation found for usb_accessory_permission_prompt (6888598803988889959) -->
+    <skip />
+    <!-- no translation found for usb_device_confirm_prompt (5161205258635253206) -->
+    <skip />
+    <!-- no translation found for usb_accessory_confirm_prompt (3808984931830229888) -->
+    <skip />
+    <!-- no translation found for usb_accessory_uri_prompt (6332150684964235705) -->
+    <skip />
+    <!-- no translation found for title_usb_accessory (4966265263465181372) -->
+    <skip />
+    <!-- no translation found for label_view (6304565553218192990) -->
+    <skip />
+    <!-- no translation found for always_use_device (1450287437017315906) -->
+    <skip />
+    <!-- no translation found for always_use_accessory (1210954576979621596) -->
+    <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-sr-xlarge/strings.xml b/packages/SystemUI/res/values-sr-xlarge/strings.xml
index d66765b..95fbc2f 100644
--- a/packages/SystemUI/res/values-sr-xlarge/strings.xml
+++ b/packages/SystemUI/res/values-sr-xlarge/strings.xml
@@ -24,8 +24,6 @@
     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="1456658018593445677">"Wi-Fi је повезан"</string>
     <string name="gps_notification_searching_text" msgid="894185519046488403">"Тражи се GPS"</string>
     <string name="gps_notification_found_text" msgid="5306445324124275852">"Локацију је подесио GPS"</string>
-    <!-- no translation found for notifications_off_title (2297252328026582111) -->
-    <skip />
-    <!-- no translation found for notifications_off_text (3754847213329718358) -->
-    <skip />
+    <string name="notifications_off_title" msgid="2297252328026582111">"Обавештења су искључена"</string>
+    <string name="notifications_off_text" msgid="3754847213329718358">"Додирните овде да бисте поново укључили обавештења."</string>
 </resources>
diff --git a/packages/SystemUI/res/values-sr/strings.xml b/packages/SystemUI/res/values-sr/strings.xml
index bd00a9c..6e67293 100644
--- a/packages/SystemUI/res/values-sr/strings.xml
+++ b/packages/SystemUI/res/values-sr/strings.xml
@@ -34,7 +34,7 @@
     <string name="status_bar_settings_settings_button" msgid="3023889916699270224">"Подешавања"</string>
     <string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"Wi-Fi"</string>
     <string name="status_bar_settings_airplane" msgid="4879879698500955300">"Режим рада у авиону"</string>
-    <string name="status_bar_settings_rotation_lock" msgid="8361452930058000609">"Закључавање положаја екрана"</string>
+    <string name="status_bar_settings_auto_rotation" msgid="3790482541357798421">"Аутоматско ротирање екрана"</string>
     <string name="status_bar_settings_mute_label" msgid="554682549917429396">"УГАСИ"</string>
     <string name="status_bar_settings_auto_brightness_label" msgid="511453614962324674">"АУТОM."</string>
     <string name="status_bar_settings_notifications" msgid="397146176280905137">"Обавештења"</string>
@@ -44,4 +44,22 @@
     <string name="bluetooth_tethered" msgid="7094101612161133267">"Веза преко Bluetooth-а"</string>
     <string name="status_bar_input_method_settings_configure_input_methods" msgid="737483394044014246">"Конфигуриши методе уноса"</string>
     <string name="status_bar_use_physical_keyboard" msgid="3695516942412442936">"Користи физичку тастатуру"</string>
+    <!-- no translation found for usb_device_permission_prompt (3816016361969816903) -->
+    <skip />
+    <!-- no translation found for usb_accessory_permission_prompt (6888598803988889959) -->
+    <skip />
+    <!-- no translation found for usb_device_confirm_prompt (5161205258635253206) -->
+    <skip />
+    <!-- no translation found for usb_accessory_confirm_prompt (3808984931830229888) -->
+    <skip />
+    <!-- no translation found for usb_accessory_uri_prompt (6332150684964235705) -->
+    <skip />
+    <!-- no translation found for title_usb_accessory (4966265263465181372) -->
+    <skip />
+    <!-- no translation found for label_view (6304565553218192990) -->
+    <skip />
+    <!-- no translation found for always_use_device (1450287437017315906) -->
+    <skip />
+    <!-- no translation found for always_use_accessory (1210954576979621596) -->
+    <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-sv-xlarge/strings.xml b/packages/SystemUI/res/values-sv-xlarge/strings.xml
index b53269e..ce608c2 100644
--- a/packages/SystemUI/res/values-sv-xlarge/strings.xml
+++ b/packages/SystemUI/res/values-sv-xlarge/strings.xml
@@ -24,8 +24,6 @@
     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="1456658018593445677">"Wi-Fi-ansluten"</string>
     <string name="gps_notification_searching_text" msgid="894185519046488403">"Sökning efter GPS pågår"</string>
     <string name="gps_notification_found_text" msgid="5306445324124275852">"Platsen har identifierats av GPS"</string>
-    <!-- no translation found for notifications_off_title (2297252328026582111) -->
-    <skip />
-    <!-- no translation found for notifications_off_text (3754847213329718358) -->
-    <skip />
+    <string name="notifications_off_title" msgid="2297252328026582111">"Aviseringar inaktiverade"</string>
+    <string name="notifications_off_text" msgid="3754847213329718358">"Knacka lätt här om du vill aktivera aviseringar igen."</string>
 </resources>
diff --git a/packages/SystemUI/res/values-sv/strings.xml b/packages/SystemUI/res/values-sv/strings.xml
index 3d8f3c9..e2905b6 100644
--- a/packages/SystemUI/res/values-sv/strings.xml
+++ b/packages/SystemUI/res/values-sv/strings.xml
@@ -34,7 +34,7 @@
     <string name="status_bar_settings_settings_button" msgid="3023889916699270224">"Inställningar"</string>
     <string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"Wi-Fi"</string>
     <string name="status_bar_settings_airplane" msgid="4879879698500955300">"Flygplansläge"</string>
-    <string name="status_bar_settings_rotation_lock" msgid="8361452930058000609">"Lås bildskärmens riktning"</string>
+    <string name="status_bar_settings_auto_rotation" msgid="3790482541357798421">"Rotera skärmen automatiskt"</string>
     <string name="status_bar_settings_mute_label" msgid="554682549917429396">"TYST"</string>
     <string name="status_bar_settings_auto_brightness_label" msgid="511453614962324674">"AUTO"</string>
     <string name="status_bar_settings_notifications" msgid="397146176280905137">"Aviseringar"</string>
@@ -44,4 +44,22 @@
     <string name="bluetooth_tethered" msgid="7094101612161133267">"Internetdelning via Bluetooth"</string>
     <string name="status_bar_input_method_settings_configure_input_methods" msgid="737483394044014246">"Konfigurera inmatningsmetoder"</string>
     <string name="status_bar_use_physical_keyboard" msgid="3695516942412442936">"Använd fysiska tangenter"</string>
+    <!-- no translation found for usb_device_permission_prompt (3816016361969816903) -->
+    <skip />
+    <!-- no translation found for usb_accessory_permission_prompt (6888598803988889959) -->
+    <skip />
+    <!-- no translation found for usb_device_confirm_prompt (5161205258635253206) -->
+    <skip />
+    <!-- no translation found for usb_accessory_confirm_prompt (3808984931830229888) -->
+    <skip />
+    <!-- no translation found for usb_accessory_uri_prompt (6332150684964235705) -->
+    <skip />
+    <!-- no translation found for title_usb_accessory (4966265263465181372) -->
+    <skip />
+    <!-- no translation found for label_view (6304565553218192990) -->
+    <skip />
+    <!-- no translation found for always_use_device (1450287437017315906) -->
+    <skip />
+    <!-- no translation found for always_use_accessory (1210954576979621596) -->
+    <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-th-xlarge/strings.xml b/packages/SystemUI/res/values-th-xlarge/strings.xml
index 8222140..824de38 100644
--- a/packages/SystemUI/res/values-th-xlarge/strings.xml
+++ b/packages/SystemUI/res/values-th-xlarge/strings.xml
@@ -24,8 +24,6 @@
     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="1456658018593445677">"เชื่อมต่อ Wi-Fi แล้ว"</string>
     <string name="gps_notification_searching_text" msgid="894185519046488403">"การค้นหาสำหรับ GPS"</string>
     <string name="gps_notification_found_text" msgid="5306445324124275852">"ตำแหน่งที่กำหนดโดย GPS"</string>
-    <!-- no translation found for notifications_off_title (2297252328026582111) -->
-    <skip />
-    <!-- no translation found for notifications_off_text (3754847213329718358) -->
-    <skip />
+    <string name="notifications_off_title" msgid="2297252328026582111">"การแจ้งเตือนปิดอยู่"</string>
+    <string name="notifications_off_text" msgid="3754847213329718358">"แตะที่นี่เพื่อเปิดการแจ้งเตือนอีกครั้ง"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-th/strings.xml b/packages/SystemUI/res/values-th/strings.xml
index c42e26d..1e7af69 100644
--- a/packages/SystemUI/res/values-th/strings.xml
+++ b/packages/SystemUI/res/values-th/strings.xml
@@ -34,7 +34,7 @@
     <string name="status_bar_settings_settings_button" msgid="3023889916699270224">"การตั้งค่า"</string>
     <string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"Wi-Fi"</string>
     <string name="status_bar_settings_airplane" msgid="4879879698500955300">"โหมดใช้งานบนเครื่องบิน"</string>
-    <string name="status_bar_settings_rotation_lock" msgid="8361452930058000609">"ล็อกแนวหน้าจอ"</string>
+    <string name="status_bar_settings_auto_rotation" msgid="3790482541357798421">"หมุนหน้าจออัตโนมัติ"</string>
     <string name="status_bar_settings_mute_label" msgid="554682549917429396">"ปิดเสียง"</string>
     <string name="status_bar_settings_auto_brightness_label" msgid="511453614962324674">"อัตโนมัติ"</string>
     <string name="status_bar_settings_notifications" msgid="397146176280905137">"การแจ้งเตือน"</string>
@@ -44,4 +44,22 @@
     <string name="bluetooth_tethered" msgid="7094101612161133267">"บลูทูธที่ปล่อยสัญญาณ"</string>
     <string name="status_bar_input_method_settings_configure_input_methods" msgid="737483394044014246">"กำหนดค่าวิธีการป้อนข้อมูล"</string>
     <string name="status_bar_use_physical_keyboard" msgid="3695516942412442936">"ใช้แป้นพิมพ์จริง"</string>
+    <!-- no translation found for usb_device_permission_prompt (3816016361969816903) -->
+    <skip />
+    <!-- no translation found for usb_accessory_permission_prompt (6888598803988889959) -->
+    <skip />
+    <!-- no translation found for usb_device_confirm_prompt (5161205258635253206) -->
+    <skip />
+    <!-- no translation found for usb_accessory_confirm_prompt (3808984931830229888) -->
+    <skip />
+    <!-- no translation found for usb_accessory_uri_prompt (6332150684964235705) -->
+    <skip />
+    <!-- no translation found for title_usb_accessory (4966265263465181372) -->
+    <skip />
+    <!-- no translation found for label_view (6304565553218192990) -->
+    <skip />
+    <!-- no translation found for always_use_device (1450287437017315906) -->
+    <skip />
+    <!-- no translation found for always_use_accessory (1210954576979621596) -->
+    <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-tl-xlarge/strings.xml b/packages/SystemUI/res/values-tl-xlarge/strings.xml
index 0eef090..582adbc 100644
--- a/packages/SystemUI/res/values-tl-xlarge/strings.xml
+++ b/packages/SystemUI/res/values-tl-xlarge/strings.xml
@@ -24,8 +24,6 @@
     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="1456658018593445677">"Konektado ang WiFi"</string>
     <string name="gps_notification_searching_text" msgid="894185519046488403">"Naghahanap ng GPS"</string>
     <string name="gps_notification_found_text" msgid="5306445324124275852">"Lokasyon na itinatakda ng GPS"</string>
-    <!-- no translation found for notifications_off_title (2297252328026582111) -->
-    <skip />
-    <!-- no translation found for notifications_off_text (3754847213329718358) -->
-    <skip />
+    <string name="notifications_off_title" msgid="2297252328026582111">"Naka-off ang mga notification"</string>
+    <string name="notifications_off_text" msgid="3754847213329718358">"Mag-tap dito upang i-on muli ang mga notification."</string>
 </resources>
diff --git a/packages/SystemUI/res/values-tl/strings.xml b/packages/SystemUI/res/values-tl/strings.xml
index 1244945..9fadf73 100644
--- a/packages/SystemUI/res/values-tl/strings.xml
+++ b/packages/SystemUI/res/values-tl/strings.xml
@@ -34,7 +34,7 @@
     <string name="status_bar_settings_settings_button" msgid="3023889916699270224">"Mga Setting"</string>
     <string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"Wi-Fi"</string>
     <string name="status_bar_settings_airplane" msgid="4879879698500955300">"Airplane mode"</string>
-    <string name="status_bar_settings_rotation_lock" msgid="8361452930058000609">"Naka-lock na screen orientation"</string>
+    <string name="status_bar_settings_auto_rotation" msgid="3790482541357798421">"I-auto-rotate ang screen"</string>
     <string name="status_bar_settings_mute_label" msgid="554682549917429396">"MUTE"</string>
     <string name="status_bar_settings_auto_brightness_label" msgid="511453614962324674">"AUTO"</string>
     <string name="status_bar_settings_notifications" msgid="397146176280905137">"Mga Notification"</string>
@@ -44,4 +44,22 @@
     <string name="bluetooth_tethered" msgid="7094101612161133267">"Na-tether ang bluetooth"</string>
     <string name="status_bar_input_method_settings_configure_input_methods" msgid="737483394044014246">"I-configure paraan ng input"</string>
     <string name="status_bar_use_physical_keyboard" msgid="3695516942412442936">"Gamitin ang pisikal na keyboard"</string>
+    <!-- no translation found for usb_device_permission_prompt (3816016361969816903) -->
+    <skip />
+    <!-- no translation found for usb_accessory_permission_prompt (6888598803988889959) -->
+    <skip />
+    <!-- no translation found for usb_device_confirm_prompt (5161205258635253206) -->
+    <skip />
+    <!-- no translation found for usb_accessory_confirm_prompt (3808984931830229888) -->
+    <skip />
+    <!-- no translation found for usb_accessory_uri_prompt (6332150684964235705) -->
+    <skip />
+    <!-- no translation found for title_usb_accessory (4966265263465181372) -->
+    <skip />
+    <!-- no translation found for label_view (6304565553218192990) -->
+    <skip />
+    <!-- no translation found for always_use_device (1450287437017315906) -->
+    <skip />
+    <!-- no translation found for always_use_accessory (1210954576979621596) -->
+    <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-tr-xlarge/strings.xml b/packages/SystemUI/res/values-tr-xlarge/strings.xml
index 8c382fb..6db515f 100644
--- a/packages/SystemUI/res/values-tr-xlarge/strings.xml
+++ b/packages/SystemUI/res/values-tr-xlarge/strings.xml
@@ -24,8 +24,6 @@
     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="1456658018593445677">"Kablosuz bağlandı"</string>
     <string name="gps_notification_searching_text" msgid="894185519046488403">"GPS aranıyor"</string>
     <string name="gps_notification_found_text" msgid="5306445324124275852">"Konum GPS ile belirlendi"</string>
-    <!-- no translation found for notifications_off_title (2297252328026582111) -->
-    <skip />
-    <!-- no translation found for notifications_off_text (3754847213329718358) -->
-    <skip />
+    <string name="notifications_off_title" msgid="2297252328026582111">"Bildirimler kapalı"</string>
+    <string name="notifications_off_text" msgid="3754847213329718358">"Bildirimleri tekrar açmak için buraya hafifçe vurun."</string>
 </resources>
diff --git a/packages/SystemUI/res/values-tr/strings.xml b/packages/SystemUI/res/values-tr/strings.xml
index e911b42..7c3585a 100644
--- a/packages/SystemUI/res/values-tr/strings.xml
+++ b/packages/SystemUI/res/values-tr/strings.xml
@@ -34,7 +34,7 @@
     <string name="status_bar_settings_settings_button" msgid="3023889916699270224">"Ayarlar"</string>
     <string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"Kablosuz"</string>
     <string name="status_bar_settings_airplane" msgid="4879879698500955300">"Uçak modu"</string>
-    <string name="status_bar_settings_rotation_lock" msgid="8361452930058000609">"Ekran yönünü kilitle"</string>
+    <string name="status_bar_settings_auto_rotation" msgid="3790482541357798421">"Ekranı otomatik döndür"</string>
     <string name="status_bar_settings_mute_label" msgid="554682549917429396">"KAPAT"</string>
     <string name="status_bar_settings_auto_brightness_label" msgid="511453614962324674">"OTOMTK"</string>
     <string name="status_bar_settings_notifications" msgid="397146176280905137">"Bildirimler"</string>
@@ -44,4 +44,22 @@
     <string name="bluetooth_tethered" msgid="7094101612161133267">"Bluetooth paylaşımı tamam"</string>
     <string name="status_bar_input_method_settings_configure_input_methods" msgid="737483394044014246">"Giriş yöntemlerini yapılandır"</string>
     <string name="status_bar_use_physical_keyboard" msgid="3695516942412442936">"Fiziksel klavyeyi kullan"</string>
+    <!-- no translation found for usb_device_permission_prompt (3816016361969816903) -->
+    <skip />
+    <!-- no translation found for usb_accessory_permission_prompt (6888598803988889959) -->
+    <skip />
+    <!-- no translation found for usb_device_confirm_prompt (5161205258635253206) -->
+    <skip />
+    <!-- no translation found for usb_accessory_confirm_prompt (3808984931830229888) -->
+    <skip />
+    <!-- no translation found for usb_accessory_uri_prompt (6332150684964235705) -->
+    <skip />
+    <!-- no translation found for title_usb_accessory (4966265263465181372) -->
+    <skip />
+    <!-- no translation found for label_view (6304565553218192990) -->
+    <skip />
+    <!-- no translation found for always_use_device (1450287437017315906) -->
+    <skip />
+    <!-- no translation found for always_use_accessory (1210954576979621596) -->
+    <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-uk-xlarge/strings.xml b/packages/SystemUI/res/values-uk-xlarge/strings.xml
index 6b1b193..81e50c0 100644
--- a/packages/SystemUI/res/values-uk-xlarge/strings.xml
+++ b/packages/SystemUI/res/values-uk-xlarge/strings.xml
@@ -24,8 +24,6 @@
     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="1456658018593445677">"Wi-Fi під\'єднано"</string>
     <string name="gps_notification_searching_text" msgid="894185519046488403">"Виконується пошук за допомогою GPS"</string>
     <string name="gps_notification_found_text" msgid="5306445324124275852">"Місцезнаходження встановлено за допомогою GPS"</string>
-    <!-- no translation found for notifications_off_title (2297252328026582111) -->
-    <skip />
-    <!-- no translation found for notifications_off_text (3754847213329718358) -->
-    <skip />
+    <string name="notifications_off_title" msgid="2297252328026582111">"Сповіщення вимкнено"</string>
+    <string name="notifications_off_text" msgid="3754847213329718358">"Торкніться тут, щоб знову ввімкнути сповіщення."</string>
 </resources>
diff --git a/packages/SystemUI/res/values-uk/strings.xml b/packages/SystemUI/res/values-uk/strings.xml
index 963a50f..a17e59d 100644
--- a/packages/SystemUI/res/values-uk/strings.xml
+++ b/packages/SystemUI/res/values-uk/strings.xml
@@ -34,7 +34,7 @@
     <string name="status_bar_settings_settings_button" msgid="3023889916699270224">"Налаштування"</string>
     <string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"Wi-Fi"</string>
     <string name="status_bar_settings_airplane" msgid="4879879698500955300">"Режим польоту"</string>
-    <string name="status_bar_settings_rotation_lock" msgid="8361452930058000609">"Заблокувати орієнтацію екрана"</string>
+    <string name="status_bar_settings_auto_rotation" msgid="3790482541357798421">"Повертати екран автоматично"</string>
     <string name="status_bar_settings_mute_label" msgid="554682549917429396">"ІГНОР."</string>
     <string name="status_bar_settings_auto_brightness_label" msgid="511453614962324674">"АВТОМ."</string>
     <string name="status_bar_settings_notifications" msgid="397146176280905137">"Сповіщення"</string>
@@ -44,4 +44,22 @@
     <string name="bluetooth_tethered" msgid="7094101612161133267">"Створено прив\'язку Bluetooth"</string>
     <string name="status_bar_input_method_settings_configure_input_methods" msgid="737483394044014246">"Налаштувати методи введення"</string>
     <string name="status_bar_use_physical_keyboard" msgid="3695516942412442936">"Викор. реальну клавіатуру"</string>
+    <!-- no translation found for usb_device_permission_prompt (3816016361969816903) -->
+    <skip />
+    <!-- no translation found for usb_accessory_permission_prompt (6888598803988889959) -->
+    <skip />
+    <!-- no translation found for usb_device_confirm_prompt (5161205258635253206) -->
+    <skip />
+    <!-- no translation found for usb_accessory_confirm_prompt (3808984931830229888) -->
+    <skip />
+    <!-- no translation found for usb_accessory_uri_prompt (6332150684964235705) -->
+    <skip />
+    <!-- no translation found for title_usb_accessory (4966265263465181372) -->
+    <skip />
+    <!-- no translation found for label_view (6304565553218192990) -->
+    <skip />
+    <!-- no translation found for always_use_device (1450287437017315906) -->
+    <skip />
+    <!-- no translation found for always_use_accessory (1210954576979621596) -->
+    <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-vi-xlarge/strings.xml b/packages/SystemUI/res/values-vi-xlarge/strings.xml
index b44e1c3..6382fae 100644
--- a/packages/SystemUI/res/values-vi-xlarge/strings.xml
+++ b/packages/SystemUI/res/values-vi-xlarge/strings.xml
@@ -24,8 +24,6 @@
     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="1456658018593445677">"Đã kết nối Wi-Fi"</string>
     <string name="gps_notification_searching_text" msgid="894185519046488403">"Tìm kiếm GPS"</string>
     <string name="gps_notification_found_text" msgid="5306445324124275852">"Vị trí đặt bởi GPS"</string>
-    <!-- no translation found for notifications_off_title (2297252328026582111) -->
-    <skip />
-    <!-- no translation found for notifications_off_text (3754847213329718358) -->
-    <skip />
+    <string name="notifications_off_title" msgid="2297252328026582111">"Tắt thông báo"</string>
+    <string name="notifications_off_text" msgid="3754847213329718358">"Chạm vào đây để bật lại thông báo."</string>
 </resources>
diff --git a/packages/SystemUI/res/values-vi/strings.xml b/packages/SystemUI/res/values-vi/strings.xml
index 108febf..a994ee0 100644
--- a/packages/SystemUI/res/values-vi/strings.xml
+++ b/packages/SystemUI/res/values-vi/strings.xml
@@ -34,7 +34,7 @@
     <string name="status_bar_settings_settings_button" msgid="3023889916699270224">"Cài đặt"</string>
     <string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"Wi-Fi"</string>
     <string name="status_bar_settings_airplane" msgid="4879879698500955300">"Chế độ trên máy bay"</string>
-    <string name="status_bar_settings_rotation_lock" msgid="8361452930058000609">"Khóa hướng màn hình"</string>
+    <string name="status_bar_settings_auto_rotation" msgid="3790482541357798421">"Tự động xoay màn hình"</string>
     <string name="status_bar_settings_mute_label" msgid="554682549917429396">"TẮT TIẾNG"</string>
     <string name="status_bar_settings_auto_brightness_label" msgid="511453614962324674">"TỰ ĐỘNG"</string>
     <string name="status_bar_settings_notifications" msgid="397146176280905137">"Thông báo"</string>
@@ -44,4 +44,22 @@
     <string name="bluetooth_tethered" msgid="7094101612161133267">"Bluetooth được dùng làm điểm truy cập Internet"</string>
     <string name="status_bar_input_method_settings_configure_input_methods" msgid="737483394044014246">"Định cấu hình phương pháp nhập liệu"</string>
     <string name="status_bar_use_physical_keyboard" msgid="3695516942412442936">"Sử dụng bàn phím vật lý"</string>
+    <!-- no translation found for usb_device_permission_prompt (3816016361969816903) -->
+    <skip />
+    <!-- no translation found for usb_accessory_permission_prompt (6888598803988889959) -->
+    <skip />
+    <!-- no translation found for usb_device_confirm_prompt (5161205258635253206) -->
+    <skip />
+    <!-- no translation found for usb_accessory_confirm_prompt (3808984931830229888) -->
+    <skip />
+    <!-- no translation found for usb_accessory_uri_prompt (6332150684964235705) -->
+    <skip />
+    <!-- no translation found for title_usb_accessory (4966265263465181372) -->
+    <skip />
+    <!-- no translation found for label_view (6304565553218192990) -->
+    <skip />
+    <!-- no translation found for always_use_device (1450287437017315906) -->
+    <skip />
+    <!-- no translation found for always_use_accessory (1210954576979621596) -->
+    <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-zh-rCN-xlarge/strings.xml b/packages/SystemUI/res/values-zh-rCN-xlarge/strings.xml
index f599dca..207ebe4 100644
--- a/packages/SystemUI/res/values-zh-rCN-xlarge/strings.xml
+++ b/packages/SystemUI/res/values-zh-rCN-xlarge/strings.xml
@@ -24,8 +24,6 @@
     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="1456658018593445677">"Wi-Fi 已连接"</string>
     <string name="gps_notification_searching_text" msgid="894185519046488403">"正在搜索 GPS"</string>
     <string name="gps_notification_found_text" msgid="5306445324124275852">"GPS 设置的位置"</string>
-    <!-- no translation found for notifications_off_title (2297252328026582111) -->
-    <skip />
-    <!-- no translation found for notifications_off_text (3754847213329718358) -->
-    <skip />
+    <string name="notifications_off_title" msgid="2297252328026582111">"通知已关闭"</string>
+    <string name="notifications_off_text" msgid="3754847213329718358">"点按此处可以重新打开通知。"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-zh-rCN/strings.xml b/packages/SystemUI/res/values-zh-rCN/strings.xml
index 5a74abc..baae9e1 100644
--- a/packages/SystemUI/res/values-zh-rCN/strings.xml
+++ b/packages/SystemUI/res/values-zh-rCN/strings.xml
@@ -34,7 +34,7 @@
     <string name="status_bar_settings_settings_button" msgid="3023889916699270224">"设置"</string>
     <string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"Wi-Fi"</string>
     <string name="status_bar_settings_airplane" msgid="4879879698500955300">"飞行模式"</string>
-    <string name="status_bar_settings_rotation_lock" msgid="8361452930058000609">"锁定屏幕浏览模式"</string>
+    <string name="status_bar_settings_auto_rotation" msgid="3790482541357798421">"自动旋转屏幕"</string>
     <string name="status_bar_settings_mute_label" msgid="554682549917429396">"静音"</string>
     <string name="status_bar_settings_auto_brightness_label" msgid="511453614962324674">"自动"</string>
     <string name="status_bar_settings_notifications" msgid="397146176280905137">"通知"</string>
@@ -44,4 +44,22 @@
     <string name="bluetooth_tethered" msgid="7094101612161133267">"蓝牙已绑定"</string>
     <string name="status_bar_input_method_settings_configure_input_methods" msgid="737483394044014246">"配置输入法"</string>
     <string name="status_bar_use_physical_keyboard" msgid="3695516942412442936">"使用物理键盘"</string>
+    <!-- no translation found for usb_device_permission_prompt (3816016361969816903) -->
+    <skip />
+    <!-- no translation found for usb_accessory_permission_prompt (6888598803988889959) -->
+    <skip />
+    <!-- no translation found for usb_device_confirm_prompt (5161205258635253206) -->
+    <skip />
+    <!-- no translation found for usb_accessory_confirm_prompt (3808984931830229888) -->
+    <skip />
+    <!-- no translation found for usb_accessory_uri_prompt (6332150684964235705) -->
+    <skip />
+    <!-- no translation found for title_usb_accessory (4966265263465181372) -->
+    <skip />
+    <!-- no translation found for label_view (6304565553218192990) -->
+    <skip />
+    <!-- no translation found for always_use_device (1450287437017315906) -->
+    <skip />
+    <!-- no translation found for always_use_accessory (1210954576979621596) -->
+    <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-zh-rTW-xlarge/strings.xml b/packages/SystemUI/res/values-zh-rTW-xlarge/strings.xml
index 2191db7..14a10f2 100644
--- a/packages/SystemUI/res/values-zh-rTW-xlarge/strings.xml
+++ b/packages/SystemUI/res/values-zh-rTW-xlarge/strings.xml
@@ -24,8 +24,6 @@
     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="1456658018593445677">"Wi-Fi 已連線"</string>
     <string name="gps_notification_searching_text" msgid="894185519046488403">"正在搜尋 GPS"</string>
     <string name="gps_notification_found_text" msgid="5306445324124275852">"GPS 已定位"</string>
-    <!-- no translation found for notifications_off_title (2297252328026582111) -->
-    <skip />
-    <!-- no translation found for notifications_off_text (3754847213329718358) -->
-    <skip />
+    <string name="notifications_off_title" msgid="2297252328026582111">"關閉通知"</string>
+    <string name="notifications_off_text" msgid="3754847213329718358">"輕觸這裡即可重新開啟通知。"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-zh-rTW/strings.xml b/packages/SystemUI/res/values-zh-rTW/strings.xml
index 7509357..0d83d44 100644
--- a/packages/SystemUI/res/values-zh-rTW/strings.xml
+++ b/packages/SystemUI/res/values-zh-rTW/strings.xml
@@ -34,7 +34,7 @@
     <string name="status_bar_settings_settings_button" msgid="3023889916699270224">"設定"</string>
     <string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"Wi-Fi"</string>
     <string name="status_bar_settings_airplane" msgid="4879879698500955300">"飛行模式"</string>
-    <string name="status_bar_settings_rotation_lock" msgid="8361452930058000609">"鎖定螢幕瀏覽模式"</string>
+    <string name="status_bar_settings_auto_rotation" msgid="3790482541357798421">"自動旋轉螢幕"</string>
     <string name="status_bar_settings_mute_label" msgid="554682549917429396">"關閉"</string>
     <string name="status_bar_settings_auto_brightness_label" msgid="511453614962324674">"自動"</string>
     <string name="status_bar_settings_notifications" msgid="397146176280905137">"通知"</string>
@@ -44,4 +44,22 @@
     <string name="bluetooth_tethered" msgid="7094101612161133267">"已透過藍牙進行網際網路共用"</string>
     <string name="status_bar_input_method_settings_configure_input_methods" msgid="737483394044014246">"設定輸入方式"</string>
     <string name="status_bar_use_physical_keyboard" msgid="3695516942412442936">"使用實體鍵盤"</string>
+    <!-- no translation found for usb_device_permission_prompt (3816016361969816903) -->
+    <skip />
+    <!-- no translation found for usb_accessory_permission_prompt (6888598803988889959) -->
+    <skip />
+    <!-- no translation found for usb_device_confirm_prompt (5161205258635253206) -->
+    <skip />
+    <!-- no translation found for usb_accessory_confirm_prompt (3808984931830229888) -->
+    <skip />
+    <!-- no translation found for usb_accessory_uri_prompt (6332150684964235705) -->
+    <skip />
+    <!-- no translation found for title_usb_accessory (4966265263465181372) -->
+    <skip />
+    <!-- no translation found for label_view (6304565553218192990) -->
+    <skip />
+    <!-- no translation found for always_use_device (1450287437017315906) -->
+    <skip />
+    <!-- no translation found for always_use_accessory (1210954576979621596) -->
+    <skip />
 </resources>
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index ebd48e7..446827b 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -115,4 +115,32 @@
 
     <!-- Label of a toggle switch to disable use of the physical keyboard in favor of the IME. [CHAR LIMIT=25] -->
     <string name="status_bar_use_physical_keyboard">Use physical keyboard</string>
+
+    <!-- Prompt for the USB device permission dialog [CHAR LIMIT=80] -->
+    <string name="usb_device_permission_prompt">Allow the application <xliff:g id="application">%1$s</xliff:g> to access the USB device?</string>
+
+    <!-- Prompt for the USB accessory permission dialog [CHAR LIMIT=80] -->
+    <string name="usb_accessory_permission_prompt">Allow the application <xliff:g id="application">%1$s</xliff:g> to access the USB accessory?</string>
+
+    <!-- Prompt for the USB device confirm dialog [CHAR LIMIT=80] -->
+    <string name="usb_device_confirm_prompt">Open <xliff:g id="activity">%1$s</xliff:g> when this USB device is connected?</string>
+
+    <!-- Prompt for the USB accessory confirm dialog [CHAR LIMIT=80] -->
+    <string name="usb_accessory_confirm_prompt">Open <xliff:g id="activity">%1$s</xliff:g> when this USB accessory is connected?</string>
+
+    <!-- Prompt for the USB accessory URI dialog [CHAR LIMIT=80] -->
+    <string name="usb_accessory_uri_prompt">No installed applications work with this USB accessory. Learn more about this accessory at <xliff:g id="url">%1$s</xliff:g></string>
+
+    <!-- Title for USB accessory dialog.  Used when the name of the accessory cannot be determined.  [CHAR LIMIT=50] -->
+    <string name="title_usb_accessory">USB accessory</string>
+
+    <!-- View button label for USB dialogs.  [CHAR LIMIT=15] -->
+    <string name="label_view">View</string>
+
+    <!-- Checkbox label for USB device dialogs.  [CHAR LIMIT=50] -->
+    <string name="always_use_device">Use by default for this USB device</string>
+
+    <!-- Checkbox label for USB accessory dialogs.  [CHAR LIMIT=50] -->
+    <string name="always_use_accessory">Use by default for this USB accessory</string>
+
 </resources>
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkController.java
index 326cd74..70a78df 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkController.java
@@ -94,6 +94,7 @@
     int mWifiLevel;
     String mWifiSsid;
     int mWifiIconId = 0;
+    int mWifiActivity = WifiManager.DATA_ACTIVITY_NONE;
 
     // bluetooth
     private boolean mBluetoothTethered = false;
@@ -153,9 +154,7 @@
 
         // wifi
         mWifiManager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
-        HandlerThread handlerThread = new HandlerThread("WifiServiceThread");
-        handlerThread.start();
-        Handler handler = new WifiHandler(handlerThread.getLooper());
+        Handler handler = new WifiHandler();
         mWifiChannel = new AsyncChannel();
         Messenger wifiMessenger = mWifiManager.getMessenger();
         if (wifiMessenger != null) {
@@ -553,11 +552,6 @@
     // ===== Wifi ===================================================================
 
     class WifiHandler extends Handler {
-
-        WifiHandler(Looper looper) {
-            super(looper);
-        }
-
         @Override
         public void handleMessage(Message msg) {
             switch (msg.what) {
@@ -570,17 +564,9 @@
                     }
                     break;
                 case WifiManager.DATA_ACTIVITY_NOTIFICATION:
-                    int dataActivity = msg.arg1;
-                    /* TODO: update icons based on data activity */
-                    switch (dataActivity) {
-                        case WifiManager.DATA_ACTIVITY_IN:
-                            break;
-                        case WifiManager.DATA_ACTIVITY_OUT:
-                            break;
-                        case WifiManager.DATA_ACTIVITY_INOUT:
-                            break;
-                        case WifiManager.DATA_ACTIVITY_NONE:
-                            break;
+                    if (msg.arg1 != mWifiActivity) {
+                        mWifiActivity = msg.arg1;
+                        refreshViews();
                     }
                     break;
                 default:
@@ -701,6 +687,19 @@
                 label = context.getString(R.string.status_bar_settings_signal_meter_wifi_nossid);
             } else {
                 label = mWifiSsid;
+                switch (mWifiActivity) {
+                    case WifiManager.DATA_ACTIVITY_IN:
+                        dataDirectionOverlayIconId = R.drawable.stat_sys_wifi_in;
+                        break;
+                    case WifiManager.DATA_ACTIVITY_OUT:
+                        dataDirectionOverlayIconId = R.drawable.stat_sys_wifi_out;
+                        break;
+                    case WifiManager.DATA_ACTIVITY_INOUT:
+                        dataDirectionOverlayIconId = R.drawable.stat_sys_wifi_inout;
+                        break;
+                    case WifiManager.DATA_ACTIVITY_NONE:
+                        break;
+                }
             }
             combinedSignalIconId = mWifiIconId;
             dataTypeIconId = 0;
@@ -813,7 +812,9 @@
 
         // the data direction overlay
         if (mLastDataDirectionOverlayIconId != dataDirectionOverlayIconId) {
-            Slog.d(TAG, "changing data overlay icon id to " + dataDirectionOverlayIconId);
+            if (DEBUG) {
+                Slog.d(TAG, "changing data overlay icon id to " + dataDirectionOverlayIconId);
+            }
             mLastDataDirectionOverlayIconId = dataDirectionOverlayIconId;
             N = mDataDirectionOverlayIconViews.size();
             for (int i=0; i<N; i++) {
@@ -888,6 +889,9 @@
         pw.println(mWifiSsid);
         pw.print("  mWifiIconId=");
         pw.println(mWifiIconId);
+        pw.print("  mWifiActivity=");
+        pw.println(mWifiActivity);
+
 
         pw.println("  - Bluetooth ----");
         pw.print(" mBtReverseTethered=");
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/InputMethodsPanel.java b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/InputMethodsPanel.java
index ce0848b..e9db998 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/InputMethodsPanel.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/InputMethodsPanel.java
@@ -89,14 +89,12 @@
         public int compare(InputMethodInfo imi1, InputMethodInfo imi2) {
             if (imi2 == null) return 0;
             if (imi1 == null) return 1;
-            if (mPackageManager != null) {
-                CharSequence imiId1 = imi1.loadLabel(mPackageManager) + "/" + imi1.getId();
-                CharSequence imiId2 = imi2.loadLabel(mPackageManager) + "/" + imi2.getId();
-                if (imiId1 != null && imiId2 != null) {
-                    return imiId1.toString().compareTo(imiId2.toString());
-                }
+            if (mPackageManager == null) {
+                return imi1.getId().compareTo(imi2.getId());
             }
-            return imi1.getId().compareTo(imi2.getId());
+            CharSequence imiId1 = imi1.loadLabel(mPackageManager) + "/" + imi1.getId();
+            CharSequence imiId2 = imi2.loadLabel(mPackageManager) + "/" + imi2.getId();
+            return imiId1.toString().compareTo(imiId2.toString());
         }
     }
 
@@ -267,7 +265,6 @@
 
         Map<InputMethodInfo, List<InputMethodSubtype>> enabledIMIs =
                 getEnabledInputMethodAndSubtypeList();
-        // TODO: Sort by alphabet and mode.
         Set<InputMethodInfo> cachedImiSet = enabledIMIs.keySet();
         for (InputMethodInfo imi: cachedImiSet) {
             List<InputMethodSubtype> subtypes = enabledIMIs.get(imi);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/NotificationPeekPanel.java b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/NotificationPeekPanel.java
index 744f667..8b68240 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/NotificationPeekPanel.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/NotificationPeekPanel.java
@@ -18,11 +18,15 @@
 
 import android.content.Context;
 import android.util.AttributeSet;
+import android.util.Slog;
+import android.view.MotionEvent;
 import android.widget.RelativeLayout;
 
 import com.android.systemui.R;
 
 public class NotificationPeekPanel extends RelativeLayout implements StatusBarPanel {
+    TabletStatusBar mBar;
+
     public NotificationPeekPanel(Context context, AttributeSet attrs) {
         this(context, attrs, 0);
     }
@@ -39,5 +43,16 @@
         return x >= l && x < r && y >= t && y < b;
     }
 
+    public void setBar(TabletStatusBar bar) {
+        mBar = bar;
+    }
+
+    // We don't really want to intercept the touch event, but we *do* want to reset the fade timer
+    // in case the user is interacting with some custom controls or something.
+    @Override
+    public boolean onInterceptTouchEvent(MotionEvent ev) {
+        mBar.resetNotificationPeekFadeTimer();
+        return false;
+    }
 }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/RecentAppsPanel.java b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/RecentAppsPanel.java
index 737a52b..c5a7df2 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/RecentAppsPanel.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/RecentAppsPanel.java
@@ -513,9 +513,7 @@
             paint.setFilterBitmap(true);
             paint.setAlpha(255);
             final int srcWidth = thumbnail.getWidth();
-            final int height = thumbnail.getHeight();
-            final int srcHeight = srcWidth > height ? height
-                    : (height - height * srcWidth / height);
+            final int srcHeight = thumbnail.getHeight();
             canvas.drawBitmap(thumbnail,
                     new Rect(0, 0, srcWidth-1, srcHeight-1),
                     new RectF(GLOW_PADDING,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBar.java
index 4557105..58c4d5a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBar.java
@@ -217,6 +217,8 @@
         // Notification preview window
         mNotificationPeekWindow = (NotificationPeekPanel) View.inflate(context,
                 R.layout.status_bar_notification_peek, null);
+        mNotificationPeekWindow.setBar(this);
+
         mNotificationPeekRow = (ViewGroup) mNotificationPeekWindow.findViewById(R.id.content);
         mNotificationPeekWindow.setVisibility(View.GONE);
         mNotificationPeekWindow.setOnTouchListener(
@@ -1211,10 +1213,20 @@
         }
     }
 
-    private class NotificationIconTouchListener implements View.OnTouchListener {
-        final static int NOTIFICATION_PEEK_HOLD_THRESH = 200; // ms
-        final static int NOTIFICATION_PEEK_FADE_DELAY = 5000; // ms
+    final static int NOTIFICATION_PEEK_HOLD_THRESH = 200; // ms
+    final static int NOTIFICATION_PEEK_FADE_DELAY = 3000; // ms
 
+    public void resetNotificationPeekFadeTimer() {
+        if (DEBUG) {
+            Slog.d(TAG, "setting peek fade timer for " + NOTIFICATION_PEEK_FADE_DELAY
+                + "ms from now");
+        }
+        mHandler.removeMessages(MSG_CLOSE_NOTIFICATION_PEEK);
+        mHandler.sendEmptyMessageDelayed(MSG_CLOSE_NOTIFICATION_PEEK,
+                NOTIFICATION_PEEK_FADE_DELAY);
+    }
+
+    private class NotificationIconTouchListener implements View.OnTouchListener {
         VelocityTracker mVT;
         int mPeekIndex;
         float mInitialTouchX, mInitialTouchY;
@@ -1303,8 +1315,7 @@
                     }
 
                     if (peeking) {
-                        mHandler.sendEmptyMessageDelayed(MSG_CLOSE_NOTIFICATION_PEEK,
-                                NOTIFICATION_PEEK_FADE_DELAY);
+                        resetNotificationPeekFadeTimer();
                     }
 
                     mVT.recycle();
diff --git a/packages/SystemUI/src/com/android/systemui/usb/UsbAccessoryUriActivity.java b/packages/SystemUI/src/com/android/systemui/usb/UsbAccessoryUriActivity.java
new file mode 100644
index 0000000..5007cf4
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/usb/UsbAccessoryUriActivity.java
@@ -0,0 +1,100 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.usb;
+
+import android.app.Activity;
+import android.app.AlertDialog;
+import android.content.ActivityNotFoundException;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.content.Intent;
+import android.net.Uri;
+import android.hardware.usb.UsbAccessory;
+import android.hardware.usb.UsbManager;
+import android.os.Bundle;
+import android.util.Log;
+
+import com.android.internal.app.AlertActivity;
+import com.android.internal.app.AlertController;
+
+import com.android.systemui.R;
+
+/**
+ * If the attached USB accessory has a URL associated with it, and that URL is valid,
+ * show this dialog to the user to allow them to optionally visit that URL for more
+ * information or software downloads.
+ * Otherwise (no valid URL) this activity does nothing at all, finishing immediately.
+ */
+public class UsbAccessoryUriActivity extends AlertActivity
+        implements DialogInterface.OnClickListener {
+
+    private static final String TAG = "UsbAccessoryUriActivity";
+
+    private UsbAccessory mAccessory;
+    private Uri mUri;
+
+    @Override
+    public void onCreate(Bundle icicle) {
+       super.onCreate(icicle);
+
+       Intent intent = getIntent();
+        mAccessory = (UsbAccessory)intent.getParcelableExtra(UsbManager.EXTRA_ACCESSORY);
+        String uriString = intent.getStringExtra("uri");
+        mUri = (uriString == null ? null : Uri.parse(uriString));
+
+        // sanity check before displaying dialog
+        if (mUri == null) {
+            Log.e(TAG, "could not parse Uri " + uriString);
+            finish();
+            return;
+        }
+        String scheme = mUri.getScheme();
+        if (!"http".equals(scheme) && !"https".equals(scheme)) {
+            Log.e(TAG, "Uri not http or https: " + mUri);
+            finish();
+            return;
+        }
+
+        final AlertController.AlertParams ap = mAlertParams;
+        ap.mTitle = mAccessory.getDescription();
+        if (ap.mTitle == null || ap.mTitle.length() == 0) {
+            ap.mTitle = getString(R.string.title_usb_accessory);
+        }
+        ap.mMessage = getString(R.string.usb_accessory_uri_prompt, mUri);
+        ap.mPositiveButtonText = getString(R.string.label_view);
+        ap.mNegativeButtonText = getString(android.R.string.cancel);
+        ap.mPositiveButtonListener = this;
+        ap.mNegativeButtonListener = this;
+
+        setupAlert();
+    }
+
+    public void onClick(DialogInterface dialog, int which) {
+        if (which == AlertDialog.BUTTON_POSITIVE) {
+            // launch the browser
+            Intent intent = new Intent(Intent.ACTION_VIEW, mUri);
+            intent.addCategory(Intent.CATEGORY_BROWSABLE);
+            intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+            try {
+                startActivity(intent);
+            } catch (ActivityNotFoundException e) {
+                Log.e(TAG, "startActivity failed for " + mUri);
+            }
+        }
+        finish();
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/usb/UsbConfirmActivity.java b/packages/SystemUI/src/com/android/systemui/usb/UsbConfirmActivity.java
new file mode 100644
index 0000000..030a261
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/usb/UsbConfirmActivity.java
@@ -0,0 +1,172 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.usb;
+
+import android.app.Activity;
+import android.app.AlertDialog;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.content.Intent;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
+import android.hardware.usb.IUsbManager;
+import android.hardware.usb.UsbDevice;
+import android.hardware.usb.UsbAccessory;
+import android.hardware.usb.UsbManager;
+import android.os.Bundle;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.util.Log;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.widget.CheckBox;
+import android.widget.CompoundButton;
+import android.widget.TextView;
+
+import com.android.internal.app.AlertActivity;
+import com.android.internal.app.AlertController;
+
+import com.android.systemui.R;
+
+public class UsbConfirmActivity extends AlertActivity
+        implements DialogInterface.OnClickListener, CheckBox.OnCheckedChangeListener {
+
+    private static final String TAG = "UsbConfirmActivity";
+
+    private CheckBox mAlwaysUse;
+    private TextView mClearDefaultHint;
+    private UsbDevice mDevice;
+    private UsbAccessory mAccessory;
+    private ResolveInfo mResolveInfo;
+    private boolean mPermissionGranted;
+    private UsbDisconnectedReceiver mDisconnectedReceiver;
+
+    @Override
+    public void onCreate(Bundle icicle) {
+        super.onCreate(icicle);
+
+       Intent intent = getIntent();
+        mDevice = (UsbDevice)intent.getParcelableExtra(UsbManager.EXTRA_DEVICE);
+        mAccessory = (UsbAccessory)intent.getParcelableExtra(UsbManager.EXTRA_ACCESSORY);
+        mResolveInfo = (ResolveInfo)intent.getParcelableExtra("rinfo");
+
+        PackageManager packageManager = getPackageManager();
+        String appName = mResolveInfo.loadLabel(packageManager).toString();
+
+        final AlertController.AlertParams ap = mAlertParams;
+        ap.mIcon = mResolveInfo.loadIcon(packageManager);
+        ap.mTitle = appName;
+        if (mDevice == null) {
+            ap.mMessage = getString(R.string.usb_accessory_confirm_prompt, appName);
+            mDisconnectedReceiver = new UsbDisconnectedReceiver(this, mAccessory);
+        } else {
+            ap.mMessage = getString(R.string.usb_device_confirm_prompt, appName);
+            mDisconnectedReceiver = new UsbDisconnectedReceiver(this, mDevice);
+        }
+        ap.mPositiveButtonText = getString(android.R.string.ok);
+        ap.mNegativeButtonText = getString(android.R.string.cancel);
+        ap.mPositiveButtonListener = this;
+        ap.mNegativeButtonListener = this;
+
+        // add "always use" checkbox
+        LayoutInflater inflater = (LayoutInflater)getSystemService(
+                Context.LAYOUT_INFLATER_SERVICE);
+        ap.mView = inflater.inflate(com.android.internal.R.layout.always_use_checkbox, null);
+        mAlwaysUse = (CheckBox)ap.mView.findViewById(com.android.internal.R.id.alwaysUse);
+        if (mDevice == null) {
+            mAlwaysUse.setText(R.string.always_use_accessory);
+        } else {
+            mAlwaysUse.setText(R.string.always_use_device);
+        }
+        mAlwaysUse.setOnCheckedChangeListener(this);
+        mClearDefaultHint = (TextView)ap.mView.findViewById(
+                                                    com.android.internal.R.id.clearDefaultHint);
+        mClearDefaultHint.setVisibility(View.GONE);
+
+        setupAlert();
+
+    }
+
+    @Override
+    protected void onDestroy() {
+        if (mDisconnectedReceiver != null) {
+            unregisterReceiver(mDisconnectedReceiver);
+        }
+        super.onDestroy();
+    }
+
+    public void onClick(DialogInterface dialog, int which) {
+        if (which == AlertDialog.BUTTON_POSITIVE) {
+            try {
+                IBinder b = ServiceManager.getService(USB_SERVICE);
+                IUsbManager service = IUsbManager.Stub.asInterface(b);
+                int uid = mResolveInfo.activityInfo.applicationInfo.uid;
+                boolean alwaysUse = mAlwaysUse.isChecked();
+                Intent intent = null;
+
+                if (mDevice != null) {
+                    intent = new Intent(UsbManager.ACTION_USB_DEVICE_ATTACHED);
+                    intent.putExtra(UsbManager.EXTRA_DEVICE, mDevice);
+
+                    // grant permission for the device
+                    service.grantDevicePermission(mDevice, uid);
+                    // set or clear default setting
+                    if (alwaysUse) {
+                        service.setDevicePackage(mDevice, mResolveInfo.activityInfo.packageName);
+                    } else {
+                        service.setDevicePackage(mDevice, null);
+                    }
+                } else if (mAccessory != null) {
+                    intent = new Intent(UsbManager.ACTION_USB_ACCESSORY_ATTACHED);
+                    intent.putExtra(UsbManager.EXTRA_ACCESSORY, mAccessory);
+
+                    // grant permission for the accessory
+                    service.grantAccessoryPermission(mAccessory, uid);
+                    // set or clear default setting
+                    if (alwaysUse) {
+                        service.setAccessoryPackage(mAccessory,
+                                mResolveInfo.activityInfo.packageName);
+                    } else {
+                        service.setAccessoryPackage(mAccessory, null);
+                    }
+                }
+
+                intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+                intent.setComponent(
+                    new ComponentName(mResolveInfo.activityInfo.packageName,
+                            mResolveInfo.activityInfo.name));
+                startActivity(intent);
+            } catch (Exception e) {
+                Log.e(TAG, "Unable to start activity", e);
+            }
+        }
+        finish();
+    }
+
+    public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
+        if (mClearDefaultHint == null) return;
+
+        if(isChecked) {
+            mClearDefaultHint.setVisibility(View.VISIBLE);
+        } else {
+            mClearDefaultHint.setVisibility(View.GONE);
+        }
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/usb/UsbDisconnectedReceiver.java b/packages/SystemUI/src/com/android/systemui/usb/UsbDisconnectedReceiver.java
new file mode 100644
index 0000000..1edebbb
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/usb/UsbDisconnectedReceiver.java
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.usb;
+
+import android.app.Activity;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.hardware.usb.UsbAccessory;
+import android.hardware.usb.UsbDevice;
+import android.hardware.usb.UsbManager;
+
+// This class is used to close UsbPermissionsActivity and UsbResolverActivity
+// if their device/accessory is disconnected while the dialog is still open
+class UsbDisconnectedReceiver extends BroadcastReceiver {
+    private final Activity mActivity;
+    private UsbDevice mDevice;
+    private UsbAccessory mAccessory;
+
+    public UsbDisconnectedReceiver(Activity activity, UsbDevice device) {
+       mActivity = activity;
+        mDevice = device;
+
+        IntentFilter filter = new IntentFilter(UsbManager.ACTION_USB_DEVICE_DETACHED);
+        activity.registerReceiver(this, filter);
+    }
+
+    public UsbDisconnectedReceiver(Activity activity, UsbAccessory accessory) {
+        mActivity = activity;
+        mAccessory = accessory;
+
+        IntentFilter filter = new IntentFilter(UsbManager.ACTION_USB_ACCESSORY_DETACHED);
+        activity.registerReceiver(this, filter);
+    }
+
+    @Override
+    public void onReceive(Context context, Intent intent) {
+        String action = intent.getAction();
+        if (UsbManager.ACTION_USB_DEVICE_DETACHED.equals(action)) {
+            UsbDevice device = (UsbDevice)intent.getParcelableExtra(UsbManager.EXTRA_DEVICE);
+            if (device != null && device.equals(mDevice)) {
+                mActivity.finish();
+            }
+        } else if (UsbManager.ACTION_USB_ACCESSORY_DETACHED.equals(action)) {
+            UsbAccessory accessory =
+                    (UsbAccessory)intent.getParcelableExtra(UsbManager.EXTRA_ACCESSORY);
+            if (accessory != null && accessory.equals(mAccessory)) {
+                mActivity.finish();
+            }
+        }
+    }
+}
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/usb/UsbPermissionActivity.java b/packages/SystemUI/src/com/android/systemui/usb/UsbPermissionActivity.java
new file mode 100644
index 0000000..c384f50
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/usb/UsbPermissionActivity.java
@@ -0,0 +1,174 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.usb;
+
+import android.app.Activity;
+import android.app.AlertDialog;
+import android.app.PendingIntent;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.content.Intent;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager;
+import android.hardware.usb.IUsbManager;
+import android.hardware.usb.UsbDevice;
+import android.hardware.usb.UsbAccessory;
+import android.hardware.usb.UsbManager;
+import android.os.Bundle;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.util.Log;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.widget.CheckBox;
+import android.widget.CompoundButton;
+import android.widget.TextView;
+
+import com.android.internal.app.AlertActivity;
+import com.android.internal.app.AlertController;
+
+import com.android.systemui.R;
+
+public class UsbPermissionActivity extends AlertActivity
+        implements DialogInterface.OnClickListener, CheckBox.OnCheckedChangeListener {
+
+    private static final String TAG = "UsbPermissionActivity";
+
+    private CheckBox mAlwaysUse;
+    private TextView mClearDefaultHint;
+    private UsbDevice mDevice;
+    private UsbAccessory mAccessory;
+    private PendingIntent mPendingIntent;
+    private String mPackageName;
+    private int mUid;
+    private boolean mPermissionGranted;
+    private UsbDisconnectedReceiver mDisconnectedReceiver;
+
+    @Override
+    public void onCreate(Bundle icicle) {
+        super.onCreate(icicle);
+
+       Intent intent = getIntent();
+        mDevice = (UsbDevice)intent.getParcelableExtra(UsbManager.EXTRA_DEVICE);
+        mAccessory = (UsbAccessory)intent.getParcelableExtra(UsbManager.EXTRA_ACCESSORY);
+        mPendingIntent = (PendingIntent)intent.getParcelableExtra(Intent.EXTRA_INTENT);
+        mUid = intent.getIntExtra("uid", 0);
+        mPackageName = intent.getStringExtra("package");
+
+        PackageManager packageManager = getPackageManager();
+        ApplicationInfo aInfo;
+        try {
+            aInfo = packageManager.getApplicationInfo(mPackageName, 0);
+        } catch (PackageManager.NameNotFoundException e) {
+            Log.e(TAG, "unable to look up package name", e);
+            finish();
+            return;
+        }
+        String appName = aInfo.loadLabel(packageManager).toString();
+
+        final AlertController.AlertParams ap = mAlertParams;
+        ap.mIcon = aInfo.loadIcon(packageManager);
+        ap.mTitle = appName;
+        if (mDevice == null) {
+            ap.mMessage = getString(R.string.usb_accessory_permission_prompt, appName);
+            mDisconnectedReceiver = new UsbDisconnectedReceiver(this, mAccessory);
+        } else {
+            ap.mMessage = getString(R.string.usb_device_permission_prompt, appName);
+            mDisconnectedReceiver = new UsbDisconnectedReceiver(this, mDevice);
+        }
+        ap.mPositiveButtonText = getString(android.R.string.ok);
+        ap.mNegativeButtonText = getString(android.R.string.cancel);
+        ap.mPositiveButtonListener = this;
+        ap.mNegativeButtonListener = this;
+
+        // add "always use" checkbox
+        LayoutInflater inflater = (LayoutInflater)getSystemService(
+                Context.LAYOUT_INFLATER_SERVICE);
+        ap.mView = inflater.inflate(com.android.internal.R.layout.always_use_checkbox, null);
+        mAlwaysUse = (CheckBox)ap.mView.findViewById(com.android.internal.R.id.alwaysUse);
+        if (mDevice == null) {
+            mAlwaysUse.setText(R.string.always_use_accessory);
+        } else {
+            mAlwaysUse.setText(R.string.always_use_device);
+        }
+        mAlwaysUse.setOnCheckedChangeListener(this);
+        mClearDefaultHint = (TextView)ap.mView.findViewById(
+                                                    com.android.internal.R.id.clearDefaultHint);
+        mClearDefaultHint.setVisibility(View.GONE);
+
+        setupAlert();
+
+    }
+
+    @Override
+    public void onDestroy() {
+        IBinder b = ServiceManager.getService(USB_SERVICE);
+        IUsbManager service = IUsbManager.Stub.asInterface(b);
+
+        // send response via pending intent
+        Intent intent = new Intent();
+        try {
+            if (mDevice != null) {
+                intent.putExtra(UsbManager.EXTRA_DEVICE, mDevice);
+                if (mPermissionGranted) {
+                    service.grantDevicePermission(mDevice, mUid);
+                    if (mAlwaysUse.isChecked()) {
+                        service.setDevicePackage(mDevice, mPackageName);
+                    }
+                }
+            }
+            if (mAccessory != null) {
+                intent.putExtra(UsbManager.EXTRA_ACCESSORY, mAccessory);
+                if (mPermissionGranted) {
+                    service.grantAccessoryPermission(mAccessory, mUid);
+                    if (mAlwaysUse.isChecked()) {
+                        service.setAccessoryPackage(mAccessory, mPackageName);
+                    }
+                }
+            }
+            intent.putExtra(UsbManager.EXTRA_PERMISSION_GRANTED, mPermissionGranted);
+            mPendingIntent.send(this, 0, intent);
+        } catch (PendingIntent.CanceledException e) {
+            Log.w(TAG, "PendingIntent was cancelled");
+        } catch (RemoteException e) {
+            Log.e(TAG, "IUsbService connection failed", e);
+        }
+
+        if (mDisconnectedReceiver != null) {
+            unregisterReceiver(mDisconnectedReceiver);
+        }
+        super.onDestroy();
+    }
+
+    public void onClick(DialogInterface dialog, int which) {
+        if (which == AlertDialog.BUTTON_POSITIVE) {
+            mPermissionGranted = true;
+        }
+        finish();
+    }
+
+    public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
+        if (mClearDefaultHint == null) return;
+
+        if(isChecked) {
+            mClearDefaultHint.setVisibility(View.VISIBLE);
+        } else {
+            mClearDefaultHint.setVisibility(View.GONE);
+        }
+    }
+}
diff --git a/services/java/com/android/server/usb/UsbResolverActivity.java b/packages/SystemUI/src/com/android/systemui/usb/UsbResolverActivity.java
similarity index 61%
rename from services/java/com/android/server/usb/UsbResolverActivity.java
rename to packages/SystemUI/src/com/android/systemui/usb/UsbResolverActivity.java
index e8a09a5..f61ecb1 100644
--- a/services/java/com/android/server/usb/UsbResolverActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/usb/UsbResolverActivity.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.android.server.usb;
+package com.android.systemui.usb;
 
 import com.android.internal.app.ResolverActivity;
 
@@ -31,6 +31,9 @@
 import android.os.RemoteException;
 import android.os.ServiceManager;
 import android.util.Log;
+import android.widget.CheckBox;
+
+import com.android.systemui.R;
 
 import java.util.ArrayList;
 
@@ -39,6 +42,10 @@
     public static final String TAG = "UsbResolverActivity";
     public static final String EXTRA_RESOLVE_INFOS = "rlist";
 
+    private UsbDevice mDevice;
+    private UsbAccessory mAccessory;
+    private UsbDisconnectedReceiver mDisconnectedReceiver;
+
     @Override
     protected void onCreate(Bundle savedInstanceState) {
         Intent intent = getIntent();
@@ -50,14 +57,39 @@
         }
         Intent target = (Intent)targetParcelable;
         ArrayList<ResolveInfo> rList = intent.getParcelableArrayListExtra(EXTRA_RESOLVE_INFOS);
-        Log.d(TAG, "rList.size() " + rList.size());
         CharSequence title = getResources().getText(com.android.internal.R.string.chooseUsbActivity);
         super.onCreate(savedInstanceState, target, title, null, rList,
-                true, /* Set alwaysUseOption to true to enable "always use this app" checkbox. */
-                true  /* Set alwaysChoose to display activity when only one choice is available.
-                         This is necessary because this activity is needed for the user to allow
-                         the application permission to access the device */
-                );
+                true /* Set alwaysUseOption to true to enable "always use this app" checkbox. */ );
+
+        CheckBox alwaysUse = (CheckBox)findViewById(com.android.internal.R.id.alwaysUse);
+        if (alwaysUse != null) {
+            if (mDevice == null) {
+                alwaysUse.setText(R.string.always_use_accessory);
+            } else {
+                alwaysUse.setText(R.string.always_use_device);
+            }
+        }
+
+        mDevice = (UsbDevice)target.getParcelableExtra(UsbManager.EXTRA_DEVICE);
+        if (mDevice != null) {
+            mDisconnectedReceiver = new UsbDisconnectedReceiver(this, mDevice);
+        } else {
+            mAccessory = (UsbAccessory)target.getParcelableExtra(UsbManager.EXTRA_ACCESSORY);
+            if (mAccessory == null) {
+                Log.e(TAG, "no device or accessory");
+                finish();
+                return;
+            }
+            mDisconnectedReceiver = new UsbDisconnectedReceiver(this, mAccessory);
+        }
+    }
+
+    @Override
+    protected void onDestroy() {
+        if (mDisconnectedReceiver != null) {
+            unregisterReceiver(mDisconnectedReceiver);
+        }
+        super.onDestroy();
     }
 
     protected void onIntentSelected(ResolveInfo ri, Intent intent, boolean alwaysCheck) {
@@ -65,28 +97,24 @@
             IBinder b = ServiceManager.getService(USB_SERVICE);
             IUsbManager service = IUsbManager.Stub.asInterface(b);
             int uid = ri.activityInfo.applicationInfo.uid;
-            String action = intent.getAction();
 
-            if (UsbManager.ACTION_USB_DEVICE_ATTACHED.equals(action)) {
-                UsbDevice device = (UsbDevice)intent.getParcelableExtra(UsbManager.EXTRA_DEVICE);
+            if (mDevice != null) {
                 // grant permission for the device
-                service.grantDevicePermission(device, uid);
+                service.grantDevicePermission(mDevice, uid);
                 // set or clear default setting
                 if (alwaysCheck) {
-                    service.setDevicePackage(device, ri.activityInfo.packageName);
+                    service.setDevicePackage(mDevice, ri.activityInfo.packageName);
                 } else {
-                    service.setDevicePackage(device, null);
+                    service.setDevicePackage(mDevice, null);
                 }
-            } else if (UsbManager.ACTION_USB_ACCESSORY_ATTACHED.equals(action)) {
-                UsbAccessory accessory = (UsbAccessory)intent.getParcelableExtra(
-                        UsbManager.EXTRA_ACCESSORY);
+            } else if (mAccessory != null) {
                 // grant permission for the accessory
-                service.grantAccessoryPermission(accessory, uid);
+                service.grantAccessoryPermission(mAccessory, uid);
                 // set or clear default setting
                 if (alwaysCheck) {
-                    service.setAccessoryPackage(accessory, ri.activityInfo.packageName);
+                    service.setAccessoryPackage(mAccessory, ri.activityInfo.packageName);
                 } else {
-                    service.setAccessoryPackage(accessory, null);
+                    service.setAccessoryPackage(mAccessory, null);
                 }
             }
 
diff --git a/policy/src/com/android/internal/policy/impl/KeyguardViewManager.java b/policy/src/com/android/internal/policy/impl/KeyguardViewManager.java
index 8d70a7b..ae23df6 100644
--- a/policy/src/com/android/internal/policy/impl/KeyguardViewManager.java
+++ b/policy/src/com/android/internal/policy/impl/KeyguardViewManager.java
@@ -103,6 +103,8 @@
             int flags = WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN
                     | WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER
                     | WindowManager.LayoutParams.FLAG_KEEP_SURFACE_WHILE_ANIMATING
+                    | WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED
+                    | WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED_SYSTEM
                     /*| WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN
                     | WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR*/ ;
             if (!mNeedsInput) {
@@ -142,7 +144,7 @@
                 mKeyguardView.onScreenTurnedOn();
             }
         }
-
+        mViewManager.updateViewLayout(mKeyguardHost, mWindowLayoutParams);
         mKeyguardHost.setVisibility(View.VISIBLE);
         mKeyguardView.requestFocus();
     }
diff --git a/policy/src/com/android/internal/policy/impl/LockScreen.java b/policy/src/com/android/internal/policy/impl/LockScreen.java
index 2bc57b5..a9d5ce4 100644
--- a/policy/src/com/android/internal/policy/impl/LockScreen.java
+++ b/policy/src/com/android/internal/policy/impl/LockScreen.java
@@ -232,6 +232,8 @@
 
         /** {@inheritDoc} */
         public void onGrabbedStateChange(View v, int grabbedState) {
+            if (DBG) Log.v(TAG, "*** LockScreen accel is " 
+                    + (mEnergyWave.isHardwareAccelerated() ? "on":"off"));
             // Don't poke the wake lock when returning to a state where the handle is
             // not grabbed since that can happen when the system (instead of the user)
             // cancels the grab.
diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindow.java b/policy/src/com/android/internal/policy/impl/PhoneWindow.java
index ec89db3..36e6b8e6 100644
--- a/policy/src/com/android/internal/policy/impl/PhoneWindow.java
+++ b/policy/src/com/android/internal/policy/impl/PhoneWindow.java
@@ -903,7 +903,7 @@
     }
 
     private void reopenMenu(boolean toggleMenuMode) {
-        if (mActionBar != null) {
+        if (mActionBar != null && mActionBar.isOverflowReserved()) {
             final Callback cb = getCallback();
             if (!mActionBar.isOverflowMenuShowing() || !toggleMenuMode) {
                 if (cb != null && !isDestroyed() && mActionBar.getVisibility() == View.VISIBLE) {
@@ -2187,7 +2187,7 @@
             super.onDetachedFromWindow();
             
             final Callback cb = getCallback();
-            if (cb != null && !isDestroyed() && mFeatureId < 0) {
+            if (cb != null && mFeatureId < 0) {
                 cb.onDetachedFromWindow();
             }
 
diff --git a/services/audioflinger/AudioFlinger.cpp b/services/audioflinger/AudioFlinger.cpp
index 2b08ab5..2702242 100644
--- a/services/audioflinger/AudioFlinger.cpp
+++ b/services/audioflinger/AudioFlinger.cpp
@@ -1738,7 +1738,10 @@
                     LOGV("BUFFER TIMEOUT: remove(%d) from active list on thread %p", track->name(), this);
                     tracksToRemove->add(track);
                     // indicate to client process that the track was disabled because of underrun
-                    cblk->flags |= CBLK_DISABLED_ON;
+                    {
+                        AutoMutex _l(cblk->lock);
+                        cblk->flags |= CBLK_DISABLED_ON;
+                    }
                 } else if (mixerStatus != MIXER_TRACKS_READY) {
                     mixerStatus = MIXER_TRACKS_ENABLED;
                 }
@@ -1787,10 +1790,9 @@
     for (size_t i = 0; i < size; i++) {
         sp<Track> t = mTracks[i];
         if (t->type() == streamType) {
-            t->mCblk->lock.lock();
+            AutoMutex _lcblk(t->mCblk->lock);
             t->mCblk->flags |= CBLK_INVALID_ON;
             t->mCblk->cv.signal();
-            t->mCblk->lock.unlock();
         }
     }
 }
@@ -2948,6 +2950,7 @@
 
     if (mCblk->framesReady() >= mCblk->frameCount ||
             (mCblk->flags & CBLK_FORCEREADY_MSK)) {
+        AutoMutex _l(mCblk->lock);
         mFillingUpStatus = FS_FILLED;
         mCblk->flags &= ~CBLK_FORCEREADY_MSK;
         return true;
@@ -3063,19 +3066,18 @@
         // STOPPED state
         mState = STOPPED;
 
-        mCblk->lock.lock();
         // NOTE: reset() will reset cblk->user and cblk->server with
         // the risk that at the same time, the AudioMixer is trying to read
         // data. In this case, getNextBuffer() would return a NULL pointer
         // as audio buffer => the AudioMixer code MUST always test that pointer
         // returned by getNextBuffer() is not NULL!
         reset();
-        mCblk->lock.unlock();
     }
 }
 
 void AudioFlinger::PlaybackThread::Track::reset()
 {
+    AutoMutex _l(mCblk->lock);
     // Do not reset twice to avoid discarding data written just after a flush and before
     // the audioflinger thread detects the track is stopped.
     if (!mResetDone) {
@@ -3209,10 +3211,13 @@
     if (thread != 0) {
         RecordThread *recordThread = (RecordThread *)thread.get();
         recordThread->stop(this);
-        TrackBase::reset();
-        // Force overerrun condition to avoid false overrun callback until first data is
-        // read from buffer
-        mCblk->flags |= CBLK_UNDERRUN_ON;
+        {
+            AutoMutex _l(mCblk->lock);
+            TrackBase::reset();
+            // Force overerrun condition to avoid false overrun callback until first data is
+            // read from buffer
+            mCblk->flags |= CBLK_UNDERRUN_ON;
+        }
     }
 }
 
diff --git a/services/audioflinger/AudioPolicyManagerBase.cpp b/services/audioflinger/AudioPolicyManagerBase.cpp
index 74be4e0..f653dc5 100644
--- a/services/audioflinger/AudioPolicyManagerBase.cpp
+++ b/services/audioflinger/AudioPolicyManagerBase.cpp
@@ -339,6 +339,7 @@
             LOGW("setForceUse() invalid config %d for FOR_COMMUNICATION", config);
             return;
         }
+        forceVolumeReeval = true;
         mForceUse[usage] = config;
         break;
     case AudioSystem::FOR_MEDIA:
@@ -384,7 +385,7 @@
     updateDeviceForStrategy();
     setOutputDevice(mHardwareOutput, newDevice);
     if (forceVolumeReeval) {
-        applyStreamVolumes(mHardwareOutput, newDevice);
+        applyStreamVolumes(mHardwareOutput, newDevice, 0, true);
     }
 
     audio_io_handle_t activeInput = getActiveInput();
@@ -1973,7 +1974,13 @@
             // offset value to reflect actual hardware volume that never reaches 0
             // 1% corresponds roughly to first step in VOICE_CALL stream volume setting (see AudioService.java)
             volume = 0.01 + 0.99 * volume;
+            // Force VOICE_CALL to track BLUETOOTH_SCO stream volume when bluetooth audio is
+            // enabled
+            if (stream == AudioSystem::BLUETOOTH_SCO) {
+                mpClientInterface->setStreamVolume(AudioSystem::VOICE_CALL, volume, output, delayMs);
+            }
         }
+
         mpClientInterface->setStreamVolume((AudioSystem::stream_type)stream, volume, output, delayMs);
     }
 
@@ -1986,6 +1993,7 @@
         } else {
             voiceVolume = 1.0;
         }
+
         if (voiceVolume != mLastVoiceVolume && output == mHardwareOutput) {
             mpClientInterface->setVoiceVolume(voiceVolume, delayMs);
             mLastVoiceVolume = voiceVolume;
@@ -1995,12 +2003,12 @@
     return NO_ERROR;
 }
 
-void AudioPolicyManagerBase::applyStreamVolumes(audio_io_handle_t output, uint32_t device, int delayMs)
+void AudioPolicyManagerBase::applyStreamVolumes(audio_io_handle_t output, uint32_t device, int delayMs, bool force)
 {
     LOGV("applyStreamVolumes() for output %d and device %x", output, device);
 
     for (int stream = 0; stream < AudioSystem::NUM_STREAM_TYPES; stream++) {
-        checkAndSetVolume(stream, mStreams[stream].mIndexCur, output, device, delayMs);
+        checkAndSetVolume(stream, mStreams[stream].mIndexCur, output, device, delayMs, force);
     }
 }
 
diff --git a/services/camera/libcameraservice/CannedJpeg.h b/services/camera/libcameraservice/CannedJpeg.h
index b6266fb..6dd99c1 100644
--- a/services/camera/libcameraservice/CannedJpeg.h
+++ b/services/camera/libcameraservice/CannedJpeg.h
@@ -1,3 +1,19 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
 const int kCannedJpegWidth = 320;
 const int kCannedJpegHeight = 240;
 const int kCannedJpegSize = 8733;
diff --git a/services/camera/tests/CameraServiceTest/CameraServiceTest.cpp b/services/camera/tests/CameraServiceTest/CameraServiceTest.cpp
index 3c8d553..8a228fd 100644
--- a/services/camera/tests/CameraServiceTest/CameraServiceTest.cpp
+++ b/services/camera/tests/CameraServiceTest/CameraServiceTest.cpp
@@ -1,3 +1,19 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
 #define LOG_TAG "CameraServiceTest"
 
 #include <stdio.h>
diff --git a/services/input/EventHub.cpp b/services/input/EventHub.cpp
index d5f78a9..7625adb 100644
--- a/services/input/EventHub.cpp
+++ b/services/input/EventHub.cpp
@@ -127,9 +127,11 @@
         mError(NO_INIT), mBuiltInKeyboardId(-1), mNextDeviceId(1),
         mOpeningDevices(0), mClosingDevices(0),
         mOpened(false), mNeedToSendFinishedDeviceScan(false),
-        mInputBufferIndex(0), mInputBufferCount(0), mInputFdIndex(0) {
+        mInputFdIndex(1) {
     acquire_wake_lock(PARTIAL_WAKE_LOCK, WAKE_LOCK_ID);
+
     memset(mSwitches, 0, sizeof(mSwitches));
+    mNumCpus = sysconf(_SC_NPROCESSORS_ONLN);
 }
 
 EventHub::~EventHub(void) {
@@ -352,14 +354,13 @@
     return NAME_NOT_FOUND;
 }
 
-status_t EventHub::mapAxis(int32_t deviceId, int scancode,
-        int32_t* outAxis) const
+status_t EventHub::mapAxis(int32_t deviceId, int scancode, AxisInfo* outAxisInfo) const
 {
     AutoMutex _l(mLock);
     Device* device = getDeviceLocked(deviceId);
 
     if (device && device->keyMap.haveKeyLayout()) {
-        status_t err = device->keyMap.keyLayoutMap->mapAxis(scancode, outAxis);
+        status_t err = device->keyMap.keyLayoutMap->mapAxis(scancode, outAxisInfo);
         if (err == NO_ERROR) {
             return NO_ERROR;
         }
@@ -369,14 +370,13 @@
         device = getDeviceLocked(mBuiltInKeyboardId);
 
         if (device && device->keyMap.haveKeyLayout()) {
-            status_t err = device->keyMap.keyLayoutMap->mapAxis(scancode, outAxis);
+            status_t err = device->keyMap.keyLayoutMap->mapAxis(scancode, outAxisInfo);
             if (err == NO_ERROR) {
                 return NO_ERROR;
             }
         }
     }
 
-    *outAxis = -1;
     return NAME_NOT_FOUND;
 }
 
@@ -447,17 +447,10 @@
     return NULL;
 }
 
-bool EventHub::getEvent(RawEvent* outEvent) {
-    outEvent->deviceId = 0;
-    outEvent->type = 0;
-    outEvent->scanCode = 0;
-    outEvent->keyCode = 0;
-    outEvent->flags = 0;
-    outEvent->value = 0;
-    outEvent->when = 0;
-
-    // Note that we only allow one caller to getEvent(), so don't need
+size_t EventHub::getEvents(int timeoutMillis, RawEvent* buffer, size_t bufferSize) {
+    // Note that we only allow one caller to getEvents(), so don't need
     // to do locking here...  only when adding/removing devices.
+    assert(bufferSize >= 1);
 
     if (!mOpened) {
         mError = openPlatformInput() ? NO_ERROR : UNKNOWN_ERROR;
@@ -465,99 +458,62 @@
         mNeedToSendFinishedDeviceScan = true;
     }
 
+    struct input_event readBuffer[bufferSize];
+
+    RawEvent* event = buffer;
+    size_t capacity = bufferSize;
     for (;;) {
+        nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
+
         // Report any devices that had last been added/removed.
-        if (mClosingDevices != NULL) {
+        while (mClosingDevices) {
             Device* device = mClosingDevices;
             LOGV("Reporting device closed: id=%d, name=%s\n",
                  device->id, device->path.string());
             mClosingDevices = device->next;
-            if (device->id == mBuiltInKeyboardId) {
-                outEvent->deviceId = 0;
-            } else {
-                outEvent->deviceId = device->id;
-            }
-            outEvent->type = DEVICE_REMOVED;
-            outEvent->when = systemTime(SYSTEM_TIME_MONOTONIC);
+            event->when = now;
+            event->deviceId = device->id == mBuiltInKeyboardId ? 0 : device->id;
+            event->type = DEVICE_REMOVED;
+            event += 1;
             delete device;
             mNeedToSendFinishedDeviceScan = true;
-            return true;
+            if (--capacity == 0) {
+                break;
+            }
         }
 
-        if (mOpeningDevices != NULL) {
+        while (mOpeningDevices != NULL) {
             Device* device = mOpeningDevices;
             LOGV("Reporting device opened: id=%d, name=%s\n",
                  device->id, device->path.string());
             mOpeningDevices = device->next;
-            if (device->id == mBuiltInKeyboardId) {
-                outEvent->deviceId = 0;
-            } else {
-                outEvent->deviceId = device->id;
-            }
-            outEvent->type = DEVICE_ADDED;
-            outEvent->when = systemTime(SYSTEM_TIME_MONOTONIC);
+            event->when = now;
+            event->deviceId = device->id == mBuiltInKeyboardId ? 0 : device->id;
+            event->type = DEVICE_ADDED;
+            event += 1;
             mNeedToSendFinishedDeviceScan = true;
-            return true;
+            if (--capacity == 0) {
+                break;
+            }
         }
 
         if (mNeedToSendFinishedDeviceScan) {
             mNeedToSendFinishedDeviceScan = false;
-            outEvent->type = FINISHED_DEVICE_SCAN;
-            outEvent->when = systemTime(SYSTEM_TIME_MONOTONIC);
-            return true;
+            event->when = now;
+            event->type = FINISHED_DEVICE_SCAN;
+            event += 1;
+            if (--capacity == 0) {
+                break;
+            }
         }
 
         // Grab the next input event.
+        // mInputFdIndex is initially 1 because index 0 is used for inotify.
         bool deviceWasRemoved = false;
-        for (;;) {
-            // Consume buffered input events, if any.
-            if (mInputBufferIndex < mInputBufferCount) {
-                const struct input_event& iev = mInputBufferData[mInputBufferIndex++];
-                const Device* device = mDevices[mInputFdIndex];
-
-                LOGV("%s got: t0=%d, t1=%d, type=%d, code=%d, v=%d", device->path.string(),
-                     (int) iev.time.tv_sec, (int) iev.time.tv_usec, iev.type, iev.code, iev.value);
-                if (device->id == mBuiltInKeyboardId) {
-                    outEvent->deviceId = 0;
-                } else {
-                    outEvent->deviceId = device->id;
-                }
-                outEvent->type = iev.type;
-                outEvent->scanCode = iev.code;
-                outEvent->flags = 0;
-                if (iev.type == EV_KEY) {
-                    outEvent->keyCode = AKEYCODE_UNKNOWN;
-                    if (device->keyMap.haveKeyLayout()) {
-                        status_t err = device->keyMap.keyLayoutMap->mapKey(iev.code,
-                                &outEvent->keyCode, &outEvent->flags);
-                        LOGV("iev.code=%d keyCode=%d flags=0x%08x err=%d\n",
-                                iev.code, outEvent->keyCode, outEvent->flags, err);
-                    }
-                } else {
-                    outEvent->keyCode = iev.code;
-                }
-                outEvent->value = iev.value;
-
-                // Use an event timestamp in the same timebase as
-                // java.lang.System.nanoTime() and android.os.SystemClock.uptimeMillis()
-                // as expected by the rest of the system.
-                outEvent->when = systemTime(SYSTEM_TIME_MONOTONIC);
-                return true;
-            }
-
-            // Finish reading all events from devices identified in previous poll().
-            // This code assumes that mInputDeviceIndex is initially 0 and that the
-            // revents member of pollfd is initialized to 0 when the device is first added.
-            // Since mFds[0] is used for inotify, we process regular events starting at index 1.
-            mInputFdIndex += 1;
-            if (mInputFdIndex >= mFds.size()) {
-                break;
-            }
-
+        while (mInputFdIndex < mFds.size()) {
             const struct pollfd& pfd = mFds[mInputFdIndex];
             if (pfd.revents & POLLIN) {
-                int32_t readSize = read(pfd.fd, mInputBufferData,
-                        sizeof(struct input_event) * INPUT_BUFFER_SIZE);
+                int32_t readSize = read(pfd.fd, readBuffer, sizeof(struct input_event) * capacity);
                 if (readSize < 0) {
                     if (errno == ENODEV) {
                         deviceWasRemoved = true;
@@ -568,11 +524,43 @@
                     }
                 } else if ((readSize % sizeof(struct input_event)) != 0) {
                     LOGE("could not get event (wrong size: %d)", readSize);
+                } else if (readSize == 0) { // eof
+                    deviceWasRemoved = true;
+                    break;
                 } else {
-                    mInputBufferCount = size_t(readSize) / sizeof(struct input_event);
-                    mInputBufferIndex = 0;
+                    const Device* device = mDevices[mInputFdIndex];
+                    int32_t deviceId = device->id == mBuiltInKeyboardId ? 0 : device->id;
+
+                    size_t count = size_t(readSize) / sizeof(struct input_event);
+                    for (size_t i = 0; i < count; i++) {
+                        const struct input_event& iev = readBuffer[i];
+                        LOGV("%s got: t0=%d, t1=%d, type=%d, code=%d, value=%d",
+                                device->path.string(),
+                                (int) iev.time.tv_sec, (int) iev.time.tv_usec,
+                                iev.type, iev.code, iev.value);
+
+                        event->when = now;
+                        event->deviceId = deviceId;
+                        event->type = iev.type;
+                        event->scanCode = iev.code;
+                        event->value = iev.value;
+                        event->keyCode = AKEYCODE_UNKNOWN;
+                        event->flags = 0;
+                        if (iev.type == EV_KEY && device->keyMap.haveKeyLayout()) {
+                            status_t err = device->keyMap.keyLayoutMap->mapKey(iev.code,
+                                        &event->keyCode, &event->flags);
+                            LOGV("iev.code=%d keyCode=%d flags=0x%08x err=%d\n",
+                                    iev.code, event->keyCode, event->flags, err);
+                        }
+                        event += 1;
+                    }
+                    capacity -= count;
+                    if (capacity == 0) {
+                        break;
+                    }
                 }
             }
+            mInputFdIndex += 1;
         }
 
         // Handle the case where a device has been removed but INotify has not yet noticed.
@@ -588,10 +576,16 @@
         if(mFds[0].revents & POLLIN) {
             readNotify(mFds[0].fd);
             mFds.editItemAt(0).revents = 0;
+            mInputFdIndex = mFds.size();
             continue; // report added or removed devices immediately
         }
 #endif
 
+        // Return now if we have collected any events, otherwise poll.
+        if (event != buffer) {
+            break;
+        }
+
         // Poll for events.  Mind the wake lock dance!
         // We hold a wake lock at all times except during poll().  This works due to some
         // subtle choreography.  When a device driver has pending (unread) events, it acquires
@@ -600,22 +594,46 @@
         // when this happens, the EventHub holds onto its own user wake lock while the client
         // is processing events.  Thus the system can only sleep if there are no events
         // pending or currently being processed.
+        //
+        // The timeout is advisory only.  If the device is asleep, it will not wake just to
+        // service the timeout.
         release_wake_lock(WAKE_LOCK_ID);
 
-        int pollResult = poll(mFds.editArray(), mFds.size(), -1);
+        int pollResult = poll(mFds.editArray(), mFds.size(), timeoutMillis);
 
         acquire_wake_lock(PARTIAL_WAKE_LOCK, WAKE_LOCK_ID);
 
-        if (pollResult <= 0) {
+        if (pollResult == 0) {
+            break; // timed out
+        }
+        if (pollResult < 0) {
+            // Sleep after errors to avoid locking up the system.
+            // Hopefully the error is transient.
             if (errno != EINTR) {
                 LOGW("poll failed (errno=%d)\n", errno);
                 usleep(100000);
             }
+        } else {
+            // On an SMP system, it is possible for the framework to read input events
+            // faster than the kernel input device driver can produce a complete packet.
+            // Because poll() wakes up as soon as the first input event becomes available,
+            // the framework will often end up reading one event at a time until the
+            // packet is complete.  Instead of one call to read() returning 71 events,
+            // it could take 71 calls to read() each returning 1 event.
+            //
+            // Sleep for a short period of time after waking up from the poll() to give
+            // the kernel time to finish writing the entire packet of input events.
+            if (mNumCpus > 1) {
+                usleep(250);
+            }
         }
 
         // Prepare to process all of the FDs we just polled.
-        mInputFdIndex = 0;
+        mInputFdIndex = 1;
     }
+
+    // All done, return the number of events we read.
+    return event - buffer;
 }
 
 /*
@@ -1076,8 +1094,34 @@
     mDevices.removeAt(index);
     device->close();
 
-    device->next = mClosingDevices;
-    mClosingDevices = device;
+    // Unlink for opening devices list if it is present.
+    Device* pred = NULL;
+    bool found = false;
+    for (Device* entry = mOpeningDevices; entry != NULL; ) {
+        if (entry == device) {
+            found = true;
+            break;
+        }
+        pred = entry;
+        entry = entry->next;
+    }
+    if (found) {
+        // Unlink the device from the opening devices list then delete it.
+        // We don't need to tell the client that the device was closed because
+        // it does not even know it was opened in the first place.
+        LOGI("Device %s was immediately closed after opening.", device->path.string());
+        if (pred) {
+            pred->next = device->next;
+        } else {
+            mOpeningDevices = device->next;
+        }
+        delete device;
+    } else {
+        // Link into closing devices list.
+        // The device will be deleted later after we have informed the client.
+        device->next = mClosingDevices;
+        mClosingDevices = device;
+    }
     return 0;
 }
 
diff --git a/services/input/EventHub.h b/services/input/EventHub.h
index 99be802..4d26a95 100644
--- a/services/input/EventHub.h
+++ b/services/input/EventHub.h
@@ -157,6 +157,8 @@
         // Sent when all added/removed devices from the most recent scan have been reported.
         // This event is always sent at least once.
         FINISHED_DEVICE_SCAN = 0x30000000,
+
+        FIRST_SYNTHETIC_EVENT = DEVICE_ADDED,
     };
 
     virtual uint32_t getDeviceClasses(int32_t deviceId) const = 0;
@@ -174,20 +176,25 @@
             int32_t* outKeycode, uint32_t* outFlags) const = 0;
 
     virtual status_t mapAxis(int32_t deviceId, int scancode,
-            int32_t* outAxis) const = 0;
+            AxisInfo* outAxisInfo) const = 0;
 
     // exclude a particular device from opening
     // this can be used to ignore input devices for sensors
     virtual void addExcludedDevice(const char* deviceName) = 0;
 
     /*
-     * Wait for the next event to become available and return it.
+     * Wait for events to become available and returns them.
      * After returning, the EventHub holds onto a wake lock until the next call to getEvent.
      * This ensures that the device will not go to sleep while the event is being processed.
      * If the device needs to remain awake longer than that, then the caller is responsible
      * for taking care of it (say, by poking the power manager user activity timer).
+     *
+     * The timeout is advisory only.  If the device is asleep, it will not wake just to
+     * service the timeout.
+     *
+     * Returns the number of events obtained, or 0 if the timeout expired.
      */
-    virtual bool getEvent(RawEvent* outEvent) = 0;
+    virtual size_t getEvents(int timeoutMillis, RawEvent* buffer, size_t bufferSize) = 0;
 
     /*
      * Query current input state.
@@ -233,7 +240,7 @@
             int32_t* outKeycode, uint32_t* outFlags) const;
 
     virtual status_t mapAxis(int32_t deviceId, int scancode,
-            int32_t* outAxis) const;
+            AxisInfo* outAxisInfo) const;
 
     virtual void addExcludedDevice(const char* deviceName);
 
@@ -244,7 +251,7 @@
     virtual bool markSupportedKeyCodes(int32_t deviceId, size_t numCodes,
             const int32_t* keyCodes, uint8_t* outFlags) const;
 
-    virtual bool getEvent(RawEvent* outEvent);
+    virtual size_t getEvents(int timeoutMillis, RawEvent* buffer, size_t bufferSize);
 
     virtual bool hasLed(int32_t deviceId, int32_t led) const;
     virtual void setLedState(int32_t deviceId, int32_t led, bool on);
@@ -331,11 +338,11 @@
     // device ids that report particular switches.
     int32_t mSwitches[SW_MAX + 1];
 
-    static const int INPUT_BUFFER_SIZE = 64;
-    struct input_event mInputBufferData[INPUT_BUFFER_SIZE];
-    size_t mInputBufferIndex;
-    size_t mInputBufferCount;
+    // The index of the next file descriptor that needs to be read.
     size_t mInputFdIndex;
+
+    // Set to the number of CPUs.
+    int32_t mNumCpus;
 };
 
 }; // namespace android
diff --git a/services/input/InputDispatcher.cpp b/services/input/InputDispatcher.cpp
index 0606307..456e0e6 100644
--- a/services/input/InputDispatcher.cpp
+++ b/services/input/InputDispatcher.cpp
@@ -238,15 +238,7 @@
 
     // Wait for callback or timeout or wake.  (make sure we round up, not down)
     nsecs_t currentTime = now();
-    int32_t timeoutMillis;
-    if (nextWakeupTime > currentTime) {
-        uint64_t timeout = uint64_t(nextWakeupTime - currentTime);
-        timeout = (timeout + 999999LL) / 1000000LL;
-        timeoutMillis = timeout > INT_MAX ? -1 : int32_t(timeout);
-    } else {
-        timeoutMillis = 0;
-    }
-
+    int timeoutMillis = toMillisecondTimeoutDelay(currentTime, nextWakeupTime);
     mLooper->pollOnce(timeoutMillis);
 }
 
@@ -354,8 +346,7 @@
                 }
 #endif
 
-                mThrottleState.lastEventTime = entry->eventTime < currentTime
-                        ? entry->eventTime : currentTime;
+                mThrottleState.lastEventTime = currentTime;
                 mThrottleState.lastDeviceId = deviceId;
                 mThrottleState.lastSource = source;
             }
@@ -2136,8 +2127,8 @@
         if (pointerIds.hasBit(pointerId)) {
             splitPointerIndexMap[splitPointerCount] = originalPointerIndex;
             splitPointerIds[splitPointerCount] = pointerId;
-            splitPointerCoords[splitPointerCount] =
-                    originalMotionEntry->firstSample.pointerCoords[originalPointerIndex];
+            splitPointerCoords[splitPointerCount].copyFrom(
+                    originalMotionEntry->firstSample.pointerCoords[originalPointerIndex]);
             splitPointerCount += 1;
         }
     }
@@ -2200,8 +2191,8 @@
         for (uint32_t splitPointerIndex = 0; splitPointerIndex < splitPointerCount;
                 splitPointerIndex++) {
             uint32_t originalPointerIndex = splitPointerIndexMap[splitPointerIndex];
-            splitPointerCoords[splitPointerIndex] =
-                    originalMotionSample->pointerCoords[originalPointerIndex];
+            splitPointerCoords[splitPointerIndex].copyFrom(
+                    originalMotionSample->pointerCoords[originalPointerIndex]);
         }
 
         mAllocator.appendMotionSample(splitMotionEntry, originalMotionSample->eventTime,
@@ -2246,6 +2237,21 @@
         policyFlags |= POLICY_FLAG_VIRTUAL;
         flags |= AKEY_EVENT_FLAG_VIRTUAL_HARD_KEY;
     }
+    if (policyFlags & POLICY_FLAG_ALT) {
+        metaState |= AMETA_ALT_ON | AMETA_ALT_LEFT_ON;
+    }
+    if (policyFlags & POLICY_FLAG_ALT_GR) {
+        metaState |= AMETA_ALT_ON | AMETA_ALT_RIGHT_ON;
+    }
+    if (policyFlags & POLICY_FLAG_SHIFT) {
+        metaState |= AMETA_SHIFT_ON | AMETA_SHIFT_LEFT_ON;
+    }
+    if (policyFlags & POLICY_FLAG_CAPS_LOCK) {
+        metaState |= AMETA_CAPS_LOCK_ON;
+    }
+    if (policyFlags & POLICY_FLAG_FUNCTION) {
+        metaState |= AMETA_FUNCTION_ON;
+    }
 
     policyFlags |= POLICY_FLAG_TRUSTED;
 
@@ -2329,17 +2335,17 @@
                 }
 
                 MotionEntry* motionEntry = static_cast<MotionEntry*>(entry);
-                if (motionEntry->deviceId != deviceId) {
-                    // Keep looking for this device.
+                if (motionEntry->deviceId != deviceId
+                        || motionEntry->source != source) {
+                    // Keep looking for this device and source.
                     continue;
                 }
 
                 if (motionEntry->action != action
-                        || motionEntry->source != source
                         || motionEntry->pointerCount != pointerCount
                         || motionEntry->isInjected()) {
-                    // Last motion event in the queue for this device is not compatible for
-                    // appending new samples.  Stop here.
+                    // Last motion event in the queue for this device and source is
+                    // not compatible for appending new samples.  Stop here.
                     goto NoBatchingOrStreaming;
                 }
 
@@ -3439,7 +3445,7 @@
     entry->lastSample = & entry->firstSample;
     for (uint32_t i = 0; i < pointerCount; i++) {
         entry->pointerIds[i] = pointerIds[i];
-        entry->firstSample.pointerCoords[i] = pointerCoords[i];
+        entry->firstSample.pointerCoords[i].copyFrom(pointerCoords[i]);
     }
     return entry;
 }
@@ -3542,7 +3548,7 @@
     sample->eventTime = eventTime;
     uint32_t pointerCount = motionEntry->pointerCount;
     for (uint32_t i = 0; i < pointerCount; i++) {
-        sample->pointerCoords[i] = pointerCoords[i];
+        sample->pointerCoords[i].copyFrom(pointerCoords[i]);
     }
 
     sample->next = NULL;
@@ -3679,7 +3685,7 @@
     pointerCount = entry->pointerCount;
     for (uint32_t i = 0; i < entry->pointerCount; i++) {
         pointerIds[i] = entry->pointerIds[i];
-        pointerCoords[i] = entry->lastSample->pointerCoords[i];
+        pointerCoords[i].copyFrom(entry->lastSample->pointerCoords[i]);
     }
 }
 
diff --git a/services/input/InputReader.cpp b/services/input/InputReader.cpp
index 084264b..94753bf 100644
--- a/services/input/InputReader.cpp
+++ b/services/input/InputReader.cpp
@@ -33,6 +33,10 @@
 // Log debug messages about pointer assignment calculations.
 #define DEBUG_POINTER_ASSIGNMENT 0
 
+// Log debug messages about gesture detection.
+#define DEBUG_GESTURES 0
+
+
 #include "InputReader.h"
 
 #include <cutils/log.h>
@@ -53,6 +57,38 @@
 
 namespace android {
 
+// --- Constants ---
+
+// Quiet time between certain gesture transitions.
+// Time to allow for all fingers or buttons to settle into a stable state before
+// starting a new gesture.
+static const nsecs_t QUIET_INTERVAL = 100 * 1000000; // 100 ms
+
+// The minimum speed that a pointer must travel for us to consider switching the active
+// touch pointer to it during a drag.  This threshold is set to avoid switching due
+// to noise from a finger resting on the touch pad (perhaps just pressing it down).
+static const float DRAG_MIN_SWITCH_SPEED = 50.0f; // pixels per second
+
+// Tap gesture delay time.
+// The time between down and up must be less than this to be considered a tap.
+static const nsecs_t TAP_INTERVAL = 100 * 1000000; // 100 ms
+
+// The distance in pixels that the pointer is allowed to move from initial down
+// to up and still be called a tap.
+static const float TAP_SLOP = 5.0f; // 5 pixels
+
+// The transition from INDETERMINATE_MULTITOUCH to SWIPE or FREEFORM gesture mode is made when
+// all of the pointers have traveled this number of pixels from the start point.
+static const float MULTITOUCH_MIN_TRAVEL = 5.0f;
+
+// The transition from INDETERMINATE_MULTITOUCH to SWIPE gesture mode can only occur when the
+// cosine of the angle between the two vectors is greater than or equal to than this value
+// which indicates that the vectors are oriented in the same direction.
+// When the vectors are oriented in the exactly same direction, the cosine is 1.0.
+// (In exactly opposite directions, the cosine is -1.0.)
+static const float SWIPE_TRANSITION_ANGLE_COSINE = 0.5f; // cosine of 45 degrees
+
+
 // --- Static Functions ---
 
 template<typename T>
@@ -80,6 +116,12 @@
     return sqrtf(x * x + y * y);
 }
 
+inline static int32_t distanceSquared(int32_t x1, int32_t y1, int32_t x2, int32_t y2) {
+    int32_t dx = x1 - x2;
+    int32_t dy = y1 - y2;
+    return dx * dx + dy * dy;
+}
+
 inline static int32_t signExtendNybble(int32_t value) {
     return value >= 8 ? value - 16 : value;
 }
@@ -140,6 +182,48 @@
     return (sources & sourceMask & ~ AINPUT_SOURCE_CLASS_MASK) != 0;
 }
 
+static uint32_t getButtonStateForScanCode(int32_t scanCode) {
+    // Currently all buttons are mapped to the primary button.
+    switch (scanCode) {
+    case BTN_LEFT:
+    case BTN_RIGHT:
+    case BTN_MIDDLE:
+    case BTN_SIDE:
+    case BTN_EXTRA:
+    case BTN_FORWARD:
+    case BTN_BACK:
+    case BTN_TASK:
+        return BUTTON_STATE_PRIMARY;
+    default:
+        return 0;
+    }
+}
+
+// Returns true if the pointer should be reported as being down given the specified
+// button states.
+static bool isPointerDown(uint32_t buttonState) {
+    return buttonState & BUTTON_STATE_PRIMARY;
+}
+
+static int32_t calculateEdgeFlagsUsingPointerBounds(
+        const sp<PointerControllerInterface>& pointerController, float x, float y) {
+    int32_t edgeFlags = 0;
+    float minX, minY, maxX, maxY;
+    if (pointerController->getBounds(&minX, &minY, &maxX, &maxY)) {
+        if (x <= minX) {
+            edgeFlags |= AMOTION_EVENT_EDGE_FLAG_LEFT;
+        } else if (x >= maxX) {
+            edgeFlags |= AMOTION_EVENT_EDGE_FLAG_RIGHT;
+        }
+        if (y <= minY) {
+            edgeFlags |= AMOTION_EVENT_EDGE_FLAG_TOP;
+        } else if (y >= maxY) {
+            edgeFlags |= AMOTION_EVENT_EDGE_FLAG_BOTTOM;
+        }
+    }
+    return edgeFlags;
+}
+
 
 // --- InputReader ---
 
@@ -147,7 +231,7 @@
         const sp<InputReaderPolicyInterface>& policy,
         const sp<InputDispatcherInterface>& dispatcher) :
         mEventHub(eventHub), mPolicy(policy), mDispatcher(dispatcher),
-        mGlobalMetaState(0), mDisableVirtualKeysTimeout(-1) {
+        mGlobalMetaState(0), mDisableVirtualKeysTimeout(LLONG_MIN), mNextTimeout(LLONG_MAX) {
     configureExcludedDevices();
     updateGlobalMetaState();
     updateInputConfiguration();
@@ -160,35 +244,61 @@
 }
 
 void InputReader::loopOnce() {
-    RawEvent rawEvent;
-    mEventHub->getEvent(& rawEvent);
+    int32_t timeoutMillis = -1;
+    if (mNextTimeout != LLONG_MAX) {
+        nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
+        timeoutMillis = toMillisecondTimeoutDelay(now, mNextTimeout);
+    }
 
+    size_t count = mEventHub->getEvents(timeoutMillis, mEventBuffer, EVENT_BUFFER_SIZE);
+    if (count) {
+        processEvents(mEventBuffer, count);
+    }
+    if (!count || timeoutMillis == 0) {
+        nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
 #if DEBUG_RAW_EVENTS
-    LOGD("Input event: device=%d type=0x%x scancode=%d keycode=%d value=%d",
-            rawEvent.deviceId, rawEvent.type, rawEvent.scanCode, rawEvent.keyCode,
-            rawEvent.value);
+        LOGD("Timeout expired, latency=%0.3fms", (now - mNextTimeout) * 0.000001f);
 #endif
-
-    process(& rawEvent);
+        mNextTimeout = LLONG_MAX;
+        timeoutExpired(now);
+    }
 }
 
-void InputReader::process(const RawEvent* rawEvent) {
-    switch (rawEvent->type) {
-    case EventHubInterface::DEVICE_ADDED:
-        addDevice(rawEvent->deviceId);
-        break;
-
-    case EventHubInterface::DEVICE_REMOVED:
-        removeDevice(rawEvent->deviceId);
-        break;
-
-    case EventHubInterface::FINISHED_DEVICE_SCAN:
-        handleConfigurationChanged(rawEvent->when);
-        break;
-
-    default:
-        consumeEvent(rawEvent);
-        break;
+void InputReader::processEvents(const RawEvent* rawEvents, size_t count) {
+    for (const RawEvent* rawEvent = rawEvents; count;) {
+        int32_t type = rawEvent->type;
+        size_t batchSize = 1;
+        if (type < EventHubInterface::FIRST_SYNTHETIC_EVENT) {
+            int32_t deviceId = rawEvent->deviceId;
+            while (batchSize < count) {
+                if (rawEvent[batchSize].type >= EventHubInterface::FIRST_SYNTHETIC_EVENT
+                        || rawEvent[batchSize].deviceId != deviceId) {
+                    break;
+                }
+                batchSize += 1;
+            }
+#if DEBUG_RAW_EVENTS
+            LOGD("BatchSize: %d Count: %d", batchSize, count);
+#endif
+            processEventsForDevice(deviceId, rawEvent, batchSize);
+        } else {
+            switch (rawEvent->type) {
+            case EventHubInterface::DEVICE_ADDED:
+                addDevice(rawEvent->deviceId);
+                break;
+            case EventHubInterface::DEVICE_REMOVED:
+                removeDevice(rawEvent->deviceId);
+                break;
+            case EventHubInterface::FINISHED_DEVICE_SCAN:
+                handleConfigurationChanged(rawEvent->when);
+                break;
+            default:
+                assert(false); // can't happen
+                break;
+            }
+        }
+        count -= batchSize;
+        rawEvent += batchSize;
     }
 }
 
@@ -270,23 +380,23 @@
     }
 
     // Keyboard-like devices.
-    uint32_t keyboardSources = 0;
+    uint32_t keyboardSource = 0;
     int32_t keyboardType = AINPUT_KEYBOARD_TYPE_NON_ALPHABETIC;
     if (classes & INPUT_DEVICE_CLASS_KEYBOARD) {
-        keyboardSources |= AINPUT_SOURCE_KEYBOARD;
+        keyboardSource |= AINPUT_SOURCE_KEYBOARD;
     }
     if (classes & INPUT_DEVICE_CLASS_ALPHAKEY) {
         keyboardType = AINPUT_KEYBOARD_TYPE_ALPHABETIC;
     }
     if (classes & INPUT_DEVICE_CLASS_DPAD) {
-        keyboardSources |= AINPUT_SOURCE_DPAD;
+        keyboardSource |= AINPUT_SOURCE_DPAD;
     }
     if (classes & INPUT_DEVICE_CLASS_GAMEPAD) {
-        keyboardSources |= AINPUT_SOURCE_GAMEPAD;
+        keyboardSource |= AINPUT_SOURCE_GAMEPAD;
     }
 
-    if (keyboardSources != 0) {
-        device->addMapper(new KeyboardInputMapper(device, keyboardSources, keyboardType));
+    if (keyboardSource != 0) {
+        device->addMapper(new KeyboardInputMapper(device, keyboardSource, keyboardType));
     }
 
     // Cursor-like devices.
@@ -309,9 +419,8 @@
     return device;
 }
 
-void InputReader::consumeEvent(const RawEvent* rawEvent) {
-    int32_t deviceId = rawEvent->deviceId;
-
+void InputReader::processEventsForDevice(int32_t deviceId,
+        const RawEvent* rawEvents, size_t count) {
     { // acquire device registry reader lock
         RWLock::AutoRLock _rl(mDeviceRegistryLock);
 
@@ -327,7 +436,20 @@
             return;
         }
 
-        device->process(rawEvent);
+        device->process(rawEvents, count);
+    } // release device registry reader lock
+}
+
+void InputReader::timeoutExpired(nsecs_t when) {
+    { // acquire device registry reader lock
+        RWLock::AutoRLock _rl(mDeviceRegistryLock);
+
+        for (size_t i = 0; i < mDevices.size(); i++) {
+            InputDevice* device = mDevices.valueAt(i);
+            if (!device->isIgnored()) {
+                device->timeoutExpired(when);
+            }
+        }
     } // release device registry reader lock
 }
 
@@ -441,6 +563,12 @@
     } // release device registry reader lock
 }
 
+void InputReader::requestTimeoutAtTime(nsecs_t when) {
+    if (when < mNextTimeout) {
+        mNextTimeout = when;
+    }
+}
+
 void InputReader::getInputConfiguration(InputConfiguration* outConfiguration) {
     { // acquire state lock
         AutoMutex _l(mStateLock);
@@ -617,22 +745,22 @@
     dump.appendFormat(INDENT2 "Sources: 0x%08x\n", deviceInfo.getSources());
     dump.appendFormat(INDENT2 "KeyboardType: %d\n", deviceInfo.getKeyboardType());
 
-    const KeyedVector<int32_t, InputDeviceInfo::MotionRange> ranges = deviceInfo.getMotionRanges();
+    const Vector<InputDeviceInfo::MotionRange>& ranges = deviceInfo.getMotionRanges();
     if (!ranges.isEmpty()) {
         dump.append(INDENT2 "Motion Ranges:\n");
         for (size_t i = 0; i < ranges.size(); i++) {
-            int32_t axis = ranges.keyAt(i);
-            const char* label = getAxisLabel(axis);
+            const InputDeviceInfo::MotionRange& range = ranges.itemAt(i);
+            const char* label = getAxisLabel(range.axis);
             char name[32];
             if (label) {
                 strncpy(name, label, sizeof(name));
                 name[sizeof(name) - 1] = '\0';
             } else {
-                snprintf(name, sizeof(name), "%d", axis);
+                snprintf(name, sizeof(name), "%d", range.axis);
             }
-            const InputDeviceInfo::MotionRange& range = ranges.valueAt(i);
-            dump.appendFormat(INDENT3 "%s: min=%0.3f, max=%0.3f, flat=%0.3f, fuzz=%0.3f\n",
-                    name, range.min, range.max, range.flat, range.fuzz);
+            dump.appendFormat(INDENT3 "%s: source=0x%08x, "
+                    "min=%0.3f, max=%0.3f, flat=%0.3f, fuzz=%0.3f\n",
+                    name, range.source, range.min, range.max, range.flat, range.fuzz);
         }
     }
 
@@ -670,11 +798,33 @@
     }
 }
 
-void InputDevice::process(const RawEvent* rawEvent) {
+void InputDevice::process(const RawEvent* rawEvents, size_t count) {
+    // Process all of the events in order for each mapper.
+    // We cannot simply ask each mapper to process them in bulk because mappers may
+    // have side-effects that must be interleaved.  For example, joystick movement events and
+    // gamepad button presses are handled by different mappers but they should be dispatched
+    // in the order received.
+    size_t numMappers = mMappers.size();
+    for (const RawEvent* rawEvent = rawEvents; count--; rawEvent++) {
+#if DEBUG_RAW_EVENTS
+        LOGD("Input event: device=%d type=0x%04x scancode=0x%04x "
+                "keycode=0x%04x value=0x%04x flags=0x%08x",
+                rawEvent->deviceId, rawEvent->type, rawEvent->scanCode, rawEvent->keyCode,
+                rawEvent->value, rawEvent->flags);
+#endif
+
+        for (size_t i = 0; i < numMappers; i++) {
+            InputMapper* mapper = mMappers[i];
+            mapper->process(rawEvent);
+        }
+    }
+}
+
+void InputDevice::timeoutExpired(nsecs_t when) {
     size_t numMappers = mMappers.size();
     for (size_t i = 0; i < numMappers; i++) {
         InputMapper* mapper = mMappers[i];
-        mapper->process(rawEvent);
+        mapper->timeoutExpired(when);
     }
 }
 
@@ -769,6 +919,9 @@
 void InputMapper::reset() {
 }
 
+void InputMapper::timeoutExpired(nsecs_t when) {
+}
+
 int32_t InputMapper::getKeyCodeState(uint32_t sourceMask, int32_t keyCode) {
     return AKEY_STATE_UNKNOWN;
 }
@@ -837,8 +990,8 @@
 // --- KeyboardInputMapper ---
 
 KeyboardInputMapper::KeyboardInputMapper(InputDevice* device,
-        uint32_t sources, int32_t keyboardType) :
-        InputMapper(device), mSources(sources),
+        uint32_t source, int32_t keyboardType) :
+        InputMapper(device), mSource(source),
         mKeyboardType(keyboardType) {
     initializeLocked();
 }
@@ -852,7 +1005,7 @@
 }
 
 uint32_t KeyboardInputMapper::getSources() {
-    return mSources;
+    return mSource;
 }
 
 void KeyboardInputMapper::populateDeviceInfo(InputDeviceInfo* info) {
@@ -1036,10 +1189,7 @@
         getContext()->fadePointer();
     }
 
-    if (policyFlags & POLICY_FLAG_FUNCTION) {
-        newMetaState |= AMETA_FUNCTION_ON;
-    }
-    getDispatcher()->notifyKey(when, getDeviceId(), mSources, policyFlags,
+    getDispatcher()->notifyKey(when, getDeviceId(), mSource, policyFlags,
             down ? AKEY_EVENT_ACTION_DOWN : AKEY_EVENT_ACTION_UP,
             AKEY_EVENT_FLAG_FROM_SYSTEM, keyCode, scanCode, newMetaState, downTime);
 }
@@ -1119,7 +1269,7 @@
 }
 
 uint32_t CursorInputMapper::getSources() {
-    return mSources;
+    return mSource;
 }
 
 void CursorInputMapper::populateDeviceInfo(InputDeviceInfo* info) {
@@ -1128,20 +1278,20 @@
     if (mParameters.mode == Parameters::MODE_POINTER) {
         float minX, minY, maxX, maxY;
         if (mPointerController->getBounds(&minX, &minY, &maxX, &maxY)) {
-            info->addMotionRange(AMOTION_EVENT_AXIS_X, minX, maxX, 0.0f, 0.0f);
-            info->addMotionRange(AMOTION_EVENT_AXIS_Y, minY, maxY, 0.0f, 0.0f);
+            info->addMotionRange(AMOTION_EVENT_AXIS_X, mSource, minX, maxX, 0.0f, 0.0f);
+            info->addMotionRange(AMOTION_EVENT_AXIS_Y, mSource, minY, maxY, 0.0f, 0.0f);
         }
     } else {
-        info->addMotionRange(AMOTION_EVENT_AXIS_X, -1.0f, 1.0f, 0.0f, mXScale);
-        info->addMotionRange(AMOTION_EVENT_AXIS_Y, -1.0f, 1.0f, 0.0f, mYScale);
+        info->addMotionRange(AMOTION_EVENT_AXIS_X, mSource, -1.0f, 1.0f, 0.0f, mXScale);
+        info->addMotionRange(AMOTION_EVENT_AXIS_Y, mSource, -1.0f, 1.0f, 0.0f, mYScale);
     }
-    info->addMotionRange(AMOTION_EVENT_AXIS_PRESSURE, 0.0f, 1.0f, 0.0f, 0.0f);
+    info->addMotionRange(AMOTION_EVENT_AXIS_PRESSURE, mSource, 0.0f, 1.0f, 0.0f, 0.0f);
 
     if (mHaveVWheel) {
-        info->addMotionRange(AMOTION_EVENT_AXIS_VSCROLL, -1.0f, 1.0f, 0.0f, 0.0f);
+        info->addMotionRange(AMOTION_EVENT_AXIS_VSCROLL, mSource, -1.0f, 1.0f, 0.0f, 0.0f);
     }
     if (mHaveHWheel) {
-        info->addMotionRange(AMOTION_EVENT_AXIS_HSCROLL, -1.0f, 1.0f, 0.0f, 0.0f);
+        info->addMotionRange(AMOTION_EVENT_AXIS_HSCROLL, mSource, -1.0f, 1.0f, 0.0f, 0.0f);
     }
 }
 
@@ -1158,7 +1308,8 @@
         dump.appendFormat(INDENT3 "HaveHWheel: %s\n", toString(mHaveHWheel));
         dump.appendFormat(INDENT3 "VWheelScale: %0.3f\n", mVWheelScale);
         dump.appendFormat(INDENT3 "HWheelScale: %0.3f\n", mHWheelScale);
-        dump.appendFormat(INDENT3 "Down: %s\n", toString(mLocked.down));
+        dump.appendFormat(INDENT3 "ButtonState: 0x%08x\n", mLocked.buttonState);
+        dump.appendFormat(INDENT3 "Down: %s\n", toString(isPointerDown(mLocked.buttonState)));
         dump.appendFormat(INDENT3 "DownTime: %lld\n", mLocked.downTime);
     } // release lock
 }
@@ -1172,7 +1323,7 @@
     // Configure device mode.
     switch (mParameters.mode) {
     case Parameters::MODE_POINTER:
-        mSources = AINPUT_SOURCE_MOUSE;
+        mSource = AINPUT_SOURCE_MOUSE;
         mXPrecision = 1.0f;
         mYPrecision = 1.0f;
         mXScale = 1.0f;
@@ -1180,7 +1331,7 @@
         mPointerController = getPolicy()->obtainPointerController(getDeviceId());
         break;
     case Parameters::MODE_NAVIGATION:
-        mSources = AINPUT_SOURCE_TRACKBALL;
+        mSource = AINPUT_SOURCE_TRACKBALL;
         mXPrecision = TRACKBALL_MOVEMENT_THRESHOLD;
         mYPrecision = TRACKBALL_MOVEMENT_THRESHOLD;
         mXScale = 1.0f / TRACKBALL_MOVEMENT_THRESHOLD;
@@ -1237,16 +1388,18 @@
 void CursorInputMapper::initializeLocked() {
     mAccumulator.clear();
 
-    mLocked.down = false;
+    mLocked.buttonState = 0;
     mLocked.downTime = 0;
 }
 
 void CursorInputMapper::reset() {
     for (;;) {
+        uint32_t buttonState;
         { // acquire lock
             AutoMutex _l(mLock);
 
-            if (! mLocked.down) {
+            buttonState = mLocked.buttonState;
+            if (!buttonState) {
                 initializeLocked();
                 break; // done
             }
@@ -1254,8 +1407,10 @@
 
         // Synthesize button up event on reset.
         nsecs_t when = systemTime(SYSTEM_TIME_MONOTONIC);
-        mAccumulator.fields = Accumulator::FIELD_BTN_MOUSE;
-        mAccumulator.btnMouse = false;
+        mAccumulator.clear();
+        mAccumulator.buttonDown = 0;
+        mAccumulator.buttonUp = buttonState;
+        mAccumulator.fields = Accumulator::FIELD_BUTTONS;
         sync(when);
     }
 
@@ -1264,24 +1419,25 @@
 
 void CursorInputMapper::process(const RawEvent* rawEvent) {
     switch (rawEvent->type) {
-    case EV_KEY:
-        switch (rawEvent->scanCode) {
-        case BTN_LEFT:
-        case BTN_RIGHT:
-        case BTN_MIDDLE:
-        case BTN_SIDE:
-        case BTN_EXTRA:
-        case BTN_FORWARD:
-        case BTN_BACK:
-        case BTN_TASK:
-            mAccumulator.fields |= Accumulator::FIELD_BTN_MOUSE;
-            mAccumulator.btnMouse = rawEvent->value != 0;
+    case EV_KEY: {
+        uint32_t buttonState = getButtonStateForScanCode(rawEvent->scanCode);
+        if (buttonState) {
+            if (rawEvent->value) {
+                mAccumulator.buttonDown = buttonState;
+                mAccumulator.buttonUp = 0;
+            } else {
+                mAccumulator.buttonDown = 0;
+                mAccumulator.buttonUp = buttonState;
+            }
+            mAccumulator.fields |= Accumulator::FIELD_BUTTONS;
+
             // Sync now since BTN_MOUSE is not necessarily followed by SYN_REPORT and
             // we need to ensure that we report the up/down promptly.
             sync(rawEvent->when);
             break;
         }
         break;
+    }
 
     case EV_REL:
         switch (rawEvent->scanCode) {
@@ -1328,23 +1484,26 @@
     { // acquire lock
         AutoMutex _l(mLock);
 
-        bool downChanged = fields & Accumulator::FIELD_BTN_MOUSE;
+        bool down, downChanged;
+        bool wasDown = isPointerDown(mLocked.buttonState);
+        bool buttonsChanged = fields & Accumulator::FIELD_BUTTONS;
+        if (buttonsChanged) {
+            mLocked.buttonState = (mLocked.buttonState | mAccumulator.buttonDown)
+                    & ~mAccumulator.buttonUp;
 
-        if (downChanged) {
-            if (mAccumulator.btnMouse) {
-                if (!mLocked.down) {
-                    mLocked.down = true;
-                    mLocked.downTime = when;
-                } else {
-                    downChanged = false;
-                }
+            down = isPointerDown(mLocked.buttonState);
+
+            if (!wasDown && down) {
+                mLocked.downTime = when;
+                downChanged = true;
+            } else if (wasDown && !down) {
+                downChanged = true;
             } else {
-                if (mLocked.down) {
-                    mLocked.down = false;
-                } else {
-                    downChanged = false;
-                }
+                downChanged = false;
             }
+        } else {
+            down = wasDown;
+            downChanged = false;
         }
 
         downTime = mLocked.downTime;
@@ -1352,8 +1511,8 @@
         float deltaY = fields & Accumulator::FIELD_REL_Y ? mAccumulator.relY * mYScale : 0.0f;
 
         if (downChanged) {
-            motionEventAction = mLocked.down ? AMOTION_EVENT_ACTION_DOWN : AMOTION_EVENT_ACTION_UP;
-        } else if (mLocked.down || mPointerController == NULL) {
+            motionEventAction = down ? AMOTION_EVENT_ACTION_DOWN : AMOTION_EVENT_ACTION_UP;
+        } else if (down || mPointerController == NULL) {
             motionEventAction = AMOTION_EVENT_ACTION_MOVE;
         } else {
             motionEventAction = AMOTION_EVENT_ACTION_HOVER_MOVE;
@@ -1396,35 +1555,25 @@
 
         if (mPointerController != NULL) {
             mPointerController->move(deltaX, deltaY);
-            if (downChanged) {
-                mPointerController->setButtonState(mLocked.down ? POINTER_BUTTON_1 : 0);
+            if (buttonsChanged) {
+                mPointerController->setButtonState(mLocked.buttonState);
             }
+
             float x, y;
             mPointerController->getPosition(&x, &y);
             pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_X, x);
             pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_Y, y);
 
             if (motionEventAction == AMOTION_EVENT_ACTION_DOWN) {
-                float minX, minY, maxX, maxY;
-                if (mPointerController->getBounds(&minX, &minY, &maxX, &maxY)) {
-                    if (x <= minX) {
-                        motionEventEdgeFlags |= AMOTION_EVENT_EDGE_FLAG_LEFT;
-                    } else if (x >= maxX) {
-                        motionEventEdgeFlags |= AMOTION_EVENT_EDGE_FLAG_RIGHT;
-                    }
-                    if (y <= minY) {
-                        motionEventEdgeFlags |= AMOTION_EVENT_EDGE_FLAG_TOP;
-                    } else if (y >= maxY) {
-                        motionEventEdgeFlags |= AMOTION_EVENT_EDGE_FLAG_BOTTOM;
-                    }
-                }
+                motionEventEdgeFlags = calculateEdgeFlagsUsingPointerBounds(
+                        mPointerController, x, y);
             }
         } else {
             pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_X, deltaX);
             pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_Y, deltaY);
         }
 
-        pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_PRESSURE, mLocked.down ? 1.0f : 0.0f);
+        pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_PRESSURE, down ? 1.0f : 0.0f);
 
         if (mHaveVWheel && (fields & Accumulator::FIELD_REL_WHEEL)) {
             vscroll = mAccumulator.relWheel;
@@ -1452,7 +1601,7 @@
 
     int32_t metaState = mContext->getGlobalMetaState();
     int32_t pointerId = 0;
-    getDispatcher()->notifyMotion(when, getDeviceId(), mSources, policyFlags,
+    getDispatcher()->notifyMotion(when, getDeviceId(), mSource, policyFlags,
             motionEventAction, 0, metaState, motionEventEdgeFlags,
             1, &pointerId, &pointerCoords, mXPrecision, mYPrecision, downTime);
 
@@ -1462,7 +1611,7 @@
         pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_VSCROLL, vscroll);
         pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_HSCROLL, hscroll);
 
-        getDispatcher()->notifyMotion(when, getDeviceId(), mSources, policyFlags,
+        getDispatcher()->notifyMotion(when, getDeviceId(), mSource, policyFlags,
                 AMOTION_EVENT_ACTION_SCROLL, 0, metaState, AMOTION_EVENT_EDGE_FLAG_NONE,
                 1, &pointerId, &pointerCoords, mXPrecision, mYPrecision, downTime);
     }
@@ -1479,7 +1628,9 @@
 void CursorInputMapper::fadePointer() {
     { // acquire lock
         AutoMutex _l(mLock);
-        mPointerController->fade();
+        if (mPointerController != NULL) {
+            mPointerController->fade();
+        }
     } // release lock
 }
 
@@ -1499,7 +1650,7 @@
 }
 
 uint32_t TouchInputMapper::getSources() {
-    return mSources;
+    return mTouchSource | mPointerSource;
 }
 
 void TouchInputMapper::populateDeviceInfo(InputDeviceInfo* info) {
@@ -1510,38 +1661,45 @@
 
         // Ensure surface information is up to date so that orientation changes are
         // noticed immediately.
-        configureSurfaceLocked();
+        if (!configureSurfaceLocked()) {
+            return;
+        }
 
-        info->addMotionRange(AMOTION_EVENT_AXIS_X, mLocked.orientedRanges.x);
-        info->addMotionRange(AMOTION_EVENT_AXIS_Y, mLocked.orientedRanges.y);
+        info->addMotionRange(mLocked.orientedRanges.x);
+        info->addMotionRange(mLocked.orientedRanges.y);
 
         if (mLocked.orientedRanges.havePressure) {
-            info->addMotionRange(AMOTION_EVENT_AXIS_PRESSURE,
-                    mLocked.orientedRanges.pressure);
+            info->addMotionRange(mLocked.orientedRanges.pressure);
         }
 
         if (mLocked.orientedRanges.haveSize) {
-            info->addMotionRange(AMOTION_EVENT_AXIS_SIZE,
-                    mLocked.orientedRanges.size);
+            info->addMotionRange(mLocked.orientedRanges.size);
         }
 
         if (mLocked.orientedRanges.haveTouchSize) {
-            info->addMotionRange(AMOTION_EVENT_AXIS_TOUCH_MAJOR,
-                    mLocked.orientedRanges.touchMajor);
-            info->addMotionRange(AMOTION_EVENT_AXIS_TOUCH_MINOR,
-                    mLocked.orientedRanges.touchMinor);
+            info->addMotionRange(mLocked.orientedRanges.touchMajor);
+            info->addMotionRange(mLocked.orientedRanges.touchMinor);
         }
 
         if (mLocked.orientedRanges.haveToolSize) {
-            info->addMotionRange(AMOTION_EVENT_AXIS_TOOL_MAJOR,
-                    mLocked.orientedRanges.toolMajor);
-            info->addMotionRange(AMOTION_EVENT_AXIS_TOOL_MINOR,
-                    mLocked.orientedRanges.toolMinor);
+            info->addMotionRange(mLocked.orientedRanges.toolMajor);
+            info->addMotionRange(mLocked.orientedRanges.toolMinor);
         }
 
         if (mLocked.orientedRanges.haveOrientation) {
-            info->addMotionRange(AMOTION_EVENT_AXIS_ORIENTATION,
-                    mLocked.orientedRanges.orientation);
+            info->addMotionRange(mLocked.orientedRanges.orientation);
+        }
+
+        if (mPointerController != NULL) {
+            float minX, minY, maxX, maxY;
+            if (mPointerController->getBounds(&minX, &minY, &maxX, &maxY)) {
+                info->addMotionRange(AMOTION_EVENT_AXIS_X, mPointerSource,
+                        minX, maxX, 0.0f, 0.0f);
+                info->addMotionRange(AMOTION_EVENT_AXIS_Y, mPointerSource,
+                        minY, maxY, 0.0f, 0.0f);
+            }
+            info->addMotionRange(AMOTION_EVENT_AXIS_PRESSURE, mPointerSource,
+                    0.0f, 1.0f, 0.0f, 0.0f);
         }
     } // release lock
 }
@@ -1555,6 +1713,7 @@
         dumpRawAxes(dump);
         dumpCalibration(dump);
         dumpSurfaceLocked(dump);
+
         dump.appendFormat(INDENT3 "Translation and Scaling Factors:\n");
         dump.appendFormat(INDENT4 "XScale: %0.3f\n", mLocked.xScale);
         dump.appendFormat(INDENT4 "YScale: %0.3f\n", mLocked.yScale);
@@ -1567,7 +1726,25 @@
         dump.appendFormat(INDENT4 "ToolSizeAreaBias: %0.3f\n", mLocked.toolSizeAreaBias);
         dump.appendFormat(INDENT4 "PressureScale: %0.3f\n", mLocked.pressureScale);
         dump.appendFormat(INDENT4 "SizeScale: %0.3f\n", mLocked.sizeScale);
-        dump.appendFormat(INDENT4 "OrientationSCale: %0.3f\n", mLocked.orientationScale);
+        dump.appendFormat(INDENT4 "OrientationScale: %0.3f\n", mLocked.orientationScale);
+
+        dump.appendFormat(INDENT3 "Last Touch:\n");
+        dump.appendFormat(INDENT4 "Pointer Count: %d\n", mLastTouch.pointerCount);
+        dump.appendFormat(INDENT4 "Button State: 0x%08x\n", mLastTouch.buttonState);
+
+        if (mParameters.deviceType == Parameters::DEVICE_TYPE_POINTER) {
+            dump.appendFormat(INDENT3 "Pointer Gesture Detector:\n");
+            dump.appendFormat(INDENT4 "XMovementScale: %0.3f\n",
+                    mLocked.pointerGestureXMovementScale);
+            dump.appendFormat(INDENT4 "YMovementScale: %0.3f\n",
+                    mLocked.pointerGestureYMovementScale);
+            dump.appendFormat(INDENT4 "XZoomScale: %0.3f\n",
+                    mLocked.pointerGestureXZoomScale);
+            dump.appendFormat(INDENT4 "YZoomScale: %0.3f\n",
+                    mLocked.pointerGestureYZoomScale);
+            dump.appendFormat(INDENT4 "MaxSwipeWidthSquared: %d\n",
+                    mLocked.pointerGestureMaxSwipeWidthSquared);
+        }
     } // release lock
 }
 
@@ -1590,6 +1767,8 @@
     mLocked.orientedRanges.haveTouchSize = false;
     mLocked.orientedRanges.haveToolSize = false;
     mLocked.orientedRanges.haveOrientation = false;
+
+    mPointerGesture.reset();
 }
 
 void TouchInputMapper::configure() {
@@ -1601,10 +1780,16 @@
     // Configure sources.
     switch (mParameters.deviceType) {
     case Parameters::DEVICE_TYPE_TOUCH_SCREEN:
-        mSources = AINPUT_SOURCE_TOUCHSCREEN;
+        mTouchSource = AINPUT_SOURCE_TOUCHSCREEN;
+        mPointerSource = 0;
         break;
     case Parameters::DEVICE_TYPE_TOUCH_PAD:
-        mSources = AINPUT_SOURCE_TOUCHPAD;
+        mTouchSource = AINPUT_SOURCE_TOUCHPAD;
+        mPointerSource = 0;
+        break;
+    case Parameters::DEVICE_TYPE_POINTER:
+        mTouchSource = AINPUT_SOURCE_TOUCHPAD;
+        mPointerSource = AINPUT_SOURCE_MOUSE;
         break;
     default:
         assert(false);
@@ -1631,23 +1816,39 @@
     mParameters.useJumpyTouchFilter = getPolicy()->filterJumpyTouchEvents();
     mParameters.virtualKeyQuietTime = getPolicy()->getVirtualKeyQuietTime();
 
+    if (getEventHub()->hasRelativeAxis(getDeviceId(), REL_X)
+            || getEventHub()->hasRelativeAxis(getDeviceId(), REL_Y)) {
+        // The device is a cursor device with a touch pad attached.
+        // By default don't use the touch pad to move the pointer.
+        mParameters.deviceType = Parameters::DEVICE_TYPE_TOUCH_PAD;
+    } else {
+        // The device is just a touch pad.
+        // By default use the touch pad to move the pointer and to perform related gestures.
+        mParameters.deviceType = Parameters::DEVICE_TYPE_POINTER;
+    }
+
     String8 deviceTypeString;
-    mParameters.deviceType = Parameters::DEVICE_TYPE_TOUCH_PAD;
     if (getDevice()->getConfiguration().tryGetProperty(String8("touch.deviceType"),
             deviceTypeString)) {
         if (deviceTypeString == "touchScreen") {
             mParameters.deviceType = Parameters::DEVICE_TYPE_TOUCH_SCREEN;
-        } else if (deviceTypeString != "touchPad") {
+        } else if (deviceTypeString == "touchPad") {
+            mParameters.deviceType = Parameters::DEVICE_TYPE_TOUCH_PAD;
+        } else if (deviceTypeString == "pointer") {
+            mParameters.deviceType = Parameters::DEVICE_TYPE_POINTER;
+        } else {
             LOGW("Invalid value for touch.deviceType: '%s'", deviceTypeString.string());
         }
     }
-    bool isTouchScreen = mParameters.deviceType == Parameters::DEVICE_TYPE_TOUCH_SCREEN;
 
-    mParameters.orientationAware = isTouchScreen;
+    mParameters.orientationAware = mParameters.deviceType == Parameters::DEVICE_TYPE_TOUCH_SCREEN;
     getDevice()->getConfiguration().tryGetProperty(String8("touch.orientationAware"),
             mParameters.orientationAware);
 
-    mParameters.associatedDisplayId = mParameters.orientationAware || isTouchScreen ? 0 : -1;
+    mParameters.associatedDisplayId = mParameters.orientationAware
+            || mParameters.deviceType == Parameters::DEVICE_TYPE_TOUCH_SCREEN
+            || mParameters.deviceType == Parameters::DEVICE_TYPE_POINTER
+            ? 0 : -1;
 }
 
 void TouchInputMapper::dumpParameters(String8& dump) {
@@ -1660,6 +1861,9 @@
     case Parameters::DEVICE_TYPE_TOUCH_PAD:
         dump.append(INDENT4 "DeviceType: touchPad\n");
         break;
+    case Parameters::DEVICE_TYPE_POINTER:
+        dump.append(INDENT4 "DeviceType: pointer\n");
+        break;
     default:
         assert(false);
     }
@@ -1714,15 +1918,28 @@
     int32_t height = mRawAxes.y.maxValue - mRawAxes.y.minValue + 1;
 
     if (mParameters.associatedDisplayId >= 0) {
-        bool wantSize = mParameters.deviceType == Parameters::DEVICE_TYPE_TOUCH_SCREEN;
-        bool wantOrientation = mParameters.orientationAware;
-
         // Note: getDisplayInfo is non-reentrant so we can continue holding the lock.
         if (! getPolicy()->getDisplayInfo(mParameters.associatedDisplayId,
-                wantSize ? &width : NULL, wantSize ? &height : NULL,
-                wantOrientation ? &orientation : NULL)) {
+                &mLocked.associatedDisplayWidth, &mLocked.associatedDisplayHeight,
+                &mLocked.associatedDisplayOrientation)) {
             return false;
         }
+
+        // A touch screen inherits the dimensions of the display.
+        if (mParameters.deviceType == Parameters::DEVICE_TYPE_TOUCH_SCREEN) {
+            width = mLocked.associatedDisplayWidth;
+            height = mLocked.associatedDisplayHeight;
+        }
+
+        // The device inherits the orientation of the display if it is orientation aware.
+        if (mParameters.orientationAware) {
+            orientation = mLocked.associatedDisplayOrientation;
+        }
+    }
+
+    if (mParameters.deviceType == Parameters::DEVICE_TYPE_POINTER
+            && mPointerController == NULL) {
+        mPointerController = getPolicy()->obtainPointerController(getDeviceId());
     }
 
     bool orientationChanged = mLocked.surfaceOrientation != orientation;
@@ -1732,7 +1949,7 @@
 
     bool sizeChanged = mLocked.surfaceWidth != width || mLocked.surfaceHeight != height;
     if (sizeChanged) {
-        LOGI("Device reconfigured: id=%d, name='%s', display size is now %dx%d",
+        LOGI("Device reconfigured: id=%d, name='%s', surface size is now %dx%d",
                 getDeviceId(), getDeviceName().string(), width, height);
 
         mLocked.surfaceWidth = width;
@@ -1744,6 +1961,11 @@
         mLocked.xPrecision = 1.0f / mLocked.xScale;
         mLocked.yPrecision = 1.0f / mLocked.yScale;
 
+        mLocked.orientedRanges.x.axis = AMOTION_EVENT_AXIS_X;
+        mLocked.orientedRanges.x.source = mTouchSource;
+        mLocked.orientedRanges.y.axis = AMOTION_EVENT_AXIS_Y;
+        mLocked.orientedRanges.y.source = mTouchSource;
+
         configureVirtualKeysLocked();
 
         // Scale factor for terms that are not oriented in a particular axis.
@@ -1757,11 +1979,16 @@
         // TouchMajor and TouchMinor factors.
         if (mCalibration.touchSizeCalibration != Calibration::TOUCH_SIZE_CALIBRATION_NONE) {
             mLocked.orientedRanges.haveTouchSize = true;
+
+            mLocked.orientedRanges.touchMajor.axis = AMOTION_EVENT_AXIS_TOUCH_MAJOR;
+            mLocked.orientedRanges.touchMajor.source = mTouchSource;
             mLocked.orientedRanges.touchMajor.min = 0;
             mLocked.orientedRanges.touchMajor.max = diagonalSize;
             mLocked.orientedRanges.touchMajor.flat = 0;
             mLocked.orientedRanges.touchMajor.fuzz = 0;
+
             mLocked.orientedRanges.touchMinor = mLocked.orientedRanges.touchMajor;
+            mLocked.orientedRanges.touchMinor.axis = AMOTION_EVENT_AXIS_TOUCH_MINOR;
         }
 
         // ToolMajor and ToolMinor factors.
@@ -1805,11 +2032,16 @@
             }
 
             mLocked.orientedRanges.haveToolSize = true;
+
+            mLocked.orientedRanges.toolMajor.axis = AMOTION_EVENT_AXIS_TOOL_MAJOR;
+            mLocked.orientedRanges.toolMajor.source = mTouchSource;
             mLocked.orientedRanges.toolMajor.min = 0;
             mLocked.orientedRanges.toolMajor.max = diagonalSize;
             mLocked.orientedRanges.toolMajor.flat = 0;
             mLocked.orientedRanges.toolMajor.fuzz = 0;
+
             mLocked.orientedRanges.toolMinor = mLocked.orientedRanges.toolMajor;
+            mLocked.orientedRanges.toolMinor.axis = AMOTION_EVENT_AXIS_TOOL_MINOR;
         }
 
         // Pressure factors.
@@ -1838,6 +2070,9 @@
             }
 
             mLocked.orientedRanges.havePressure = true;
+
+            mLocked.orientedRanges.pressure.axis = AMOTION_EVENT_AXIS_PRESSURE;
+            mLocked.orientedRanges.pressure.source = mTouchSource;
             mLocked.orientedRanges.pressure.min = 0;
             mLocked.orientedRanges.pressure.max = 1.0;
             mLocked.orientedRanges.pressure.flat = 0;
@@ -1854,6 +2089,9 @@
             }
 
             mLocked.orientedRanges.haveSize = true;
+
+            mLocked.orientedRanges.size.axis = AMOTION_EVENT_AXIS_SIZE;
+            mLocked.orientedRanges.size.source = mTouchSource;
             mLocked.orientedRanges.size.min = 0;
             mLocked.orientedRanges.size.max = 1.0;
             mLocked.orientedRanges.size.flat = 0;
@@ -1870,6 +2108,8 @@
                 }
             }
 
+            mLocked.orientedRanges.orientation.axis = AMOTION_EVENT_AXIS_ORIENTATION;
+            mLocked.orientedRanges.orientation.source = mTouchSource;
             mLocked.orientedRanges.orientation.min = - M_PI_2;
             mLocked.orientedRanges.orientation.max = M_PI_2;
             mLocked.orientedRanges.orientation.flat = 0;
@@ -1923,6 +2163,37 @@
             mLocked.orientedRanges.y.fuzz = mLocked.yScale;
             break;
         }
+
+        // Compute pointer gesture detection parameters.
+        // TODO: These factors should not be hardcoded.
+        if (mParameters.deviceType == Parameters::DEVICE_TYPE_POINTER) {
+            int32_t rawWidth = mRawAxes.x.maxValue - mRawAxes.x.minValue + 1;
+            int32_t rawHeight = mRawAxes.y.maxValue - mRawAxes.y.minValue + 1;
+
+            // Scale movements such that one whole swipe of the touch pad covers a portion
+            // of the display along whichever axis of the touch pad is longer.
+            // Assume that the touch pad has a square aspect ratio such that movements in
+            // X and Y of the same number of raw units cover the same physical distance.
+            const float scaleFactor = 0.8f;
+
+            mLocked.pointerGestureXMovementScale = rawWidth > rawHeight
+                    ? scaleFactor * float(mLocked.associatedDisplayWidth) / rawWidth
+                    : scaleFactor * float(mLocked.associatedDisplayHeight) / rawHeight;
+            mLocked.pointerGestureYMovementScale = mLocked.pointerGestureXMovementScale;
+
+            // Scale zooms to cover a smaller range of the display than movements do.
+            // This value determines the area around the pointer that is affected by freeform
+            // pointer gestures.
+            mLocked.pointerGestureXZoomScale = mLocked.pointerGestureXMovementScale * 0.4f;
+            mLocked.pointerGestureYZoomScale = mLocked.pointerGestureYMovementScale * 0.4f;
+
+            // Max width between pointers to detect a swipe gesture is 3/4 of the short
+            // axis of the touch pad.  Touches that are wider than this are translated
+            // into freeform gestures.
+            mLocked.pointerGestureMaxSwipeWidthSquared = min(rawWidth, rawHeight) * 3 / 4;
+            mLocked.pointerGestureMaxSwipeWidthSquared *=
+                    mLocked.pointerGestureMaxSwipeWidthSquared;
+        }
     }
 
     return true;
@@ -2354,6 +2625,19 @@
 }
 
 void TouchInputMapper::syncTouch(nsecs_t when, bool havePointerIds) {
+#if DEBUG_RAW_EVENTS
+    if (!havePointerIds) {
+        LOGD("syncTouch: pointerCount=%d, no pointer ids", mCurrentTouch.pointerCount);
+    } else {
+        LOGD("syncTouch: pointerCount=%d, up=0x%08x, down=0x%08x, move=0x%08x, "
+                "last=0x%08x, current=0x%08x", mCurrentTouch.pointerCount,
+                mLastTouch.idBits.value & ~mCurrentTouch.idBits.value,
+                mCurrentTouch.idBits.value & ~mLastTouch.idBits.value,
+                mLastTouch.idBits.value & mCurrentTouch.idBits.value,
+                mLastTouch.idBits.value, mCurrentTouch.idBits.value);
+    }
+#endif
+
     // Preprocess pointer data.
     if (mParameters.useBadTouchFilter) {
         if (applyBadTouchFilter()) {
@@ -2367,7 +2651,7 @@
         }
     }
 
-    if (! havePointerIds) {
+    if (!havePointerIds) {
         calculatePointerIds();
     }
 
@@ -2384,8 +2668,10 @@
 
     uint32_t policyFlags = 0;
     if (mLastTouch.pointerCount == 0 && mCurrentTouch.pointerCount != 0) {
-        // Hide the pointer on an initial down.
-        getContext()->fadePointer();
+        if (mParameters.deviceType == Parameters::DEVICE_TYPE_TOUCH_SCREEN) {
+            // If this is a touch screen, hide the pointer on an initial down.
+            getContext()->fadePointer();
+        }
 
         // Initial downs on external touch devices should wake the device.
         // We don't do this for internal touch screens to prevent them from waking
@@ -2399,13 +2685,18 @@
     // Process touches and virtual keys.
     TouchResult touchResult = consumeOffScreenTouches(when, policyFlags);
     if (touchResult == DISPATCH_TOUCH) {
-        detectGestures(when);
+        suppressSwipeOntoVirtualKeys(when);
+        if (mPointerController != NULL) {
+            dispatchPointerGestures(when, policyFlags);
+        }
         dispatchTouches(when, policyFlags);
     }
 
     // Copy current touch to last touch in preparation for the next cycle.
+    // Keep the button state so we can track edge-triggered button state changes.
     if (touchResult == DROP_STROKE) {
         mLastTouch.clear();
+        mLastTouch.buttonState = savedTouch->buttonState;
     } else {
         mLastTouch.copyFrom(*savedTouch);
     }
@@ -2526,7 +2817,7 @@
     return touchResult;
 }
 
-void TouchInputMapper::detectGestures(nsecs_t when) {
+void TouchInputMapper::suppressSwipeOntoVirtualKeys(nsecs_t when) {
     // Disable all virtual key touches that happen within a short time interval of the
     // most recent touch.  The idea is to filter out stray virtual key presses when
     // interacting with the touch screen.
@@ -2553,329 +2844,1097 @@
         return; // nothing to do!
     }
 
+    // Update current touch coordinates.
+    int32_t edgeFlags;
+    float xPrecision, yPrecision;
+    prepareTouches(&edgeFlags, &xPrecision, &yPrecision);
+
+    // Dispatch motions.
     BitSet32 currentIdBits = mCurrentTouch.idBits;
     BitSet32 lastIdBits = mLastTouch.idBits;
+    uint32_t metaState = getContext()->getGlobalMetaState();
 
     if (currentIdBits == lastIdBits) {
         // No pointer id changes so this is a move event.
         // The dispatcher takes care of batching moves so we don't have to deal with that here.
-        int32_t motionEventAction = AMOTION_EVENT_ACTION_MOVE;
-        dispatchTouch(when, policyFlags, & mCurrentTouch,
-                currentIdBits, -1, currentPointerCount, motionEventAction);
+        dispatchMotion(when, policyFlags, mTouchSource,
+                AMOTION_EVENT_ACTION_MOVE, 0, metaState, AMOTION_EVENT_EDGE_FLAG_NONE,
+                mCurrentTouchCoords, mCurrentTouch.idToIndex, currentIdBits, -1,
+                xPrecision, yPrecision, mDownTime);
     } else {
         // There may be pointers going up and pointers going down and pointers moving
         // all at the same time.
-        BitSet32 upIdBits(lastIdBits.value & ~ currentIdBits.value);
-        BitSet32 downIdBits(currentIdBits.value & ~ lastIdBits.value);
-        BitSet32 activeIdBits(lastIdBits.value);
-        uint32_t pointerCount = lastPointerCount;
-
-        // Produce an intermediate representation of the touch data that consists of the
-        // old location of pointers that have just gone up and the new location of pointers that
-        // have just moved but omits the location of pointers that have just gone down.
-        TouchData interimTouch;
-        interimTouch.copyFrom(mLastTouch);
-
+        BitSet32 upIdBits(lastIdBits.value & ~currentIdBits.value);
+        BitSet32 downIdBits(currentIdBits.value & ~lastIdBits.value);
         BitSet32 moveIdBits(lastIdBits.value & currentIdBits.value);
-        bool moveNeeded = false;
-        while (!moveIdBits.isEmpty()) {
-            uint32_t moveId = moveIdBits.firstMarkedBit();
-            moveIdBits.clearBit(moveId);
+        BitSet32 dispatchedIdBits(lastIdBits.value);
 
-            int32_t oldIndex = mLastTouch.idToIndex[moveId];
-            int32_t newIndex = mCurrentTouch.idToIndex[moveId];
-            if (mLastTouch.pointers[oldIndex] != mCurrentTouch.pointers[newIndex]) {
-                interimTouch.pointers[oldIndex] = mCurrentTouch.pointers[newIndex];
-                moveNeeded = true;
-            }
-        }
+        // Update last coordinates of pointers that have moved so that we observe the new
+        // pointer positions at the same time as other pointers that have just gone up.
+        bool moveNeeded = updateMovedPointerCoords(
+                mCurrentTouchCoords, mCurrentTouch.idToIndex,
+                mLastTouchCoords, mLastTouch.idToIndex,
+                moveIdBits);
 
-        // Dispatch pointer up events using the interim pointer locations.
+        // Dispatch pointer up events.
         while (!upIdBits.isEmpty()) {
             uint32_t upId = upIdBits.firstMarkedBit();
             upIdBits.clearBit(upId);
-            BitSet32 oldActiveIdBits = activeIdBits;
-            activeIdBits.clearBit(upId);
 
-            int32_t motionEventAction;
-            if (activeIdBits.isEmpty()) {
-                motionEventAction = AMOTION_EVENT_ACTION_UP;
-            } else {
-                motionEventAction = AMOTION_EVENT_ACTION_POINTER_UP;
-            }
-
-            dispatchTouch(when, policyFlags, &interimTouch,
-                    oldActiveIdBits, upId, pointerCount, motionEventAction);
-            pointerCount -= 1;
+            dispatchMotion(when, policyFlags, mTouchSource,
+                    AMOTION_EVENT_ACTION_POINTER_UP, 0, metaState, 0,
+                    mLastTouchCoords, mLastTouch.idToIndex, dispatchedIdBits, upId,
+                    xPrecision, yPrecision, mDownTime);
+            dispatchedIdBits.clearBit(upId);
         }
 
         // Dispatch move events if any of the remaining pointers moved from their old locations.
         // Although applications receive new locations as part of individual pointer up
         // events, they do not generally handle them except when presented in a move event.
         if (moveNeeded) {
-            dispatchTouch(when, policyFlags, &mCurrentTouch,
-                    activeIdBits, -1, pointerCount, AMOTION_EVENT_ACTION_MOVE);
+            assert(moveIdBits.value == dispatchedIdBits.value);
+            dispatchMotion(when, policyFlags, mTouchSource,
+                    AMOTION_EVENT_ACTION_MOVE, 0, metaState, 0,
+                    mCurrentTouchCoords, mCurrentTouch.idToIndex, dispatchedIdBits, -1,
+                    xPrecision, yPrecision, mDownTime);
         }
 
         // Dispatch pointer down events using the new pointer locations.
         while (!downIdBits.isEmpty()) {
             uint32_t downId = downIdBits.firstMarkedBit();
             downIdBits.clearBit(downId);
-            BitSet32 oldActiveIdBits = activeIdBits;
-            activeIdBits.markBit(downId);
+            dispatchedIdBits.markBit(downId);
 
-            int32_t motionEventAction;
-            if (oldActiveIdBits.isEmpty()) {
-                motionEventAction = AMOTION_EVENT_ACTION_DOWN;
+            if (dispatchedIdBits.count() == 1) {
+                // First pointer is going down.  Set down time.
                 mDownTime = when;
             } else {
-                motionEventAction = AMOTION_EVENT_ACTION_POINTER_DOWN;
+                // Only send edge flags with first pointer down.
+                edgeFlags = AMOTION_EVENT_EDGE_FLAG_NONE;
             }
 
-            pointerCount += 1;
-            dispatchTouch(when, policyFlags, &mCurrentTouch,
-                    activeIdBits, downId, pointerCount, motionEventAction);
+            dispatchMotion(when, policyFlags, mTouchSource,
+                    AMOTION_EVENT_ACTION_POINTER_DOWN, 0, metaState, edgeFlags,
+                    mCurrentTouchCoords, mCurrentTouch.idToIndex, dispatchedIdBits, downId,
+                    xPrecision, yPrecision, mDownTime);
+        }
+    }
+
+    // Update state for next time.
+    for (uint32_t i = 0; i < currentPointerCount; i++) {
+        mLastTouchCoords[i].copyFrom(mCurrentTouchCoords[i]);
+    }
+}
+
+void TouchInputMapper::prepareTouches(int32_t* outEdgeFlags,
+        float* outXPrecision, float* outYPrecision) {
+    uint32_t currentPointerCount = mCurrentTouch.pointerCount;
+    uint32_t lastPointerCount = mLastTouch.pointerCount;
+
+    AutoMutex _l(mLock);
+
+    // Walk through the the active pointers and map touch screen coordinates (TouchData) into
+    // display or surface coordinates (PointerCoords) and adjust for display orientation.
+    for (uint32_t i = 0; i < currentPointerCount; i++) {
+        const PointerData& in = mCurrentTouch.pointers[i];
+
+        // ToolMajor and ToolMinor
+        float toolMajor, toolMinor;
+        switch (mCalibration.toolSizeCalibration) {
+        case Calibration::TOOL_SIZE_CALIBRATION_GEOMETRIC:
+            toolMajor = in.toolMajor * mLocked.geometricScale;
+            if (mRawAxes.toolMinor.valid) {
+                toolMinor = in.toolMinor * mLocked.geometricScale;
+            } else {
+                toolMinor = toolMajor;
+            }
+            break;
+        case Calibration::TOOL_SIZE_CALIBRATION_LINEAR:
+            toolMajor = in.toolMajor != 0
+                    ? in.toolMajor * mLocked.toolSizeLinearScale + mLocked.toolSizeLinearBias
+                    : 0;
+            if (mRawAxes.toolMinor.valid) {
+                toolMinor = in.toolMinor != 0
+                        ? in.toolMinor * mLocked.toolSizeLinearScale
+                                + mLocked.toolSizeLinearBias
+                        : 0;
+            } else {
+                toolMinor = toolMajor;
+            }
+            break;
+        case Calibration::TOOL_SIZE_CALIBRATION_AREA:
+            if (in.toolMajor != 0) {
+                float diameter = sqrtf(in.toolMajor
+                        * mLocked.toolSizeAreaScale + mLocked.toolSizeAreaBias);
+                toolMajor = diameter * mLocked.toolSizeLinearScale + mLocked.toolSizeLinearBias;
+            } else {
+                toolMajor = 0;
+            }
+            toolMinor = toolMajor;
+            break;
+        default:
+            toolMajor = 0;
+            toolMinor = 0;
+            break;
+        }
+
+        if (mCalibration.haveToolSizeIsSummed && mCalibration.toolSizeIsSummed) {
+            toolMajor /= currentPointerCount;
+            toolMinor /= currentPointerCount;
+        }
+
+        // Pressure
+        float rawPressure;
+        switch (mCalibration.pressureSource) {
+        case Calibration::PRESSURE_SOURCE_PRESSURE:
+            rawPressure = in.pressure;
+            break;
+        case Calibration::PRESSURE_SOURCE_TOUCH:
+            rawPressure = in.touchMajor;
+            break;
+        default:
+            rawPressure = 0;
+        }
+
+        float pressure;
+        switch (mCalibration.pressureCalibration) {
+        case Calibration::PRESSURE_CALIBRATION_PHYSICAL:
+        case Calibration::PRESSURE_CALIBRATION_AMPLITUDE:
+            pressure = rawPressure * mLocked.pressureScale;
+            break;
+        default:
+            pressure = 1;
+            break;
+        }
+
+        // TouchMajor and TouchMinor
+        float touchMajor, touchMinor;
+        switch (mCalibration.touchSizeCalibration) {
+        case Calibration::TOUCH_SIZE_CALIBRATION_GEOMETRIC:
+            touchMajor = in.touchMajor * mLocked.geometricScale;
+            if (mRawAxes.touchMinor.valid) {
+                touchMinor = in.touchMinor * mLocked.geometricScale;
+            } else {
+                touchMinor = touchMajor;
+            }
+            break;
+        case Calibration::TOUCH_SIZE_CALIBRATION_PRESSURE:
+            touchMajor = toolMajor * pressure;
+            touchMinor = toolMinor * pressure;
+            break;
+        default:
+            touchMajor = 0;
+            touchMinor = 0;
+            break;
+        }
+
+        if (touchMajor > toolMajor) {
+            touchMajor = toolMajor;
+        }
+        if (touchMinor > toolMinor) {
+            touchMinor = toolMinor;
+        }
+
+        // Size
+        float size;
+        switch (mCalibration.sizeCalibration) {
+        case Calibration::SIZE_CALIBRATION_NORMALIZED: {
+            float rawSize = mRawAxes.toolMinor.valid
+                    ? avg(in.toolMajor, in.toolMinor)
+                    : in.toolMajor;
+            size = rawSize * mLocked.sizeScale;
+            break;
+        }
+        default:
+            size = 0;
+            break;
+        }
+
+        // Orientation
+        float orientation;
+        switch (mCalibration.orientationCalibration) {
+        case Calibration::ORIENTATION_CALIBRATION_INTERPOLATED:
+            orientation = in.orientation * mLocked.orientationScale;
+            break;
+        case Calibration::ORIENTATION_CALIBRATION_VECTOR: {
+            int32_t c1 = signExtendNybble((in.orientation & 0xf0) >> 4);
+            int32_t c2 = signExtendNybble(in.orientation & 0x0f);
+            if (c1 != 0 || c2 != 0) {
+                orientation = atan2f(c1, c2) * 0.5f;
+                float scale = 1.0f + pythag(c1, c2) / 16.0f;
+                touchMajor *= scale;
+                touchMinor /= scale;
+                toolMajor *= scale;
+                toolMinor /= scale;
+            } else {
+                orientation = 0;
+            }
+            break;
+        }
+        default:
+            orientation = 0;
+        }
+
+        // X and Y
+        // Adjust coords for surface orientation.
+        float x, y;
+        switch (mLocked.surfaceOrientation) {
+        case DISPLAY_ORIENTATION_90:
+            x = float(in.y - mRawAxes.y.minValue) * mLocked.yScale;
+            y = float(mRawAxes.x.maxValue - in.x) * mLocked.xScale;
+            orientation -= M_PI_2;
+            if (orientation < - M_PI_2) {
+                orientation += M_PI;
+            }
+            break;
+        case DISPLAY_ORIENTATION_180:
+            x = float(mRawAxes.x.maxValue - in.x) * mLocked.xScale;
+            y = float(mRawAxes.y.maxValue - in.y) * mLocked.yScale;
+            break;
+        case DISPLAY_ORIENTATION_270:
+            x = float(mRawAxes.y.maxValue - in.y) * mLocked.yScale;
+            y = float(in.x - mRawAxes.x.minValue) * mLocked.xScale;
+            orientation += M_PI_2;
+            if (orientation > M_PI_2) {
+                orientation -= M_PI;
+            }
+            break;
+        default:
+            x = float(in.x - mRawAxes.x.minValue) * mLocked.xScale;
+            y = float(in.y - mRawAxes.y.minValue) * mLocked.yScale;
+            break;
+        }
+
+        // Write output coords.
+        PointerCoords& out = mCurrentTouchCoords[i];
+        out.clear();
+        out.setAxisValue(AMOTION_EVENT_AXIS_X, x);
+        out.setAxisValue(AMOTION_EVENT_AXIS_Y, y);
+        out.setAxisValue(AMOTION_EVENT_AXIS_PRESSURE, pressure);
+        out.setAxisValue(AMOTION_EVENT_AXIS_SIZE, size);
+        out.setAxisValue(AMOTION_EVENT_AXIS_TOUCH_MAJOR, touchMajor);
+        out.setAxisValue(AMOTION_EVENT_AXIS_TOUCH_MINOR, touchMinor);
+        out.setAxisValue(AMOTION_EVENT_AXIS_TOOL_MAJOR, toolMajor);
+        out.setAxisValue(AMOTION_EVENT_AXIS_TOOL_MINOR, toolMinor);
+        out.setAxisValue(AMOTION_EVENT_AXIS_ORIENTATION, orientation);
+    }
+
+    // Check edge flags by looking only at the first pointer since the flags are
+    // global to the event.
+    *outEdgeFlags = AMOTION_EVENT_EDGE_FLAG_NONE;
+    if (lastPointerCount == 0 && currentPointerCount > 0) {
+        const PointerData& in = mCurrentTouch.pointers[0];
+
+        if (in.x <= mRawAxes.x.minValue) {
+            *outEdgeFlags |= rotateEdgeFlag(AMOTION_EVENT_EDGE_FLAG_LEFT,
+                    mLocked.surfaceOrientation);
+        } else if (in.x >= mRawAxes.x.maxValue) {
+            *outEdgeFlags |= rotateEdgeFlag(AMOTION_EVENT_EDGE_FLAG_RIGHT,
+                    mLocked.surfaceOrientation);
+        }
+        if (in.y <= mRawAxes.y.minValue) {
+            *outEdgeFlags |= rotateEdgeFlag(AMOTION_EVENT_EDGE_FLAG_TOP,
+                    mLocked.surfaceOrientation);
+        } else if (in.y >= mRawAxes.y.maxValue) {
+            *outEdgeFlags |= rotateEdgeFlag(AMOTION_EVENT_EDGE_FLAG_BOTTOM,
+                    mLocked.surfaceOrientation);
+        }
+    }
+
+    *outXPrecision = mLocked.orientedXPrecision;
+    *outYPrecision = mLocked.orientedYPrecision;
+}
+
+void TouchInputMapper::dispatchPointerGestures(nsecs_t when, uint32_t policyFlags) {
+    // Update current gesture coordinates.
+    bool cancelPreviousGesture, finishPreviousGesture;
+    preparePointerGestures(when, &cancelPreviousGesture, &finishPreviousGesture);
+
+    // Send events!
+    uint32_t metaState = getContext()->getGlobalMetaState();
+
+    // Update last coordinates of pointers that have moved so that we observe the new
+    // pointer positions at the same time as other pointers that have just gone up.
+    bool down = mPointerGesture.currentGestureMode == PointerGesture::CLICK_OR_DRAG
+            || mPointerGesture.currentGestureMode == PointerGesture::SWIPE
+            || mPointerGesture.currentGestureMode == PointerGesture::FREEFORM;
+    bool moveNeeded = false;
+    if (down && !cancelPreviousGesture && !finishPreviousGesture
+            && mPointerGesture.lastGesturePointerCount != 0
+            && mPointerGesture.currentGesturePointerCount != 0) {
+        BitSet32 movedGestureIdBits(mPointerGesture.currentGestureIdBits.value
+                & mPointerGesture.lastGestureIdBits.value);
+        moveNeeded = updateMovedPointerCoords(
+                mPointerGesture.currentGestureCoords, mPointerGesture.currentGestureIdToIndex,
+                mPointerGesture.lastGestureCoords, mPointerGesture.lastGestureIdToIndex,
+                movedGestureIdBits);
+    }
+
+    // Send motion events for all pointers that went up or were canceled.
+    BitSet32 dispatchedGestureIdBits(mPointerGesture.lastGestureIdBits);
+    if (!dispatchedGestureIdBits.isEmpty()) {
+        if (cancelPreviousGesture) {
+            dispatchMotion(when, policyFlags, mPointerSource,
+                    AMOTION_EVENT_ACTION_CANCEL, 0, metaState, AMOTION_EVENT_EDGE_FLAG_NONE,
+                    mPointerGesture.lastGestureCoords, mPointerGesture.lastGestureIdToIndex,
+                    dispatchedGestureIdBits, -1,
+                    0, 0, mPointerGesture.downTime);
+
+            dispatchedGestureIdBits.clear();
+        } else {
+            BitSet32 upGestureIdBits;
+            if (finishPreviousGesture) {
+                upGestureIdBits = dispatchedGestureIdBits;
+            } else {
+                upGestureIdBits.value = dispatchedGestureIdBits.value
+                        & ~mPointerGesture.currentGestureIdBits.value;
+            }
+            while (!upGestureIdBits.isEmpty()) {
+                uint32_t id = upGestureIdBits.firstMarkedBit();
+                upGestureIdBits.clearBit(id);
+
+                dispatchMotion(when, policyFlags, mPointerSource,
+                        AMOTION_EVENT_ACTION_POINTER_UP, 0,
+                        metaState, AMOTION_EVENT_EDGE_FLAG_NONE,
+                        mPointerGesture.lastGestureCoords, mPointerGesture.lastGestureIdToIndex,
+                        dispatchedGestureIdBits, id,
+                        0, 0, mPointerGesture.downTime);
+
+                dispatchedGestureIdBits.clearBit(id);
+            }
+        }
+    }
+
+    // Send motion events for all pointers that moved.
+    if (moveNeeded) {
+        dispatchMotion(when, policyFlags, mPointerSource,
+                AMOTION_EVENT_ACTION_MOVE, 0, metaState, AMOTION_EVENT_EDGE_FLAG_NONE,
+                mPointerGesture.currentGestureCoords, mPointerGesture.currentGestureIdToIndex,
+                dispatchedGestureIdBits, -1,
+                0, 0, mPointerGesture.downTime);
+    }
+
+    // Send motion events for all pointers that went down.
+    if (down) {
+        BitSet32 downGestureIdBits(mPointerGesture.currentGestureIdBits.value
+                & ~dispatchedGestureIdBits.value);
+        while (!downGestureIdBits.isEmpty()) {
+            uint32_t id = downGestureIdBits.firstMarkedBit();
+            downGestureIdBits.clearBit(id);
+            dispatchedGestureIdBits.markBit(id);
+
+            int32_t edgeFlags = AMOTION_EVENT_EDGE_FLAG_NONE;
+            if (dispatchedGestureIdBits.count() == 1) {
+                // First pointer is going down.  Calculate edge flags and set down time.
+                uint32_t index = mPointerGesture.currentGestureIdToIndex[id];
+                const PointerCoords& downCoords = mPointerGesture.currentGestureCoords[index];
+                edgeFlags = calculateEdgeFlagsUsingPointerBounds(mPointerController,
+                        downCoords.getAxisValue(AMOTION_EVENT_AXIS_X),
+                        downCoords.getAxisValue(AMOTION_EVENT_AXIS_Y));
+                mPointerGesture.downTime = when;
+            }
+
+            dispatchMotion(when, policyFlags, mPointerSource,
+                    AMOTION_EVENT_ACTION_POINTER_DOWN, 0, metaState, edgeFlags,
+                    mPointerGesture.currentGestureCoords, mPointerGesture.currentGestureIdToIndex,
+                    dispatchedGestureIdBits, id,
+                    0, 0, mPointerGesture.downTime);
+        }
+    }
+
+    // Send down and up for a tap.
+    if (mPointerGesture.currentGestureMode == PointerGesture::TAP) {
+        const PointerCoords& coords = mPointerGesture.currentGestureCoords[0];
+        int32_t edgeFlags = calculateEdgeFlagsUsingPointerBounds(mPointerController,
+                coords.getAxisValue(AMOTION_EVENT_AXIS_X),
+                coords.getAxisValue(AMOTION_EVENT_AXIS_Y));
+        nsecs_t downTime = mPointerGesture.downTime = mPointerGesture.tapTime;
+        mPointerGesture.resetTapTime();
+
+        dispatchMotion(downTime, policyFlags, mPointerSource,
+                AMOTION_EVENT_ACTION_DOWN, 0, metaState, edgeFlags,
+                mPointerGesture.currentGestureCoords, mPointerGesture.currentGestureIdToIndex,
+                mPointerGesture.currentGestureIdBits, -1,
+                0, 0, downTime);
+        dispatchMotion(when, policyFlags, mPointerSource,
+                AMOTION_EVENT_ACTION_UP, 0, metaState, edgeFlags,
+                mPointerGesture.currentGestureCoords, mPointerGesture.currentGestureIdToIndex,
+                mPointerGesture.currentGestureIdBits, -1,
+                0, 0, downTime);
+    }
+
+    // Send motion events for hover.
+    if (mPointerGesture.currentGestureMode == PointerGesture::HOVER) {
+        dispatchMotion(when, policyFlags, mPointerSource,
+                AMOTION_EVENT_ACTION_HOVER_MOVE, 0, metaState, AMOTION_EVENT_EDGE_FLAG_NONE,
+                mPointerGesture.currentGestureCoords, mPointerGesture.currentGestureIdToIndex,
+                mPointerGesture.currentGestureIdBits, -1,
+                0, 0, mPointerGesture.downTime);
+    }
+
+    // Update state.
+    mPointerGesture.lastGestureMode = mPointerGesture.currentGestureMode;
+    if (!down) {
+        mPointerGesture.lastGesturePointerCount = 0;
+        mPointerGesture.lastGestureIdBits.clear();
+    } else {
+        uint32_t currentGesturePointerCount = mPointerGesture.currentGesturePointerCount;
+        mPointerGesture.lastGesturePointerCount = currentGesturePointerCount;
+        mPointerGesture.lastGestureIdBits = mPointerGesture.currentGestureIdBits;
+        for (BitSet32 idBits(mPointerGesture.currentGestureIdBits); !idBits.isEmpty(); ) {
+            uint32_t id = idBits.firstMarkedBit();
+            idBits.clearBit(id);
+            uint32_t index = mPointerGesture.currentGestureIdToIndex[id];
+            mPointerGesture.lastGestureCoords[index].copyFrom(
+                    mPointerGesture.currentGestureCoords[index]);
+            mPointerGesture.lastGestureIdToIndex[id] = index;
         }
     }
 }
 
-void TouchInputMapper::dispatchTouch(nsecs_t when, uint32_t policyFlags,
-        TouchData* touch, BitSet32 idBits, uint32_t changedId, uint32_t pointerCount,
-        int32_t motionEventAction) {
-    int32_t pointerIds[MAX_POINTERS];
-    PointerCoords pointerCoords[MAX_POINTERS];
-    int32_t motionEventEdgeFlags = AMOTION_EVENT_EDGE_FLAG_NONE;
-    float xPrecision, yPrecision;
+void TouchInputMapper::preparePointerGestures(nsecs_t when,
+        bool* outCancelPreviousGesture, bool* outFinishPreviousGesture) {
+    *outCancelPreviousGesture = false;
+    *outFinishPreviousGesture = false;
 
-    { // acquire lock
-        AutoMutex _l(mLock);
+    AutoMutex _l(mLock);
 
-        // Walk through the the active pointers and map touch screen coordinates (TouchData) into
-        // display coordinates (PointerCoords) and adjust for display orientation.
-        for (uint32_t outIndex = 0; ! idBits.isEmpty(); outIndex++) {
+    // Update the velocity tracker.
+    {
+        VelocityTracker::Position positions[MAX_POINTERS];
+        uint32_t count = 0;
+        for (BitSet32 idBits(mCurrentTouch.idBits); !idBits.isEmpty(); count++) {
             uint32_t id = idBits.firstMarkedBit();
             idBits.clearBit(id);
-            uint32_t inIndex = touch->idToIndex[id];
+            uint32_t index = mCurrentTouch.idToIndex[id];
+            positions[count].x = mCurrentTouch.pointers[index].x
+                    * mLocked.pointerGestureXMovementScale;
+            positions[count].y = mCurrentTouch.pointers[index].y
+                    * mLocked.pointerGestureYMovementScale;
+        }
+        mPointerGesture.velocityTracker.addMovement(when, mCurrentTouch.idBits, positions);
+    }
 
-            const PointerData& in = touch->pointers[inIndex];
+    // Pick a new active touch id if needed.
+    // Choose an arbitrary pointer that just went down, if there is one.
+    // Otherwise choose an arbitrary remaining pointer.
+    // This guarantees we always have an active touch id when there is at least one pointer.
+    // We always switch to the newest pointer down because that's usually where the user's
+    // attention is focused.
+    int32_t activeTouchId;
+    BitSet32 downTouchIdBits(mCurrentTouch.idBits.value & ~mLastTouch.idBits.value);
+    if (!downTouchIdBits.isEmpty()) {
+        activeTouchId = mPointerGesture.activeTouchId = downTouchIdBits.firstMarkedBit();
+    } else {
+        activeTouchId = mPointerGesture.activeTouchId;
+        if (activeTouchId < 0 || !mCurrentTouch.idBits.hasBit(activeTouchId)) {
+            if (!mCurrentTouch.idBits.isEmpty()) {
+                activeTouchId = mPointerGesture.activeTouchId =
+                        mCurrentTouch.idBits.firstMarkedBit();
+            } else {
+                activeTouchId = mPointerGesture.activeTouchId = -1;
+            }
+        }
+    }
 
-            // ToolMajor and ToolMinor
-            float toolMajor, toolMinor;
-            switch (mCalibration.toolSizeCalibration) {
-            case Calibration::TOOL_SIZE_CALIBRATION_GEOMETRIC:
-                toolMajor = in.toolMajor * mLocked.geometricScale;
-                if (mRawAxes.toolMinor.valid) {
-                    toolMinor = in.toolMinor * mLocked.geometricScale;
-                } else {
-                    toolMinor = toolMajor;
+    // Update the touch origin data to track where each finger originally went down.
+    if (mCurrentTouch.pointerCount == 0 || mPointerGesture.touchOrigin.pointerCount == 0) {
+        // Fast path when all fingers have gone up or down.
+        mPointerGesture.touchOrigin.copyFrom(mCurrentTouch);
+    } else {
+        // Slow path when only some fingers have gone up or down.
+        for (BitSet32 idBits(mPointerGesture.touchOrigin.idBits.value
+                & ~mCurrentTouch.idBits.value); !idBits.isEmpty(); ) {
+            uint32_t id = idBits.firstMarkedBit();
+            idBits.clearBit(id);
+            mPointerGesture.touchOrigin.idBits.clearBit(id);
+            uint32_t index = mPointerGesture.touchOrigin.idToIndex[id];
+            uint32_t count = --mPointerGesture.touchOrigin.pointerCount;
+            while (index < count) {
+                mPointerGesture.touchOrigin.pointers[index] =
+                        mPointerGesture.touchOrigin.pointers[index + 1];
+                uint32_t movedId = mPointerGesture.touchOrigin.pointers[index].id;
+                mPointerGesture.touchOrigin.idToIndex[movedId] = index;
+                index += 1;
+            }
+        }
+        for (BitSet32 idBits(mCurrentTouch.idBits.value
+                & ~mPointerGesture.touchOrigin.idBits.value); !idBits.isEmpty(); ) {
+            uint32_t id = idBits.firstMarkedBit();
+            idBits.clearBit(id);
+            mPointerGesture.touchOrigin.idBits.markBit(id);
+            uint32_t index = mPointerGesture.touchOrigin.pointerCount++;
+            mPointerGesture.touchOrigin.pointers[index] =
+                    mCurrentTouch.pointers[mCurrentTouch.idToIndex[id]];
+            mPointerGesture.touchOrigin.idToIndex[id] = index;
+        }
+    }
+
+    // Determine whether we are in quiet time.
+    bool isQuietTime = when < mPointerGesture.quietTime + QUIET_INTERVAL;
+    if (!isQuietTime) {
+        if ((mPointerGesture.lastGestureMode == PointerGesture::SWIPE
+                || mPointerGesture.lastGestureMode == PointerGesture::FREEFORM)
+                && mCurrentTouch.pointerCount < 2) {
+            // Enter quiet time when exiting swipe or freeform state.
+            // This is to prevent accidentally entering the hover state and flinging the
+            // pointer when finishing a swipe and there is still one pointer left onscreen.
+            isQuietTime = true;
+        } else if (mPointerGesture.lastGestureMode == PointerGesture::CLICK_OR_DRAG
+                && mCurrentTouch.pointerCount >= 2
+                && !isPointerDown(mCurrentTouch.buttonState)) {
+            // Enter quiet time when releasing the button and there are still two or more
+            // fingers down.  This may indicate that one finger was used to press the button
+            // but it has not gone up yet.
+            isQuietTime = true;
+        }
+        if (isQuietTime) {
+            mPointerGesture.quietTime = when;
+        }
+    }
+
+    // Switch states based on button and pointer state.
+    if (isQuietTime) {
+        // Case 1: Quiet time. (QUIET)
+#if DEBUG_GESTURES
+        LOGD("Gestures: QUIET for next %0.3fms",
+                (mPointerGesture.quietTime + QUIET_INTERVAL - when) * 0.000001f);
+#endif
+        *outFinishPreviousGesture = true;
+
+        mPointerGesture.activeGestureId = -1;
+        mPointerGesture.currentGestureMode = PointerGesture::QUIET;
+        mPointerGesture.currentGesturePointerCount = 0;
+        mPointerGesture.currentGestureIdBits.clear();
+    } else if (isPointerDown(mCurrentTouch.buttonState)) {
+        // Case 2: Button is pressed. (DRAG)
+        // The pointer follows the active touch point.
+        // Emit DOWN, MOVE, UP events at the pointer location.
+        //
+        // Only the active touch matters; other fingers are ignored.  This policy helps
+        // to handle the case where the user places a second finger on the touch pad
+        // to apply the necessary force to depress an integrated button below the surface.
+        // We don't want the second finger to be delivered to applications.
+        //
+        // For this to work well, we need to make sure to track the pointer that is really
+        // active.  If the user first puts one finger down to click then adds another
+        // finger to drag then the active pointer should switch to the finger that is
+        // being dragged.
+#if DEBUG_GESTURES
+        LOGD("Gestures: CLICK_OR_DRAG activeTouchId=%d, "
+                "currentTouchPointerCount=%d", activeTouchId, mCurrentTouch.pointerCount);
+#endif
+        // Reset state when just starting.
+        if (mPointerGesture.lastGestureMode != PointerGesture::CLICK_OR_DRAG) {
+            *outFinishPreviousGesture = true;
+            mPointerGesture.activeGestureId = 0;
+        }
+
+        // Switch pointers if needed.
+        // Find the fastest pointer and follow it.
+        if (activeTouchId >= 0) {
+            if (mCurrentTouch.pointerCount > 1) {
+                int32_t bestId = -1;
+                float bestSpeed = DRAG_MIN_SWITCH_SPEED;
+                for (uint32_t i = 0; i < mCurrentTouch.pointerCount; i++) {
+                    uint32_t id = mCurrentTouch.pointers[i].id;
+                    float vx, vy;
+                    if (mPointerGesture.velocityTracker.getVelocity(id, &vx, &vy)) {
+                        float speed = pythag(vx, vy);
+                        if (speed > bestSpeed) {
+                            bestId = id;
+                            bestSpeed = speed;
+                        }
+                    }
                 }
-                break;
-            case Calibration::TOOL_SIZE_CALIBRATION_LINEAR:
-                toolMajor = in.toolMajor != 0
-                        ? in.toolMajor * mLocked.toolSizeLinearScale + mLocked.toolSizeLinearBias
-                        : 0;
-                if (mRawAxes.toolMinor.valid) {
-                    toolMinor = in.toolMinor != 0
-                            ? in.toolMinor * mLocked.toolSizeLinearScale
-                                    + mLocked.toolSizeLinearBias
-                            : 0;
-                } else {
-                    toolMinor = toolMajor;
+                if (bestId >= 0 && bestId != activeTouchId) {
+                    mPointerGesture.activeTouchId = activeTouchId = bestId;
+#if DEBUG_GESTURES
+                    LOGD("Gestures: CLICK_OR_DRAG switched pointers, "
+                            "bestId=%d, bestSpeed=%0.3f", bestId, bestSpeed);
+#endif
                 }
-                break;
-            case Calibration::TOOL_SIZE_CALIBRATION_AREA:
-                if (in.toolMajor != 0) {
-                    float diameter = sqrtf(in.toolMajor
-                            * mLocked.toolSizeAreaScale + mLocked.toolSizeAreaBias);
-                    toolMajor = diameter * mLocked.toolSizeLinearScale + mLocked.toolSizeLinearBias;
-                } else {
-                    toolMajor = 0;
-                }
-                toolMinor = toolMajor;
-                break;
-            default:
-                toolMajor = 0;
-                toolMinor = 0;
-                break;
             }
 
-            if (mCalibration.haveToolSizeIsSummed && mCalibration.toolSizeIsSummed) {
-                toolMajor /= pointerCount;
-                toolMinor /= pointerCount;
-            }
-
-            // Pressure
-            float rawPressure;
-            switch (mCalibration.pressureSource) {
-            case Calibration::PRESSURE_SOURCE_PRESSURE:
-                rawPressure = in.pressure;
-                break;
-            case Calibration::PRESSURE_SOURCE_TOUCH:
-                rawPressure = in.touchMajor;
-                break;
-            default:
-                rawPressure = 0;
-            }
-
-            float pressure;
-            switch (mCalibration.pressureCalibration) {
-            case Calibration::PRESSURE_CALIBRATION_PHYSICAL:
-            case Calibration::PRESSURE_CALIBRATION_AMPLITUDE:
-                pressure = rawPressure * mLocked.pressureScale;
-                break;
-            default:
-                pressure = 1;
-                break;
-            }
-
-            // TouchMajor and TouchMinor
-            float touchMajor, touchMinor;
-            switch (mCalibration.touchSizeCalibration) {
-            case Calibration::TOUCH_SIZE_CALIBRATION_GEOMETRIC:
-                touchMajor = in.touchMajor * mLocked.geometricScale;
-                if (mRawAxes.touchMinor.valid) {
-                    touchMinor = in.touchMinor * mLocked.geometricScale;
-                } else {
-                    touchMinor = touchMajor;
-                }
-                break;
-            case Calibration::TOUCH_SIZE_CALIBRATION_PRESSURE:
-                touchMajor = toolMajor * pressure;
-                touchMinor = toolMinor * pressure;
-                break;
-            default:
-                touchMajor = 0;
-                touchMinor = 0;
-                break;
-            }
-
-            if (touchMajor > toolMajor) {
-                touchMajor = toolMajor;
-            }
-            if (touchMinor > toolMinor) {
-                touchMinor = toolMinor;
-            }
-
-            // Size
-            float size;
-            switch (mCalibration.sizeCalibration) {
-            case Calibration::SIZE_CALIBRATION_NORMALIZED: {
-                float rawSize = mRawAxes.toolMinor.valid
-                        ? avg(in.toolMajor, in.toolMinor)
-                        : in.toolMajor;
-                size = rawSize * mLocked.sizeScale;
-                break;
-            }
-            default:
-                size = 0;
-                break;
-            }
-
-            // Orientation
-            float orientation;
-            switch (mCalibration.orientationCalibration) {
-            case Calibration::ORIENTATION_CALIBRATION_INTERPOLATED:
-                orientation = in.orientation * mLocked.orientationScale;
-                break;
-            case Calibration::ORIENTATION_CALIBRATION_VECTOR: {
-                int32_t c1 = signExtendNybble((in.orientation & 0xf0) >> 4);
-                int32_t c2 = signExtendNybble(in.orientation & 0x0f);
-                if (c1 != 0 || c2 != 0) {
-                    orientation = atan2f(c1, c2) * 0.5f;
-                    float scale = 1.0f + pythag(c1, c2) / 16.0f;
-                    touchMajor *= scale;
-                    touchMinor /= scale;
-                    toolMajor *= scale;
-                    toolMinor /= scale;
-                } else {
-                    orientation = 0;
-                }
-                break;
-            }
-            default:
-                orientation = 0;
-            }
-
-            // X and Y
-            // Adjust coords for surface orientation.
-            float x, y;
-            switch (mLocked.surfaceOrientation) {
-            case DISPLAY_ORIENTATION_90:
-                x = float(in.y - mRawAxes.y.minValue) * mLocked.yScale;
-                y = float(mRawAxes.x.maxValue - in.x) * mLocked.xScale;
-                orientation -= M_PI_2;
-                if (orientation < - M_PI_2) {
-                    orientation += M_PI;
-                }
-                break;
-            case DISPLAY_ORIENTATION_180:
-                x = float(mRawAxes.x.maxValue - in.x) * mLocked.xScale;
-                y = float(mRawAxes.y.maxValue - in.y) * mLocked.yScale;
-                break;
-            case DISPLAY_ORIENTATION_270:
-                x = float(mRawAxes.y.maxValue - in.y) * mLocked.yScale;
-                y = float(in.x - mRawAxes.x.minValue) * mLocked.xScale;
-                orientation += M_PI_2;
-                if (orientation > M_PI_2) {
-                    orientation -= M_PI;
-                }
-                break;
-            default:
-                x = float(in.x - mRawAxes.x.minValue) * mLocked.xScale;
-                y = float(in.y - mRawAxes.y.minValue) * mLocked.yScale;
-                break;
-            }
-
-            // Write output coords.
-            PointerCoords& out = pointerCoords[outIndex];
-            out.clear();
-            out.setAxisValue(AMOTION_EVENT_AXIS_X, x);
-            out.setAxisValue(AMOTION_EVENT_AXIS_Y, y);
-            out.setAxisValue(AMOTION_EVENT_AXIS_PRESSURE, pressure);
-            out.setAxisValue(AMOTION_EVENT_AXIS_SIZE, size);
-            out.setAxisValue(AMOTION_EVENT_AXIS_TOUCH_MAJOR, touchMajor);
-            out.setAxisValue(AMOTION_EVENT_AXIS_TOUCH_MINOR, touchMinor);
-            out.setAxisValue(AMOTION_EVENT_AXIS_TOOL_MAJOR, toolMajor);
-            out.setAxisValue(AMOTION_EVENT_AXIS_TOOL_MINOR, toolMinor);
-            out.setAxisValue(AMOTION_EVENT_AXIS_ORIENTATION, orientation);
-
-            pointerIds[outIndex] = int32_t(id);
-
-            if (id == changedId) {
-                motionEventAction |= outIndex << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT;
+            if (mLastTouch.idBits.hasBit(activeTouchId)) {
+                const PointerData& currentPointer =
+                        mCurrentTouch.pointers[mCurrentTouch.idToIndex[activeTouchId]];
+                const PointerData& lastPointer =
+                        mLastTouch.pointers[mLastTouch.idToIndex[activeTouchId]];
+                float deltaX = (currentPointer.x - lastPointer.x)
+                        * mLocked.pointerGestureXMovementScale;
+                float deltaY = (currentPointer.y - lastPointer.y)
+                        * mLocked.pointerGestureYMovementScale;
+                mPointerController->move(deltaX, deltaY);
             }
         }
 
-        // Check edge flags by looking only at the first pointer since the flags are
-        // global to the event.
-        if (motionEventAction == AMOTION_EVENT_ACTION_DOWN) {
-            uint32_t inIndex = touch->idToIndex[pointerIds[0]];
-            const PointerData& in = touch->pointers[inIndex];
+        float x, y;
+        mPointerController->getPosition(&x, &y);
 
-            if (in.x <= mRawAxes.x.minValue) {
-                motionEventEdgeFlags |= rotateEdgeFlag(AMOTION_EVENT_EDGE_FLAG_LEFT,
-                        mLocked.surfaceOrientation);
-            } else if (in.x >= mRawAxes.x.maxValue) {
-                motionEventEdgeFlags |= rotateEdgeFlag(AMOTION_EVENT_EDGE_FLAG_RIGHT,
-                        mLocked.surfaceOrientation);
+        mPointerGesture.currentGestureMode = PointerGesture::CLICK_OR_DRAG;
+        mPointerGesture.currentGesturePointerCount = 1;
+        mPointerGesture.currentGestureIdBits.clear();
+        mPointerGesture.currentGestureIdBits.markBit(mPointerGesture.activeGestureId);
+        mPointerGesture.currentGestureIdToIndex[mPointerGesture.activeGestureId] = 0;
+        mPointerGesture.currentGestureCoords[0].clear();
+        mPointerGesture.currentGestureCoords[0].setAxisValue(AMOTION_EVENT_AXIS_X, x);
+        mPointerGesture.currentGestureCoords[0].setAxisValue(AMOTION_EVENT_AXIS_Y, y);
+        mPointerGesture.currentGestureCoords[0].setAxisValue(AMOTION_EVENT_AXIS_PRESSURE, 1.0f);
+    } else if (mCurrentTouch.pointerCount == 0) {
+        // Case 3. No fingers down and button is not pressed. (NEUTRAL)
+        *outFinishPreviousGesture = true;
+
+        // Watch for taps coming out of HOVER or INDETERMINATE_MULTITOUCH mode.
+        bool tapped = false;
+        if (mPointerGesture.lastGestureMode == PointerGesture::HOVER
+                || mPointerGesture.lastGestureMode
+                        == PointerGesture::INDETERMINATE_MULTITOUCH) {
+            if (when <= mPointerGesture.tapTime + TAP_INTERVAL) {
+                float x, y;
+                mPointerController->getPosition(&x, &y);
+                if (fabs(x - mPointerGesture.initialPointerX) <= TAP_SLOP
+                        && fabs(y - mPointerGesture.initialPointerY) <= TAP_SLOP) {
+#if DEBUG_GESTURES
+                    LOGD("Gestures: TAP");
+#endif
+                    mPointerGesture.activeGestureId = 0;
+                    mPointerGesture.currentGestureMode = PointerGesture::TAP;
+                    mPointerGesture.currentGesturePointerCount = 1;
+                    mPointerGesture.currentGestureIdBits.clear();
+                    mPointerGesture.currentGestureIdBits.markBit(
+                            mPointerGesture.activeGestureId);
+                    mPointerGesture.currentGestureIdToIndex[
+                            mPointerGesture.activeGestureId] = 0;
+                    mPointerGesture.currentGestureCoords[0].clear();
+                    mPointerGesture.currentGestureCoords[0].setAxisValue(
+                            AMOTION_EVENT_AXIS_X, mPointerGesture.initialPointerX);
+                    mPointerGesture.currentGestureCoords[0].setAxisValue(
+                            AMOTION_EVENT_AXIS_Y, mPointerGesture.initialPointerY);
+                    mPointerGesture.currentGestureCoords[0].setAxisValue(
+                            AMOTION_EVENT_AXIS_PRESSURE, 1.0f);
+                    tapped = true;
+                } else {
+#if DEBUG_GESTURES
+                    LOGD("Gestures: Not a TAP, deltaX=%f, deltaY=%f",
+                            x - mPointerGesture.initialPointerX,
+                            y - mPointerGesture.initialPointerY);
+#endif
+                }
+            } else {
+#if DEBUG_GESTURES
+                LOGD("Gestures: Not a TAP, delay=%lld",
+                        when - mPointerGesture.tapTime);
+#endif
             }
-            if (in.y <= mRawAxes.y.minValue) {
-                motionEventEdgeFlags |= rotateEdgeFlag(AMOTION_EVENT_EDGE_FLAG_TOP,
-                        mLocked.surfaceOrientation);
-            } else if (in.y >= mRawAxes.y.maxValue) {
-                motionEventEdgeFlags |= rotateEdgeFlag(AMOTION_EVENT_EDGE_FLAG_BOTTOM,
-                        mLocked.surfaceOrientation);
+        }
+        if (!tapped) {
+#if DEBUG_GESTURES
+            LOGD("Gestures: NEUTRAL");
+#endif
+            mPointerGesture.activeGestureId = -1;
+            mPointerGesture.currentGestureMode = PointerGesture::NEUTRAL;
+            mPointerGesture.currentGesturePointerCount = 0;
+            mPointerGesture.currentGestureIdBits.clear();
+        }
+    } else if (mCurrentTouch.pointerCount == 1) {
+        // Case 4. Exactly one finger down, button is not pressed. (HOVER)
+        // The pointer follows the active touch point.
+        // Emit HOVER_MOVE events at the pointer location.
+        assert(activeTouchId >= 0);
+
+#if DEBUG_GESTURES
+        LOGD("Gestures: HOVER");
+#endif
+
+        if (mLastTouch.idBits.hasBit(activeTouchId)) {
+            const PointerData& currentPointer =
+                    mCurrentTouch.pointers[mCurrentTouch.idToIndex[activeTouchId]];
+            const PointerData& lastPointer =
+                    mLastTouch.pointers[mLastTouch.idToIndex[activeTouchId]];
+            float deltaX = (currentPointer.x - lastPointer.x)
+                    * mLocked.pointerGestureXMovementScale;
+            float deltaY = (currentPointer.y - lastPointer.y)
+                    * mLocked.pointerGestureYMovementScale;
+            mPointerController->move(deltaX, deltaY);
+        }
+
+        *outFinishPreviousGesture = true;
+        mPointerGesture.activeGestureId = 0;
+
+        float x, y;
+        mPointerController->getPosition(&x, &y);
+
+        mPointerGesture.currentGestureMode = PointerGesture::HOVER;
+        mPointerGesture.currentGesturePointerCount = 1;
+        mPointerGesture.currentGestureIdBits.clear();
+        mPointerGesture.currentGestureIdBits.markBit(mPointerGesture.activeGestureId);
+        mPointerGesture.currentGestureIdToIndex[mPointerGesture.activeGestureId] = 0;
+        mPointerGesture.currentGestureCoords[0].clear();
+        mPointerGesture.currentGestureCoords[0].setAxisValue(AMOTION_EVENT_AXIS_X, x);
+        mPointerGesture.currentGestureCoords[0].setAxisValue(AMOTION_EVENT_AXIS_Y, y);
+        mPointerGesture.currentGestureCoords[0].setAxisValue(AMOTION_EVENT_AXIS_PRESSURE, 0.0f);
+
+        if (mLastTouch.pointerCount == 0 && mCurrentTouch.pointerCount != 0) {
+            mPointerGesture.tapTime = when;
+            mPointerGesture.initialPointerX = x;
+            mPointerGesture.initialPointerY = y;
+        }
+    } else {
+        // Case 5. At least two fingers down, button is not pressed. (SWIPE or FREEFORM
+        // or INDETERMINATE_MULTITOUCH)
+        // Initially we watch and wait for something interesting to happen so as to
+        // avoid making a spurious guess as to the nature of the gesture.  For example,
+        // the fingers may be in transition to some other state such as pressing or
+        // releasing the button or we may be performing a two finger tap.
+        //
+        // Fix the centroid of the figure when the gesture actually starts.
+        // We do not recalculate the centroid at any other time during the gesture because
+        // it would affect the relationship of the touch points relative to the pointer location.
+        assert(activeTouchId >= 0);
+
+        uint32_t currentTouchPointerCount = mCurrentTouch.pointerCount;
+        if (currentTouchPointerCount > MAX_POINTERS) {
+            currentTouchPointerCount = MAX_POINTERS;
+        }
+
+        if (mPointerGesture.lastGestureMode != PointerGesture::INDETERMINATE_MULTITOUCH
+                && mPointerGesture.lastGestureMode != PointerGesture::SWIPE
+                && mPointerGesture.lastGestureMode != PointerGesture::FREEFORM) {
+            mPointerGesture.currentGestureMode = PointerGesture::INDETERMINATE_MULTITOUCH;
+
+            *outFinishPreviousGesture = true;
+            mPointerGesture.activeGestureId = -1;
+
+            // Remember the initial pointer location.
+            // Everything we do will be relative to this location.
+            mPointerController->getPosition(&mPointerGesture.initialPointerX,
+                    &mPointerGesture.initialPointerY);
+
+            // Track taps.
+            if (mLastTouch.pointerCount == 0 && mCurrentTouch.pointerCount != 0) {
+                mPointerGesture.tapTime = when;
+            }
+
+            // Reset the touch origin to be relative to exactly where the fingers are now
+            // in case they have moved some distance away as part of a previous gesture.
+            // We want to know how far the fingers have traveled since we started considering
+            // a multitouch gesture.
+            mPointerGesture.touchOrigin.copyFrom(mCurrentTouch);
+        } else {
+            mPointerGesture.currentGestureMode = mPointerGesture.lastGestureMode;
+        }
+
+        if (mPointerGesture.currentGestureMode == PointerGesture::INDETERMINATE_MULTITOUCH) {
+            // Wait for the pointers to start moving before doing anything.
+            bool decideNow = true;
+            for (uint32_t i = 0; i < currentTouchPointerCount; i++) {
+                const PointerData& current = mCurrentTouch.pointers[i];
+                const PointerData& origin = mPointerGesture.touchOrigin.pointers[
+                        mPointerGesture.touchOrigin.idToIndex[current.id]];
+                float distance = pythag(
+                        (current.x - origin.x) * mLocked.pointerGestureXZoomScale,
+                        (current.y - origin.y) * mLocked.pointerGestureYZoomScale);
+                if (distance < MULTITOUCH_MIN_TRAVEL) {
+                    decideNow = false;
+                    break;
+                }
+            }
+
+            if (decideNow) {
+                mPointerGesture.currentGestureMode = PointerGesture::FREEFORM;
+                if (currentTouchPointerCount == 2
+                        && distanceSquared(
+                                mCurrentTouch.pointers[0].x, mCurrentTouch.pointers[0].y,
+                                mCurrentTouch.pointers[1].x, mCurrentTouch.pointers[1].y)
+                                <= mLocked.pointerGestureMaxSwipeWidthSquared) {
+                    const PointerData& current1 = mCurrentTouch.pointers[0];
+                    const PointerData& current2 = mCurrentTouch.pointers[1];
+                    const PointerData& origin1 = mPointerGesture.touchOrigin.pointers[
+                            mPointerGesture.touchOrigin.idToIndex[current1.id]];
+                    const PointerData& origin2 = mPointerGesture.touchOrigin.pointers[
+                            mPointerGesture.touchOrigin.idToIndex[current2.id]];
+
+                    float x1 = (current1.x - origin1.x) * mLocked.pointerGestureXZoomScale;
+                    float y1 = (current1.y - origin1.y) * mLocked.pointerGestureYZoomScale;
+                    float x2 = (current2.x - origin2.x) * mLocked.pointerGestureXZoomScale;
+                    float y2 = (current2.y - origin2.y) * mLocked.pointerGestureYZoomScale;
+                    float magnitude1 = pythag(x1, y1);
+                    float magnitude2 = pythag(x2, y2);
+
+                    // Calculate the dot product of the vectors.
+                    // When the vectors are oriented in approximately the same direction,
+                    // the angle betweeen them is near zero and the cosine of the angle
+                    // approches 1.0.  Recall that dot(v1, v2) = cos(angle) * mag(v1) * mag(v2).
+                    // We know that the magnitude is at least MULTITOUCH_MIN_TRAVEL because
+                    // we checked it above.
+                    float dot = x1 * x2 + y1 * y2;
+                    float cosine = dot / (magnitude1 * magnitude2); // denominator always > 0
+                    if (cosine > SWIPE_TRANSITION_ANGLE_COSINE) {
+                        mPointerGesture.currentGestureMode = PointerGesture::SWIPE;
+                    }
+                }
+
+                // Remember the initial centroid for the duration of the gesture.
+                mPointerGesture.initialCentroidX = 0;
+                mPointerGesture.initialCentroidY = 0;
+                for (uint32_t i = 0; i < currentTouchPointerCount; i++) {
+                    const PointerData& touch = mCurrentTouch.pointers[i];
+                    mPointerGesture.initialCentroidX += touch.x;
+                    mPointerGesture.initialCentroidY += touch.y;
+                }
+                mPointerGesture.initialCentroidX /= int32_t(currentTouchPointerCount);
+                mPointerGesture.initialCentroidY /= int32_t(currentTouchPointerCount);
+
+                mPointerGesture.activeGestureId = 0;
+            }
+        } else if (mPointerGesture.currentGestureMode == PointerGesture::SWIPE) {
+            // Switch to FREEFORM if additional pointers go down.
+            if (currentTouchPointerCount > 2) {
+                *outCancelPreviousGesture = true;
+                mPointerGesture.currentGestureMode = PointerGesture::FREEFORM;
             }
         }
 
-        xPrecision = mLocked.orientedXPrecision;
-        yPrecision = mLocked.orientedYPrecision;
+        if (mPointerGesture.currentGestureMode == PointerGesture::SWIPE) {
+            // SWIPE mode.
+#if DEBUG_GESTURES
+            LOGD("Gestures: SWIPE activeTouchId=%d,"
+                    "activeGestureId=%d, currentTouchPointerCount=%d",
+                    activeTouchId, mPointerGesture.activeGestureId, currentTouchPointerCount);
+#endif
+            assert(mPointerGesture.activeGestureId >= 0);
+
+            float x = (mCurrentTouch.pointers[0].x + mCurrentTouch.pointers[1].x
+                    - mPointerGesture.initialCentroidX * 2) * 0.5f
+                    * mLocked.pointerGestureXMovementScale + mPointerGesture.initialPointerX;
+            float y = (mCurrentTouch.pointers[0].y + mCurrentTouch.pointers[1].y
+                    - mPointerGesture.initialCentroidY * 2) * 0.5f
+                    * mLocked.pointerGestureYMovementScale + mPointerGesture.initialPointerY;
+
+            mPointerGesture.currentGesturePointerCount = 1;
+            mPointerGesture.currentGestureIdBits.clear();
+            mPointerGesture.currentGestureIdBits.markBit(mPointerGesture.activeGestureId);
+            mPointerGesture.currentGestureIdToIndex[mPointerGesture.activeGestureId] = 0;
+            mPointerGesture.currentGestureCoords[0].clear();
+            mPointerGesture.currentGestureCoords[0].setAxisValue(AMOTION_EVENT_AXIS_X, x);
+            mPointerGesture.currentGestureCoords[0].setAxisValue(AMOTION_EVENT_AXIS_Y, y);
+            mPointerGesture.currentGestureCoords[0].setAxisValue(AMOTION_EVENT_AXIS_PRESSURE, 1.0f);
+        } else if (mPointerGesture.currentGestureMode == PointerGesture::FREEFORM) {
+            // FREEFORM mode.
+#if DEBUG_GESTURES
+            LOGD("Gestures: FREEFORM activeTouchId=%d,"
+                    "activeGestureId=%d, currentTouchPointerCount=%d",
+                    activeTouchId, mPointerGesture.activeGestureId, currentTouchPointerCount);
+#endif
+            assert(mPointerGesture.activeGestureId >= 0);
+
+            mPointerGesture.currentGesturePointerCount = currentTouchPointerCount;
+            mPointerGesture.currentGestureIdBits.clear();
+
+            BitSet32 mappedTouchIdBits;
+            BitSet32 usedGestureIdBits;
+            if (mPointerGesture.lastGestureMode != PointerGesture::FREEFORM) {
+                // Initially, assign the active gesture id to the active touch point
+                // if there is one.  No other touch id bits are mapped yet.
+                if (!*outCancelPreviousGesture) {
+                    mappedTouchIdBits.markBit(activeTouchId);
+                    usedGestureIdBits.markBit(mPointerGesture.activeGestureId);
+                    mPointerGesture.freeformTouchToGestureIdMap[activeTouchId] =
+                            mPointerGesture.activeGestureId;
+                } else {
+                    mPointerGesture.activeGestureId = -1;
+                }
+            } else {
+                // Otherwise, assume we mapped all touches from the previous frame.
+                // Reuse all mappings that are still applicable.
+                mappedTouchIdBits.value = mLastTouch.idBits.value & mCurrentTouch.idBits.value;
+                usedGestureIdBits = mPointerGesture.lastGestureIdBits;
+
+                // Check whether we need to choose a new active gesture id because the
+                // current went went up.
+                for (BitSet32 upTouchIdBits(mLastTouch.idBits.value & ~mCurrentTouch.idBits.value);
+                        !upTouchIdBits.isEmpty(); ) {
+                    uint32_t upTouchId = upTouchIdBits.firstMarkedBit();
+                    upTouchIdBits.clearBit(upTouchId);
+                    uint32_t upGestureId = mPointerGesture.freeformTouchToGestureIdMap[upTouchId];
+                    if (upGestureId == uint32_t(mPointerGesture.activeGestureId)) {
+                        mPointerGesture.activeGestureId = -1;
+                        break;
+                    }
+                }
+            }
+
+#if DEBUG_GESTURES
+            LOGD("Gestures: FREEFORM follow up "
+                    "mappedTouchIdBits=0x%08x, usedGestureIdBits=0x%08x, "
+                    "activeGestureId=%d",
+                    mappedTouchIdBits.value, usedGestureIdBits.value,
+                    mPointerGesture.activeGestureId);
+#endif
+
+            for (uint32_t i = 0; i < currentTouchPointerCount; i++) {
+                uint32_t touchId = mCurrentTouch.pointers[i].id;
+                uint32_t gestureId;
+                if (!mappedTouchIdBits.hasBit(touchId)) {
+                    gestureId = usedGestureIdBits.firstUnmarkedBit();
+                    usedGestureIdBits.markBit(gestureId);
+                    mPointerGesture.freeformTouchToGestureIdMap[touchId] = gestureId;
+#if DEBUG_GESTURES
+                    LOGD("Gestures: FREEFORM "
+                            "new mapping for touch id %d -> gesture id %d",
+                            touchId, gestureId);
+#endif
+                } else {
+                    gestureId = mPointerGesture.freeformTouchToGestureIdMap[touchId];
+#if DEBUG_GESTURES
+                    LOGD("Gestures: FREEFORM "
+                            "existing mapping for touch id %d -> gesture id %d",
+                            touchId, gestureId);
+#endif
+                }
+                mPointerGesture.currentGestureIdBits.markBit(gestureId);
+                mPointerGesture.currentGestureIdToIndex[gestureId] = i;
+
+                float x = (mCurrentTouch.pointers[i].x - mPointerGesture.initialCentroidX)
+                        * mLocked.pointerGestureXZoomScale + mPointerGesture.initialPointerX;
+                float y = (mCurrentTouch.pointers[i].y - mPointerGesture.initialCentroidY)
+                        * mLocked.pointerGestureYZoomScale + mPointerGesture.initialPointerY;
+
+                mPointerGesture.currentGestureCoords[i].clear();
+                mPointerGesture.currentGestureCoords[i].setAxisValue(
+                        AMOTION_EVENT_AXIS_X, x);
+                mPointerGesture.currentGestureCoords[i].setAxisValue(
+                        AMOTION_EVENT_AXIS_Y, y);
+                mPointerGesture.currentGestureCoords[i].setAxisValue(
+                        AMOTION_EVENT_AXIS_PRESSURE, 1.0f);
+            }
+
+            if (mPointerGesture.activeGestureId < 0) {
+                mPointerGesture.activeGestureId =
+                        mPointerGesture.currentGestureIdBits.firstMarkedBit();
+#if DEBUG_GESTURES
+                LOGD("Gestures: FREEFORM new "
+                        "activeGestureId=%d", mPointerGesture.activeGestureId);
+#endif
+            }
+        } else {
+            // INDETERMINATE_MULTITOUCH mode.
+            // Do nothing.
+#if DEBUG_GESTURES
+            LOGD("Gestures: INDETERMINATE_MULTITOUCH");
+#endif
+        }
+    }
+
+    // Unfade the pointer if the user is doing anything with the touch pad.
+    mPointerController->setButtonState(mCurrentTouch.buttonState);
+    if (mCurrentTouch.buttonState || mCurrentTouch.pointerCount != 0) {
+        mPointerController->unfade();
+    }
+
+#if DEBUG_GESTURES
+    LOGD("Gestures: finishPreviousGesture=%s, cancelPreviousGesture=%s, "
+            "currentGestureMode=%d, currentGesturePointerCount=%d, currentGestureIdBits=0x%08x, "
+            "lastGestureMode=%d, lastGesturePointerCount=%d, lastGestureIdBits=0x%08x",
+            toString(*outFinishPreviousGesture), toString(*outCancelPreviousGesture),
+            mPointerGesture.currentGestureMode, mPointerGesture.currentGesturePointerCount,
+            mPointerGesture.currentGestureIdBits.value,
+            mPointerGesture.lastGestureMode, mPointerGesture.lastGesturePointerCount,
+            mPointerGesture.lastGestureIdBits.value);
+    for (BitSet32 idBits = mPointerGesture.currentGestureIdBits; !idBits.isEmpty(); ) {
+        uint32_t id = idBits.firstMarkedBit();
+        idBits.clearBit(id);
+        uint32_t index = mPointerGesture.currentGestureIdToIndex[id];
+        const PointerCoords& coords = mPointerGesture.currentGestureCoords[index];
+        LOGD("  currentGesture[%d]: index=%d, x=%0.3f, y=%0.3f, pressure=%0.3f",
+                id, index, coords.getAxisValue(AMOTION_EVENT_AXIS_X),
+                coords.getAxisValue(AMOTION_EVENT_AXIS_Y),
+                coords.getAxisValue(AMOTION_EVENT_AXIS_PRESSURE));
+    }
+    for (BitSet32 idBits = mPointerGesture.lastGestureIdBits; !idBits.isEmpty(); ) {
+        uint32_t id = idBits.firstMarkedBit();
+        idBits.clearBit(id);
+        uint32_t index = mPointerGesture.lastGestureIdToIndex[id];
+        const PointerCoords& coords = mPointerGesture.lastGestureCoords[index];
+        LOGD("  lastGesture[%d]: index=%d, x=%0.3f, y=%0.3f, pressure=%0.3f",
+                id, index, coords.getAxisValue(AMOTION_EVENT_AXIS_X),
+                coords.getAxisValue(AMOTION_EVENT_AXIS_Y),
+                coords.getAxisValue(AMOTION_EVENT_AXIS_PRESSURE));
+    }
+#endif
+}
+
+void TouchInputMapper::dispatchMotion(nsecs_t when, uint32_t policyFlags, uint32_t source,
+        int32_t action, int32_t flags, uint32_t metaState, int32_t edgeFlags,
+        const PointerCoords* coords, const uint32_t* idToIndex, BitSet32 idBits,
+        int32_t changedId, float xPrecision, float yPrecision, nsecs_t downTime) {
+    PointerCoords pointerCoords[MAX_POINTERS];
+    int32_t pointerIds[MAX_POINTERS];
+    uint32_t pointerCount = 0;
+    while (!idBits.isEmpty()) {
+        uint32_t id = idBits.firstMarkedBit();
+        idBits.clearBit(id);
+        uint32_t index = idToIndex[id];
+        pointerIds[pointerCount] = id;
+        pointerCoords[pointerCount].copyFrom(coords[index]);
+
+        if (changedId >= 0 && id == uint32_t(changedId)) {
+            action |= pointerCount << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT;
+        }
+
+        pointerCount += 1;
+    }
+
+    assert(pointerCount != 0);
+
+    if (changedId >= 0 && pointerCount == 1) {
+        // Replace initial down and final up action.
+        // We can compare the action without masking off the changed pointer index
+        // because we know the index is 0.
+        if (action == AMOTION_EVENT_ACTION_POINTER_DOWN) {
+            action = AMOTION_EVENT_ACTION_DOWN;
+        } else if (action == AMOTION_EVENT_ACTION_POINTER_UP) {
+            action = AMOTION_EVENT_ACTION_UP;
+        } else {
+            // Can't happen.
+            assert(false);
+        }
+    }
+
+    getDispatcher()->notifyMotion(when, getDeviceId(), source, policyFlags,
+            action, flags, metaState, edgeFlags,
+            pointerCount, pointerIds, pointerCoords, xPrecision, yPrecision, downTime);
+}
+
+bool TouchInputMapper::updateMovedPointerCoords(
+        const PointerCoords* inCoords, const uint32_t* inIdToIndex,
+        PointerCoords* outCoords, const uint32_t* outIdToIndex, BitSet32 idBits) const {
+    bool changed = false;
+    while (!idBits.isEmpty()) {
+        uint32_t id = idBits.firstMarkedBit();
+        idBits.clearBit(id);
+
+        uint32_t inIndex = inIdToIndex[id];
+        uint32_t outIndex = outIdToIndex[id];
+        const PointerCoords& curInCoords = inCoords[inIndex];
+        PointerCoords& curOutCoords = outCoords[outIndex];
+
+        if (curInCoords != curOutCoords) {
+            curOutCoords.copyFrom(curInCoords);
+            changed = true;
+        }
+    }
+    return changed;
+}
+
+void TouchInputMapper::fadePointer() {
+    { // acquire lock
+        AutoMutex _l(mLock);
+        if (mPointerController != NULL) {
+            mPointerController->fade();
+        }
     } // release lock
-
-    getDispatcher()->notifyMotion(when, getDeviceId(), mSources, policyFlags,
-            motionEventAction, 0, getContext()->getGlobalMetaState(), motionEventEdgeFlags,
-            pointerCount, pointerIds, pointerCoords,
-            xPrecision, yPrecision, mDownTime);
 }
 
 bool TouchInputMapper::isPointInsideSurfaceLocked(int32_t x, int32_t y) {
@@ -3516,6 +4575,7 @@
     mY = 0;
     mPressure = 0; // default to 0 for devices that don't report pressure
     mToolWidth = 0; // default to 0 for devices that don't report tool width
+    mButtonState = 0;
 }
 
 void SingleTouchInputMapper::reset() {
@@ -3535,6 +4595,19 @@
             // not have received valid position information yet.  This logic assumes that
             // BTN_TOUCH is always followed by SYN_REPORT as part of a complete packet.
             break;
+        default:
+            if (mParameters.deviceType == Parameters::DEVICE_TYPE_POINTER) {
+                uint32_t buttonState = getButtonStateForScanCode(rawEvent->scanCode);
+                if (buttonState) {
+                    if (rawEvent->value) {
+                        mAccumulator.buttonDown |= buttonState;
+                    } else {
+                        mAccumulator.buttonUp |= buttonState;
+                    }
+                    mAccumulator.fields |= Accumulator::FIELD_BUTTONS;
+                }
+            }
+            break;
         }
         break;
 
@@ -3595,6 +4668,10 @@
         mToolWidth = mAccumulator.absToolWidth;
     }
 
+    if (fields & Accumulator::FIELD_BUTTONS) {
+        mButtonState = (mButtonState | mAccumulator.buttonDown) & ~mAccumulator.buttonUp;
+    }
+
     mCurrentTouch.clear();
 
     if (mDown) {
@@ -3610,6 +4687,7 @@
         mCurrentTouch.pointers[0].orientation = 0;
         mCurrentTouch.idToIndex[0] = 0;
         mCurrentTouch.idBits.markBit(0);
+        mCurrentTouch.buttonState = mButtonState;
     }
 
     syncTouch(when, true);
@@ -3639,6 +4717,7 @@
 
 void MultiTouchInputMapper::initialize() {
     mAccumulator.clear();
+    mButtonState = 0;
 }
 
 void MultiTouchInputMapper::reset() {
@@ -3649,6 +4728,20 @@
 
 void MultiTouchInputMapper::process(const RawEvent* rawEvent) {
     switch (rawEvent->type) {
+    case EV_KEY: {
+        if (mParameters.deviceType == Parameters::DEVICE_TYPE_POINTER) {
+            uint32_t buttonState = getButtonStateForScanCode(rawEvent->scanCode);
+            if (buttonState) {
+                if (rawEvent->value) {
+                    mAccumulator.buttonDown |= buttonState;
+                } else {
+                    mAccumulator.buttonUp |= buttonState;
+                }
+            }
+        }
+        break;
+    }
+
     case EV_ABS: {
         uint32_t pointerIndex = mAccumulator.pointerCount;
         Accumulator::Pointer* pointer = & mAccumulator.pointers[pointerIndex];
@@ -3826,6 +4919,9 @@
 
     mCurrentTouch.pointerCount = outCount;
 
+    mButtonState = (mButtonState | mAccumulator.buttonDown) & ~mAccumulator.buttonUp;
+    mCurrentTouch.buttonState = mButtonState;
+
     syncTouch(when, havePointerIds);
 
     mAccumulator.clear();
@@ -3863,7 +4959,12 @@
 
     for (size_t i = 0; i < mAxes.size(); i++) {
         const Axis& axis = mAxes.valueAt(i);
-        info->addMotionRange(axis.axis, axis.min, axis.max, axis.flat, axis.fuzz);
+        info->addMotionRange(axis.axisInfo.axis, AINPUT_SOURCE_JOYSTICK,
+                axis.min, axis.max, axis.flat, axis.fuzz);
+        if (axis.axisInfo.mode == AxisInfo::MODE_SPLIT) {
+            info->addMotionRange(axis.axisInfo.highAxis, AINPUT_SOURCE_JOYSTICK,
+                    axis.min, axis.max, axis.flat, axis.fuzz);
+        }
     }
 }
 
@@ -3874,18 +4975,29 @@
     size_t numAxes = mAxes.size();
     for (size_t i = 0; i < numAxes; i++) {
         const Axis& axis = mAxes.valueAt(i);
-        const char* label = getAxisLabel(axis.axis);
-        char name[32];
+        const char* label = getAxisLabel(axis.axisInfo.axis);
         if (label) {
-            strncpy(name, label, sizeof(name));
-            name[sizeof(name) - 1] = '\0';
+            dump.appendFormat(INDENT4 "%s", label);
         } else {
-            snprintf(name, sizeof(name), "%d", axis.axis);
+            dump.appendFormat(INDENT4 "%d", axis.axisInfo.axis);
         }
-        dump.appendFormat(INDENT4 "%s: min=%0.3f, max=%0.3f, flat=%0.3f, fuzz=%0.3f, "
-                "scale=%0.3f, offset=%0.3f\n",
-                name, axis.min, axis.max, axis.flat, axis.fuzz,
-                axis.scale, axis.offset);
+        if (axis.axisInfo.mode == AxisInfo::MODE_SPLIT) {
+            label = getAxisLabel(axis.axisInfo.highAxis);
+            if (label) {
+                dump.appendFormat(" / %s (split at %d)", label, axis.axisInfo.splitValue);
+            } else {
+                dump.appendFormat(" / %d (split at %d)", axis.axisInfo.highAxis,
+                        axis.axisInfo.splitValue);
+            }
+        } else if (axis.axisInfo.mode == AxisInfo::MODE_INVERT) {
+            dump.append(" (invert)");
+        }
+
+        dump.appendFormat(": min=%0.5f, max=%0.5f, flat=%0.5f, fuzz=%0.5f\n",
+                axis.min, axis.max, axis.flat, axis.fuzz);
+        dump.appendFormat(INDENT4 "  scale=%0.5f, offset=%0.5f, "
+                "highScale=%0.5f, highOffset=%0.5f\n",
+                axis.scale, axis.offset, axis.highScale, axis.highOffset);
         dump.appendFormat(INDENT4 "  rawAxis=%d, rawMin=%d, rawMax=%d, rawFlat=%d, rawFuzz=%d\n",
                 mAxes.keyAt(i), axis.rawAxisInfo.minValue, axis.rawAxisInfo.maxValue,
                 axis.rawAxisInfo.flat, axis.rawAxisInfo.fuzz);
@@ -3900,25 +5012,38 @@
         RawAbsoluteAxisInfo rawAxisInfo;
         getEventHub()->getAbsoluteAxisInfo(getDeviceId(), abs, &rawAxisInfo);
         if (rawAxisInfo.valid) {
-            int32_t axisId;
-            bool explicitlyMapped = !getEventHub()->mapAxis(getDeviceId(), abs, &axisId);
+            // Map axis.
+            AxisInfo axisInfo;
+            bool explicitlyMapped = !getEventHub()->mapAxis(getDeviceId(), abs, &axisInfo);
             if (!explicitlyMapped) {
                 // Axis is not explicitly mapped, will choose a generic axis later.
-                axisId = -1;
+                axisInfo.mode = AxisInfo::MODE_NORMAL;
+                axisInfo.axis = -1;
             }
 
+            // Apply flat override.
+            int32_t rawFlat = axisInfo.flatOverride < 0
+                    ? rawAxisInfo.flat : axisInfo.flatOverride;
+
+            // Calculate scaling factors and limits.
             Axis axis;
-            if (isCenteredAxis(axisId)) {
+            if (axisInfo.mode == AxisInfo::MODE_SPLIT) {
+                float scale = 1.0f / (axisInfo.splitValue - rawAxisInfo.minValue);
+                float highScale = 1.0f / (rawAxisInfo.maxValue - axisInfo.splitValue);
+                axis.initialize(rawAxisInfo, axisInfo, explicitlyMapped,
+                        scale, 0.0f, highScale, 0.0f,
+                        0.0f, 1.0f, rawFlat * scale, rawAxisInfo.fuzz * scale);
+            } else if (isCenteredAxis(axisInfo.axis)) {
                 float scale = 2.0f / (rawAxisInfo.maxValue - rawAxisInfo.minValue);
                 float offset = avg(rawAxisInfo.minValue, rawAxisInfo.maxValue) * -scale;
-                axis.initialize(rawAxisInfo, axisId, explicitlyMapped,
-                        scale, offset, -1.0f, 1.0f,
-                        rawAxisInfo.flat * scale, rawAxisInfo.fuzz * scale);
+                axis.initialize(rawAxisInfo, axisInfo, explicitlyMapped,
+                        scale, offset, scale, offset,
+                        -1.0f, 1.0f, rawFlat * scale, rawAxisInfo.fuzz * scale);
             } else {
                 float scale = 1.0f / (rawAxisInfo.maxValue - rawAxisInfo.minValue);
-                axis.initialize(rawAxisInfo, axisId, explicitlyMapped,
-                        scale, 0.0f, 0.0f, 1.0f,
-                        rawAxisInfo.flat * scale, rawAxisInfo.fuzz * scale);
+                axis.initialize(rawAxisInfo, axisInfo, explicitlyMapped,
+                        scale, 0.0f, scale, 0.0f,
+                        0.0f, 1.0f, rawFlat * scale, rawAxisInfo.fuzz * scale);
             }
 
             // To eliminate noise while the joystick is at rest, filter out small variations
@@ -3943,14 +5068,14 @@
     size_t numAxes = mAxes.size();
     for (size_t i = 0; i < numAxes; i++) {
         Axis& axis = mAxes.editValueAt(i);
-        if (axis.axis < 0) {
+        if (axis.axisInfo.axis < 0) {
             while (nextGenericAxisId <= AMOTION_EVENT_AXIS_GENERIC_16
                     && haveAxis(nextGenericAxisId)) {
                 nextGenericAxisId += 1;
             }
 
             if (nextGenericAxisId <= AMOTION_EVENT_AXIS_GENERIC_16) {
-                axis.axis = nextGenericAxisId;
+                axis.axisInfo.axis = nextGenericAxisId;
                 nextGenericAxisId += 1;
             } else {
                 LOGI("Ignoring joystick '%s' axis %d because all of the generic axis ids "
@@ -3963,10 +5088,13 @@
     }
 }
 
-bool JoystickInputMapper::haveAxis(int32_t axis) {
+bool JoystickInputMapper::haveAxis(int32_t axisId) {
     size_t numAxes = mAxes.size();
     for (size_t i = 0; i < numAxes; i++) {
-        if (mAxes.valueAt(i).axis == axis) {
+        const Axis& axis = mAxes.valueAt(i);
+        if (axis.axisInfo.axis == axisId
+                || (axis.axisInfo.mode == AxisInfo::MODE_SPLIT
+                        && axis.axisInfo.highAxis == axisId)) {
             return true;
         }
     }
@@ -3996,6 +5124,8 @@
     case AMOTION_EVENT_AXIS_HAT_X:
     case AMOTION_EVENT_AXIS_HAT_Y:
     case AMOTION_EVENT_AXIS_ORIENTATION:
+    case AMOTION_EVENT_AXIS_RUDDER:
+    case AMOTION_EVENT_AXIS_WHEEL:
         return true;
     default:
         return false;
@@ -4009,7 +5139,7 @@
     size_t numAxes = mAxes.size();
     for (size_t i = 0; i < numAxes; i++) {
         Axis& axis = mAxes.editValueAt(i);
-        axis.newValue = 0;
+        axis.resetValue();
     }
 
     sync(when, true /*force*/);
@@ -4023,10 +5153,34 @@
         ssize_t index = mAxes.indexOfKey(rawEvent->scanCode);
         if (index >= 0) {
             Axis& axis = mAxes.editValueAt(index);
-            float newValue = rawEvent->value * axis.scale + axis.offset;
-            if (newValue != axis.newValue) {
-                axis.newValue = newValue;
+            float newValue, highNewValue;
+            switch (axis.axisInfo.mode) {
+            case AxisInfo::MODE_INVERT:
+                newValue = (axis.rawAxisInfo.maxValue - rawEvent->value)
+                        * axis.scale + axis.offset;
+                highNewValue = 0.0f;
+                break;
+            case AxisInfo::MODE_SPLIT:
+                if (rawEvent->value < axis.axisInfo.splitValue) {
+                    newValue = (axis.axisInfo.splitValue - rawEvent->value)
+                            * axis.scale + axis.offset;
+                    highNewValue = 0.0f;
+                } else if (rawEvent->value > axis.axisInfo.splitValue) {
+                    newValue = 0.0f;
+                    highNewValue = (rawEvent->value - axis.axisInfo.splitValue)
+                            * axis.highScale + axis.highOffset;
+                } else {
+                    newValue = 0.0f;
+                    highNewValue = 0.0f;
+                }
+                break;
+            default:
+                newValue = rawEvent->value * axis.scale + axis.offset;
+                highNewValue = 0.0f;
+                break;
             }
+            axis.newValue = newValue;
+            axis.highNewValue = highNewValue;
         }
         break;
     }
@@ -4042,7 +5196,7 @@
 }
 
 void JoystickInputMapper::sync(nsecs_t when, bool force) {
-    if (!force && !haveAxesChangedSignificantly()) {
+    if (!filterAxes(force)) {
         return;
     }
 
@@ -4053,9 +5207,11 @@
 
     size_t numAxes = mAxes.size();
     for (size_t i = 0; i < numAxes; i++) {
-        Axis& axis = mAxes.editValueAt(i);
-        pointerCoords.setAxisValue(axis.axis, axis.newValue);
-        axis.oldValue = axis.newValue;
+        const Axis& axis = mAxes.valueAt(i);
+        pointerCoords.setAxisValue(axis.axisInfo.axis, axis.currentValue);
+        if (axis.axisInfo.mode == AxisInfo::MODE_SPLIT) {
+            pointerCoords.setAxisValue(axis.axisInfo.highAxis, axis.highCurrentValue);
+        }
     }
 
     // Moving a joystick axis should not wake the devide because joysticks can
@@ -4070,12 +5226,49 @@
             1, &pointerId, &pointerCoords, 0, 0, 0);
 }
 
-bool JoystickInputMapper::haveAxesChangedSignificantly() {
+bool JoystickInputMapper::filterAxes(bool force) {
+    bool atLeastOneSignificantChange = force;
     size_t numAxes = mAxes.size();
     for (size_t i = 0; i < numAxes; i++) {
-        const Axis& axis = mAxes.valueAt(i);
-        if (axis.newValue != axis.oldValue
-                && fabs(axis.newValue - axis.oldValue) > axis.filter) {
+        Axis& axis = mAxes.editValueAt(i);
+        if (force || hasValueChangedSignificantly(axis.filter,
+                axis.newValue, axis.currentValue, axis.min, axis.max)) {
+            axis.currentValue = axis.newValue;
+            atLeastOneSignificantChange = true;
+        }
+        if (axis.axisInfo.mode == AxisInfo::MODE_SPLIT) {
+            if (force || hasValueChangedSignificantly(axis.filter,
+                    axis.highNewValue, axis.highCurrentValue, axis.min, axis.max)) {
+                axis.highCurrentValue = axis.highNewValue;
+                atLeastOneSignificantChange = true;
+            }
+        }
+    }
+    return atLeastOneSignificantChange;
+}
+
+bool JoystickInputMapper::hasValueChangedSignificantly(
+        float filter, float newValue, float currentValue, float min, float max) {
+    if (newValue != currentValue) {
+        // Filter out small changes in value unless the value is converging on the axis
+        // bounds or center point.  This is intended to reduce the amount of information
+        // sent to applications by particularly noisy joysticks (such as PS3).
+        if (fabs(newValue - currentValue) > filter
+                || hasMovedNearerToValueWithinFilteredRange(filter, newValue, currentValue, min)
+                || hasMovedNearerToValueWithinFilteredRange(filter, newValue, currentValue, max)
+                || hasMovedNearerToValueWithinFilteredRange(filter, newValue, currentValue, 0)) {
+            return true;
+        }
+    }
+    return false;
+}
+
+bool JoystickInputMapper::hasMovedNearerToValueWithinFilteredRange(
+        float filter, float newValue, float currentValue, float thresholdValue) {
+    float newDistance = fabs(newValue - thresholdValue);
+    if (newDistance < filter) {
+        float oldDistance = fabs(currentValue - thresholdValue);
+        if (newDistance < oldDistance) {
             return true;
         }
     }
diff --git a/services/input/InputReader.h b/services/input/InputReader.h
index 9b79690..cf9b13d 100644
--- a/services/input/InputReader.h
+++ b/services/input/InputReader.h
@@ -159,6 +159,8 @@
 
     virtual void fadePointer() = 0;
 
+    virtual void requestTimeoutAtTime(nsecs_t when) = 0;
+
     virtual InputReaderPolicyInterface* getPolicy() = 0;
     virtual InputDispatcherInterface* getDispatcher() = 0;
     virtual EventHubInterface* getEventHub() = 0;
@@ -214,6 +216,10 @@
     virtual InputDispatcherInterface* getDispatcher() { return mDispatcher.get(); }
     virtual EventHubInterface* getEventHub() { return mEventHub.get(); }
 
+    // The event queue.
+    static const int EVENT_BUFFER_SIZE = 256;
+    RawEvent mEventBuffer[EVENT_BUFFER_SIZE];
+
     // This reader/writer lock guards the list of input devices.
     // The writer lock must be held whenever the list of input devices is modified
     //   and then promptly released.
@@ -226,15 +232,15 @@
     KeyedVector<int32_t, InputDevice*> mDevices;
 
     // low-level input event decoding and device management
-    void process(const RawEvent* rawEvent);
+    void processEvents(const RawEvent* rawEvents, size_t count);
 
     void addDevice(int32_t deviceId);
     void removeDevice(int32_t deviceId);
-    void configureExcludedDevices();
-
-    void consumeEvent(const RawEvent* rawEvent);
+    void processEventsForDevice(int32_t deviceId, const RawEvent* rawEvents, size_t count);
+    void timeoutExpired(nsecs_t when);
 
     void handleConfigurationChanged(nsecs_t when);
+    void configureExcludedDevices();
 
     // state management for all devices
     Mutex mStateLock;
@@ -248,11 +254,14 @@
     InputConfiguration mInputConfiguration;
     void updateInputConfiguration();
 
-    nsecs_t mDisableVirtualKeysTimeout;
+    nsecs_t mDisableVirtualKeysTimeout; // only accessed by reader thread
     virtual void disableVirtualKeysUntil(nsecs_t time);
     virtual bool shouldDropVirtualKey(nsecs_t now,
             InputDevice* device, int32_t keyCode, int32_t scanCode);
 
+    nsecs_t mNextTimeout; // only accessed by reader thread
+    virtual void requestTimeoutAtTime(nsecs_t when);
+
     // state queries
     typedef int32_t (InputDevice::*GetStateFunc)(uint32_t sourceMask, int32_t code);
     int32_t getState(int32_t deviceId, uint32_t sourceMask, int32_t code,
@@ -295,7 +304,8 @@
     void addMapper(InputMapper* mapper);
     void configure();
     void reset();
-    void process(const RawEvent* rawEvent);
+    void process(const RawEvent* rawEvents, size_t count);
+    void timeoutExpired(nsecs_t when);
 
     void getDeviceInfo(InputDeviceInfo* outDeviceInfo);
     int32_t getKeyCodeState(uint32_t sourceMask, int32_t keyCode);
@@ -352,6 +362,7 @@
     virtual void configure();
     virtual void reset();
     virtual void process(const RawEvent* rawEvent) = 0;
+    virtual void timeoutExpired(nsecs_t when);
 
     virtual int32_t getKeyCodeState(uint32_t sourceMask, int32_t keyCode);
     virtual int32_t getScanCodeState(uint32_t sourceMask, int32_t scanCode);
@@ -389,7 +400,7 @@
 
 class KeyboardInputMapper : public InputMapper {
 public:
-    KeyboardInputMapper(InputDevice* device, uint32_t sources, int32_t keyboardType);
+    KeyboardInputMapper(InputDevice* device, uint32_t source, int32_t keyboardType);
     virtual ~KeyboardInputMapper();
 
     virtual uint32_t getSources();
@@ -414,7 +425,7 @@
         int32_t scanCode;
     };
 
-    uint32_t mSources;
+    uint32_t mSource;
     int32_t mKeyboardType;
 
     // Immutable configuration parameters.
@@ -493,7 +504,7 @@
 
     struct Accumulator {
         enum {
-            FIELD_BTN_MOUSE = 1,
+            FIELD_BUTTONS = 1,
             FIELD_REL_X = 2,
             FIELD_REL_Y = 4,
             FIELD_REL_WHEEL = 8,
@@ -502,7 +513,9 @@
 
         uint32_t fields;
 
-        bool btnMouse;
+        uint32_t buttonDown;
+        uint32_t buttonUp;
+
         int32_t relX;
         int32_t relY;
         int32_t relWheel;
@@ -513,7 +526,7 @@
         }
     } mAccumulator;
 
-    int32_t mSources;
+    int32_t mSource;
     float mXScale;
     float mYScale;
     float mXPrecision;
@@ -527,7 +540,7 @@
     sp<PointerControllerInterface> mPointerController;
 
     struct LockedState {
-        bool down;
+        uint32_t buttonState;
         nsecs_t downTime;
     } mLocked;
 
@@ -556,6 +569,8 @@
     virtual bool markSupportedKeyCodes(uint32_t sourceMask, size_t numCodes,
             const int32_t* keyCodes, uint8_t* outFlags);
 
+    virtual void fadePointer();
+
 protected:
     Mutex mLock;
 
@@ -609,10 +624,12 @@
         PointerData pointers[MAX_POINTERS];
         BitSet32 idBits;
         uint32_t idToIndex[MAX_POINTER_ID + 1];
+        uint32_t buttonState;
 
         void copyFrom(const TouchData& other) {
             pointerCount = other.pointerCount;
             idBits = other.idBits;
+            buttonState = other.buttonState;
 
             for (uint32_t i = 0; i < pointerCount; i++) {
                 pointers[i] = other.pointers[i];
@@ -625,17 +642,20 @@
         inline void clear() {
             pointerCount = 0;
             idBits.clear();
+            buttonState = 0;
         }
     };
 
     // Input sources supported by the device.
-    int32_t mSources;
+    uint32_t mTouchSource; // sources when reporting touch data
+    uint32_t mPointerSource; // sources when reporting pointer gestures
 
     // Immutable configuration parameters.
     struct Parameters {
         enum DeviceType {
             DEVICE_TYPE_TOUCH_SCREEN,
             DEVICE_TYPE_TOUCH_PAD,
+            DEVICE_TYPE_POINTER,
         };
 
         DeviceType deviceType;
@@ -733,11 +753,17 @@
 
     // Current and previous touch sample data.
     TouchData mCurrentTouch;
+    PointerCoords mCurrentTouchCoords[MAX_POINTERS];
+
     TouchData mLastTouch;
+    PointerCoords mLastTouchCoords[MAX_POINTERS];
 
     // The time the primary pointer last went down.
     nsecs_t mDownTime;
 
+    // The pointer controller, or null if the device is not a pointer.
+    sp<PointerControllerInterface> mPointerController;
+
     struct LockedState {
         Vector<VirtualKey> virtualKeys;
 
@@ -745,6 +771,10 @@
         int32_t surfaceOrientation;
         int32_t surfaceWidth, surfaceHeight;
 
+        // The associated display orientation and width and height set by configureSurfaceLocked().
+        int32_t associatedDisplayOrientation;
+        int32_t associatedDisplayWidth, associatedDisplayHeight;
+
         // Translation and scaling factors, orientation-independent.
         float xScale;
         float xPrecision;
@@ -798,6 +828,17 @@
             int32_t keyCode;
             int32_t scanCode;
         } currentVirtualKey;
+
+        // Scale factor for gesture based pointer movements.
+        float pointerGestureXMovementScale;
+        float pointerGestureYMovementScale;
+
+        // Scale factor for gesture based zooming and other freeform motions.
+        float pointerGestureXZoomScale;
+        float pointerGestureYZoomScale;
+
+        // The maximum swipe width squared.
+        int32_t pointerGestureMaxSwipeWidthSquared;
     } mLocked;
 
     virtual void configureParameters();
@@ -863,14 +904,149 @@
         uint64_t distance : 48; // squared distance
     };
 
+    struct PointerGesture {
+        enum Mode {
+            // No fingers, button is not pressed.
+            // Nothing happening.
+            NEUTRAL,
+
+            // No fingers, button is not pressed.
+            // Tap detected.
+            // Emits DOWN and UP events at the pointer location.
+            TAP,
+
+            // Button is pressed.
+            // Pointer follows the active finger if there is one.  Other fingers are ignored.
+            // Emits DOWN, MOVE and UP events at the pointer location.
+            CLICK_OR_DRAG,
+
+            // Exactly one finger, button is not pressed.
+            // Pointer follows the active finger.
+            // Emits HOVER_MOVE events at the pointer location.
+            HOVER,
+
+            // More than two fingers involved but they haven't moved enough for us
+            // to figure out what is intended.
+            INDETERMINATE_MULTITOUCH,
+
+            // Exactly two fingers moving in the same direction, button is not pressed.
+            // Pointer does not move.
+            // Emits DOWN, MOVE and UP events with a single pointer coordinate that
+            // follows the midpoint between both fingers.
+            // The centroid is fixed when entering this state.
+            SWIPE,
+
+            // Two or more fingers moving in arbitrary directions, button is not pressed.
+            // Pointer does not move.
+            // Emits DOWN, POINTER_DOWN, MOVE, POINTER_UP and UP events that follow
+            // each finger individually relative to the initial centroid of the finger.
+            // The centroid is fixed when entering this state.
+            FREEFORM,
+
+            // Waiting for quiet time to end before starting the next gesture.
+            QUIET,
+        };
+
+        // The active pointer id from the raw touch data.
+        int32_t activeTouchId; // -1 if none
+
+        // The active pointer id from the gesture last delivered to the application.
+        int32_t activeGestureId; // -1 if none
+
+        // Pointer coords and ids for the current and previous pointer gesture.
+        Mode currentGestureMode;
+        uint32_t currentGesturePointerCount;
+        BitSet32 currentGestureIdBits;
+        uint32_t currentGestureIdToIndex[MAX_POINTER_ID + 1];
+        PointerCoords currentGestureCoords[MAX_POINTERS];
+
+        Mode lastGestureMode;
+        uint32_t lastGesturePointerCount;
+        BitSet32 lastGestureIdBits;
+        uint32_t lastGestureIdToIndex[MAX_POINTER_ID + 1];
+        PointerCoords lastGestureCoords[MAX_POINTERS];
+
+        // Tracks for all pointers originally went down.
+        TouchData touchOrigin;
+
+        // Describes how touch ids are mapped to gesture ids for freeform gestures.
+        uint32_t freeformTouchToGestureIdMap[MAX_POINTER_ID + 1];
+
+        // Initial centroid of the movement.
+        // Used to calculate how far the touch pointers have moved since the gesture started.
+        int32_t initialCentroidX;
+        int32_t initialCentroidY;
+
+        // Initial pointer location.
+        // Used to track where the pointer was when the gesture started.
+        float initialPointerX;
+        float initialPointerY;
+
+        // Time the pointer gesture last went down.
+        nsecs_t downTime;
+
+        // Time we started waiting for a tap gesture.
+        nsecs_t tapTime;
+
+        // Time we started waiting for quiescence.
+        nsecs_t quietTime;
+
+        // A velocity tracker for determining whether to switch active pointers during drags.
+        VelocityTracker velocityTracker;
+
+        void reset() {
+            activeTouchId = -1;
+            activeGestureId = -1;
+            currentGestureMode = NEUTRAL;
+            currentGesturePointerCount = 0;
+            currentGestureIdBits.clear();
+            lastGestureMode = NEUTRAL;
+            lastGesturePointerCount = 0;
+            lastGestureIdBits.clear();
+            touchOrigin.clear();
+            initialCentroidX = 0;
+            initialCentroidY = 0;
+            initialPointerX = 0;
+            initialPointerY = 0;
+            downTime = 0;
+            velocityTracker.clear();
+            resetTapTime();
+            resetQuietTime();
+        }
+
+        void resetTapTime() {
+            tapTime = LLONG_MIN;
+        }
+
+        void resetQuietTime() {
+            quietTime = LLONG_MIN;
+        }
+    } mPointerGesture;
+
     void initializeLocked();
 
     TouchResult consumeOffScreenTouches(nsecs_t when, uint32_t policyFlags);
     void dispatchTouches(nsecs_t when, uint32_t policyFlags);
-    void dispatchTouch(nsecs_t when, uint32_t policyFlags, TouchData* touch,
-            BitSet32 idBits, uint32_t changedId, uint32_t pointerCount,
-            int32_t motionEventAction);
-    void detectGestures(nsecs_t when);
+    void prepareTouches(int32_t* outEdgeFlags, float* outXPrecision, float* outYPrecision);
+    void dispatchPointerGestures(nsecs_t when, uint32_t policyFlags);
+    void preparePointerGestures(nsecs_t when,
+            bool* outCancelPreviousGesture, bool* outFinishPreviousGesture);
+
+    // Dispatches a motion event.
+    // If the changedId is >= 0 and the action is POINTER_DOWN or POINTER_UP, the
+    // method will take care of setting the index and transmuting the action to DOWN or UP
+    // it is the first / last pointer to go down / up.
+    void dispatchMotion(nsecs_t when, uint32_t policyFlags, uint32_t source,
+            int32_t action, int32_t flags, uint32_t metaState, int32_t edgeFlags,
+            const PointerCoords* coords, const uint32_t* idToIndex, BitSet32 idBits,
+            int32_t changedId, float xPrecision, float yPrecision, nsecs_t downTime);
+
+    // Updates pointer coords for pointers with specified ids that have moved.
+    // Returns true if any of them changed.
+    bool updateMovedPointerCoords(const PointerCoords* inCoords, const uint32_t* inIdToIndex,
+            PointerCoords* outCoords, const uint32_t* outIdToIndex, BitSet32 idBits) const;
+
+    void suppressSwipeOntoVirtualKeys(nsecs_t when);
 
     bool isPointInsideSurfaceLocked(int32_t x, int32_t y);
     const VirtualKey* findVirtualKeyHitLocked(int32_t x, int32_t y);
@@ -900,7 +1076,8 @@
             FIELD_ABS_X = 2,
             FIELD_ABS_Y = 4,
             FIELD_ABS_PRESSURE = 8,
-            FIELD_ABS_TOOL_WIDTH = 16
+            FIELD_ABS_TOOL_WIDTH = 16,
+            FIELD_BUTTONS = 32,
         };
 
         uint32_t fields;
@@ -911,8 +1088,13 @@
         int32_t absPressure;
         int32_t absToolWidth;
 
+        uint32_t buttonDown;
+        uint32_t buttonUp;
+
         inline void clear() {
             fields = 0;
+            buttonDown = 0;
+            buttonUp = 0;
         }
     } mAccumulator;
 
@@ -921,6 +1103,7 @@
     int32_t mY;
     int32_t mPressure;
     int32_t mToolWidth;
+    uint32_t mButtonState;
 
     void initialize();
 
@@ -972,12 +1155,20 @@
             }
         } pointers[MAX_POINTERS + 1]; // + 1 to remove the need for extra range checks
 
+        // Bitfield of buttons that went down or up.
+        uint32_t buttonDown;
+        uint32_t buttonUp;
+
         inline void clear() {
             pointerCount = 0;
             pointers[0].clear();
+            buttonDown = 0;
+            buttonUp = 0;
         }
     } mAccumulator;
 
+    uint32_t mButtonState;
+
     void initialize();
 
     void sync(nsecs_t when);
@@ -999,38 +1190,50 @@
 private:
     struct Axis {
         RawAbsoluteAxisInfo rawAxisInfo;
+        AxisInfo axisInfo;
 
-        int32_t axis;  // axis id
         bool explicitlyMapped; // true if the axis was explicitly assigned an axis id
 
         float scale;   // scale factor from raw to normalized values
         float offset;  // offset to add after scaling for normalization
+        float highScale;  // scale factor from raw to normalized values of high split
+        float highOffset; // offset to add after scaling for normalization of high split
 
         float min;     // normalized inclusive minimum
         float max;     // normalized inclusive maximum
         float flat;    // normalized flat region size
         float fuzz;    // normalized error tolerance
 
-        float oldValue; // previous value
-        float newValue; // most recent value
-
         float filter;  // filter out small variations of this size
+        float currentValue; // current value
+        float newValue; // most recent value
+        float highCurrentValue; // current value of high split
+        float highNewValue; // most recent value of high split
 
-        void initialize(const RawAbsoluteAxisInfo& rawAxisInfo,
-                int32_t axis, bool explicitlyMapped, float scale, float offset,
+        void initialize(const RawAbsoluteAxisInfo& rawAxisInfo, const AxisInfo& axisInfo,
+                bool explicitlyMapped, float scale, float offset,
+                float highScale, float highOffset,
                 float min, float max, float flat, float fuzz) {
             this->rawAxisInfo = rawAxisInfo;
-            this->axis = axis;
+            this->axisInfo = axisInfo;
             this->explicitlyMapped = explicitlyMapped;
             this->scale = scale;
             this->offset = offset;
+            this->highScale = highScale;
+            this->highOffset = highOffset;
             this->min = min;
             this->max = max;
             this->flat = flat;
             this->fuzz = fuzz;
             this->filter = 0;
-            this->oldValue = 0;
+            resetValue();
+        }
+
+        void resetValue() {
+            this->currentValue = 0;
             this->newValue = 0;
+            this->highCurrentValue = 0;
+            this->highNewValue = 0;
         }
     };
 
@@ -1039,9 +1242,14 @@
 
     void sync(nsecs_t when, bool force);
 
-    bool haveAxis(int32_t axis);
+    bool haveAxis(int32_t axisId);
     void pruneAxes(bool ignoreExplicitlyMappedAxes);
-    bool haveAxesChangedSignificantly();
+    bool filterAxes(bool force);
+
+    static bool hasValueChangedSignificantly(float filter,
+            float newValue, float currentValue, float min, float max);
+    static bool hasMovedNearerToValueWithinFilteredRange(float filter,
+            float newValue, float currentValue, float thresholdValue);
 
     static bool isCenteredAxis(int32_t axis);
 };
diff --git a/services/input/PointerController.h b/services/input/PointerController.h
index e28dd7d..e1dab5c 100644
--- a/services/input/PointerController.h
+++ b/services/input/PointerController.h
@@ -31,10 +31,6 @@
 
 namespace android {
 
-enum {
-    POINTER_BUTTON_1 = 1 << 0,
-};
-
 /**
  * Interface for tracking a single (mouse) pointer.
  *
diff --git a/services/input/tests/InputDispatcher_test.cpp b/services/input/tests/InputDispatcher_test.cpp
index bb3449b..2f846c4 100644
--- a/services/input/tests/InputDispatcher_test.cpp
+++ b/services/input/tests/InputDispatcher_test.cpp
@@ -1,6 +1,18 @@
-//
-// Copyright 2010 The Android Open Source Project
-//
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 
 #include "../InputDispatcher.h"
 
diff --git a/services/input/tests/InputReader_test.cpp b/services/input/tests/InputReader_test.cpp
index 1180b83..60549c6 100644
--- a/services/input/tests/InputReader_test.cpp
+++ b/services/input/tests/InputReader_test.cpp
@@ -1,6 +1,18 @@
-//
-// Copyright 2010 The Android Open Source Project
-//
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 
 #include "../InputReader.h"
 
@@ -405,7 +417,8 @@
         String8 name;
         uint32_t classes;
         PropertyMap configuration;
-        KeyedVector<int, RawAbsoluteAxisInfo> axes;
+        KeyedVector<int, RawAbsoluteAxisInfo> absoluteAxes;
+        KeyedVector<int, bool> relativeAxes;
         KeyedVector<int32_t, int32_t> keyCodeStates;
         KeyedVector<int32_t, int32_t> scanCodeStates;
         KeyedVector<int32_t, int32_t> switchStates;
@@ -460,7 +473,7 @@
         device->configuration.addAll(configuration);
     }
 
-    void addAxis(int32_t deviceId, int axis,
+    void addAbsoluteAxis(int32_t deviceId, int axis,
             int32_t minValue, int32_t maxValue, int flat, int fuzz) {
         Device* device = getDevice(deviceId);
 
@@ -470,7 +483,12 @@
         info.maxValue = maxValue;
         info.flat = flat;
         info.fuzz = fuzz;
-        device->axes.add(axis, info);
+        device->absoluteAxes.add(axis, info);
+    }
+
+    void addRelativeAxis(int32_t deviceId, int32_t axis) {
+        Device* device = getDevice(deviceId);
+        device->relativeAxes.add(axis, true);
     }
 
     void setKeyCodeState(int32_t deviceId, int32_t keyCode, int32_t state) {
@@ -560,9 +578,9 @@
             RawAbsoluteAxisInfo* outAxisInfo) const {
         Device* device = getDevice(deviceId);
         if (device) {
-            ssize_t index = device->axes.indexOfKey(axis);
+            ssize_t index = device->absoluteAxes.indexOfKey(axis);
             if (index >= 0) {
-                *outAxisInfo = device->axes.valueAt(index);
+                *outAxisInfo = device->absoluteAxes.valueAt(index);
                 return OK;
             }
         }
@@ -570,6 +588,10 @@
     }
 
     virtual bool hasRelativeAxis(int32_t deviceId, int axis) const {
+        Device* device = getDevice(deviceId);
+        if (device) {
+            return device->relativeAxes.indexOfKey(axis) >= 0;
+        }
         return false;
     }
 
@@ -592,7 +614,7 @@
     }
 
     virtual status_t mapAxis(int32_t deviceId, int scancode,
-            int32_t* outAxis) const {
+            AxisInfo* outAxisInfo) const {
         return NAME_NOT_FOUND;
     }
 
@@ -600,14 +622,14 @@
         mExcludedDevices.add(String8(deviceName));
     }
 
-    virtual bool getEvent(RawEvent* outEvent) {
+    virtual size_t getEvents(int timeoutMillis, RawEvent* buffer, size_t bufferSize) {
         if (mEvents.empty()) {
-            return false;
+            return 0;
         }
 
-        *outEvent = *mEvents.begin();
+        *buffer = *mEvents.begin();
         mEvents.erase(mEvents.begin());
-        return true;
+        return 1;
     }
 
     virtual int32_t getScanCodeState(int32_t deviceId, int32_t scanCode) const {
@@ -758,6 +780,9 @@
 
     virtual void fadePointer() {
     }
+
+    virtual void requestTimeoutAtTime(nsecs_t when) {
+    }
 };
 
 
@@ -1420,7 +1445,7 @@
 
     // Event handling.
     RawEvent event;
-    mDevice->process(&event);
+    mDevice->process(&event, 1);
 
     ASSERT_NO_FATAL_FAILURE(mapper1->assertProcessWasCalled());
     ASSERT_NO_FATAL_FAILURE(mapper2->assertProcessWasCalled());
@@ -1487,13 +1512,15 @@
     }
 
     static void assertMotionRange(const InputDeviceInfo& info,
-            int32_t rangeType, float min, float max, float flat, float fuzz) {
-        const InputDeviceInfo::MotionRange* range = info.getMotionRange(rangeType);
-        ASSERT_TRUE(range != NULL) << "Range: " << rangeType;
-        ASSERT_NEAR(min, range->min, EPSILON) << "Range: " << rangeType;
-        ASSERT_NEAR(max, range->max, EPSILON) << "Range: " << rangeType;
-        ASSERT_NEAR(flat, range->flat, EPSILON) << "Range: " << rangeType;
-        ASSERT_NEAR(fuzz, range->fuzz, EPSILON) << "Range: " << rangeType;
+            int32_t axis, uint32_t source, float min, float max, float flat, float fuzz) {
+        const InputDeviceInfo::MotionRange* range = info.getMotionRange(axis, source);
+        ASSERT_TRUE(range != NULL) << "Axis: " << axis << " Source: " << source;
+        ASSERT_EQ(axis, range->axis) << "Axis: " << axis << " Source: " << source;
+        ASSERT_EQ(source, range->source) << "Axis: " << axis << " Source: " << source;
+        ASSERT_NEAR(min, range->min, EPSILON) << "Axis: " << axis << " Source: " << source;
+        ASSERT_NEAR(max, range->max, EPSILON) << "Axis: " << axis << " Source: " << source;
+        ASSERT_NEAR(flat, range->flat, EPSILON) << "Axis: " << axis << " Source: " << source;
+        ASSERT_NEAR(fuzz, range->fuzz, EPSILON) << "Axis: " << axis << " Source: " << source;
     }
 
     static void assertPointerCoords(const PointerCoords& coords,
@@ -2001,10 +2028,10 @@
     mapper->populateDeviceInfo(&info);
 
     // Initially there may not be a valid motion range.
-    ASSERT_EQ(NULL, info.getMotionRange(AINPUT_MOTION_RANGE_X));
-    ASSERT_EQ(NULL, info.getMotionRange(AINPUT_MOTION_RANGE_Y));
-    ASSERT_NO_FATAL_FAILURE(assertMotionRange(info, AINPUT_MOTION_RANGE_PRESSURE,
-            0.0f, 1.0f, 0.0f, 0.0f));
+    ASSERT_EQ(NULL, info.getMotionRange(AINPUT_MOTION_RANGE_X, AINPUT_SOURCE_MOUSE));
+    ASSERT_EQ(NULL, info.getMotionRange(AINPUT_MOTION_RANGE_Y, AINPUT_SOURCE_MOUSE));
+    ASSERT_NO_FATAL_FAILURE(assertMotionRange(info,
+            AINPUT_MOTION_RANGE_PRESSURE, AINPUT_SOURCE_MOUSE, 0.0f, 1.0f, 0.0f, 0.0f));
 
     // When the bounds are set, then there should be a valid motion range.
     mFakePointerController->setBounds(1, 2, 800 - 1, 480 - 1);
@@ -2012,11 +2039,14 @@
     InputDeviceInfo info2;
     mapper->populateDeviceInfo(&info2);
 
-    ASSERT_NO_FATAL_FAILURE(assertMotionRange(info2, AINPUT_MOTION_RANGE_X,
+    ASSERT_NO_FATAL_FAILURE(assertMotionRange(info2,
+            AINPUT_MOTION_RANGE_X, AINPUT_SOURCE_MOUSE,
             1, 800 - 1, 0.0f, 0.0f));
-    ASSERT_NO_FATAL_FAILURE(assertMotionRange(info2, AINPUT_MOTION_RANGE_Y,
+    ASSERT_NO_FATAL_FAILURE(assertMotionRange(info2,
+            AINPUT_MOTION_RANGE_Y, AINPUT_SOURCE_MOUSE,
             2, 480 - 1, 0.0f, 0.0f));
-    ASSERT_NO_FATAL_FAILURE(assertMotionRange(info2, AINPUT_MOTION_RANGE_PRESSURE,
+    ASSERT_NO_FATAL_FAILURE(assertMotionRange(info2,
+            AINPUT_MOTION_RANGE_PRESSURE, AINPUT_SOURCE_MOUSE,
             0.0f, 1.0f, 0.0f, 0.0f));
 }
 
@@ -2028,11 +2058,14 @@
     InputDeviceInfo info;
     mapper->populateDeviceInfo(&info);
 
-    ASSERT_NO_FATAL_FAILURE(assertMotionRange(info, AINPUT_MOTION_RANGE_X,
+    ASSERT_NO_FATAL_FAILURE(assertMotionRange(info,
+            AINPUT_MOTION_RANGE_X, AINPUT_SOURCE_TRACKBALL,
             -1.0f, 1.0f, 0.0f, 1.0f / TRACKBALL_MOVEMENT_THRESHOLD));
-    ASSERT_NO_FATAL_FAILURE(assertMotionRange(info, AINPUT_MOTION_RANGE_Y,
+    ASSERT_NO_FATAL_FAILURE(assertMotionRange(info,
+            AINPUT_MOTION_RANGE_Y, AINPUT_SOURCE_TRACKBALL,
             -1.0f, 1.0f, 0.0f, 1.0f / TRACKBALL_MOVEMENT_THRESHOLD));
-    ASSERT_NO_FATAL_FAILURE(assertMotionRange(info, AINPUT_MOTION_RANGE_PRESSURE,
+    ASSERT_NO_FATAL_FAILURE(assertMotionRange(info,
+            AINPUT_MOTION_RANGE_PRESSURE, AINPUT_SOURCE_TRACKBALL,
             0.0f, 1.0f, 0.0f, 0.0f));
 }
 
@@ -2385,14 +2418,18 @@
 
 void SingleTouchInputMapperTest::prepareAxes(int axes) {
     if (axes & POSITION) {
-        mFakeEventHub->addAxis(DEVICE_ID, ABS_X, RAW_X_MIN, RAW_X_MAX, 0, 0);
-        mFakeEventHub->addAxis(DEVICE_ID, ABS_Y, RAW_Y_MIN, RAW_Y_MAX, 0, 0);
+        mFakeEventHub->addAbsoluteAxis(DEVICE_ID, ABS_X,
+                RAW_X_MIN, RAW_X_MAX, 0, 0);
+        mFakeEventHub->addAbsoluteAxis(DEVICE_ID, ABS_Y,
+                RAW_Y_MIN, RAW_Y_MAX, 0, 0);
     }
     if (axes & PRESSURE) {
-        mFakeEventHub->addAxis(DEVICE_ID, ABS_PRESSURE, RAW_PRESSURE_MIN, RAW_PRESSURE_MAX, 0, 0);
+        mFakeEventHub->addAbsoluteAxis(DEVICE_ID, ABS_PRESSURE,
+                RAW_PRESSURE_MIN, RAW_PRESSURE_MAX, 0, 0);
     }
     if (axes & TOOL) {
-        mFakeEventHub->addAxis(DEVICE_ID, ABS_TOOL_WIDTH, RAW_TOOL_MIN, RAW_TOOL_MAX, 0, 0);
+        mFakeEventHub->addAbsoluteAxis(DEVICE_ID, ABS_TOOL_WIDTH,
+                RAW_TOOL_MIN, RAW_TOOL_MAX, 0, 0);
     }
 }
 
@@ -2426,11 +2463,21 @@
 }
 
 
-TEST_F(SingleTouchInputMapperTest, GetSources_WhenDeviceTypeIsNotSpecified_ReturnsTouchPad) {
+TEST_F(SingleTouchInputMapperTest, GetSources_WhenDeviceTypeIsNotSpecifiedAndNotACursor_ReturnsPointer) {
     SingleTouchInputMapper* mapper = new SingleTouchInputMapper(mDevice);
     prepareAxes(POSITION);
     addMapperAndConfigure(mapper);
 
+    ASSERT_EQ(AINPUT_SOURCE_MOUSE | AINPUT_SOURCE_TOUCHPAD, mapper->getSources());
+}
+
+TEST_F(SingleTouchInputMapperTest, GetSources_WhenDeviceTypeIsNotSpecifiedAndIsACursor_ReturnsTouchPad) {
+    SingleTouchInputMapper* mapper = new SingleTouchInputMapper(mDevice);
+    mFakeEventHub->addRelativeAxis(DEVICE_ID, REL_X);
+    mFakeEventHub->addRelativeAxis(DEVICE_ID, REL_Y);
+    prepareAxes(POSITION);
+    addMapperAndConfigure(mapper);
+
     ASSERT_EQ(AINPUT_SOURCE_TOUCHPAD, mapper->getSources());
 }
 
@@ -3040,33 +3087,37 @@
 
 void MultiTouchInputMapperTest::prepareAxes(int axes) {
     if (axes & POSITION) {
-        mFakeEventHub->addAxis(DEVICE_ID, ABS_MT_POSITION_X, RAW_X_MIN, RAW_X_MAX, 0, 0);
-        mFakeEventHub->addAxis(DEVICE_ID, ABS_MT_POSITION_Y, RAW_Y_MIN, RAW_Y_MAX, 0, 0);
+        mFakeEventHub->addAbsoluteAxis(DEVICE_ID, ABS_MT_POSITION_X,
+                RAW_X_MIN, RAW_X_MAX, 0, 0);
+        mFakeEventHub->addAbsoluteAxis(DEVICE_ID, ABS_MT_POSITION_Y,
+                RAW_Y_MIN, RAW_Y_MAX, 0, 0);
     }
     if (axes & TOUCH) {
-        mFakeEventHub->addAxis(DEVICE_ID, ABS_MT_TOUCH_MAJOR, RAW_TOUCH_MIN, RAW_TOUCH_MAX, 0, 0);
+        mFakeEventHub->addAbsoluteAxis(DEVICE_ID, ABS_MT_TOUCH_MAJOR,
+                RAW_TOUCH_MIN, RAW_TOUCH_MAX, 0, 0);
         if (axes & MINOR) {
-            mFakeEventHub->addAxis(DEVICE_ID, ABS_MT_TOUCH_MINOR,
+            mFakeEventHub->addAbsoluteAxis(DEVICE_ID, ABS_MT_TOUCH_MINOR,
                     RAW_TOUCH_MIN, RAW_TOUCH_MAX, 0, 0);
         }
     }
     if (axes & TOOL) {
-        mFakeEventHub->addAxis(DEVICE_ID, ABS_MT_WIDTH_MAJOR, RAW_TOOL_MIN, RAW_TOOL_MAX, 0, 0);
+        mFakeEventHub->addAbsoluteAxis(DEVICE_ID, ABS_MT_WIDTH_MAJOR,
+                RAW_TOOL_MIN, RAW_TOOL_MAX, 0, 0);
         if (axes & MINOR) {
-            mFakeEventHub->addAxis(DEVICE_ID, ABS_MT_WIDTH_MINOR,
+            mFakeEventHub->addAbsoluteAxis(DEVICE_ID, ABS_MT_WIDTH_MINOR,
                     RAW_TOOL_MAX, RAW_TOOL_MAX, 0, 0);
         }
     }
     if (axes & ORIENTATION) {
-        mFakeEventHub->addAxis(DEVICE_ID, ABS_MT_ORIENTATION,
+        mFakeEventHub->addAbsoluteAxis(DEVICE_ID, ABS_MT_ORIENTATION,
                 RAW_ORIENTATION_MIN, RAW_ORIENTATION_MAX, 0, 0);
     }
     if (axes & PRESSURE) {
-        mFakeEventHub->addAxis(DEVICE_ID, ABS_MT_PRESSURE,
+        mFakeEventHub->addAbsoluteAxis(DEVICE_ID, ABS_MT_PRESSURE,
                 RAW_PRESSURE_MIN, RAW_PRESSURE_MAX, 0, 0);
     }
     if (axes & ID) {
-        mFakeEventHub->addAxis(DEVICE_ID, ABS_MT_TRACKING_ID,
+        mFakeEventHub->addAbsoluteAxis(DEVICE_ID, ABS_MT_TRACKING_ID,
                 RAW_ID_MIN, RAW_ID_MAX, 0, 0);
     }
 }
diff --git a/services/java/com/android/server/AppWidgetService.java b/services/java/com/android/server/AppWidgetService.java
index f28e2b1..a4a95a0 100644
--- a/services/java/com/android/server/AppWidgetService.java
+++ b/services/java/com/android/server/AppWidgetService.java
@@ -135,7 +135,7 @@
                 IRemoteViewsAdapterConnection.Stub.asInterface(mConnectionCb);
             try {
                 cb.onServiceConnected(service);
-            } catch (RemoteException e) {
+            } catch (Exception e) {
                 e.printStackTrace();
             }
         }
@@ -147,7 +147,7 @@
                 IRemoteViewsAdapterConnection.Stub.asInterface(mConnectionCb);
             try {
                 cb.onServiceDisconnected();
-            } catch (RemoteException e) {
+            } catch (Exception e) {
                 e.printStackTrace();
             }
         }
@@ -541,7 +541,7 @@
                     IRemoteViewsFactory.Stub.asInterface(service);
                 try {
                     cb.onDestroy(intent);
-                } catch (RemoteException e) {
+                } catch (Exception e) {
                     e.printStackTrace();
                 }
                 mContext.unbindService(this);
diff --git a/services/java/com/android/server/BackupManagerService.java b/services/java/com/android/server/BackupManagerService.java
index c48f360..ea38fbb 100644
--- a/services/java/com/android/server/BackupManagerService.java
+++ b/services/java/com/android/server/BackupManagerService.java
@@ -379,6 +379,10 @@
                         }
                     }
 
+                    // Done: reset the session timeout clock
+                    removeMessages(MSG_RESTORE_TIMEOUT);
+                    sendEmptyMessageDelayed(MSG_RESTORE_TIMEOUT, TIMEOUT_RESTORE_INTERVAL);
+
                     mWakelock.release();
                 }
                 break;
diff --git a/services/java/com/android/server/ConnectivityService.java b/services/java/com/android/server/ConnectivityService.java
index b7d0a8f..12ac052 100644
--- a/services/java/com/android/server/ConnectivityService.java
+++ b/services/java/com/android/server/ConnectivityService.java
@@ -24,6 +24,7 @@
 import android.database.ContentObserver;
 import android.net.ConnectivityManager;
 import android.net.DummyDataStateTracker;
+import android.net.EthernetDataTracker;
 import android.net.IConnectivityManager;
 import android.net.LinkProperties;
 import android.net.MobileDataStateTracker;
@@ -420,6 +421,10 @@
                 mNetTrackers[netType] = BluetoothTetheringDataTracker.getInstance();
                 mNetTrackers[netType].startMonitoring(context, mHandler);
                 break;
+            case ConnectivityManager.TYPE_ETHERNET:
+                mNetTrackers[netType] = EthernetDataTracker.getInstance();
+                mNetTrackers[netType].startMonitoring(context, mHandler);
+                break;
             default:
                 loge("Trying to create a DataStateTracker for an unknown radio type " +
                         mNetAttributes[netType].mRadio);
@@ -1404,10 +1409,13 @@
         if (TextUtils.isEmpty(interfaceName)) return;
         for (InetAddress gateway : p.getGateways()) {
 
-            if (!NetworkUtils.addDefaultRoute(interfaceName, gateway) && DBG) {
-                NetworkInfo networkInfo = nt.getNetworkInfo();
-                log("addDefaultRoute for " + networkInfo.getTypeName() +
-                        " (" + interfaceName + "), GatewayAddr=" + gateway.getHostAddress());
+            if (NetworkUtils.addHostRoute(interfaceName, gateway, null) &&
+                    NetworkUtils.addDefaultRoute(interfaceName, gateway)) {
+                if (DBG) {
+                    NetworkInfo networkInfo = nt.getNetworkInfo();
+                    log("addDefaultRoute for " + networkInfo.getTypeName() +
+                            " (" + interfaceName + "), GatewayAddr=" + gateway.getHostAddress());
+                }
             }
         }
     }
@@ -1419,10 +1427,12 @@
         String interfaceName = p.getInterfaceName();
 
         if (interfaceName != null) {
-            if ((NetworkUtils.removeDefaultRoute(interfaceName) >= 0) && DBG) {
-                NetworkInfo networkInfo = nt.getNetworkInfo();
-                log("removeDefaultRoute for " + networkInfo.getTypeName() + " (" +
-                        interfaceName + ")");
+            if (NetworkUtils.removeDefaultRoute(interfaceName) >= 0) {
+                if (DBG) {
+                    NetworkInfo networkInfo = nt.getNetworkInfo();
+                    log("removeDefaultRoute for " + networkInfo.getTypeName() + " (" +
+                            interfaceName + ")");
+                }
             }
         }
     }
diff --git a/services/java/com/android/server/DeviceStorageMonitorService.java b/services/java/com/android/server/DeviceStorageMonitorService.java
index 0fba7c3..b0d2158 100644
--- a/services/java/com/android/server/DeviceStorageMonitorService.java
+++ b/services/java/com/android/server/DeviceStorageMonitorService.java
@@ -398,4 +398,24 @@
         // force an early check
         postCheckMemoryMsg(true, 0);
     }
+
+    /**
+     * Callable from other things in the system service to obtain the low memory
+     * threshold.
+     * 
+     * @return low memory threshold in bytes
+     */
+    public long getMemoryLowThreshold() {
+        return mMemLowThreshold;
+    }
+
+    /**
+     * Callable from other things in the system process to check whether memory
+     * is low.
+     * 
+     * @return true is memory is low
+     */
+    public boolean isMemoryLow() {
+        return mLowMemFlag;
+    }
 }
diff --git a/services/java/com/android/server/InputMethodManagerService.java b/services/java/com/android/server/InputMethodManagerService.java
index 44b8590..1455764 100644
--- a/services/java/com/android/server/InputMethodManagerService.java
+++ b/services/java/com/android/server/InputMethodManagerService.java
@@ -60,7 +60,6 @@
 import android.os.ResultReceiver;
 import android.os.ServiceManager;
 import android.os.SystemClock;
-import android.os.SystemProperties;
 import android.provider.Settings;
 import android.provider.Settings.Secure;
 import android.provider.Settings.SettingNotFoundException;
@@ -82,8 +81,8 @@
 import java.io.FileDescriptor;
 import java.io.IOException;
 import java.io.PrintWriter;
-import java.text.Collator;
 import java.util.ArrayList;
+import java.util.Comparator;
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.List;
@@ -315,7 +314,6 @@
 
     int mBackDisposition = InputMethodService.BACK_DISPOSITION_DEFAULT;
     int mImeWindowVis;
-    long mOldSystemSettingsVersion;
 
     AlertDialog.Builder mDialogBuilder;
     AlertDialog mSwitchingDialog;
@@ -490,8 +488,6 @@
                 handleMessage(msg);
             }
         });
-        // Initialize the system settings version to undefined.
-        mOldSystemSettingsVersion = -1;
 
         (new MyPackageMonitor()).register(mContext, true);
 
@@ -1012,15 +1008,7 @@
         }
     }
 
-    // TODO: Investigate and fix why are settings changes getting processed before the settings seq
-    // number is updated?
-    // TODO: Change this stuff to not rely on modifying settings for normal user interactions.
     void updateFromSettingsLocked() {
-        long newSystemSettingsVersion = getSystemSettingsVersion();
-        // This is a workaround to avoid a situation that old cached value in Settings.Secure
-        // will be handled.
-        if (newSystemSettingsVersion == mOldSystemSettingsVersion) return;
-
         // We are assuming that whoever is changing DEFAULT_INPUT_METHOD and
         // ENABLED_INPUT_METHODS is taking care of keeping them correctly in
         // sync, so we will never have a DEFAULT_INPUT_METHOD that is not
@@ -1750,10 +1738,28 @@
 
             hideInputMethodMenuLocked();
 
-            final Map<CharSequence, Pair<InputMethodInfo, Integer>> imMap =
-                new TreeMap<CharSequence, Pair<InputMethodInfo, Integer>>(Collator.getInstance());
+            final TreeMap<InputMethodInfo, List<InputMethodSubtype>> sortedImmis =
+                    new TreeMap<InputMethodInfo, List<InputMethodSubtype>>(
+                            new Comparator<InputMethodInfo>() {
+                                @Override
+                                public int compare(InputMethodInfo imi1, InputMethodInfo imi2) {
+                                    if (imi2 == null) return 0;
+                                    if (imi1 == null) return 1;
+                                    if (pm == null) {
+                                        return imi1.getId().compareTo(imi2.getId());
+                                    }
+                                    CharSequence imiId1 = imi1.loadLabel(pm) + "/" + imi1.getId();
+                                    CharSequence imiId2 = imi2.loadLabel(pm) + "/" + imi2.getId();
+                                    return imiId1.toString().compareTo(imiId2.toString());
+                                }
+                            });
 
-            for (InputMethodInfo imi: immis.keySet()) {
+            sortedImmis.putAll(immis);
+
+            final ArrayList<Pair<CharSequence, Pair<InputMethodInfo, Integer>>> imList =
+                    new ArrayList<Pair<CharSequence, Pair<InputMethodInfo, Integer>>>();
+
+            for (InputMethodInfo imi : sortedImmis.keySet()) {
                 if (imi == null) continue;
                 List<InputMethodSubtype> explicitlyOrImplicitlyEnabledSubtypeList = immis.get(imi);
                 HashSet<String> enabledSubtypeSet = new HashSet<String>();
@@ -1761,40 +1767,45 @@
                     enabledSubtypeSet.add(String.valueOf(subtype.hashCode()));
                 }
                 ArrayList<InputMethodSubtype> subtypes = getSubtypes(imi);
-                CharSequence label = imi.loadLabel(pm);
+                final CharSequence label = imi.loadLabel(pm);
                 if (showSubtypes && enabledSubtypeSet.size() > 0) {
                     final int subtypeCount = imi.getSubtypeCount();
                     for (int j = 0; j < subtypeCount; ++j) {
                         InputMethodSubtype subtype = imi.getSubtypeAt(j);
                         if (enabledSubtypeSet.contains(String.valueOf(subtype.hashCode()))) {
-                            CharSequence title;
+                            final CharSequence title;
                             int nameResId = subtype.getNameResId();
                             String mode = subtype.getMode();
                             if (nameResId != 0) {
-                                title = pm.getText(imi.getPackageName(), nameResId,
-                                        imi.getServiceInfo().applicationInfo);
+                                title = TextUtils.concat(pm.getText(imi.getPackageName(),
+                                        nameResId, imi.getServiceInfo().applicationInfo),
+                                        (TextUtils.isEmpty(label) ? "" : " (" + label + ")"));
                             } else {
                                 CharSequence language = subtype.getLocale();
                                 // TODO: Use more friendly Title and UI
                                 title = label + "," + (mode == null ? "" : mode) + ","
                                         + (language == null ? "" : language);
                             }
-                            imMap.put(title, new Pair<InputMethodInfo, Integer>(imi, j));
+                            imList.add(new Pair<CharSequence, Pair<InputMethodInfo, Integer>>(
+                                    title, new Pair<InputMethodInfo, Integer>(imi, j)));
                         }
                     }
                 } else {
-                    imMap.put(label,
-                            new Pair<InputMethodInfo, Integer>(imi, NOT_A_SUBTYPE_ID));
+                    imList.add(new Pair<CharSequence, Pair<InputMethodInfo, Integer>>(
+                            label, new Pair<InputMethodInfo, Integer>(imi, NOT_A_SUBTYPE_ID)));
                 }
             }
 
-            final int N = imMap.size();
-            mItems = imMap.keySet().toArray(new CharSequence[N]);
+            final int N = imList.size();
+            mItems = new CharSequence[N];
+            for (int i = 0; i < N; ++i) {
+                mItems[i] = imList.get(i).first;
+            }
             mIms = new InputMethodInfo[N];
             mSubtypeIds = new int[N];
             int checkedItem = 0;
             for (int i = 0; i < N; ++i) {
-                Pair<InputMethodInfo, Integer> value = imMap.get(mItems[i]);
+                Pair<InputMethodInfo, Integer> value = imList.get(i).second;
                 mIms[i] = value.first;
                 mSubtypeIds[i] = value.second;
                 if (mIms[i].getId().equals(lastInputMethodId)) {
@@ -1859,8 +1870,10 @@
                         });
             }
             mSwitchingDialog = mDialogBuilder.create();
+            mSwitchingDialog.setCanceledOnTouchOutside(true);
             mSwitchingDialog.getWindow().setType(
                     WindowManager.LayoutParams.TYPE_INPUT_METHOD_DIALOG);
+            mSwitchingDialog.getWindow().getAttributes().setTitle("Select input method");
             mSwitchingDialog.show();
         }
     }
@@ -1964,7 +1977,6 @@
 
     private void setSelectedInputMethodAndSubtypeLocked(InputMethodInfo imi, int subtypeId,
             boolean setSubtypeOnly) {
-        mOldSystemSettingsVersion = getSystemSettingsVersion();
         // Update the history of InputMethod and Subtype
         saveCurrentInputMethodAndSubtypeToHistory();
 
@@ -2214,10 +2226,6 @@
         }
     }
 
-    private static long getSystemSettingsVersion() {
-        return SystemProperties.getLong(Settings.Secure.SYS_PROP_SETTING_VERSION, 0);
-    }
-
     /**
      * @return Return the current subtype of this input method.
      */
diff --git a/services/java/com/android/server/PackageManagerService.java b/services/java/com/android/server/PackageManagerService.java
index 461a3e5..3d8dccb 100644
--- a/services/java/com/android/server/PackageManagerService.java
+++ b/services/java/com/android/server/PackageManagerService.java
@@ -16,6 +16,10 @@
 
 package com.android.server;
 
+import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DEFAULT;
+import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DISABLED;
+import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_ENABLED;
+
 import com.android.internal.app.IMediaContainerService;
 import com.android.internal.app.ResolverActivity;
 import com.android.internal.content.NativeLibraryHelper;
@@ -32,8 +36,8 @@
 import android.app.IActivityManager;
 import android.app.admin.IDevicePolicyManager;
 import android.app.backup.IBackupManager;
-import android.content.Context;
 import android.content.ComponentName;
+import android.content.Context;
 import android.content.IIntentReceiver;
 import android.content.Intent;
 import android.content.IntentFilter;
@@ -54,13 +58,10 @@
 import android.content.pm.PackageInfo;
 import android.content.pm.PackageInfoLite;
 import android.content.pm.PackageManager;
-import android.content.pm.PackageStats;
-import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DEFAULT;
-import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DISABLED;
-import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_ENABLED;
 import android.content.pm.PackageParser;
-import android.content.pm.PermissionInfo;
+import android.content.pm.PackageStats;
 import android.content.pm.PermissionGroupInfo;
+import android.content.pm.PermissionInfo;
 import android.content.pm.ProviderInfo;
 import android.content.pm.ResolveInfo;
 import android.content.pm.ServiceInfo;
@@ -69,24 +70,29 @@
 import android.os.Binder;
 import android.os.Build;
 import android.os.Bundle;
-import android.os.Debug;
+import android.os.Environment;
+import android.os.FileObserver;
+import android.os.FileUtils;
+import android.os.Handler;
 import android.os.HandlerThread;
 import android.os.IBinder;
 import android.os.Looper;
 import android.os.Message;
 import android.os.Parcel;
-import android.os.RemoteException;
-import android.os.Environment;
-import android.os.FileObserver;
-import android.os.FileUtils;
-import android.os.Handler;
 import android.os.ParcelFileDescriptor;
 import android.os.Process;
+import android.os.RemoteException;
 import android.os.ServiceManager;
 import android.os.SystemClock;
 import android.os.SystemProperties;
 import android.security.SystemKeyStore;
-import android.util.*;
+import android.util.DisplayMetrics;
+import android.util.EventLog;
+import android.util.Log;
+import android.util.LogPrinter;
+import android.util.Slog;
+import android.util.SparseArray;
+import android.util.Xml;
 import android.view.Display;
 import android.view.WindowManager;
 
@@ -138,6 +144,12 @@
     private static final boolean DEBUG_UPGRADE = false;
     private static final boolean DEBUG_INSTALL = false;
     private static final boolean DEBUG_STOPPED = false;
+    private static final boolean DEBUG_REMOVE = false;
+    private static final boolean DEBUG_SHOW_INFO = false;
+    private static final boolean DEBUG_PACKAGE_INFO = false;
+    private static final boolean DEBUG_INTENT_MATCHING = false;
+    private static final boolean DEBUG_PACKAGE_SCANNING = false;
+    private static final boolean DEBUG_APP_DIR_OBSERVER = false;
 
     private static final boolean MULTIPLE_APPLICATION_UIDS = true;
     private static final int RADIO_UID = Process.PHONE_UID;
@@ -147,8 +159,6 @@
         Process.FIRST_APPLICATION_UID;
     private static final int MAX_APPLICATION_UIDS = 1000;
 
-    private static final boolean SHOW_INFO = false;
-
     private static final boolean GET_CERTIFICATES = true;
 
     private static final int REMOVE_EVENTS =
@@ -362,6 +372,7 @@
 
     // Delay time in millisecs
     static final int BROADCAST_DELAY = 10 * 1000;
+
     final private DefaultContainerConnection mDefContainerConn =
             new DefaultContainerConnection();
     class DefaultContainerConnection implements ServiceConnection {
@@ -526,12 +537,12 @@
                 }
                 case MCS_GIVE_UP: {
                     if (DEBUG_SD_INSTALL) Log.i(TAG, "mcs_giveup too many retries");
-                    HandlerParams params = mPendingInstalls.remove(0);
+                    mPendingInstalls.remove(0);
                     break;
                 }
                 case SEND_PENDING_BROADCAST : {
                     String packages[];
-                    ArrayList components[];
+                    ArrayList<String> components[];
                     int size = 0;
                     int uids[];
                     Process.setThreadPriority(Process.THREAD_PRIORITY_DEFAULT);
@@ -563,8 +574,7 @@
                     }
                     // Send broadcasts
                     for (int i = 0; i < size; i++) {
-                        sendPackageChangedBroadcast(packages[i], true,
-                                (ArrayList<String>)components[i], uids[i]);
+                        sendPackageChangedBroadcast(packages[i], true, components[i], uids[i]);
                     }
                     Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
                     break;
@@ -1347,9 +1357,8 @@
     public PackageInfo getPackageInfo(String packageName, int flags) {
         synchronized (mPackages) {
             PackageParser.Package p = mPackages.get(packageName);
-            if (Config.LOGV) Log.v(
-                TAG, "getPackageInfo " + packageName
-                + ": " + p);
+            if (DEBUG_PACKAGE_INFO)
+                Log.v(TAG, "getPackageInfo " + packageName + ": " + p);
             if (p != null) {
                 return generatePackageInfo(p, flags);
             }
@@ -1400,9 +1409,8 @@
     public int[] getPackageGids(String packageName) {
         synchronized (mPackages) {
             PackageParser.Package p = mPackages.get(packageName);
-            if (Config.LOGV) Log.v(
-                TAG, "getPackageGids" + packageName
-                + ": " + p);
+            if (DEBUG_PACKAGE_INFO)
+                Log.v(TAG, "getPackageGids" + packageName + ": " + p);
             if (p != null) {
                 final PackageSetting ps = (PackageSetting)p.mExtras;
                 final SharedUserSetting suid = ps.sharedUser;
@@ -1514,7 +1522,7 @@
     public ApplicationInfo getApplicationInfo(String packageName, int flags) {
         synchronized (mPackages) {
             PackageParser.Package p = mPackages.get(packageName);
-            if (Config.LOGV) Log.v(
+            if (DEBUG_PACKAGE_INFO) Log.v(
                     TAG, "getApplicationInfo " + packageName
                     + ": " + p);
             if (p != null) {
@@ -1589,7 +1597,7 @@
         synchronized (mPackages) {
             PackageParser.Activity a = mActivities.mActivities.get(component);
 
-            if (Config.LOGV) Log.v(TAG, "getActivityInfo " + component + ": " + a);
+            if (DEBUG_PACKAGE_INFO) Log.v(TAG, "getActivityInfo " + component + ": " + a);
             if (a != null && mSettings.isEnabledLP(a.info, flags)) {
                 return PackageParser.generateActivityInfo(a, flags);
             }
@@ -1603,7 +1611,7 @@
     public ActivityInfo getReceiverInfo(ComponentName component, int flags) {
         synchronized (mPackages) {
             PackageParser.Activity a = mReceivers.mActivities.get(component);
-            if (Config.LOGV) Log.v(
+            if (DEBUG_PACKAGE_INFO) Log.v(
                 TAG, "getReceiverInfo " + component + ": " + a);
             if (a != null && mSettings.isEnabledLP(a.info, flags)) {
                 return PackageParser.generateActivityInfo(a, flags);
@@ -1615,7 +1623,7 @@
     public ServiceInfo getServiceInfo(ComponentName component, int flags) {
         synchronized (mPackages) {
             PackageParser.Service s = mServices.mServices.get(component);
-            if (Config.LOGV) Log.v(
+            if (DEBUG_PACKAGE_INFO) Log.v(
                 TAG, "getServiceInfo " + component + ": " + s);
             if (s != null && mSettings.isEnabledLP(s.info, flags)) {
                 return PackageParser.generateServiceInfo(s, flags);
@@ -1627,7 +1635,7 @@
     public ProviderInfo getProviderInfo(ComponentName component, int flags) {
         synchronized (mPackages) {
             PackageParser.Provider p = mProvidersByComponent.get(component);
-            if (Config.LOGV) Log.v(
+            if (DEBUG_PACKAGE_INFO) Log.v(
                 TAG, "getProviderInfo " + component + ": " + p);
             if (p != null && mSettings.isEnabledLP(p.info, flags)) {
                 return PackageParser.generateProviderInfo(p, flags);
@@ -1973,11 +1981,9 @@
                 // then let the user decide between them.
                 ResolveInfo r0 = query.get(0);
                 ResolveInfo r1 = query.get(1);
-                if (false) {
-                    System.out.println(r0.activityInfo.name +
-                                       "=" + r0.priority + " vs " +
-                                       r1.activityInfo.name +
-                                       "=" + r1.priority);
+                if (DEBUG_INTENT_MATCHING) {
+                    Log.d(TAG, r0.activityInfo.name + "=" + r0.priority + " vs "
+                            + r1.activityInfo.name + "=" + r1.priority);
                 }
                 // If the first activity has a higher priority, or a different
                 // default, then it is always desireable to pick it.
@@ -2025,10 +2031,10 @@
                 final int M = prefs.size();
                 for (int i=0; i<M; i++) {
                     PreferredActivity pa = prefs.get(i);
-                    if (pa.mMatch != match) {
+                    if (pa.mPref.mMatch != match) {
                         continue;
                     }
-                    ActivityInfo ai = getActivityInfo(pa.mActivity, flags);
+                    ActivityInfo ai = getActivityInfo(pa.mPref.mComponent, flags);
                     if (DEBUG_PREFERRED) {
                         Log.v(TAG, "Got preferred activity:");
                         if (ai != null) {
@@ -2052,7 +2058,7 @@
                             // If the result set is different from when this
                             // was created, we need to clear it and re-ask the
                             // user their preference.
-                            if (!pa.sameSet(query, priority)) {
+                            if (!pa.mPref.sameSet(query, priority)) {
                                 Slog.i(TAG, "Result set changed, dropping preferred activity for "
                                         + intent + " type " + resolvedType);
                                 mSettings.mPreferredActivities.removeFilter(pa);
@@ -2105,7 +2111,7 @@
 
         List<ResolveInfo> results = queryIntentActivities(
             intent, resolvedType, flags|PackageManager.GET_RESOLVED_FILTER);
-        if (Config.LOGV) Log.v(TAG, "Query " + intent + ": " + results);
+        if (DEBUG_INTENT_MATCHING) Log.v(TAG, "Query " + intent + ": " + results);
 
         int specificsPos = 0;
         int N;
@@ -2125,7 +2131,7 @@
                     continue;
                 }
 
-                if (Config.LOGV) Log.v(TAG, "Specific #" + i + ": " + sintent);
+                if (DEBUG_INTENT_MATCHING) Log.v(TAG, "Specific #" + i + ": " + sintent);
                 String action = sintent.getAction();
                 if (resultsAction != null && resultsAction.equals(action)) {
                     // If this action was explicitly requested, then don't
@@ -2158,7 +2164,7 @@
 
                 // Look for any generic query activities that are duplicates
                 // of this specific one, and remove them from the results.
-                if (Config.LOGV) Log.v(TAG, "Specific #" + i + ": " + ai);
+                if (DEBUG_INTENT_MATCHING) Log.v(TAG, "Specific #" + i + ": " + ai);
                 N = results.size();
                 int j;
                 for (j=specificsPos; j<N; j++) {
@@ -2168,7 +2174,7 @@
                                     comp.getPackageName()))
                         || (action != null && sri.filter.matchAction(action))) {
                         results.remove(j);
-                        if (Config.LOGV) Log.v(
+                        if (DEBUG_INTENT_MATCHING) Log.v(
                             TAG, "Removing duplicate item from " + j
                             + " due to specific " + specificsPos);
                         if (ri == null) {
@@ -2216,7 +2222,7 @@
                     final ResolveInfo rij = results.get(j);
                     if (rij.filter != null && rij.filter.hasAction(action)) {
                         results.remove(j);
-                        if (Config.LOGV) Log.v(
+                        if (DEBUG_INTENT_MATCHING) Log.v(
                             TAG, "Removing duplicate item from " + j
                             + " due to action " + action + " at " + i);
                         j--;
@@ -2255,7 +2261,7 @@
             }
         }
 
-        if (Config.LOGV) Log.v(TAG, "Result: " + results);
+        if (DEBUG_INTENT_MATCHING) Log.v(TAG, "Result: " + results);
         return results;
     }
 
@@ -2423,7 +2429,8 @@
     /**
      * @deprecated
      */
-    public void querySyncProviders(List outNames, List outInfo) {
+    @Deprecated
+    public void querySyncProviders(List<String> outNames, List<ProviderInfo> outInfo) {
         synchronized (mPackages) {
             Iterator<Map.Entry<String, PackageParser.Provider>> i
                 = mProviders.entrySet().iterator();
@@ -2508,7 +2515,7 @@
             return;
         }
 
-        if (false) {
+        if (DEBUG_PACKAGE_SCANNING) {
             Log.d(TAG, "Scanning app dir " + dir);
         }
 
@@ -2861,8 +2868,11 @@
             }
         }
 
-        if ((parseFlags&PackageParser.PARSE_CHATTY) != 0 && Config.LOGD) Log.d(
-                TAG, "Scanning package " + pkg.packageName);
+        if (DEBUG_PACKAGE_SCANNING) {
+            if ((parseFlags & PackageParser.PARSE_CHATTY) != 0)
+                Log.d(TAG, "Scanning package " + pkg.packageName);
+        }
+
         if (mPackages.containsKey(pkg.packageName)
                 || mSharedLibraries.containsKey(pkg.packageName)) {
             Slog.w(TAG, "Application package " + pkg.packageName
@@ -2934,18 +2944,10 @@
                     mLastScanError = PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE;
                     return null;
                 }
-                if ((parseFlags&PackageParser.PARSE_CHATTY) != 0 && Config.LOGD) {
-                    Log.d(TAG, "Shared UserID " + pkg.mSharedUserId + " (uid="
-                            + suid.userId + "): packages=" + suid.packages);
-                }
-            }
-
-            if (false) {
-                if (pkg.mOriginalPackages != null) {
-                    Log.w(TAG, "WAITING FOR DEBUGGER");
-                    Debug.waitForDebugger();
-                    Log.i(TAG, "Package " + pkg.packageName + " from original packages"
-                            + pkg.mOriginalPackages);
+                if (DEBUG_PACKAGE_SCANNING) {
+                    if ((parseFlags & PackageParser.PARSE_CHATTY) != 0)
+                        Log.d(TAG, "Shared UserID " + pkg.mSharedUserId + " (uid=" + suid.userId
+                                + "): packages=" + suid.packages);
                 }
             }
             
@@ -3077,7 +3079,7 @@
             // package isn't already installed, since we don't want to break
             // things that are installed.
             if ((scanMode&SCAN_NEW_INSTALL) != 0) {
-                int N = pkg.providers.size();
+                final int N = pkg.providers.size();
                 int i;
                 for (i=0; i<N; i++) {
                     PackageParser.Provider p = pkg.providers.get(i);
@@ -3120,7 +3122,6 @@
         
         final long scanFileTime = scanFile.lastModified();
         final boolean forceDex = (scanMode&SCAN_FORCE_DEX) != 0;
-        final boolean scanFileNewer = forceDex || scanFileTime != pkgSetting.timeStamp;
         pkg.applicationInfo.processName = fixProcessName(
                 pkg.applicationInfo.packageName,
                 pkg.applicationInfo.processName,
@@ -3197,8 +3198,10 @@
                 }
                 pkg.applicationInfo.dataDir = dataPath.getPath();
             } else {
-                if ((parseFlags&PackageParser.PARSE_CHATTY) != 0 && Config.LOGV)
-                    Log.v(TAG, "Want this data dir: " + dataPath);
+                if (DEBUG_PACKAGE_SCANNING) {
+                    if ((parseFlags & PackageParser.PARSE_CHATTY) != 0)
+                        Log.v(TAG, "Want this data dir: " + dataPath);
+                }
                 //invoke installer to do the actual installation
                 if (mInstaller != null) {
                     int ret = mInstaller.install(pkgName, pkg.applicationInfo.uid,
@@ -3378,10 +3381,12 @@
                             } else {
                                 p.info.authority = p.info.authority + ";" + names[j];
                             }
-                            if ((parseFlags&PackageParser.PARSE_CHATTY) != 0 && Config.LOGD)
-                                Log.d(TAG, "Registered content provider: " + names[j] +
-                                        ", className = " + p.info.name +
-                                        ", isSyncable = " + p.info.isSyncable);
+                            if (DEBUG_PACKAGE_SCANNING) {
+                                if ((parseFlags & PackageParser.PARSE_CHATTY) != 0)
+                                    Log.d(TAG, "Registered content provider: " + names[j]
+                                            + ", className = " + p.info.name + ", isSyncable = "
+                                            + p.info.isSyncable);
+                            }
                         } else {
                             PackageParser.Provider other = mProviders.get(names[j]);
                             Slog.w(TAG, "Skipping provider name " + names[j] +
@@ -3402,7 +3407,7 @@
                 }
             }
             if (r != null) {
-                if (Config.LOGD) Log.d(TAG, "  Providers: " + r);
+                if (DEBUG_PACKAGE_SCANNING) Log.d(TAG, "  Providers: " + r);
             }
 
             N = pkg.services.size();
@@ -3422,7 +3427,7 @@
                 }
             }
             if (r != null) {
-                if (Config.LOGD) Log.d(TAG, "  Services: " + r);
+                if (DEBUG_PACKAGE_SCANNING) Log.d(TAG, "  Services: " + r);
             }
 
             N = pkg.receivers.size();
@@ -3442,7 +3447,7 @@
                 }
             }
             if (r != null) {
-                if (Config.LOGD) Log.d(TAG, "  Receivers: " + r);
+                if (DEBUG_PACKAGE_SCANNING) Log.d(TAG, "  Receivers: " + r);
             }
 
             N = pkg.activities.size();
@@ -3462,7 +3467,7 @@
                 }
             }
             if (r != null) {
-                if (Config.LOGD) Log.d(TAG, "  Activities: " + r);
+                if (DEBUG_PACKAGE_SCANNING) Log.d(TAG, "  Activities: " + r);
             }
 
             N = pkg.permissionGroups.size();
@@ -3496,7 +3501,7 @@
                 }
             }
             if (r != null) {
-                if (Config.LOGD) Log.d(TAG, "  Permission Groups: " + r);
+                if (DEBUG_PACKAGE_SCANNING) Log.d(TAG, "  Permission Groups: " + r);
             }
 
             N = pkg.permissions.size();
@@ -3561,7 +3566,7 @@
                 }
             }
             if (r != null) {
-                if (Config.LOGD) Log.d(TAG, "  Permissions: " + r);
+                if (DEBUG_PACKAGE_SCANNING) Log.d(TAG, "  Permissions: " + r);
             }
 
             N = pkg.instrumentation.size();
@@ -3584,7 +3589,7 @@
                 }
             }
             if (r != null) {
-                if (Config.LOGD) Log.d(TAG, "  Instrumentation: " + r);
+                if (DEBUG_PACKAGE_SCANNING) Log.d(TAG, "  Instrumentation: " + r);
             }
 
             if (pkg.protectedBroadcasts != null) {
@@ -3613,22 +3618,11 @@
         }
     }
 
-    // Return the path of the directory that will contain the native binaries
-    // of a given installed package. This is relative to the data path.
-    //
-    private File getNativeBinaryDirForPackage(PackageParser.Package pkg) {
-        final String nativeLibraryDir = pkg.applicationInfo.nativeLibraryDir;
-        if (nativeLibraryDir != null) {
-            return new File(nativeLibraryDir);
-        } else {
-            // Fall back for old packages
-            return new File(pkg.applicationInfo.dataDir, LIB_DIR_NAME);
-        }
-    }
-
     void removePackageLI(PackageParser.Package pkg, boolean chatty) {
-        if (chatty && Config.LOGD) Log.d(
-            TAG, "Removing package " + pkg.applicationInfo.packageName );
+        if (DEBUG_INSTALL) {
+            if (chatty)
+                Log.d(TAG, "Removing package " + pkg.applicationInfo.packageName);
+        }
 
         synchronized (mPackages) {
             clearPackagePreferredActivitiesLP(pkg.packageName);
@@ -3657,10 +3651,12 @@
                 for (int j = 0; j < names.length; j++) {
                     if (mProviders.get(names[j]) == p) {
                         mProviders.remove(names[j]);
-                        if (chatty && Config.LOGD) Log.d(
-                            TAG, "Unregistered content provider: " + names[j] +
-                            ", className = " + p.info.name +
-                            ", isSyncable = " + p.info.isSyncable);
+                        if (DEBUG_REMOVE) {
+                            if (chatty)
+                                Log.d(TAG, "Unregistered content provider: " + names[j]
+                                        + ", className = " + p.info.name + ", isSyncable = "
+                                        + p.info.isSyncable);
+                        }
                     }
                 }
                 if (chatty) {
@@ -3673,7 +3669,7 @@
                 }
             }
             if (r != null) {
-                if (Config.LOGD) Log.d(TAG, "  Providers: " + r);
+                if (DEBUG_REMOVE) Log.d(TAG, "  Providers: " + r);
             }
 
             N = pkg.services.size();
@@ -3691,7 +3687,7 @@
                 }
             }
             if (r != null) {
-                if (Config.LOGD) Log.d(TAG, "  Services: " + r);
+                if (DEBUG_REMOVE) Log.d(TAG, "  Services: " + r);
             }
 
             N = pkg.receivers.size();
@@ -3709,7 +3705,7 @@
                 }
             }
             if (r != null) {
-                if (Config.LOGD) Log.d(TAG, "  Receivers: " + r);
+                if (DEBUG_REMOVE) Log.d(TAG, "  Receivers: " + r);
             }
 
             N = pkg.activities.size();
@@ -3727,17 +3723,15 @@
                 }
             }
             if (r != null) {
-                if (Config.LOGD) Log.d(TAG, "  Activities: " + r);
+                if (DEBUG_REMOVE) Log.d(TAG, "  Activities: " + r);
             }
 
             N = pkg.permissions.size();
             r = null;
             for (i=0; i<N; i++) {
                 PackageParser.Permission p = pkg.permissions.get(i);
-                boolean tree = false;
                 BasePermission bp = mSettings.mPermissions.get(p.info.name);
                 if (bp == null) {
-                    tree = true;
                     bp = mSettings.mPermissionTrees.get(p.info.name);
                 }
                 if (bp != null && bp.perm == p) {
@@ -3753,7 +3747,7 @@
                 }
             }
             if (r != null) {
-                if (Config.LOGD) Log.d(TAG, "  Permissions: " + r);
+                if (DEBUG_REMOVE) Log.d(TAG, "  Permissions: " + r);
             }
 
             N = pkg.instrumentation.size();
@@ -3771,7 +3765,7 @@
                 }
             }
             if (r != null) {
-                if (Config.LOGD) Log.d(TAG, "  Instrumentation: " + r);
+                if (DEBUG_REMOVE) Log.d(TAG, "  Instrumentation: " + r);
             }
         }
     }
@@ -3895,10 +3889,9 @@
         for (int i=0; i<N; i++) {
             String name = pkg.requestedPermissions.get(i);
             BasePermission bp = mSettings.mPermissions.get(name);
-            if (false) {
+            if (DEBUG_INSTALL) {
                 if (gp != ps) {
-                    Log.i(TAG, "Package " + pkg.packageName + " checking " + name
-                            + ": " + bp);
+                    Log.i(TAG, "Package " + pkg.packageName + " checking " + name + ": " + bp);
                 }
             }
             if (bp != null && bp.packageSetting != null) {
@@ -3944,7 +3937,7 @@
                 } else {
                     allowed = false;
                 }
-                if (false) {
+                if (DEBUG_INSTALL) {
                     if (gp != ps) {
                         Log.i(TAG, "Package " + pkg.packageName + " granting " + perm);
                     }
@@ -4022,25 +4015,26 @@
     
     private final class ActivityIntentResolver
             extends IntentResolver<PackageParser.ActivityIntentInfo, ResolveInfo> {
-        public List queryIntent(Intent intent, String resolvedType, boolean defaultOnly) {
+        public List<ResolveInfo> queryIntent(Intent intent, String resolvedType,
+                boolean defaultOnly) {
             mFlags = defaultOnly ? PackageManager.MATCH_DEFAULT_ONLY : 0;
             return super.queryIntent(intent, resolvedType, defaultOnly);
         }
 
-        public List queryIntent(Intent intent, String resolvedType, int flags) {
+        public List<ResolveInfo> queryIntent(Intent intent, String resolvedType, int flags) {
             mFlags = flags;
             return super.queryIntent(intent, resolvedType,
                 (flags&PackageManager.MATCH_DEFAULT_ONLY) != 0);
         }
 
-        public List queryIntentForPackage(Intent intent, String resolvedType, int flags,
-                                          ArrayList<PackageParser.Activity> packageActivities) {
+        public List<ResolveInfo> queryIntentForPackage(Intent intent, String resolvedType,
+                int flags, ArrayList<PackageParser.Activity> packageActivities) {
             if (packageActivities == null) {
                 return null;
             }
             mFlags = flags;
             final boolean defaultOnly = (flags&PackageManager.MATCH_DEFAULT_ONLY) != 0;
-            int N = packageActivities.size();
+            final int N = packageActivities.size();
             ArrayList<ArrayList<PackageParser.ActivityIntentInfo>> listCut =
                 new ArrayList<ArrayList<PackageParser.ActivityIntentInfo>>(N);
 
@@ -4057,11 +4051,13 @@
         public final void addActivity(PackageParser.Activity a, String type) {
             final boolean systemApp = isSystemApp(a.info.applicationInfo);
             mActivities.put(a.getComponentName(), a);
-            if (SHOW_INFO || Config.LOGV) Log.v(
+            if (DEBUG_SHOW_INFO)
+                Log.v(
                 TAG, "  " + type + " " +
                 (a.info.nonLocalizedLabel != null ? a.info.nonLocalizedLabel : a.info.name) + ":");
-            if (SHOW_INFO || Config.LOGV) Log.v(TAG, "    Class=" + a.info.name);
-            int NI = a.intents.size();
+            if (DEBUG_SHOW_INFO)
+                Log.v(TAG, "    Class=" + a.info.name);
+            final int NI = a.intents.size();
             for (int j=0; j<NI; j++) {
                 PackageParser.ActivityIntentInfo intent = a.intents.get(j);
                 if (!systemApp && intent.getPriority() > 0 && "activity".equals(type)) {
@@ -4069,7 +4065,7 @@
                     Log.w(TAG, "Package " + a.info.applicationInfo.packageName + " has activity "
                             + a.className + " with priority > 0, forcing to 0");
                 }
-                if (SHOW_INFO || Config.LOGV) {
+                if (DEBUG_SHOW_INFO) {
                     Log.v(TAG, "    IntentFilter:");
                     intent.dump(new LogPrinter(Log.VERBOSE, TAG), "      ");
                 }
@@ -4082,14 +4078,16 @@
 
         public final void removeActivity(PackageParser.Activity a, String type) {
             mActivities.remove(a.getComponentName());
-            if (SHOW_INFO || Config.LOGV) Log.v(
-                TAG, "  " + type + " " +
-                (a.info.nonLocalizedLabel != null ? a.info.nonLocalizedLabel : a.info.name) + ":");
-            if (SHOW_INFO || Config.LOGV) Log.v(TAG, "    Class=" + a.info.name);
-            int NI = a.intents.size();
+            if (DEBUG_SHOW_INFO) {
+                Log.v(TAG, "  " + type + " "
+                        + (a.info.nonLocalizedLabel != null ? a.info.nonLocalizedLabel
+                                : a.info.name) + ":");
+                Log.v(TAG, "    Class=" + a.info.name);
+            }
+            final int NI = a.intents.size();
             for (int j=0; j<NI; j++) {
                 PackageParser.ActivityIntentInfo intent = a.intents.get(j);
-                if (SHOW_INFO || Config.LOGV) {
+                if (DEBUG_SHOW_INFO) {
                     Log.v(TAG, "    IntentFilter:");
                     intent.dump(new LogPrinter(Log.VERBOSE, TAG), "      ");
                 }
@@ -4193,25 +4191,26 @@
 
     private final class ServiceIntentResolver
             extends IntentResolver<PackageParser.ServiceIntentInfo, ResolveInfo> {
-        public List queryIntent(Intent intent, String resolvedType, boolean defaultOnly) {
+        public List<ResolveInfo> queryIntent(Intent intent, String resolvedType,
+                boolean defaultOnly) {
             mFlags = defaultOnly ? PackageManager.MATCH_DEFAULT_ONLY : 0;
             return super.queryIntent(intent, resolvedType, defaultOnly);
         }
 
-        public List queryIntent(Intent intent, String resolvedType, int flags) {
+        public List<ResolveInfo> queryIntent(Intent intent, String resolvedType, int flags) {
             mFlags = flags;
             return super.queryIntent(intent, resolvedType,
                 (flags&PackageManager.MATCH_DEFAULT_ONLY) != 0);
         }
 
-        public List queryIntentForPackage(Intent intent, String resolvedType, int flags,
-                                          ArrayList<PackageParser.Service> packageServices) {
+        public List<ResolveInfo> queryIntentForPackage(Intent intent, String resolvedType,
+                int flags, ArrayList<PackageParser.Service> packageServices) {
             if (packageServices == null) {
                 return null;
             }
             mFlags = flags;
             final boolean defaultOnly = (flags&PackageManager.MATCH_DEFAULT_ONLY) != 0;
-            int N = packageServices.size();
+            final int N = packageServices.size();
             ArrayList<ArrayList<PackageParser.ServiceIntentInfo>> listCut =
                 new ArrayList<ArrayList<PackageParser.ServiceIntentInfo>>(N);
 
@@ -4227,16 +4226,17 @@
 
         public final void addService(PackageParser.Service s) {
             mServices.put(s.getComponentName(), s);
-            if (SHOW_INFO || Config.LOGV) Log.v(
-                TAG, "  " + (s.info.nonLocalizedLabel != null
+            if (DEBUG_SHOW_INFO) {
+                Log.v(TAG, "  "
+                        + (s.info.nonLocalizedLabel != null
                         ? s.info.nonLocalizedLabel : s.info.name) + ":");
-            if (SHOW_INFO || Config.LOGV) Log.v(
-                    TAG, "    Class=" + s.info.name);
-            int NI = s.intents.size();
+                Log.v(TAG, "    Class=" + s.info.name);
+            }
+            final int NI = s.intents.size();
             int j;
             for (j=0; j<NI; j++) {
                 PackageParser.ServiceIntentInfo intent = s.intents.get(j);
-                if (SHOW_INFO || Config.LOGV) {
+                if (DEBUG_SHOW_INFO) {
                     Log.v(TAG, "    IntentFilter:");
                     intent.dump(new LogPrinter(Log.VERBOSE, TAG), "      ");
                 }
@@ -4249,16 +4249,16 @@
 
         public final void removeService(PackageParser.Service s) {
             mServices.remove(s.getComponentName());
-            if (SHOW_INFO || Config.LOGV) Log.v(
-                TAG, "  " + (s.info.nonLocalizedLabel != null
+            if (DEBUG_SHOW_INFO) {
+                Log.v(TAG, "  " + (s.info.nonLocalizedLabel != null
                         ? s.info.nonLocalizedLabel : s.info.name) + ":");
-            if (SHOW_INFO || Config.LOGV) Log.v(
-                    TAG, "    Class=" + s.info.name);
-            int NI = s.intents.size();
+                Log.v(TAG, "    Class=" + s.info.name);
+            }
+            final int NI = s.intents.size();
             int j;
             for (j=0; j<NI; j++) {
                 PackageParser.ServiceIntentInfo intent = s.intents.get(j);
-                if (SHOW_INFO || Config.LOGV) {
+                if (DEBUG_SHOW_INFO) {
                     Log.v(TAG, "    IntentFilter:");
                     intent.dump(new LogPrinter(Log.VERBOSE, TAG), "      ");
                 }
@@ -4485,13 +4485,12 @@
                     fullPathStr = fullPath.getPath();
                 }
 
-                if (Config.LOGV) Log.v(
-                    TAG, "File " + fullPathStr + " changed: "
-                    + Integer.toHexString(event));
+                if (DEBUG_APP_DIR_OBSERVER)
+                    Log.v(TAG, "File " + fullPathStr + " changed: " + Integer.toHexString(event));
 
                 if (!isPackageFilename(path)) {
-                    if (Config.LOGV) Log.v(
-                        TAG, "Ignoring change of non-package file: " + fullPathStr);
+                    if (DEBUG_APP_DIR_OBSERVER)
+                        Log.v(TAG, "Ignoring change of non-package file: " + fullPathStr);
                     return;
                 }
 
@@ -4581,13 +4580,8 @@
         mHandler.sendMessage(msg);
     }
 
-    public void setInstallerPackageName(String targetPackage,
-            String installerPackageName) {
-        PackageSetting pkgSetting;
+    public void setInstallerPackageName(String targetPackage, String installerPackageName) {
         final int uid = Binder.getCallingUid();
-        final int permission = mContext.checkCallingPermission(
-                android.Manifest.permission.INSTALL_PACKAGES);
-        final boolean allowedByPermission = (permission == PackageManager.PERMISSION_GRANTED);
         synchronized (mPackages) {
             PackageSetting targetPackageSetting = mSettings.mPackages.get(targetPackage);
             if (targetPackageSetting == null) {
@@ -4919,12 +4913,24 @@
                 Slog.w(TAG, "Cannot install fwd locked apps on sdcard");
                 ret = PackageManager.INSTALL_FAILED_INVALID_INSTALL_LOCATION;
             } else {
+                final long lowThreshold;
+
+                final DeviceStorageMonitorService dsm = (DeviceStorageMonitorService) ServiceManager
+                        .getService(DeviceStorageMonitorService.SERVICE);
+                if (dsm == null) {
+                    Log.w(TAG, "Couldn't get low memory threshold; no free limit imposed");
+                    lowThreshold = 0L;
+                } else {
+                    lowThreshold = dsm.getMemoryLowThreshold();
+                }
+
                 // Remote call to find out default install location
                 final PackageInfoLite pkgLite;
                 try {
                     mContext.grantUriPermission(DEFAULT_CONTAINER_PACKAGE, packageURI,
                             Intent.FLAG_GRANT_READ_URI_PERMISSION);
-                    pkgLite = mContainerService.getMinimalPackageInfo(packageURI, flags);
+                    pkgLite = mContainerService.getMinimalPackageInfo(packageURI, flags,
+                            lowThreshold);
                 } finally {
                     mContext.revokeUriPermission(packageURI, Intent.FLAG_GRANT_READ_URI_PERMISSION);
                 }
@@ -5144,10 +5150,26 @@
         }
 
         boolean checkFreeStorage(IMediaContainerService imcs) throws RemoteException {
+            final long lowThreshold;
+
+            final DeviceStorageMonitorService dsm = (DeviceStorageMonitorService) ServiceManager
+                    .getService(DeviceStorageMonitorService.SERVICE);
+            if (dsm == null) {
+                Log.w(TAG, "Couldn't get low memory threshold; no free limit imposed");
+                lowThreshold = 0L;
+            } else {
+                if (dsm.isMemoryLow()) {
+                    Log.w(TAG, "Memory is reported as being too low; aborting package install");
+                    return false;
+                }
+
+                lowThreshold = dsm.getMemoryLowThreshold();
+            }
+
             try {
                 mContext.grantUriPermission(DEFAULT_CONTAINER_PACKAGE, packageURI,
                         Intent.FLAG_GRANT_READ_URI_PERMISSION);
-                return imcs.checkFreeStorage(false, packageURI);
+                return imcs.checkInternalFreeStorage(packageURI, lowThreshold);
             } finally {
                 mContext.revokeUriPermission(packageURI, Intent.FLAG_GRANT_READ_URI_PERMISSION);
             }
@@ -5373,7 +5395,7 @@
             try {
                 mContext.grantUriPermission(DEFAULT_CONTAINER_PACKAGE, packageURI,
                         Intent.FLAG_GRANT_READ_URI_PERMISSION);
-                return imcs.checkFreeStorage(true, packageURI);
+                return imcs.checkExternalFreeStorage(packageURI);
             } finally {
                 mContext.revokeUriPermission(packageURI, Intent.FLAG_GRANT_READ_URI_PERMISSION);
             }
@@ -5720,11 +5742,6 @@
         boolean deletedPkg = true;
         boolean updatedSettings = false;
 
-        String oldInstallerPackageName = null;
-        synchronized (mPackages) {
-            oldInstallerPackageName = mSettings.getInstallerPackageName(pkgName);
-        }
-
         long origUpdateTime;
         if (pkg.mExtras != null) {
             origUpdateTime = ((PackageSetting)pkg.mExtras).lastUpdateTime;
@@ -6040,7 +6057,6 @@
     }
 
     private int setPermissionsLI(PackageParser.Package newPackage) {
-        String pkgName = newPackage.packageName;
         int retCode = 0;
         // TODO Gross hack but fix later. Ideally move this to be a post installation
         // check after alloting uid.
@@ -6070,9 +6086,8 @@
         }
 
         if (retCode != 0) {
-            Slog.e(TAG, "Couldn't set new package file permissions for " +
-                    newPackage.mPath
-                       + ". The return code was: " + retCode);
+            Slog.e(TAG, "Couldn't set new package file permissions for " + newPackage.mPath
+                    + ". The return code was: " + retCode);
             // TODO Define new internal error
             return PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE;
         }
@@ -6358,7 +6373,7 @@
                 // remove from preferred activities.
                 ArrayList<PreferredActivity> removed = new ArrayList<PreferredActivity>();
                 for (PreferredActivity pa : mSettings.mPreferredActivities.filterSet()) {
-                    if (pa.mActivity.getPackageName().equals(deletedPs.name)) {
+                    if (pa.mPref.mComponent.getPackageName().equals(deletedPs.name)) {
                         removed.add(pa);
                     }
                 }
@@ -6717,14 +6732,12 @@
         return new ArrayList<PackageInfo>();
     }
 
-    int getUidTargetSdkVersionLockedLP(int uid) {
+    private int getUidTargetSdkVersionLockedLP(int uid) {
         Object obj = mSettings.getUserIdLP(uid);
         if (obj instanceof SharedUserSetting) {
-            SharedUserSetting sus = (SharedUserSetting)obj;
-            final int N = sus.packages.size();
+            final SharedUserSetting sus = (SharedUserSetting) obj;
             int vers = Build.VERSION_CODES.CUR_DEVELOPMENT;
-            Iterator<PackageSetting> it = sus.packages.iterator();
-            int i=0;
+            final Iterator<PackageSetting> it = sus.packages.iterator();
             while (it.hasNext()) {
                 PackageSetting ps = it.next();
                 if (ps.pkg != null) {
@@ -6734,7 +6747,7 @@
             }
             return vers;
         } else if (obj instanceof PackageSetting) {
-            PackageSetting ps = (PackageSetting)obj;
+            final PackageSetting ps = (PackageSetting) obj;
             if (ps.pkg != null) {
                 return ps.pkg.applicationInfo.targetSdkVersion;
             }
@@ -6805,7 +6818,7 @@
                 PreferredActivity pa = it.next();
                 if (pa.getAction(0).equals(action) && pa.getCategory(0).equals(category)) {
                     it.remove();
-                    Log.i(TAG, "Removed preferred activity " + pa.mActivity + ":");
+                    Log.i(TAG, "Removed preferred activity " + pa.mPref.mComponent + ":");
                     filter.dump(new LogPrinter(Log.INFO, TAG), "  ");
                 }
             }
@@ -6843,7 +6856,7 @@
         Iterator<PreferredActivity> it = mSettings.mPreferredActivities.filterIterator();
         while (it.hasNext()) {
             PreferredActivity pa = it.next();
-            if (pa.mActivity.getPackageName().equals(packageName)) {
+            if (pa.mPref.mComponent.getPackageName().equals(packageName)) {
                 it.remove();
                 changed = true;
             }
@@ -6860,12 +6873,12 @@
             while (it.hasNext()) {
                 PreferredActivity pa = it.next();
                 if (packageName == null
-                        || pa.mActivity.getPackageName().equals(packageName)) {
+                        || pa.mPref.mComponent.getPackageName().equals(packageName)) {
                     if (outFilters != null) {
                         outFilters.add(new IntentFilter(pa));
                     }
                     if (outActivities != null) {
-                        outActivities.add(pa.mActivity);
+                        outActivities.add(pa.mPref.mComponent);
                     }
                 }
             }
@@ -6990,8 +7003,9 @@
 
     private void sendPackageChangedBroadcast(String packageName,
             boolean killFlag, ArrayList<String> componentNames, int packageUid) {
-        if (false) Log.v(TAG, "Sending package changed: package=" + packageName
-                + " components=" + componentNames);
+        if (DEBUG_INSTALL)
+            Log.v(TAG, "Sending package changed: package=" + packageName + " components="
+                    + componentNames);
         Bundle extras = new Bundle(4);
         extras.putString(Intent.EXTRA_CHANGED_COMPONENT_NAME, componentNames.get(0));
         String nameList[] = new String[componentNames.size()];
@@ -7030,8 +7044,8 @@
                 if (pkgSetting.notLaunched) {
                     if (pkgSetting.installerPackageName != null) {
                         sendPackageBroadcast(Intent.ACTION_PACKAGE_FIRST_LAUNCH,
-                                pkgSetting.installerPackageName, null,
-                                pkgSetting.name, null);
+                                pkgSetting.name, null,
+                                pkgSetting.installerPackageName, null);
                     }
                     pkgSetting.notLaunched = false;
                 }
@@ -7717,168 +7731,41 @@
         }
     }
 
-    static class PreferredActivity extends IntentFilter {
-        final int mMatch;
-        final String[] mSetPackages;
-        final String[] mSetClasses;
-        final String[] mSetComponents;
-        final ComponentName mActivity;
-        final String mShortActivity;
-        String mParseError;
+    static class PreferredActivity extends IntentFilter implements PreferredComponent.Callbacks {
+        final PreferredComponent mPref;
 
         PreferredActivity(IntentFilter filter, int match, ComponentName[] set,
                 ComponentName activity) {
             super(filter);
-            mMatch = match&IntentFilter.MATCH_CATEGORY_MASK;
-            mActivity = activity;
-            mShortActivity = activity.flattenToShortString();
-            mParseError = null;
-            if (set != null) {
-                final int N = set.length;
-                String[] myPackages = new String[N];
-                String[] myClasses = new String[N];
-                String[] myComponents = new String[N];
-                for (int i=0; i<N; i++) {
-                    ComponentName cn = set[i];
-                    if (cn == null) {
-                        mSetPackages = null;
-                        mSetClasses = null;
-                        mSetComponents = null;
-                        return;
-                    }
-                    myPackages[i] = cn.getPackageName().intern();
-                    myClasses[i] = cn.getClassName().intern();
-                    myComponents[i] = cn.flattenToShortString().intern();
-                }
-                mSetPackages = myPackages;
-                mSetClasses = myClasses;
-                mSetComponents = myComponents;
-            } else {
-                mSetPackages = null;
-                mSetClasses = null;
-                mSetComponents = null;
-            }
+            mPref = new PreferredComponent(this, match, set, activity);
         }
 
         PreferredActivity(XmlPullParser parser) throws XmlPullParserException,
                 IOException {
-            mShortActivity = parser.getAttributeValue(null, "name");
-            mActivity = ComponentName.unflattenFromString(mShortActivity);
-            if (mActivity == null) {
-                mParseError = "Bad activity name " + mShortActivity;
-            }
-            String matchStr = parser.getAttributeValue(null, "match");
-            mMatch = matchStr != null ? Integer.parseInt(matchStr, 16) : 0;
-            String setCountStr = parser.getAttributeValue(null, "set");
-            int setCount = setCountStr != null ? Integer.parseInt(setCountStr) : 0;
-
-            String[] myPackages = setCount > 0 ? new String[setCount] : null;
-            String[] myClasses = setCount > 0 ? new String[setCount] : null;
-            String[] myComponents = setCount > 0 ? new String[setCount] : null;
-
-            int setPos = 0;
-
-            int outerDepth = parser.getDepth();
-            int type;
-            while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
-                   && (type != XmlPullParser.END_TAG
-                           || parser.getDepth() > outerDepth)) {
-                if (type == XmlPullParser.END_TAG
-                        || type == XmlPullParser.TEXT) {
-                    continue;
-                }
-
-                String tagName = parser.getName();
-                //Log.i(TAG, "Parse outerDepth=" + outerDepth + " depth="
-                //        + parser.getDepth() + " tag=" + tagName);
-                if (tagName.equals("set")) {
-                    String name = parser.getAttributeValue(null, "name");
-                    if (name == null) {
-                        if (mParseError == null) {
-                            mParseError = "No name in set tag in preferred activity "
-                                + mShortActivity;
-                        }
-                    } else if (setPos >= setCount) {
-                        if (mParseError == null) {
-                            mParseError = "Too many set tags in preferred activity "
-                                + mShortActivity;
-                        }
-                    } else {
-                        ComponentName cn = ComponentName.unflattenFromString(name);
-                        if (cn == null) {
-                            if (mParseError == null) {
-                                mParseError = "Bad set name " + name + " in preferred activity "
-                                    + mShortActivity;
-                            }
-                        } else {
-                            myPackages[setPos] = cn.getPackageName();
-                            myClasses[setPos] = cn.getClassName();
-                            myComponents[setPos] = name;
-                            setPos++;
-                        }
-                    }
-                    XmlUtils.skipCurrentTag(parser);
-                } else if (tagName.equals("filter")) {
-                    //Log.i(TAG, "Starting to parse filter...");
-                    readFromXml(parser);
-                    //Log.i(TAG, "Finished filter: outerDepth=" + outerDepth + " depth="
-                    //        + parser.getDepth() + " tag=" + parser.getName());
-                } else {
-                    reportSettingsProblem(Log.WARN,
-                            "Unknown element under <preferred-activities>: "
-                            + parser.getName());
-                    XmlUtils.skipCurrentTag(parser);
-                }
-            }
-
-            if (setPos != setCount) {
-                if (mParseError == null) {
-                    mParseError = "Not enough set tags (expected " + setCount
-                        + " but found " + setPos + ") in " + mShortActivity;
-                }
-            }
-
-            mSetPackages = myPackages;
-            mSetClasses = myClasses;
-            mSetComponents = myComponents;
+            mPref = new PreferredComponent(this, parser);
         }
 
         public void writeToXml(XmlSerializer serializer) throws IOException {
-            final int NS = mSetClasses != null ? mSetClasses.length : 0;
-            serializer.attribute(null, "name", mShortActivity);
-            serializer.attribute(null, "match", Integer.toHexString(mMatch));
-            serializer.attribute(null, "set", Integer.toString(NS));
-            for (int s=0; s<NS; s++) {
-                serializer.startTag(null, "set");
-                serializer.attribute(null, "name", mSetComponents[s]);
-                serializer.endTag(null, "set");
-            }
+            mPref.writeToXml(serializer);
             serializer.startTag(null, "filter");
             super.writeToXml(serializer);
             serializer.endTag(null, "filter");
         }
 
-        boolean sameSet(List<ResolveInfo> query, int priority) {
-            if (mSetPackages == null) return false;
-            final int NQ = query.size();
-            final int NS = mSetPackages.length;
-            int numMatch = 0;
-            for (int i=0; i<NQ; i++) {
-                ResolveInfo ri = query.get(i);
-                if (ri.priority != priority) continue;
-                ActivityInfo ai = ri.activityInfo;
-                boolean good = false;
-                for (int j=0; j<NS; j++) {
-                    if (mSetPackages[j].equals(ai.packageName)
-                            && mSetClasses[j].equals(ai.name)) {
-                        numMatch++;
-                        good = true;
-                        break;
-                    }
-                }
-                if (!good) return false;
+        public boolean onReadTag(String tagName, XmlPullParser parser)
+                throws XmlPullParserException, IOException {
+            if (tagName.equals("filter")) {
+                //Log.i(TAG, "Starting to parse filter...");
+                readFromXml(parser);
+                //Log.i(TAG, "Finished filter: outerDepth=" + outerDepth + " depth="
+                //        + parser.getDepth() + " tag=" + parser.getName());
+            } else {
+                reportSettingsProblem(Log.WARN,
+                        "Unknown element under <preferred-activities>: "
+                        + parser.getName());
+                XmlUtils.skipCurrentTag(parser);
             }
-            return numMatch == NS;
+            return true;
         }
     }
 
@@ -8161,24 +8048,12 @@
                     new IntentResolver<PreferredActivity, PreferredActivity>() {
             @Override
             protected String packageForFilter(PreferredActivity filter) {
-                return filter.mActivity.getPackageName();
+                return filter.mPref.mComponent.getPackageName();
             }
             @Override
             protected void dumpFilter(PrintWriter out, String prefix,
                     PreferredActivity filter) {
-                out.print(prefix); out.print(
-                        Integer.toHexString(System.identityHashCode(filter)));
-                        out.print(' ');
-                        out.print(filter.mActivity.flattenToShortString());
-                        out.print(" match=0x");
-                        out.println( Integer.toHexString(filter.mMatch));
-                if (filter.mSetComponents != null) {
-                    out.print(prefix); out.println("  Selected from:");
-                    for (int i=0; i<filter.mSetComponents.length; i++) {
-                        out.print(prefix); out.print("    ");
-                                out.println(filter.mSetComponents[i]);
-                    }
-                }
+                filter.mPref.dump(out, prefix, filter);
             }
         };
         private final HashMap<String, SharedUserSetting> mSharedUsers =
@@ -8283,19 +8158,6 @@
             }
         }
 
-        String getInstallerPackageName(String pkgName) {
-            PackageSetting p = mPackages.get(pkgName);
-            return (p == null) ? null : p.getInstallerPackageName();
-        }
-
-        int getInstallStatus(String pkgName) {
-            PackageSetting p = mPackages.get(pkgName);
-            if(p != null) {
-                return p.getInstallStatus();
-            }
-            return -1;
-        }
-
         SharedUserSetting getSharedUserLP(String name,
                 int pkgFlags, boolean create) {
             SharedUserSetting s = mSharedUsers.get(name);
@@ -8733,7 +8595,7 @@
 
         public Object getUserIdLP(int uid) {
             if (uid >= FIRST_APPLICATION_UID) {
-                int N = mUserIds.size();
+                final int N = mUserIds.size();
                 final int index = uid - FIRST_APPLICATION_UID;
                 return index < N ? mUserIds.get(index) : null;
             } else {
@@ -8741,20 +8603,9 @@
             }
         }
 
-        private Set<String> findPackagesWithFlag(int flag) {
-            Set<String> ret = new HashSet<String>();
-            for (PackageSetting ps : mPackages.values()) {
-                // Has to match atleast all the flag bits set on flag
-                if ((ps.pkgFlags & flag) == flag) {
-                    ret.add(ps.name);
-                }
-            }
-            return ret;
-        }
-
         private void removeUserIdLP(int uid) {
             if (uid >= FIRST_APPLICATION_UID) {
-                int N = mUserIds.size();
+                final int N = mUserIds.size();
                 final int index = uid - FIRST_APPLICATION_UID;
                 if (index < N) mUserIds.set(index, null);
             } else {
@@ -8764,7 +8615,7 @@
 
         private void replaceUserIdLP(int uid, Object obj) {
             if (uid >= FIRST_APPLICATION_UID) {
-                int N = mUserIds.size();
+                final int N = mUserIds.size();
                 final int index = uid - FIRST_APPLICATION_UID;
                 if (index < N) mUserIds.set(index, obj);
             } else {
@@ -9299,10 +9150,6 @@
             }
         }
 
-        String getReadMessagesLP() {
-            return mReadMessages.toString();
-        }
-
         ArrayList<PackageSetting> getListOfIncompleteInstallPackages() {
             HashSet<String> kList = new HashSet<String>(mPackages.keySet());
             Iterator<String> its = kList.iterator();
@@ -9432,7 +9279,7 @@
 
             }
 
-            int N = mPendingPackages.size();
+            final int N = mPendingPackages.size();
             for (int i=0; i<N; i++) {
                 final PendingPackage pp = mPendingPackages.get(i);
                 Object idObj = getUserIdLP(pp.sharedId);
@@ -10010,12 +9857,12 @@
                 String tagName = parser.getName();
                 if (tagName.equals("item")) {
                     PreferredActivity pa = new PreferredActivity(parser);
-                    if (pa.mParseError == null) {
+                    if (pa.mPref.getParseError() == null) {
                         mPreferredActivities.addFilter(pa);
                     } else {
                         reportSettingsProblem(Log.WARN,
                                 "Error in package manager settings: <preferred-activity> "
-                                + pa.mParseError + " at "
+                                + pa.mPref.getParseError() + " at "
                                 + parser.getPositionDescription());
                     }
                 } else {
@@ -10059,7 +9906,7 @@
                 return true;
             }
             final PackageSetting packageSettings = mPackages.get(componentInfo.packageName);
-            if (Config.LOGV) {
+            if (DEBUG_SETTINGS) {
                 Log.v(TAG, "isEnabledLock - packageName = " + componentInfo.packageName
                            + " componentName = " + componentInfo.name);
                 Log.v(TAG, "enabledComponents: "
@@ -10068,11 +9915,6 @@
                            + Arrays.toString(packageSettings.disabledComponents.toArray()));
             }
             if (packageSettings == null) {
-                if (false) {
-                    Log.w(TAG, "WAITING FOR DEBUGGER");
-                    Debug.waitForDebugger();
-                    Log.i(TAG, "We will crash!");
-                }
                 return false;
             }
             if (packageSettings.enabled == COMPONENT_ENABLED_STATE_DISABLED
@@ -10399,7 +10241,6 @@
        ArrayList<SdInstallArgs> failedList = new ArrayList<SdInstallArgs>();
        final Set<SdInstallArgs> keys = processCids.keySet();
        for (SdInstallArgs args : keys) {
-           String cid = args.cid;
            String pkgName = args.getPackageName();
            if (DEBUG_SD_INSTALL) Log.i(TAG, "Trying to unload pkg : " + pkgName);
            // Delete package internally
diff --git a/services/java/com/android/server/PreferredComponent.java b/services/java/com/android/server/PreferredComponent.java
new file mode 100644
index 0000000..718b05d
--- /dev/null
+++ b/services/java/com/android/server/PreferredComponent.java
@@ -0,0 +1,219 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server;
+
+import com.android.internal.util.XmlUtils;
+
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+import org.xmlpull.v1.XmlSerializer;
+
+import android.content.ComponentName;
+import android.content.IntentFilter;
+import android.content.pm.ActivityInfo;
+import android.content.pm.ResolveInfo;
+import android.util.Slog;
+
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.util.List;
+
+public class PreferredComponent {
+    public final int mMatch;
+    public final ComponentName mComponent;
+
+    private final String[] mSetPackages;
+    private final String[] mSetClasses;
+    private final String[] mSetComponents;
+    private final String mShortComponent;
+    private String mParseError;
+
+    private final Callbacks mCallbacks;
+
+    public interface Callbacks {
+        public boolean onReadTag(String tagName, XmlPullParser parser)
+                throws XmlPullParserException, IOException;
+    }
+
+    public PreferredComponent(Callbacks callbacks, int match, ComponentName[] set,
+            ComponentName component) {
+        mCallbacks = callbacks;
+        mMatch = match&IntentFilter.MATCH_CATEGORY_MASK;
+        mComponent = component;
+        mShortComponent = component.flattenToShortString();
+        mParseError = null;
+        if (set != null) {
+            final int N = set.length;
+            String[] myPackages = new String[N];
+            String[] myClasses = new String[N];
+            String[] myComponents = new String[N];
+            for (int i=0; i<N; i++) {
+                ComponentName cn = set[i];
+                if (cn == null) {
+                    mSetPackages = null;
+                    mSetClasses = null;
+                    mSetComponents = null;
+                    return;
+                }
+                myPackages[i] = cn.getPackageName().intern();
+                myClasses[i] = cn.getClassName().intern();
+                myComponents[i] = cn.flattenToShortString().intern();
+            }
+            mSetPackages = myPackages;
+            mSetClasses = myClasses;
+            mSetComponents = myComponents;
+        } else {
+            mSetPackages = null;
+            mSetClasses = null;
+            mSetComponents = null;
+        }
+    }
+
+    public PreferredComponent(Callbacks callbacks, XmlPullParser parser)
+            throws XmlPullParserException, IOException {
+        mCallbacks = callbacks;
+        mShortComponent = parser.getAttributeValue(null, "name");
+        mComponent = ComponentName.unflattenFromString(mShortComponent);
+        if (mComponent == null) {
+            mParseError = "Bad activity name " + mShortComponent;
+        }
+        String matchStr = parser.getAttributeValue(null, "match");
+        mMatch = matchStr != null ? Integer.parseInt(matchStr, 16) : 0;
+        String setCountStr = parser.getAttributeValue(null, "set");
+        int setCount = setCountStr != null ? Integer.parseInt(setCountStr) : 0;
+
+        String[] myPackages = setCount > 0 ? new String[setCount] : null;
+        String[] myClasses = setCount > 0 ? new String[setCount] : null;
+        String[] myComponents = setCount > 0 ? new String[setCount] : null;
+
+        int setPos = 0;
+
+        int outerDepth = parser.getDepth();
+        int type;
+        while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
+               && (type != XmlPullParser.END_TAG
+                       || parser.getDepth() > outerDepth)) {
+            if (type == XmlPullParser.END_TAG
+                    || type == XmlPullParser.TEXT) {
+                continue;
+            }
+
+            String tagName = parser.getName();
+            //Log.i(TAG, "Parse outerDepth=" + outerDepth + " depth="
+            //        + parser.getDepth() + " tag=" + tagName);
+            if (tagName.equals("set")) {
+                String name = parser.getAttributeValue(null, "name");
+                if (name == null) {
+                    if (mParseError == null) {
+                        mParseError = "No name in set tag in preferred activity "
+                            + mShortComponent;
+                    }
+                } else if (setPos >= setCount) {
+                    if (mParseError == null) {
+                        mParseError = "Too many set tags in preferred activity "
+                            + mShortComponent;
+                    }
+                } else {
+                    ComponentName cn = ComponentName.unflattenFromString(name);
+                    if (cn == null) {
+                        if (mParseError == null) {
+                            mParseError = "Bad set name " + name + " in preferred activity "
+                                + mShortComponent;
+                        }
+                    } else {
+                        myPackages[setPos] = cn.getPackageName();
+                        myClasses[setPos] = cn.getClassName();
+                        myComponents[setPos] = name;
+                        setPos++;
+                    }
+                }
+                XmlUtils.skipCurrentTag(parser);
+            } else if (!mCallbacks.onReadTag(tagName, parser)) {
+                Slog.w("PreferredComponent", "Unknown element: " + parser.getName());
+                XmlUtils.skipCurrentTag(parser);
+            }
+        }
+
+        if (setPos != setCount) {
+            if (mParseError == null) {
+                mParseError = "Not enough set tags (expected " + setCount
+                    + " but found " + setPos + ") in " + mShortComponent;
+            }
+        }
+
+        mSetPackages = myPackages;
+        mSetClasses = myClasses;
+        mSetComponents = myComponents;
+    }
+
+    public String getParseError() {
+        return mParseError;
+    }
+
+    public void writeToXml(XmlSerializer serializer) throws IOException {
+        final int NS = mSetClasses != null ? mSetClasses.length : 0;
+        serializer.attribute(null, "name", mShortComponent);
+        if (mMatch != 0) {
+            serializer.attribute(null, "match", Integer.toHexString(mMatch));
+        }
+        serializer.attribute(null, "set", Integer.toString(NS));
+        for (int s=0; s<NS; s++) {
+            serializer.startTag(null, "set");
+            serializer.attribute(null, "name", mSetComponents[s]);
+            serializer.endTag(null, "set");
+        }
+    }
+
+    public boolean sameSet(List<ResolveInfo> query, int priority) {
+        if (mSetPackages == null) return false;
+        final int NQ = query.size();
+        final int NS = mSetPackages.length;
+        int numMatch = 0;
+        for (int i=0; i<NQ; i++) {
+            ResolveInfo ri = query.get(i);
+            if (ri.priority != priority) continue;
+            ActivityInfo ai = ri.activityInfo;
+            boolean good = false;
+            for (int j=0; j<NS; j++) {
+                if (mSetPackages[j].equals(ai.packageName)
+                        && mSetClasses[j].equals(ai.name)) {
+                    numMatch++;
+                    good = true;
+                    break;
+                }
+            }
+            if (!good) return false;
+        }
+        return numMatch == NS;
+    }
+
+    public void dump(PrintWriter out, String prefix, Object ident) {
+        out.print(prefix); out.print(
+                Integer.toHexString(System.identityHashCode(ident)));
+                out.print(' ');
+                out.print(mComponent.flattenToShortString());
+                out.print(" match=0x");
+                out.println( Integer.toHexString(mMatch));
+        if (mSetComponents != null) {
+            out.print(prefix); out.println("  Selected from:");
+            for (int i=0; i<mSetComponents.length; i++) {
+                out.print(prefix); out.print("    ");
+                        out.println(mSetComponents[i]);
+            }
+        }
+    }
+}
diff --git a/services/java/com/android/server/WifiService.java b/services/java/com/android/server/WifiService.java
index adc49ae..915b679 100644
--- a/services/java/com/android/server/WifiService.java
+++ b/services/java/com/android/server/WifiService.java
@@ -29,12 +29,12 @@
 import android.content.pm.PackageManager;
 import android.database.ContentObserver;
 import android.net.wifi.IWifiManager;
+import android.net.wifi.ScanResult;
+import android.net.wifi.SupplicantState;
 import android.net.wifi.WifiInfo;
 import android.net.wifi.WifiManager;
 import android.net.wifi.WifiStateMachine;
-import android.net.wifi.ScanResult;
 import android.net.wifi.WifiConfiguration;
-import android.net.wifi.SupplicantState;
 import android.net.wifi.WifiConfiguration.KeyMgmt;
 import android.net.wifi.WpsConfiguration;
 import android.net.wifi.WpsResult;
@@ -62,6 +62,7 @@
 import java.util.ArrayList;
 import java.util.List;
 import java.util.Set;
+import java.util.concurrent.atomic.AtomicInteger;
 import java.util.concurrent.atomic.AtomicBoolean;
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
@@ -99,9 +100,6 @@
     /* Chipset supports background scan */
     private final boolean mBackgroundScanSupported;
 
-    // true if the user enabled Wifi while in airplane mode
-    private AtomicBoolean mAirplaneModeOverwridden = new AtomicBoolean(false);
-
     private final LockList mLocks = new LockList();
     // some wifi lock statistics
     private int mFullHighPerfLocksAcquired;
@@ -144,6 +142,14 @@
     private static final String ACTION_DEVICE_IDLE =
             "com.android.server.WifiManager.action.DEVICE_IDLE";
 
+    private static final int WIFI_DISABLED                  = 0;
+    private static final int WIFI_ENABLED                   = 1;
+    /* Wifi enabled while in airplane mode */
+    private static final int WIFI_ENABLED_AIRPLANE_OVERRIDE = 2;
+
+    private AtomicInteger mWifiState = new AtomicInteger(WIFI_DISABLED);
+    private AtomicBoolean mAirplaneModeOn = new AtomicBoolean(false);
+
     private boolean mIsReceiverRegistered = false;
 
 
@@ -229,6 +235,15 @@
                     }
                     break;
                 }
+                case AsyncChannel.CMD_CHANNEL_DISCONNECTED: {
+                    if (msg.arg1 == AsyncChannel.STATUS_SEND_UNSUCCESSFUL) {
+                        Slog.d(TAG, "Send failed, client connection lost");
+                    } else {
+                        Slog.d(TAG, "Client connection lost with reason: " + msg.arg1);
+                    }
+                    mClients.remove((AsyncChannel) msg.obj);
+                    break;
+                }
                 case AsyncChannel.CMD_CHANNEL_FULL_CONNECTION: {
                     AsyncChannel ac = new AsyncChannel();
                     ac.connect(mContext, this, msg.replyTo);
@@ -338,11 +353,11 @@
                 new BroadcastReceiver() {
                     @Override
                     public void onReceive(Context context, Intent intent) {
-                        // clear our flag indicating the user has overwridden airplane mode
-                        mAirplaneModeOverwridden.set(false);
-                        // on airplane disable, restore Wifi if the saved state indicates so
-                        if (!isAirplaneModeOn() && testAndClearWifiSavedState()) {
-                            persistWifiEnabled(true);
+                        mAirplaneModeOn.set(isAirplaneModeOn());
+                        /* On airplane mode disable, restore wifi state if necessary */
+                        if (!mAirplaneModeOn.get() && (testAndClearWifiSavedState() ||
+                            mWifiState.get() == WIFI_ENABLED_AIRPLANE_OVERRIDE)) {
+                                persistWifiEnabled(true);
                         }
                         updateWifiState();
                     }
@@ -402,9 +417,10 @@
      * This function is used only at boot time
      */
     public void checkAndStartWifi() {
-        /* Start if Wi-Fi is enabled or the saved state indicates Wi-Fi was on */
-        boolean wifiEnabled = !isAirplaneModeOn()
-                && (getPersistedWifiEnabled() || testAndClearWifiSavedState());
+        mAirplaneModeOn.set(isAirplaneModeOn());
+        mWifiState.set(getPersistedWifiState());
+        /* Start if Wi-Fi should be enabled or the saved state indicates Wi-Fi was on */
+        boolean wifiEnabled = shouldWifiBeEnabled() || testAndClearWifiSavedState();
         Slog.i(TAG, "WifiService starting up with Wi-Fi " +
                 (wifiEnabled ? "enabled" : "disabled"));
         setWifiEnabled(wifiEnabled);
@@ -423,21 +439,39 @@
         return (wifiSavedState == 1);
     }
 
-    private boolean getPersistedWifiEnabled() {
+    private int getPersistedWifiState() {
         final ContentResolver cr = mContext.getContentResolver();
         try {
-            return Settings.Secure.getInt(cr, Settings.Secure.WIFI_ON) == 1;
+            return Settings.Secure.getInt(cr, Settings.Secure.WIFI_ON);
         } catch (Settings.SettingNotFoundException e) {
-            Settings.Secure.putInt(cr, Settings.Secure.WIFI_ON, 0);
-            return false;
+            Settings.Secure.putInt(cr, Settings.Secure.WIFI_ON, WIFI_DISABLED);
+            return WIFI_DISABLED;
+        }
+    }
+
+    private boolean shouldWifiBeEnabled() {
+        if (mAirplaneModeOn.get()) {
+            return mWifiState.get() == WIFI_ENABLED_AIRPLANE_OVERRIDE;
+        } else {
+            return mWifiState.get() != WIFI_DISABLED;
         }
     }
 
     private void persistWifiEnabled(boolean enabled) {
         final ContentResolver cr = mContext.getContentResolver();
-        Settings.Secure.putInt(cr, Settings.Secure.WIFI_ON, enabled ? 1 : 0);
+        if (enabled) {
+            if (isAirplaneModeOn() && isAirplaneToggleable()) {
+                mWifiState.set(WIFI_ENABLED_AIRPLANE_OVERRIDE);
+            } else {
+                mWifiState.set(WIFI_ENABLED);
+            }
+        } else {
+            mWifiState.set(WIFI_DISABLED);
+        }
+        Settings.Secure.putInt(cr, Settings.Secure.WIFI_ON, mWifiState.get());
     }
 
+
     /**
      * see {@link android.net.wifi.WifiManager#pingSupplicant()}
      * @return {@code true} if the operation succeeds, {@code false} otherwise
@@ -490,11 +524,6 @@
             Slog.e(TAG, "Invoking mWifiStateMachine.setWifiEnabled\n");
         }
 
-        // set a flag if the user is enabling Wifi while in airplane mode
-        if (enable && isAirplaneModeOn() && isAirplaneToggleable()) {
-            mAirplaneModeOverwridden.set(true);
-        }
-
         if (enable) {
             reportStartWorkSource();
         }
@@ -862,8 +891,6 @@
         mWifiStateMachine.clearBlacklist();
     }
 
-
-
     /**
      * Get a reference to handler. This is used by a client to establish
      * an AsyncChannel communication with WifiService
@@ -878,6 +905,14 @@
         return new Messenger(mAsyncServiceHandler);
     }
 
+    /**
+     * Get the IP and proxy configuration file
+     */
+    public String getConfigFile() {
+        enforceAccessPermission();
+        return mWifiStateMachine.getConfigFile();
+    }
+
     private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
         @Override
         public void onReceive(Context context, Intent intent) {
@@ -1037,11 +1072,8 @@
     }
 
     private void updateWifiState() {
-        boolean wifiEnabled = getPersistedWifiEnabled();
-        boolean airplaneMode = isAirplaneModeOn() && !mAirplaneModeOverwridden.get();
         boolean lockHeld = mLocks.hasLocks();
         int strongestLockMode = WifiManager.WIFI_MODE_FULL;
-        boolean wifiShouldBeEnabled = wifiEnabled && !airplaneMode;
         boolean wifiShouldBeStarted = !mDeviceIdle || lockHeld;
 
         if (lockHeld) {
@@ -1053,11 +1085,11 @@
         }
 
         /* Disable tethering when airplane mode is enabled */
-        if (airplaneMode) {
+        if (mAirplaneModeOn.get()) {
             mWifiStateMachine.setWifiApEnabled(null, false);
         }
 
-        if (wifiShouldBeEnabled) {
+        if (shouldWifiBeEnabled()) {
             if (wifiShouldBeStarted) {
                 reportStartWorkSource();
                 mWifiStateMachine.setWifiEnabled(true);
diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java
index 0fab964..50fffd0 100644
--- a/services/java/com/android/server/am/ActivityManagerService.java
+++ b/services/java/com/android/server/am/ActivityManagerService.java
@@ -3151,6 +3151,9 @@
                 try {
                     pm.setPackageStoppedState(packageName, true);
                 } catch (RemoteException e) {
+                } catch (IllegalArgumentException e) {
+                    Slog.w(TAG, "Failed trying to unstop package "
+                            + packageName + ": " + e);
                 }
             }
         } finally {
@@ -5559,6 +5562,9 @@
                             AppGlobals.getPackageManager().setPackageStoppedState(
                                     cpr.appInfo.packageName, false);
                         } catch (RemoteException e) {
+                        } catch (IllegalArgumentException e) {
+                            Slog.w(TAG, "Failed trying to unstop package "
+                                    + cpr.appInfo.packageName + ": " + e);
                         }
 
                         ProcessRecord proc = startProcessLocked(cpi.processName,
@@ -5840,6 +5846,9 @@
             AppGlobals.getPackageManager().setPackageStoppedState(
                     info.packageName, false);
         } catch (RemoteException e) {
+        } catch (IllegalArgumentException e) {
+            Slog.w(TAG, "Failed trying to unstop package "
+                    + info.packageName + ": " + e);
         }
 
         if ((info.flags&(ApplicationInfo.FLAG_SYSTEM|ApplicationInfo.FLAG_PERSISTENT))
@@ -6673,8 +6682,10 @@
                 mProcessCrashTimes.remove(app.info.processName, app.info.uid);
                 app.removed = true;
                 removeProcessLocked(app, false);
+                mMainStack.resumeTopActivityLocked(null);
                 return false;
             }
+            mMainStack.resumeTopActivityLocked(null);
         } else {
             ActivityRecord r = mMainStack.topRunningActivityLocked(null);
             if (r.app == app) {
@@ -6780,7 +6791,7 @@
      * @param crashInfo describing the exception
      */
     public void handleApplicationCrash(IBinder app, ApplicationErrorReport.CrashInfo crashInfo) {
-        ProcessRecord r = findAppProcess(app);
+        ProcessRecord r = findAppProcess(app, "Crash");
 
         EventLog.writeEvent(EventLogTags.AM_CRASH, Binder.getCallingPid(),
                 app == null ? "system" : (r == null ? "unknown" : r.processName),
@@ -6799,7 +6810,10 @@
             IBinder app,
             int violationMask,
             StrictMode.ViolationInfo info) {
-        ProcessRecord r = findAppProcess(app);
+        ProcessRecord r = findAppProcess(app, "StrictMode");
+        if (r == null) {
+            return;
+        }
 
         if ((violationMask & StrictMode.PENALTY_DROPBOX) != 0) {
             Integer stackFingerprint = info.hashCode();
@@ -6973,7 +6987,7 @@
      */
     public boolean handleApplicationWtf(IBinder app, String tag,
             ApplicationErrorReport.CrashInfo crashInfo) {
-        ProcessRecord r = findAppProcess(app);
+        ProcessRecord r = findAppProcess(app, "WTF");
 
         EventLog.writeEvent(EventLogTags.AM_WTF, Binder.getCallingPid(),
                 app == null ? "system" : (r == null ? "unknown" : r.processName),
@@ -6982,8 +6996,9 @@
 
         addErrorToDropBox("wtf", r, null, null, tag, null, null, crashInfo);
 
-        if (Settings.Secure.getInt(mContext.getContentResolver(),
-                Settings.Secure.WTF_IS_FATAL, 0) != 0) {
+        if (r != null && r.pid != Process.myPid() &&
+                Settings.Secure.getInt(mContext.getContentResolver(),
+                        Settings.Secure.WTF_IS_FATAL, 0) != 0) {
             crashApplication(r, crashInfo);
             return true;
         } else {
@@ -6995,7 +7010,7 @@
      * @param app object of some object (as stored in {@link com.android.internal.os.RuntimeInit})
      * @return the corresponding {@link ProcessRecord} object, or null if none could be found
      */
-    private ProcessRecord findAppProcess(IBinder app) {
+    private ProcessRecord findAppProcess(IBinder app, String reason) {
         if (app == null) {
             return null;
         }
@@ -7011,7 +7026,9 @@
                 }
             }
 
-            Slog.w(TAG, "Can't find mystery application: " + app);
+            Slog.w(TAG, "Can't find mystery application for " + reason
+                    + " from pid=" + Binder.getCallingPid()
+                    + " uid=" + Binder.getCallingUid() + ": " + app);
             return null;
         }
     }
@@ -9396,6 +9413,9 @@
             AppGlobals.getPackageManager().setPackageStoppedState(
                     r.packageName, false);
         } catch (RemoteException e) {
+        } catch (IllegalArgumentException e) {
+            Slog.w(TAG, "Failed trying to unstop package "
+                    + r.packageName + ": " + e);
         }
 
         final String appName = r.processName;
@@ -10297,6 +10317,9 @@
                 AppGlobals.getPackageManager().setPackageStoppedState(
                         app.packageName, false);
             } catch (RemoteException e) {
+            } catch (IllegalArgumentException e) {
+                Slog.w(TAG, "Failed trying to unstop package "
+                        + app.packageName + ": " + e);
             }
 
             BackupRecord r = new BackupRecord(ss, app, backupMode);
@@ -11625,6 +11648,9 @@
                 AppGlobals.getPackageManager().setPackageStoppedState(
                         r.curComponent.getPackageName(), false);
             } catch (RemoteException e) {
+            } catch (IllegalArgumentException e) {
+                Slog.w(TAG, "Failed trying to unstop package "
+                        + r.curComponent.getPackageName() + ": " + e);
             }
 
             // Is this receiver's application already running?
diff --git a/services/java/com/android/server/am/ActivityStack.java b/services/java/com/android/server/am/ActivityStack.java
index 3a613bb..c087aecf 100644
--- a/services/java/com/android/server/am/ActivityStack.java
+++ b/services/java/com/android/server/am/ActivityStack.java
@@ -1299,6 +1299,9 @@
             AppGlobals.getPackageManager().setPackageStoppedState(
                     next.packageName, false);
         } catch (RemoteException e1) {
+        } catch (IllegalArgumentException e) {
+            Slog.w(TAG, "Failed trying to unstop package "
+                    + next.packageName + ": " + e);
         }
 
         // We are starting up the next activity, so tell the window manager
diff --git a/services/java/com/android/server/am/CoreSettingsObserver.java b/services/java/com/android/server/am/CoreSettingsObserver.java
index 25db84a..585cf2b 100644
--- a/services/java/com/android/server/am/CoreSettingsObserver.java
+++ b/services/java/com/android/server/am/CoreSettingsObserver.java
@@ -52,7 +52,7 @@
         super(activityManagerService.mHandler);
         mActivityManagerService = activityManagerService;
         beginObserveCoreSettings();
-        populateCoreSettings(mCoreSettings);
+        sendCoreSettings();
     }
 
     public Bundle getCoreSettingsLocked() {
@@ -62,11 +62,15 @@
     @Override
     public void onChange(boolean selfChange) {
         synchronized (mActivityManagerService) {
-            populateCoreSettings(mCoreSettings);
-            mActivityManagerService.onCoreSettingsChange(mCoreSettings);
+            sendCoreSettings();
         }
     }
 
+    private void sendCoreSettings() {
+        populateCoreSettings(mCoreSettings);
+        mActivityManagerService.onCoreSettingsChange(mCoreSettings);
+    }
+
     private void beginObserveCoreSettings() {
         for (String setting : sCoreSettingToTypeMap.keySet()) {
             Uri uri = Settings.Secure.getUriFor(setting);
diff --git a/services/java/com/android/server/am/LaunchWarningWindow.java b/services/java/com/android/server/am/LaunchWarningWindow.java
index 1114a31..cb2b7bb 100644
--- a/services/java/com/android/server/am/LaunchWarningWindow.java
+++ b/services/java/com/android/server/am/LaunchWarningWindow.java
@@ -1,3 +1,19 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
 package com.android.server.am;
 
 import com.android.internal.R;
diff --git a/services/java/com/android/server/location/GpsLocationProvider.java b/services/java/com/android/server/location/GpsLocationProvider.java
index 3561862..63ce0bd 100755
--- a/services/java/com/android/server/location/GpsLocationProvider.java
+++ b/services/java/com/android/server/location/GpsLocationProvider.java
@@ -203,7 +203,7 @@
     // flags to trigger NTP or XTRA data download when network becomes available
     // initialized to true so we do NTP and XTRA when the network comes up after booting
     private boolean mInjectNtpTimePending = true;
-    private boolean mDownloadXtraDataPending = false;
+    private boolean mDownloadXtraDataPending = true;
 
     // true if GPS is navigating
     private boolean mNavigating;
diff --git a/services/java/com/android/server/usb/UsbDeviceSettingsManager.java b/services/java/com/android/server/usb/UsbDeviceSettingsManager.java
index 2f22fe1..de0b114 100644
--- a/services/java/com/android/server/usb/UsbDeviceSettingsManager.java
+++ b/services/java/com/android/server/usb/UsbDeviceSettingsManager.java
@@ -16,11 +16,14 @@
 
 package com.android.server.usb;
 
+import android.app.PendingIntent;
 import android.content.ActivityNotFoundException;
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
 import android.content.pm.ActivityInfo;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageInfo;
 import android.content.pm.PackageManager;
 import android.content.pm.PackageManager.NameNotFoundException;
 import android.content.pm.ResolveInfo;
@@ -33,7 +36,7 @@
 import android.os.FileUtils;
 import android.os.Process;
 import android.util.Log;
-import android.util.SparseArray;
+import android.util.SparseBooleanArray;
 import android.util.Xml;
 
 import com.android.internal.content.PackageMonitor;
@@ -62,17 +65,18 @@
     private static final File sSettingsFile = new File("/data/system/usb_device_manager.xml");
 
     private final Context mContext;
+    private final PackageManager mPackageManager;
 
-    // maps UID to user approved USB devices
-    private final SparseArray<ArrayList<DeviceFilter>> mDevicePermissionMap =
-            new SparseArray<ArrayList<DeviceFilter>>();
-    // maps UID to user approved USB accessories
-    private final SparseArray<ArrayList<AccessoryFilter>> mAccessoryPermissionMap =
-            new SparseArray<ArrayList<AccessoryFilter>>();
+    // Temporary mapping USB device name to list of UIDs with permissions for the device
+    private final HashMap<String, SparseBooleanArray> mDevicePermissionMap =
+            new HashMap<String, SparseBooleanArray>();
+    // Temporary mapping UsbAccessory to list of UIDs with permissions for the accessory
+    private final HashMap<UsbAccessory, SparseBooleanArray> mAccessoryPermissionMap =
+            new HashMap<UsbAccessory, SparseBooleanArray>();
     // Maps DeviceFilter to user preferred application package
     private final HashMap<DeviceFilter, String> mDevicePreferenceMap =
             new HashMap<DeviceFilter, String>();
-    // Maps DeviceFilter to user preferred application package
+    // Maps AccessoryFilter to user preferred application package
     private final HashMap<AccessoryFilter, String> mAccessoryPreferenceMap =
             new HashMap<AccessoryFilter, String>();
 
@@ -185,6 +189,14 @@
             return false;
         }
 
+        public boolean matches(DeviceFilter f) {
+            if (mVendorId != -1 && f.mVendorId != mVendorId) return false;
+            if (mProductId != -1 && f.mProductId != mProductId) return false;
+
+            // check device class/subclass/protocol
+            return matches(f.mClass, f.mSubclass, f.mProtocol);
+        }
+
         @Override
         public boolean equals(Object obj) {
             // can't compare if we have wildcard strings
@@ -234,22 +246,18 @@
         public final String mManufacturer;
         // USB accessory model (or null for unspecified)
         public final String mModel;
-        // USB accessory type (or null for unspecified)
-        public final String mType;
         // USB accessory version (or null for unspecified)
         public final String mVersion;
 
-        public AccessoryFilter(String manufacturer, String model, String type, String version) {
+        public AccessoryFilter(String manufacturer, String model, String version) {
             mManufacturer = manufacturer;
             mModel = model;
-            mType = type;
             mVersion = version;
         }
 
         public AccessoryFilter(UsbAccessory accessory) {
             mManufacturer = accessory.getManufacturer();
             mModel = accessory.getModel();
-            mType = accessory.getType();
             mVersion = accessory.getVersion();
         }
 
@@ -257,7 +265,6 @@
                 throws XmlPullParserException, IOException {
             String manufacturer = null;
             String model = null;
-            String type = null;
             String version = null;
 
             int count = parser.getAttributeCount();
@@ -269,13 +276,11 @@
                     manufacturer = value;
                 } else if ("model".equals(name)) {
                     model = value;
-                } else if ("type".equals(name)) {
-                    type = value;
                 } else if ("version".equals(name)) {
                     version = value;
                 }
              }
-             return new AccessoryFilter(manufacturer, model, type, version);
+             return new AccessoryFilter(manufacturer, model, version);
         }
 
         public void write(XmlSerializer serializer)throws IOException {
@@ -286,9 +291,6 @@
             if (mModel != null) {
                 serializer.attribute(null, "model", mModel);
             }
-            if (mType != null) {
-                serializer.attribute(null, "type", mType);
-            }
             if (mVersion != null) {
                 serializer.attribute(null, "version", mVersion);
             }
@@ -298,29 +300,33 @@
         public boolean matches(UsbAccessory acc) {
             if (mManufacturer != null && !acc.getManufacturer().equals(mManufacturer)) return false;
             if (mModel != null && !acc.getModel().equals(mModel)) return false;
-            if (mType != null && !acc.getType().equals(mType)) return false;
             if (mVersion != null && !acc.getVersion().equals(mVersion)) return false;
             return true;
         }
 
+        public boolean matches(AccessoryFilter f) {
+            if (mManufacturer != null && !f.mManufacturer.equals(mManufacturer)) return false;
+            if (mModel != null && !f.mModel.equals(mModel)) return false;
+            if (mVersion != null && !f.mVersion.equals(mVersion)) return false;
+            return true;
+        }
+
         @Override
         public boolean equals(Object obj) {
             // can't compare if we have wildcard strings
-            if (mManufacturer == null || mModel == null || mType == null || mVersion == null) {
+            if (mManufacturer == null || mModel == null || mVersion == null) {
                 return false;
             }
             if (obj instanceof AccessoryFilter) {
                 AccessoryFilter filter = (AccessoryFilter)obj;
                 return (mManufacturer.equals(filter.mManufacturer) &&
                         mModel.equals(filter.mModel) &&
-                        mType.equals(filter.mType) &&
                         mVersion.equals(filter.mVersion));
             }
             if (obj instanceof UsbAccessory) {
                 UsbAccessory accessory = (UsbAccessory)obj;
                 return (mManufacturer.equals(accessory.getManufacturer()) &&
                         mModel.equals(accessory.getModel()) &&
-                        mType.equals(accessory.getType()) &&
                         mVersion.equals(accessory.getVersion()));
             }
             return false;
@@ -330,7 +336,6 @@
         public int hashCode() {
             return ((mManufacturer == null ? 0 : mManufacturer.hashCode()) ^
                     (mModel == null ? 0 : mModel.hashCode()) ^
-                    (mType == null ? 0 : mType.hashCode()) ^
                     (mVersion == null ? 0 : mVersion.hashCode()));
         }
 
@@ -338,78 +343,35 @@
         public String toString() {
             return "AccessoryFilter[mManufacturer=\"" + mManufacturer +
                                 "\", mModel=\"" + mModel +
-                                "\", mType=\"" + mType +
                                 "\", mVersion=\"" + mVersion + "\"]";
         }
     }
 
     private class MyPackageMonitor extends PackageMonitor {
-        public void onPackageRemoved(String packageName, int uid) {
-            synchronized (mLock) {
-                // clear all activity preferences for the package
-                if (clearPackageDefaultsLocked(packageName)) {
-                    writeSettingsLocked();
-                }
-            }
+
+        public void onPackageAdded(String packageName, int uid) {
+            handlePackageUpdate(packageName);
         }
 
-        public void onUidRemoved(int uid) {
-            synchronized (mLock) {
-                // clear all permissions for the UID
-                if (clearUidDefaultsLocked(uid)) {
-                    writeSettingsLocked();
-                }
-            }
+        public void onPackageChanged(String packageName, int uid, String[] components) {
+            handlePackageUpdate(packageName);
+        }
+
+        public void onPackageRemoved(String packageName, int uid) {
+            clearDefaults(packageName);
         }
     }
     MyPackageMonitor mPackageMonitor = new MyPackageMonitor();
 
     public UsbDeviceSettingsManager(Context context) {
         mContext = context;
+        mPackageManager = context.getPackageManager();
         synchronized (mLock) {
             readSettingsLocked();
         }
         mPackageMonitor.register(context, true);
     }
 
-    private void readDevicePermission(XmlPullParser parser)
-            throws XmlPullParserException, IOException {
-        int uid = -1;
-        ArrayList<DeviceFilter> filters = new ArrayList<DeviceFilter>();
-        int count = parser.getAttributeCount();
-        for (int i = 0; i < count; i++) {
-            if ("uid".equals(parser.getAttributeName(i))) {
-                uid = Integer.parseInt(parser.getAttributeValue(i));
-                break;
-            }
-        }
-        XmlUtils.nextElement(parser);
-        while ("usb-device".equals(parser.getName())) {
-            filters.add(DeviceFilter.read(parser));
-            XmlUtils.nextElement(parser);
-        }
-        mDevicePermissionMap.put(uid, filters);
-    }
-
-    private void readAccessoryPermission(XmlPullParser parser)
-            throws XmlPullParserException, IOException {
-        int uid = -1;
-        ArrayList<AccessoryFilter> filters = new ArrayList<AccessoryFilter>();
-        int count = parser.getAttributeCount();
-        for (int i = 0; i < count; i++) {
-            if ("uid".equals(parser.getAttributeName(i))) {
-                uid = Integer.parseInt(parser.getAttributeValue(i));
-                break;
-            }
-        }
-        XmlUtils.nextElement(parser);
-        while ("usb-accessory".equals(parser.getName())) {
-            filters.add(AccessoryFilter.read(parser));
-            XmlUtils.nextElement(parser);
-        }
-        mAccessoryPermissionMap.put(uid, filters);
-    }
-
     private void readPreference(XmlPullParser parser)
             throws XmlPullParserException, IOException {
         String packageName = null;
@@ -441,11 +403,7 @@
             XmlUtils.nextElement(parser);
             while (parser.getEventType() != XmlPullParser.END_DOCUMENT) {
                 String tagName = parser.getName();
-                if ("device-permission".equals(tagName)) {
-                    readDevicePermission(parser);
-                } else if ("accessory-permission".equals(tagName)) {
-                    readAccessoryPermission(parser);
-                } else if ("preference".equals(tagName)) {
+                if ("preference".equals(tagName)) {
                     readPreference(parser);
                  } else {
                     XmlUtils.nextElement(parser);
@@ -478,32 +436,6 @@
             serializer.setFeature("http://xmlpull.org/v1/doc/features.html#indent-output", true);
             serializer.startTag(null, "settings");
 
-            int count = mDevicePermissionMap.size();
-            for (int i = 0; i < count; i++) {
-                int uid = mDevicePermissionMap.keyAt(i);
-                ArrayList<DeviceFilter> filters = mDevicePermissionMap.valueAt(i);
-                serializer.startTag(null, "device-permission");
-                serializer.attribute(null, "uid", Integer.toString(uid));
-                int filterCount = filters.size();
-                for (int j = 0; j < filterCount; j++) {
-                    filters.get(j).write(serializer);
-                }
-                serializer.endTag(null, "device-permission");
-            }
-
-            count = mAccessoryPermissionMap.size();
-            for (int i = 0; i < count; i++) {
-                int uid = mAccessoryPermissionMap.keyAt(i);
-                ArrayList<AccessoryFilter> filters = mAccessoryPermissionMap.valueAt(i);
-                serializer.startTag(null, "accessory-permission");
-                serializer.attribute(null, "uid", Integer.toString(uid));
-                int filterCount = filters.size();
-                for (int j = 0; j < filterCount; j++) {
-                    filters.get(j).write(serializer);
-                }
-                serializer.endTag(null, "accessory-permission");
-            }
-
             for (DeviceFilter filter : mDevicePreferenceMap.keySet()) {
                 serializer.startTag(null, "preference");
                 serializer.attribute(null, "package", mDevicePreferenceMap.get(filter));
@@ -535,11 +467,10 @@
     private boolean packageMatchesLocked(ResolveInfo info, String metaDataName,
             UsbDevice device, UsbAccessory accessory) {
         ActivityInfo ai = info.activityInfo;
-        PackageManager pm = mContext.getPackageManager();
 
         XmlResourceParser parser = null;
         try {
-            parser = ai.loadXmlMetaData(pm, metaDataName);
+            parser = ai.loadXmlMetaData(mPackageManager, metaDataName);
             if (parser == null) {
                 Log.w(TAG, "no meta-data for " + info);
                 return false;
@@ -572,8 +503,7 @@
 
     private final ArrayList<ResolveInfo> getDeviceMatchesLocked(UsbDevice device, Intent intent) {
         ArrayList<ResolveInfo> matches = new ArrayList<ResolveInfo>();
-        PackageManager pm = mContext.getPackageManager();
-        List<ResolveInfo> resolveInfos = pm.queryIntentActivities(intent,
+        List<ResolveInfo> resolveInfos = mPackageManager.queryIntentActivities(intent,
                 PackageManager.GET_META_DATA);
         int count = resolveInfos.size();
         for (int i = 0; i < count; i++) {
@@ -588,8 +518,7 @@
     private final ArrayList<ResolveInfo> getAccessoryMatchesLocked(
             UsbAccessory accessory, Intent intent) {
         ArrayList<ResolveInfo> matches = new ArrayList<ResolveInfo>();
-        PackageManager pm = mContext.getPackageManager();
-        List<ResolveInfo> resolveInfos = pm.queryIntentActivities(intent,
+        List<ResolveInfo> resolveInfos = mPackageManager.queryIntentActivities(intent,
                 PackageManager.GET_META_DATA);
         int count = resolveInfos.size();
         for (int i = 0; i < count; i++) {
@@ -602,53 +531,26 @@
     }
 
     public void deviceAttached(UsbDevice device) {
-        Intent deviceIntent = new Intent(UsbManager.ACTION_USB_DEVICE_ATTACHED);
-        deviceIntent.putExtra(UsbManager.EXTRA_DEVICE, device);
-        deviceIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+        Intent intent = new Intent(UsbManager.ACTION_USB_DEVICE_ATTACHED);
+        intent.putExtra(UsbManager.EXTRA_DEVICE, device);
+        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
 
         ArrayList<ResolveInfo> matches;
         String defaultPackage;
         synchronized (mLock) {
-            matches = getDeviceMatchesLocked(device, deviceIntent);
+            matches = getDeviceMatchesLocked(device, intent);
             // Launch our default activity directly, if we have one.
             // Otherwise we will start the UsbResolverActivity to allow the user to choose.
             defaultPackage = mDevicePreferenceMap.get(new DeviceFilter(device));
         }
 
-        int count = matches.size();
-        // don't show the resolver activity if there are no choices available
-        if (count == 0) return;
-
-        if (defaultPackage != null) {
-            for (int i = 0; i < count; i++) {
-                ResolveInfo rInfo = matches.get(i);
-                if (rInfo.activityInfo != null &&
-                        defaultPackage.equals(rInfo.activityInfo.packageName)) {
-                    try {
-                        deviceIntent.setComponent(new ComponentName(
-                                defaultPackage, rInfo.activityInfo.name));
-                        mContext.startActivity(deviceIntent);
-                    } catch (ActivityNotFoundException e) {
-                        Log.e(TAG, "startActivity failed", e);
-                    }
-                    return;
-                }
-            }
-        }
-
-        Intent intent = new Intent(mContext, UsbResolverActivity.class);
-        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
-
-        intent.putExtra(Intent.EXTRA_INTENT, deviceIntent);
-        intent.putParcelableArrayListExtra(UsbResolverActivity.EXTRA_RESOLVE_INFOS, matches);
-        try {
-            mContext.startActivity(intent);
-        } catch (ActivityNotFoundException e) {
-            Log.w(TAG, "unable to start UsbResolverActivity");
-        }
+        resolveActivity(intent, matches, defaultPackage, device, null);
     }
 
     public void deviceDetached(UsbDevice device) {
+        // clear temporary permissions for the device
+        mDevicePermissionMap.remove(device.getDeviceName());
+
         Intent intent = new Intent(UsbManager.ACTION_USB_DEVICE_DETACHED);
         intent.putExtra(UsbManager.EXTRA_DEVICE, device);
         Log.d(TAG, "usbDeviceRemoved, sending " + intent);
@@ -656,93 +558,322 @@
     }
 
     public void accessoryAttached(UsbAccessory accessory) {
-        Intent accessoryIntent = new Intent(UsbManager.ACTION_USB_ACCESSORY_ATTACHED);
-        accessoryIntent.putExtra(UsbManager.EXTRA_ACCESSORY, accessory);
-        accessoryIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+        Intent intent = new Intent(UsbManager.ACTION_USB_ACCESSORY_ATTACHED);
+        intent.putExtra(UsbManager.EXTRA_ACCESSORY, accessory);
+        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
 
         ArrayList<ResolveInfo> matches;
         String defaultPackage;
         synchronized (mLock) {
-            matches = getAccessoryMatchesLocked(accessory, accessoryIntent);
+            matches = getAccessoryMatchesLocked(accessory, intent);
             // Launch our default activity directly, if we have one.
             // Otherwise we will start the UsbResolverActivity to allow the user to choose.
             defaultPackage = mAccessoryPreferenceMap.get(new AccessoryFilter(accessory));
         }
 
-        int count = matches.size();
-        // don't show the resolver activity if there are no choices available
-        if (count == 0) return;
-
-        if (defaultPackage != null) {
-            for (int i = 0; i < count; i++) {
-                ResolveInfo rInfo = matches.get(i);
-                if (rInfo.activityInfo != null &&
-                        defaultPackage.equals(rInfo.activityInfo.packageName)) {
-                    try {
-                        accessoryIntent.setComponent(new ComponentName(
-                                defaultPackage, rInfo.activityInfo.name));
-                        mContext.startActivity(accessoryIntent);
-                    } catch (ActivityNotFoundException e) {
-                        Log.e(TAG, "startActivity failed", e);
-                    }
-                    return;
-                }
-            }
-        }
-
-        Intent intent = new Intent(mContext, UsbResolverActivity.class);
-        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
-
-        intent.putExtra(Intent.EXTRA_INTENT, accessoryIntent);
-        intent.putParcelableArrayListExtra(UsbResolverActivity.EXTRA_RESOLVE_INFOS, matches);
-        try {
-            mContext.startActivity(intent);
-        } catch (ActivityNotFoundException e) {
-            Log.w(TAG, "unable to start UsbResolverActivity");
-        }
+        resolveActivity(intent, matches, defaultPackage, null, accessory);
     }
 
     public void accessoryDetached(UsbAccessory accessory) {
+        // clear temporary permissions for the accessory
+        mAccessoryPermissionMap.remove(accessory);
+
         Intent intent = new Intent(
                 UsbManager.ACTION_USB_ACCESSORY_DETACHED);
         intent.putExtra(UsbManager.EXTRA_ACCESSORY, accessory);
         mContext.sendBroadcast(intent);
     }
 
-    public void checkPermission(UsbDevice device) {
-        if (device == null) return;
-        synchronized (mLock) {
-            ArrayList<DeviceFilter> filterList = mDevicePermissionMap.get(Binder.getCallingUid());
-            if (filterList != null) {
-                int count = filterList.size();
-                for (int i = 0; i < count; i++) {
-                    DeviceFilter filter = filterList.get(i);
-                    if (filter.equals(device)) {
-                        // permission allowed
-                        return;
+    private void resolveActivity(Intent intent, ArrayList<ResolveInfo> matches,
+            String defaultPackage, UsbDevice device, UsbAccessory accessory) {
+        int count = matches.size();
+
+        // don't show the resolver activity if there are no choices available
+        if (count == 0) {
+            if (accessory != null) {
+                String uri = accessory.getUri();
+                if (uri != null && uri.length() > 0) {
+                    // display URI to user
+                    // start UsbResolverActivity so user can choose an activity
+                    Intent dialogIntent = new Intent();
+                    dialogIntent.setClassName("com.android.systemui",
+                            "com.android.systemui.usb.UsbAccessoryUriActivity");
+                    dialogIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+                    dialogIntent.putExtra(UsbManager.EXTRA_ACCESSORY, accessory);
+                    dialogIntent.putExtra("uri", uri);
+                    try {
+                        mContext.startActivity(dialogIntent);
+                    } catch (ActivityNotFoundException e) {
+                        Log.e(TAG, "unable to start UsbAccessoryUriActivity");
                     }
                 }
             }
+
+            // do nothing
+            return;
         }
-        throw new SecurityException("User has not given permission to device " + device);
+
+        ResolveInfo defaultRI = null;
+        if (count == 1 && defaultPackage == null) {
+            // Check to see if our single choice is on the system partition.
+            // If so, treat it as our default without calling UsbResolverActivity
+            ResolveInfo rInfo = matches.get(0);
+            if (rInfo.activityInfo != null &&
+                    rInfo.activityInfo.applicationInfo != null &&
+                    (rInfo.activityInfo.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0) {
+                defaultRI = rInfo;
+            }
+        }
+
+        if (defaultRI == null && defaultPackage != null) {
+            // look for default activity
+            for (int i = 0; i < count; i++) {
+                ResolveInfo rInfo = matches.get(i);
+                if (rInfo.activityInfo != null &&
+                        defaultPackage.equals(rInfo.activityInfo.packageName)) {
+                    defaultRI = rInfo;
+                    break;
+                }
+            }
+        }
+
+        if (defaultRI != null) {
+            // grant permission for default activity
+            if (device != null) {
+                grantDevicePermission(device, defaultRI.activityInfo.applicationInfo.uid);
+            } else if (accessory != null) {
+                grantAccessoryPermission(accessory, defaultRI.activityInfo.applicationInfo.uid);
+            }
+
+            // start default activity directly
+            try {
+                intent.setComponent(
+                        new ComponentName(defaultRI.activityInfo.packageName,
+                                defaultRI.activityInfo.name));
+                mContext.startActivity(intent);
+            } catch (ActivityNotFoundException e) {
+                Log.e(TAG, "startActivity failed", e);
+            }
+        } else {
+            Intent resolverIntent = new Intent();
+            resolverIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+
+            if (count == 1) {
+                // start UsbConfirmActivity if there is only one choice
+                resolverIntent.setClassName("com.android.systemui",
+                        "com.android.systemui.usb.UsbConfirmActivity");
+                resolverIntent.putExtra("rinfo", matches.get(0));
+
+                if (device != null) {
+                    resolverIntent.putExtra(UsbManager.EXTRA_DEVICE, device);
+                } else {
+                    resolverIntent.putExtra(UsbManager.EXTRA_ACCESSORY, accessory);
+                }
+            } else {
+                // start UsbResolverActivity so user can choose an activity
+                resolverIntent.setClassName("com.android.systemui",
+                        "com.android.systemui.usb.UsbResolverActivity");
+                resolverIntent.putParcelableArrayListExtra("rlist", matches);
+                resolverIntent.putExtra(Intent.EXTRA_INTENT, intent);
+            }
+            try {
+                mContext.startActivity(resolverIntent);
+            } catch (ActivityNotFoundException e) {
+                Log.e(TAG, "unable to start activity " + resolverIntent);
+            }
+        }
+    }
+
+    private boolean clearCompatibleMatchesLocked(String packageName, DeviceFilter filter) {
+        boolean changed = false;
+        for (DeviceFilter test : mDevicePreferenceMap.keySet()) {
+            if (filter.matches(test)) {
+                mDevicePreferenceMap.remove(test);
+                changed = true;
+            }
+        }
+        return changed;
+    }
+
+    private boolean clearCompatibleMatchesLocked(String packageName, AccessoryFilter filter) {
+        boolean changed = false;
+        for (AccessoryFilter test : mAccessoryPreferenceMap.keySet()) {
+            if (filter.matches(test)) {
+                mAccessoryPreferenceMap.remove(test);
+                changed = true;
+            }
+        }
+        return changed;
+    }
+
+    private boolean handlePackageUpdateLocked(String packageName, ActivityInfo aInfo,
+            String metaDataName) {
+        XmlResourceParser parser = null;
+        boolean changed = false;
+
+        try {
+            parser = aInfo.loadXmlMetaData(mPackageManager, metaDataName);
+            if (parser == null) return false;
+
+            XmlUtils.nextElement(parser);
+            while (parser.getEventType() != XmlPullParser.END_DOCUMENT) {
+                String tagName = parser.getName();
+                if ("usb-device".equals(tagName)) {
+                    DeviceFilter filter = DeviceFilter.read(parser);
+                    if (clearCompatibleMatchesLocked(packageName, filter)) {
+                        changed = true;
+                    }
+                }
+                else if ("usb-accessory".equals(tagName)) {
+                    AccessoryFilter filter = AccessoryFilter.read(parser);
+                    if (clearCompatibleMatchesLocked(packageName, filter)) {
+                        changed = true;
+                    }
+                }
+                XmlUtils.nextElement(parser);
+            }
+        } catch (Exception e) {
+            Log.w(TAG, "Unable to load component info " + aInfo.toString(), e);
+        } finally {
+            if (parser != null) parser.close();
+        }
+        return changed;
+    }
+
+    // Check to see if the package supports any USB devices or accessories.
+    // If so, clear any non-matching preferences for matching devices/accessories.
+    private void handlePackageUpdate(String packageName) {
+        synchronized (mLock) {
+            PackageInfo info;
+            boolean changed = false;
+
+            try {
+                info = mPackageManager.getPackageInfo(packageName,
+                        PackageManager.GET_ACTIVITIES | PackageManager.GET_META_DATA);
+            } catch (NameNotFoundException e) {
+                Log.e(TAG, "handlePackageUpdate could not find package " + packageName, e);
+                return;
+            }
+
+            ActivityInfo[] activities = info.activities;
+            if (activities == null) return;
+            for (int i = 0; i < activities.length; i++) {
+                // check for meta-data, both for devices and accessories
+                if (handlePackageUpdateLocked(packageName, activities[i],
+                        UsbManager.ACTION_USB_DEVICE_ATTACHED)) {
+                    changed = true;
+                }
+                if (handlePackageUpdateLocked(packageName, activities[i],
+                        UsbManager.ACTION_USB_ACCESSORY_ATTACHED)) {
+                    changed = true;
+                }
+            }
+
+            if (changed) {
+                writeSettingsLocked();
+            }
+        }
+    }
+
+    public boolean hasPermission(UsbDevice device) {
+        synchronized (mLock) {
+            SparseBooleanArray uidList = mDevicePermissionMap.get(device.getDeviceName());
+            if (uidList == null) {
+                return false;
+            }
+            return uidList.get(Binder.getCallingUid());
+        }
+    }
+
+    public boolean hasPermission(UsbAccessory accessory) {
+        synchronized (mLock) {
+            SparseBooleanArray uidList = mAccessoryPermissionMap.get(accessory);
+            if (uidList == null) {
+                return false;
+            }
+            return uidList.get(Binder.getCallingUid());
+        }
+    }
+
+    public void checkPermission(UsbDevice device) {
+        if (!hasPermission(device)) {
+            throw new SecurityException("User has not given permission to device " + device);
+        }
     }
 
     public void checkPermission(UsbAccessory accessory) {
-        if (accessory == null) return;
-        synchronized (mLock) {
-            ArrayList<AccessoryFilter> filterList = mAccessoryPermissionMap.get(Binder.getCallingUid());
-            if (filterList != null) {
-                int count = filterList.size();
-                for (int i = 0; i < count; i++) {
-                    AccessoryFilter filter = filterList.get(i);
-                    if (filter.equals(accessory)) {
-                        // permission allowed
-                        return;
-                    }
-                }
-            }
+        if (!hasPermission(accessory)) {
+            throw new SecurityException("User has not given permission to accessory " + accessory);
         }
-        throw new SecurityException("User has not given permission to accessory " + accessory);
+    }
+
+    private void requestPermissionDialog(Intent intent, String packageName, PendingIntent pi) {
+        int uid = Binder.getCallingUid();
+
+        // compare uid with packageName to foil apps pretending to be someone else
+        try {
+            ApplicationInfo aInfo = mPackageManager.getApplicationInfo(packageName, 0);
+            if (aInfo.uid != uid) {
+                throw new IllegalArgumentException("package " + packageName +
+                        " does not match caller's uid " + uid);
+            }
+        } catch (PackageManager.NameNotFoundException e) {
+            throw new IllegalArgumentException("package " + packageName + " not found");
+        }
+
+        long identity = Binder.clearCallingIdentity();
+        intent.setClassName("com.android.systemui",
+                "com.android.systemui.usb.UsbPermissionActivity");
+        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+        intent.putExtra(Intent.EXTRA_INTENT, pi);
+        intent.putExtra("package", packageName);
+        intent.putExtra("uid", uid);
+        try {
+            mContext.startActivity(intent);
+        } catch (ActivityNotFoundException e) {
+            Log.e(TAG, "unable to start UsbPermissionActivity");
+        } finally {
+            Binder.restoreCallingIdentity(identity);
+        }
+    }
+
+    public void requestPermission(UsbDevice device, String packageName, PendingIntent pi) {
+      Intent intent = new Intent();
+
+        // respond immediately if permission has already been granted
+      if (hasPermission(device)) {
+            intent.putExtra(UsbManager.EXTRA_DEVICE, device);
+            intent.putExtra(UsbManager.EXTRA_PERMISSION_GRANTED, true);
+            try {
+                pi.send(mContext, 0, intent);
+            } catch (PendingIntent.CanceledException e) {
+                Log.w(TAG, "requestPermission PendingIntent was cancelled");
+            }
+            return;
+        }
+
+        // start UsbPermissionActivity so user can choose an activity
+        intent.putExtra(UsbManager.EXTRA_DEVICE, device);
+        requestPermissionDialog(intent, packageName, pi);
+    }
+
+    public void requestPermission(UsbAccessory accessory, String packageName, PendingIntent pi) {
+      Intent intent = new Intent();
+
+        // respond immediately if permission has already been granted
+        if (hasPermission(accessory)) {
+            intent.putExtra(UsbManager.EXTRA_ACCESSORY, accessory);
+            intent.putExtra(UsbManager.EXTRA_PERMISSION_GRANTED, true);
+           try {
+                pi.send(mContext, 0, intent);
+            } catch (PendingIntent.CanceledException e) {
+                Log.w(TAG, "requestPermission PendingIntent was cancelled");
+            }
+            return;
+        }
+
+        intent.putExtra(UsbManager.EXTRA_ACCESSORY, accessory);
+        requestPermissionDialog(intent, packageName, pi);
     }
 
     public void setDevicePackage(UsbDevice device, String packageName) {
@@ -783,73 +914,43 @@
 
     public void grantDevicePermission(UsbDevice device, int uid) {
         synchronized (mLock) {
-            ArrayList<DeviceFilter> filterList = mDevicePermissionMap.get(uid);
-            if (filterList == null) {
-                filterList = new ArrayList<DeviceFilter>();
-                mDevicePermissionMap.put(uid, filterList);
-            } else {
-                int count = filterList.size();
-                for (int i = 0; i < count; i++) {
-                    if (filterList.get(i).equals(device)) return;
-                }
+            String deviceName = device.getDeviceName();
+            SparseBooleanArray uidList = mDevicePermissionMap.get(deviceName);
+            if (uidList == null) {
+                uidList = new SparseBooleanArray(1);
+                mDevicePermissionMap.put(deviceName, uidList);
             }
-            filterList.add(new DeviceFilter(device));
-            writeSettingsLocked();
+            uidList.put(uid, true);
         }
     }
 
     public void grantAccessoryPermission(UsbAccessory accessory, int uid) {
         synchronized (mLock) {
-            ArrayList<AccessoryFilter> filterList = mAccessoryPermissionMap.get(uid);
-            if (filterList == null) {
-                filterList = new ArrayList<AccessoryFilter>();
-                mAccessoryPermissionMap.put(uid, filterList);
-            } else {
-                int count = filterList.size();
-                for (int i = 0; i < count; i++) {
-                    if (filterList.get(i).equals(accessory)) return;
-                }
+            SparseBooleanArray uidList = mAccessoryPermissionMap.get(accessory);
+            if (uidList == null) {
+                uidList = new SparseBooleanArray(1);
+                mAccessoryPermissionMap.put(accessory, uidList);
             }
-            filterList.add(new AccessoryFilter(accessory));
-            writeSettingsLocked();
+            uidList.put(uid, true);
         }
     }
 
-    public boolean hasDefaults(String packageName, int uid) {
+    public boolean hasDefaults(String packageName) {
         synchronized (mLock) {
-            if (mDevicePermissionMap.get(uid) != null) return true;
-            if (mAccessoryPermissionMap.get(uid) != null) return true;
             if (mDevicePreferenceMap.values().contains(packageName)) return true;
             if (mAccessoryPreferenceMap.values().contains(packageName)) return true;
             return false;
         }
     }
 
-    public void clearDefaults(String packageName, int uid) {
+    public void clearDefaults(String packageName) {
         synchronized (mLock) {
-            boolean packageCleared = clearPackageDefaultsLocked(packageName);
-            boolean uidCleared = clearUidDefaultsLocked(uid);
-            if (packageCleared || uidCleared) {
+            if (clearPackageDefaultsLocked(packageName)) {
                 writeSettingsLocked();
             }
         }
     }
 
-    private boolean clearUidDefaultsLocked(int uid) {
-        boolean cleared = false;
-        int index = mDevicePermissionMap.indexOfKey(uid);
-        if (index >= 0) {
-            mDevicePermissionMap.removeAt(index);
-            cleared = true;
-        }
-        index = mAccessoryPermissionMap.indexOfKey(uid);
-        if (index >= 0) {
-            mAccessoryPermissionMap.removeAt(index);
-            cleared = true;
-        }
-        return cleared;
-    }
-
     private boolean clearPackageDefaultsLocked(String packageName) {
         boolean cleared = false;
         synchronized (mLock) {
@@ -882,24 +983,24 @@
     public void dump(FileDescriptor fd, PrintWriter pw) {
         synchronized (mLock) {
             pw.println("  Device permissions:");
-            int count = mDevicePermissionMap.size();
-            for (int i = 0; i < count; i++) {
-                int uid = mDevicePermissionMap.keyAt(i);
-                pw.println("    " + "uid " + uid + ":");
-                ArrayList<DeviceFilter> filters = mDevicePermissionMap.valueAt(i);
-                for (DeviceFilter filter : filters) {
-                    pw.println("      " + filter);
+            for (String deviceName : mDevicePermissionMap.keySet()) {
+                pw.print("    " + deviceName + ": ");
+                SparseBooleanArray uidList = mDevicePermissionMap.get(deviceName);
+                int count = uidList.size();
+                for (int i = 0; i < count; i++) {
+                    pw.print(Integer.toString(uidList.keyAt(i)) + " ");
                 }
+                pw.println("");
             }
             pw.println("  Accessory permissions:");
-            count = mAccessoryPermissionMap.size();
-            for (int i = 0; i < count; i++) {
-                int uid = mAccessoryPermissionMap.keyAt(i);
-                pw.println("    " + "uid " + uid + ":");
-                ArrayList<AccessoryFilter> filters = mAccessoryPermissionMap.valueAt(i);
-                for (AccessoryFilter filter : filters) {
-                    pw.println("      " + filter);
+            for (UsbAccessory accessory : mAccessoryPermissionMap.keySet()) {
+                pw.print("    " + accessory + ": ");
+                SparseBooleanArray uidList = mAccessoryPermissionMap.get(accessory);
+                int count = uidList.size();
+                for (int i = 0; i < count; i++) {
+                    pw.print(Integer.toString(uidList.keyAt(i)) + " ");
                 }
+                pw.println("");
             }
             pw.println("  Device preferences:");
             for (DeviceFilter filter : mDevicePreferenceMap.keySet()) {
diff --git a/services/java/com/android/server/usb/UsbService.java b/services/java/com/android/server/usb/UsbService.java
index 8170c61..b7f6346 100644
--- a/services/java/com/android/server/usb/UsbService.java
+++ b/services/java/com/android/server/usb/UsbService.java
@@ -16,9 +16,12 @@
 
 package com.android.server.usb;
 
+import android.app.PendingIntent;
+import android.content.BroadcastReceiver;
 import android.content.ContentResolver;
 import android.content.Context;
 import android.content.Intent;
+import android.content.IntentFilter;
 import android.content.pm.PackageManager;
 import android.hardware.usb.IUsbManager;
 import android.hardware.usb.UsbAccessory;
@@ -111,35 +114,40 @@
     private final boolean mHasUsbHost;
     private final boolean mHasUsbAccessory;
 
+    private final void readCurrentAccessoryLocked() {
+        if (mHasUsbAccessory) {
+            String[] strings = nativeGetAccessoryStrings();
+            if (strings != null) {
+                mCurrentAccessory = new UsbAccessory(strings);
+                Log.d(TAG, "entering USB accessory mode: " + mCurrentAccessory);
+                if (mSystemReady) {
+                    mDeviceManager.accessoryAttached(mCurrentAccessory);
+                }
+            } else {
+                Log.e(TAG, "nativeGetAccessoryStrings failed");
+            }
+        }
+    }
+
     /*
      * Handles USB function enable/disable events (device mode)
      */
     private final void functionEnabledLocked(String function, boolean enabled) {
-        boolean enteringAccessoryMode =
-            (mHasUsbAccessory && enabled && UsbManager.USB_FUNCTION_ACCESSORY.equals(function));
-
         if (enabled) {
             if (!mEnabledFunctions.contains(function)) {
                 mEnabledFunctions.add(function);
             }
             mDisabledFunctions.remove(function);
+
+            if (UsbManager.USB_FUNCTION_ACCESSORY.equals(function)) {
+                readCurrentAccessoryLocked();
+            }
         } else {
             if (!mDisabledFunctions.contains(function)) {
                 mDisabledFunctions.add(function);
             }
             mEnabledFunctions.remove(function);
         }
-
-        if (enteringAccessoryMode) {
-            String[] strings = nativeGetAccessoryStrings();
-            if (strings != null) {
-                mCurrentAccessory = new UsbAccessory(strings);
-                Log.d(TAG, "entering USB accessory mode: " + mCurrentAccessory);
-                mDeviceManager.accessoryAttached(mCurrentAccessory);
-            } else {
-                Log.e(TAG, "nativeGetAccessoryStrings failed");
-            }
-        }
     }
 
     /*
@@ -192,6 +200,17 @@
         }
     };
 
+   private final BroadcastReceiver mBootCompletedReceiver = new BroadcastReceiver() {
+        public void onReceive(Context context, Intent intent) {
+            // handle accessories attached at boot time
+            synchronized (mLock) {
+                if (mCurrentAccessory != null) {
+                    mDeviceManager.accessoryAttached(mCurrentAccessory);
+                }
+            }
+        }
+    };
+
     public UsbService(Context context) {
         mContext = context;
         mDeviceManager = new UsbDeviceSettingsManager(context);
@@ -202,17 +221,21 @@
         mHostBlacklist = context.getResources().getStringArray(
                 com.android.internal.R.array.config_usbHostBlacklist);
 
-        init();  // set initial status
+        synchronized (mLock) {
+            init();  // set initial status
 
-        if (mConfiguration >= 0) {
-            mUEventObserver.startObserving(USB_CONNECTED_MATCH);
-            mUEventObserver.startObserving(USB_CONFIGURATION_MATCH);
-            mUEventObserver.startObserving(USB_FUNCTIONS_MATCH);
+            // Watch for USB configuration changes
+            if (mConfiguration >= 0) {
+                mUEventObserver.startObserving(USB_CONNECTED_MATCH);
+                mUEventObserver.startObserving(USB_CONFIGURATION_MATCH);
+                mUEventObserver.startObserving(USB_FUNCTIONS_MATCH);
+            }
         }
     }
 
     private final void init() {
         char[] buffer = new char[1024];
+        boolean inAccessoryMode = false;
 
         // Read initial USB state (device mode)
         mConfiguration = -1;
@@ -232,8 +255,10 @@
         } catch (Exception e) {
             Slog.e(TAG, "" , e);
         }
-        if (mConfiguration < 0)
+        if (mConfiguration < 0) {
+            // This may happen in the emulator or devices without USB device mode support
             return;
+        }
 
         // Read initial list of enabled and disabled functions (device mode)
         try {
@@ -247,9 +272,13 @@
                 String functionName = files[i].getName();
                 if (value == 1) {
                     mEnabledFunctions.add(functionName);
-                    // adb is enabled/disabled automatically by the adbd daemon,
-                    // so don't treat it as a default function
-                    if (!UsbManager.USB_FUNCTION_ADB.equals(functionName)) {
+                if (UsbManager.USB_FUNCTION_ACCESSORY.equals(functionName)) {
+                        // The USB accessory driver is on by default, but it might have been
+                        // enabled before the USB service has initialized.
+                        inAccessoryMode = true;
+                    } else if (!UsbManager.USB_FUNCTION_ADB.equals(functionName)) {
+                        // adb is enabled/disabled automatically by the adbd daemon,
+                        // so don't treat it as a default function.
                         mDefaultFunctions.add(functionName);
                     }
                 } else {
@@ -261,6 +290,21 @@
         } catch (Exception e) {
             Slog.e(TAG, "" , e);
         }
+
+        // handle the case where an accessory switched the driver to accessory mode
+        // before the framework finished booting
+        if (inAccessoryMode) {
+            readCurrentAccessoryLocked();
+
+            // FIXME - if we booted in accessory mode, then we have no way to figure out
+            // which functions are enabled by default.
+            // For now, assume that MTP or mass storage are the only possibilities
+            if (mDisabledFunctions.contains(UsbManager.USB_FUNCTION_MTP)) {
+                mDefaultFunctions.add(UsbManager.USB_FUNCTION_MTP);
+            } else if (mDisabledFunctions.contains(UsbManager.USB_FUNCTION_MASS_STORAGE)) {
+                mDefaultFunctions.add(UsbManager.USB_FUNCTION_MASS_STORAGE);
+            }
+        }
     }
 
     private boolean isBlackListed(String deviceName) {
@@ -380,6 +424,13 @@
             }
 
             update(false);
+            if (mCurrentAccessory != null) {
+                Log.d(TAG, "accessoryAttached at systemReady");
+                // its still too early to handle accessories, so add a BOOT_COMPLETED receiver
+                // to handle this later.
+                mContext.registerReceiver(mBootCompletedReceiver,
+                        new IntentFilter(Intent.ACTION_BOOT_COMPLETED));
+            }
             mSystemReady = true;
         }
     }
@@ -422,10 +473,7 @@
 
     /* returns the currently attached USB accessory (device mode) */
     public UsbAccessory getCurrentAccessory() {
-        synchronized (mLock) {
-            mDeviceManager.checkPermission(mCurrentAccessory);
-            return mCurrentAccessory;
-        }
+        return mCurrentAccessory;
     }
 
     /* opens the currently attached USB accessory (device mode) */
@@ -454,6 +502,24 @@
         mDeviceManager.setAccessoryPackage(accessory, packageName);
     }
 
+    public boolean hasDevicePermission(UsbDevice device) {
+        return mDeviceManager.hasPermission(device);
+    }
+
+    public boolean hasAccessoryPermission(UsbAccessory accessory) {
+        return mDeviceManager.hasPermission(accessory);
+    }
+
+    public void requestDevicePermission(UsbDevice device, String packageName,
+            PendingIntent pi) {
+        mDeviceManager.requestPermission(device, packageName, pi);
+    }
+
+    public void requestAccessoryPermission(UsbAccessory accessory, String packageName,
+            PendingIntent pi) {
+        mDeviceManager.requestPermission(accessory, packageName, pi);
+    }
+
     public void grantDevicePermission(UsbDevice device, int uid) {
         mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_USB, null);
         mDeviceManager.grantDevicePermission(device, uid);
@@ -464,14 +530,14 @@
         mDeviceManager.grantAccessoryPermission(accessory, uid);
     }
 
-    public boolean hasDefaults(String packageName, int uid) {
+    public boolean hasDefaults(String packageName) {
         mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_USB, null);
-        return mDeviceManager.hasDefaults(packageName, uid);
+        return mDeviceManager.hasDefaults(packageName);
     }
 
-    public void clearDefaults(String packageName, int uid) {
+    public void clearDefaults(String packageName) {
         mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_USB, null);
-        mDeviceManager.clearDefaults(packageName, uid);
+        mDeviceManager.clearDefaults(packageName);
     }
 
     /*
@@ -496,20 +562,18 @@
                         if (mConnected != mLastConnected || mConfiguration != mLastConfiguration) {
                             if (mConnected == 0) {
                                 // make sure accessory mode is off, and restore default functions
-                                if (UsbManager.setFunctionEnabled(
+                                if (mCurrentAccessory != null && UsbManager.setFunctionEnabled(
                                         UsbManager.USB_FUNCTION_ACCESSORY, false)) {
                                     Log.d(TAG, "exited USB accessory mode");
 
                                     int count = mDefaultFunctions.size();
                                     for (int i = 0; i < count; i++) {
                                         String function = mDefaultFunctions.get(i);
-                                        if (UsbManager.setFunctionEnabled(function, true)) {
+                                        if (!UsbManager.setFunctionEnabled(function, true)) {
                                             Log.e(TAG, "could not reenable function " + function);
                                         }
                                     }
-                                }
 
-                                if (mCurrentAccessory != null) {
                                     mDeviceManager.accessoryDetached(mCurrentAccessory);
                                     mCurrentAccessory = null;
                                 }
diff --git a/services/java/com/android/server/wm/InputManager.java b/services/java/com/android/server/wm/InputManager.java
index fc32d5a..ca1da95 100644
--- a/services/java/com/android/server/wm/InputManager.java
+++ b/services/java/com/android/server/wm/InputManager.java
@@ -549,7 +549,7 @@
             } catch (NumberFormatException e) {
             }
             if (result < 1) {
-                result = 60;
+                result = 55;
             }
             return result;
         }
diff --git a/services/java/com/android/server/wm/WindowManagerService.java b/services/java/com/android/server/wm/WindowManagerService.java
index eed41a0..33e6a36 100644
--- a/services/java/com/android/server/wm/WindowManagerService.java
+++ b/services/java/com/android/server/wm/WindowManagerService.java
@@ -4727,7 +4727,15 @@
         SystemProperties.set(StrictMode.VISUAL_PROPERTY, value);
     }
 
-    public Bitmap screenshotApplications(IBinder appToken, int maxWidth, int maxHeight) {
+    /**
+     * Takes a snapshot of the screen.  In landscape mode this grabs the whole screen.
+     * In portrait mode, it grabs the upper region of the screen based on the vertical dimension
+     * of the target image.
+     * 
+     * @param width the width of the target bitmap
+     * @param height the height of the target bitmap
+     */
+    public Bitmap screenshotApplications(IBinder appToken, int width, int height) {
         if (!checkCallingPermission(android.Manifest.permission.READ_FRAME_BUFFER,
                 "screenshotApplications()")) {
             throw new SecurityException("Requires READ_FRAME_BUFFER permission");
@@ -4739,7 +4747,7 @@
         final Rect frame = new Rect();
 
         float scale;
-        int sw, sh, dw, dh;
+        int dw, dh;
         int rot;
 
         synchronized(mWindowMap) {
@@ -4791,19 +4799,23 @@
                 if (maxLayer < ws.mAnimLayer) {
                     maxLayer = ws.mAnimLayer;
                 }
-                final Rect wf = ws.mFrame;
-                final Rect cr = ws.mContentInsets;
-                int left = wf.left + cr.left;
-                int top = wf.top + cr.top;
-                int right = wf.right - cr.right;
-                int bottom = wf.bottom - cr.bottom;
-                frame.union(left, top, right, bottom);
+                
+                // Don't include wallpaper in bounds calculation
+                if (!ws.mIsWallpaper) {
+                    final Rect wf = ws.mFrame;
+                    final Rect cr = ws.mContentInsets;
+                    int left = wf.left + cr.left;
+                    int top = wf.top + cr.top;
+                    int right = wf.right - cr.right;
+                    int bottom = wf.bottom - cr.bottom;
+                    frame.union(left, top, right, bottom);
+                }
             }
             Binder.restoreCallingIdentity(ident);
 
             // Constrain frame to the screen size.
             frame.intersect(0, 0, dw, dh);
-            
+
             if (frame.isEmpty() || maxLayer == 0) {
                 return null;
             }
@@ -4814,15 +4826,7 @@
             int fh = frame.height();
 
             // First try reducing to fit in x dimension.
-            scale = maxWidth/(float)fw;
-            sw = maxWidth;
-            sh = (int)(fh*scale);
-            if (sh > maxHeight) {
-                // y dimension became too long; constrain by that.
-                scale = maxHeight/(float)fh;
-                sw = (int)(fw*scale);
-                sh = maxHeight;
-            }
+            scale = width/(float)fw;
 
             // The screen shot will contain the entire screen.
             dw = (int)(dw*scale);
@@ -4841,8 +4845,8 @@
                     + ") to layer " + maxLayer);
             return null;
         }
-        
-        Bitmap bm = Bitmap.createBitmap(sw, sh, rawss.getConfig());
+
+        Bitmap bm = Bitmap.createBitmap(width, height, rawss.getConfig());
         Matrix matrix = new Matrix();
         ScreenRotationAnimation.createRotationMatrix(rot, dw, dh, matrix);
         matrix.postTranslate(-(int)(frame.left*scale), -(int)(frame.top*scale));
@@ -5460,8 +5464,9 @@
             shortSize = (int)(shortSize/dm.density);
 
             // These semi-magic numbers define our compatibility modes for
-            // applications with different screens.  Don't change unless you
-            // make sure to test lots and lots of apps!
+            // applications with different screens.  These are guarantees to
+            // app developers about the space they can expect for a particular
+            // configuration.  DO NOT CHANGE!
             if (longSize < 470) {
                 // This is shorter than an HVGA normal density screen (which
                 // is 480 pixels on its long side).
@@ -5469,12 +5474,12 @@
                         | Configuration.SCREENLAYOUT_LONG_NO;
             } else {
                 // What size is this screen screen?
-                if (longSize >= 800 && shortSize >= 600) {
-                    // SVGA or larger screens at medium density are the point
+                if (longSize >= 960 && shortSize >= 720) {
+                    // 1.5xVGA or larger screens at medium density are the point
                     // at which we consider it to be an extra large screen.
                     mScreenLayout = Configuration.SCREENLAYOUT_SIZE_XLARGE;
-                } else if (longSize >= 530 && shortSize >= 400) {
-                    // SVGA or larger screens at high density are the point
+                } else if (longSize >= 640 && shortSize >= 480) {
+                    // VGA or larger screens at medium density are the point
                     // at which we consider it to be a large screen.
                     mScreenLayout = Configuration.SCREENLAYOUT_SIZE_LARGE;
                 } else {
diff --git a/services/jni/com_android_server_InputApplication.cpp b/services/jni/com_android_server_InputApplication.cpp
index e64ec4e..1f80242 100644
--- a/services/jni/com_android_server_InputApplication.cpp
+++ b/services/jni/com_android_server_InputApplication.cpp
@@ -26,8 +26,6 @@
 namespace android {
 
 static struct {
-    jclass clazz;
-
     jfieldID inputApplicationHandle;
     jfieldID name;
     jfieldID dispatchingTimeoutNanos;
@@ -69,25 +67,25 @@
 
 #define FIND_CLASS(var, className) \
         var = env->FindClass(className); \
-        LOG_FATAL_IF(! var, "Unable to find class " className); \
-        var = jclass(env->NewGlobalRef(var));
+        LOG_FATAL_IF(! var, "Unable to find class " className);
 
 #define GET_FIELD_ID(var, clazz, fieldName, fieldDescriptor) \
         var = env->GetFieldID(clazz, fieldName, fieldDescriptor); \
         LOG_FATAL_IF(! var, "Unable to find field " fieldName);
 
 int register_android_server_InputApplication(JNIEnv* env) {
-    FIND_CLASS(gInputApplicationClassInfo.clazz, "com/android/server/wm/InputApplication");
+    jclass clazz;
+    FIND_CLASS(clazz, "com/android/server/wm/InputApplication");
 
     GET_FIELD_ID(gInputApplicationClassInfo.inputApplicationHandle,
-            gInputApplicationClassInfo.clazz,
+            clazz,
             "inputApplicationHandle", "Lcom/android/server/wm/InputApplicationHandle;");
 
-    GET_FIELD_ID(gInputApplicationClassInfo.name, gInputApplicationClassInfo.clazz,
+    GET_FIELD_ID(gInputApplicationClassInfo.name, clazz,
             "name", "Ljava/lang/String;");
 
     GET_FIELD_ID(gInputApplicationClassInfo.dispatchingTimeoutNanos,
-            gInputApplicationClassInfo.clazz,
+            clazz,
             "dispatchingTimeoutNanos", "J");
     return 0;
 }
diff --git a/services/jni/com_android_server_InputApplicationHandle.cpp b/services/jni/com_android_server_InputApplicationHandle.cpp
index 3a1214f..9516964 100644
--- a/services/jni/com_android_server_InputApplicationHandle.cpp
+++ b/services/jni/com_android_server_InputApplicationHandle.cpp
@@ -26,8 +26,6 @@
 namespace android {
 
 static struct {
-    jclass clazz;
-
     jfieldID ptr;
 } gInputApplicationHandleClassInfo;
 
@@ -98,8 +96,7 @@
 
 #define FIND_CLASS(var, className) \
         var = env->FindClass(className); \
-        LOG_FATAL_IF(! var, "Unable to find class " className); \
-        var = jclass(env->NewGlobalRef(var));
+        LOG_FATAL_IF(! var, "Unable to find class " className);
 
 #define GET_FIELD_ID(var, clazz, fieldName, fieldDescriptor) \
         var = env->GetFieldID(clazz, fieldName, fieldDescriptor); \
@@ -110,9 +107,10 @@
             gInputApplicationHandleMethods, NELEM(gInputApplicationHandleMethods));
     LOG_FATAL_IF(res < 0, "Unable to register native methods.");
 
-    FIND_CLASS(gInputApplicationHandleClassInfo.clazz, "com/android/server/wm/InputApplicationHandle");
+    jclass clazz;
+    FIND_CLASS(clazz, "com/android/server/wm/InputApplicationHandle");
 
-    GET_FIELD_ID(gInputApplicationHandleClassInfo.ptr, gInputApplicationHandleClassInfo.clazz,
+    GET_FIELD_ID(gInputApplicationHandleClassInfo.ptr, clazz,
             "ptr", "I");
 
     return 0;
diff --git a/services/jni/com_android_server_InputManager.cpp b/services/jni/com_android_server_InputManager.cpp
index 3be3b1b..e7e1fa2 100644
--- a/services/jni/com_android_server_InputManager.cpp
+++ b/services/jni/com_android_server_InputManager.cpp
@@ -52,8 +52,6 @@
 namespace android {
 
 static struct {
-    jclass clazz;
-
     jmethodID notifyConfigurationChanged;
     jmethodID notifyLidSwitchChanged;
     jmethodID notifyInputChannelBroken;
@@ -95,16 +93,12 @@
 } gInputDeviceClassInfo;
 
 static struct {
-    jclass clazz;
-
     jfieldID touchscreen;
     jfieldID keyboard;
     jfieldID navigation;
 } gConfigurationClassInfo;
 
 static struct {
-    jclass clazz;
-
     jfieldID bitmap;
     jfieldID hotSpotX;
     jfieldID hotSpotY;
@@ -727,14 +721,14 @@
     };
 
     if (wmActions & WM_ACTION_GO_TO_SLEEP) {
-#ifdef DEBUG_INPUT_DISPATCHER_POLICY
+#if DEBUG_INPUT_DISPATCHER_POLICY
         LOGD("handleInterceptActions: Going to sleep.");
 #endif
         android_server_PowerManagerService_goToSleep(when);
     }
 
     if (wmActions & WM_ACTION_POKE_USER_ACTIVITY) {
-#ifdef DEBUG_INPUT_DISPATCHER_POLICY
+#if DEBUG_INPUT_DISPATCHER_POLICY
         LOGD("handleInterceptActions: Poking user activity.");
 #endif
         android_server_PowerManagerService_userActivity(when, POWER_MANAGER_BUTTON_EVENT);
@@ -743,7 +737,7 @@
     if (wmActions & WM_ACTION_PASS_TO_USER) {
         policyFlags |= POLICY_FLAG_PASS_TO_USER;
     } else {
-#ifdef DEBUG_INPUT_DISPATCHER_POLICY
+#if DEBUG_INPUT_DISPATCHER_POLICY
         LOGD("handleInterceptActions: Not passing key to user.");
 #endif
     }
@@ -1024,15 +1018,14 @@
         return gNativeInputManager->getInputManager()->getDispatcher()->injectInputEvent(
                 & keyEvent, injectorPid, injectorUid, syncMode, timeoutMillis);
     } else if (env->IsInstanceOf(inputEventObj, gMotionEventClassInfo.clazz)) {
-        MotionEvent motionEvent;
-        status_t status = android_view_MotionEvent_toNative(env, inputEventObj, & motionEvent);
-        if (status) {
+        const MotionEvent* motionEvent = android_view_MotionEvent_getNativePtr(env, inputEventObj);
+        if (!motionEvent) {
             jniThrowRuntimeException(env, "Could not read contents of MotionEvent object.");
             return INPUT_EVENT_INJECTION_FAILED;
         }
 
         return gNativeInputManager->getInputManager()->getDispatcher()->injectInputEvent(
-                & motionEvent, injectorPid, injectorUid, syncMode, timeoutMillis);
+                motionEvent, injectorPid, injectorUid, syncMode, timeoutMillis);
     } else {
         jniThrowRuntimeException(env, "Invalid input event type.");
         return INPUT_EVENT_INJECTION_FAILED;
@@ -1103,12 +1096,11 @@
     env->SetIntField(deviceObj, gInputDeviceClassInfo.mSources, deviceInfo.getSources());
     env->SetIntField(deviceObj, gInputDeviceClassInfo.mKeyboardType, deviceInfo.getKeyboardType());
 
-    const KeyedVector<int, InputDeviceInfo::MotionRange>& ranges = deviceInfo.getMotionRanges();
+    const Vector<InputDeviceInfo::MotionRange>& ranges = deviceInfo.getMotionRanges();
     for (size_t i = 0; i < ranges.size(); i++) {
-        int rangeType = ranges.keyAt(i);
-        const InputDeviceInfo::MotionRange& range = ranges.valueAt(i);
+        const InputDeviceInfo::MotionRange& range = ranges.itemAt(i);
         env->CallVoidMethod(deviceObj, gInputDeviceClassInfo.addMotionRange,
-                rangeType, range.min, range.max, range.flat, range.fuzz);
+                range.axis, range.source, range.min, range.max, range.flat, range.fuzz);
         if (env->ExceptionCheck()) {
             return NULL;
         }
@@ -1227,8 +1219,7 @@
 
 #define FIND_CLASS(var, className) \
         var = env->FindClass(className); \
-        LOG_FATAL_IF(! var, "Unable to find class " className); \
-        var = jclass(env->NewGlobalRef(var));
+        LOG_FATAL_IF(! var, "Unable to find class " className);
 
 #define GET_METHOD_ID(var, clazz, methodName, methodDescriptor) \
         var = env->GetMethodID(clazz, methodName, methodDescriptor); \
@@ -1245,83 +1236,88 @@
 
     // Callbacks
 
-    FIND_CLASS(gCallbacksClassInfo.clazz, "com/android/server/wm/InputManager$Callbacks");
+    jclass clazz;
+    FIND_CLASS(clazz, "com/android/server/wm/InputManager$Callbacks");
 
-    GET_METHOD_ID(gCallbacksClassInfo.notifyConfigurationChanged, gCallbacksClassInfo.clazz,
+    GET_METHOD_ID(gCallbacksClassInfo.notifyConfigurationChanged, clazz,
             "notifyConfigurationChanged", "(J)V");
 
-    GET_METHOD_ID(gCallbacksClassInfo.notifyLidSwitchChanged, gCallbacksClassInfo.clazz,
+    GET_METHOD_ID(gCallbacksClassInfo.notifyLidSwitchChanged, clazz,
             "notifyLidSwitchChanged", "(JZ)V");
 
-    GET_METHOD_ID(gCallbacksClassInfo.notifyInputChannelBroken, gCallbacksClassInfo.clazz,
+    GET_METHOD_ID(gCallbacksClassInfo.notifyInputChannelBroken, clazz,
             "notifyInputChannelBroken", "(Lcom/android/server/wm/InputWindowHandle;)V");
 
-    GET_METHOD_ID(gCallbacksClassInfo.notifyANR, gCallbacksClassInfo.clazz,
+    GET_METHOD_ID(gCallbacksClassInfo.notifyANR, clazz,
             "notifyANR",
             "(Lcom/android/server/wm/InputApplicationHandle;Lcom/android/server/wm/InputWindowHandle;)J");
 
-    GET_METHOD_ID(gCallbacksClassInfo.interceptKeyBeforeQueueing, gCallbacksClassInfo.clazz,
+    GET_METHOD_ID(gCallbacksClassInfo.interceptKeyBeforeQueueing, clazz,
             "interceptKeyBeforeQueueing", "(Landroid/view/KeyEvent;IZ)I");
 
     GET_METHOD_ID(gCallbacksClassInfo.interceptMotionBeforeQueueingWhenScreenOff,
-            gCallbacksClassInfo.clazz,
+            clazz,
             "interceptMotionBeforeQueueingWhenScreenOff", "(I)I");
 
-    GET_METHOD_ID(gCallbacksClassInfo.interceptKeyBeforeDispatching, gCallbacksClassInfo.clazz,
+    GET_METHOD_ID(gCallbacksClassInfo.interceptKeyBeforeDispatching, clazz,
             "interceptKeyBeforeDispatching",
             "(Lcom/android/server/wm/InputWindowHandle;Landroid/view/KeyEvent;I)Z");
 
-    GET_METHOD_ID(gCallbacksClassInfo.dispatchUnhandledKey, gCallbacksClassInfo.clazz,
+    GET_METHOD_ID(gCallbacksClassInfo.dispatchUnhandledKey, clazz,
             "dispatchUnhandledKey",
             "(Lcom/android/server/wm/InputWindowHandle;Landroid/view/KeyEvent;I)Landroid/view/KeyEvent;");
 
-    GET_METHOD_ID(gCallbacksClassInfo.checkInjectEventsPermission, gCallbacksClassInfo.clazz,
+    GET_METHOD_ID(gCallbacksClassInfo.checkInjectEventsPermission, clazz,
             "checkInjectEventsPermission", "(II)Z");
 
-    GET_METHOD_ID(gCallbacksClassInfo.filterTouchEvents, gCallbacksClassInfo.clazz,
+    GET_METHOD_ID(gCallbacksClassInfo.filterTouchEvents, clazz,
             "filterTouchEvents", "()Z");
 
-    GET_METHOD_ID(gCallbacksClassInfo.filterJumpyTouchEvents, gCallbacksClassInfo.clazz,
+    GET_METHOD_ID(gCallbacksClassInfo.filterJumpyTouchEvents, clazz,
             "filterJumpyTouchEvents", "()Z");
 
-    GET_METHOD_ID(gCallbacksClassInfo.getVirtualKeyQuietTimeMillis, gCallbacksClassInfo.clazz,
+    GET_METHOD_ID(gCallbacksClassInfo.getVirtualKeyQuietTimeMillis, clazz,
             "getVirtualKeyQuietTimeMillis", "()I");
 
-    GET_METHOD_ID(gCallbacksClassInfo.getExcludedDeviceNames, gCallbacksClassInfo.clazz,
+    GET_METHOD_ID(gCallbacksClassInfo.getExcludedDeviceNames, clazz,
             "getExcludedDeviceNames", "()[Ljava/lang/String;");
 
-    GET_METHOD_ID(gCallbacksClassInfo.getKeyRepeatTimeout, gCallbacksClassInfo.clazz,
+    GET_METHOD_ID(gCallbacksClassInfo.getKeyRepeatTimeout, clazz,
             "getKeyRepeatTimeout", "()I");
 
-    GET_METHOD_ID(gCallbacksClassInfo.getKeyRepeatDelay, gCallbacksClassInfo.clazz,
+    GET_METHOD_ID(gCallbacksClassInfo.getKeyRepeatDelay, clazz,
             "getKeyRepeatDelay", "()I");
 
-    GET_METHOD_ID(gCallbacksClassInfo.getMaxEventsPerSecond, gCallbacksClassInfo.clazz,
+    GET_METHOD_ID(gCallbacksClassInfo.getMaxEventsPerSecond, clazz,
             "getMaxEventsPerSecond", "()I");
 
-    GET_METHOD_ID(gCallbacksClassInfo.getPointerLayer, gCallbacksClassInfo.clazz,
+    GET_METHOD_ID(gCallbacksClassInfo.getPointerLayer, clazz,
             "getPointerLayer", "()I");
 
-    GET_METHOD_ID(gCallbacksClassInfo.getPointerIcon, gCallbacksClassInfo.clazz,
+    GET_METHOD_ID(gCallbacksClassInfo.getPointerIcon, clazz,
             "getPointerIcon", "()Lcom/android/server/wm/InputManager$PointerIcon;");
 
     // KeyEvent
 
     FIND_CLASS(gKeyEventClassInfo.clazz, "android/view/KeyEvent");
+    gKeyEventClassInfo.clazz = jclass(env->NewGlobalRef(gKeyEventClassInfo.clazz));
+
 
     // MotionEvent
 
     FIND_CLASS(gMotionEventClassInfo.clazz, "android/view/MotionEvent");
+    gMotionEventClassInfo.clazz = jclass(env->NewGlobalRef(gMotionEventClassInfo.clazz));
 
     // InputDevice
 
     FIND_CLASS(gInputDeviceClassInfo.clazz, "android/view/InputDevice");
+    gInputDeviceClassInfo.clazz = jclass(env->NewGlobalRef(gInputDeviceClassInfo.clazz));
 
     GET_METHOD_ID(gInputDeviceClassInfo.ctor, gInputDeviceClassInfo.clazz,
             "<init>", "()V");
 
     GET_METHOD_ID(gInputDeviceClassInfo.addMotionRange, gInputDeviceClassInfo.clazz,
-            "addMotionRange", "(IFFFF)V");
+            "addMotionRange", "(IIFFFF)V");
 
     GET_FIELD_ID(gInputDeviceClassInfo.mId, gInputDeviceClassInfo.clazz,
             "mId", "I");
@@ -1337,28 +1333,28 @@
 
     // Configuration
 
-    FIND_CLASS(gConfigurationClassInfo.clazz, "android/content/res/Configuration");
+    FIND_CLASS(clazz, "android/content/res/Configuration");
 
-    GET_FIELD_ID(gConfigurationClassInfo.touchscreen, gConfigurationClassInfo.clazz,
+    GET_FIELD_ID(gConfigurationClassInfo.touchscreen, clazz,
             "touchscreen", "I");
 
-    GET_FIELD_ID(gConfigurationClassInfo.keyboard, gConfigurationClassInfo.clazz,
+    GET_FIELD_ID(gConfigurationClassInfo.keyboard, clazz,
             "keyboard", "I");
 
-    GET_FIELD_ID(gConfigurationClassInfo.navigation, gConfigurationClassInfo.clazz,
+    GET_FIELD_ID(gConfigurationClassInfo.navigation, clazz,
             "navigation", "I");
 
     // PointerIcon
 
-    FIND_CLASS(gPointerIconClassInfo.clazz, "com/android/server/wm/InputManager$PointerIcon");
+    FIND_CLASS(clazz, "com/android/server/wm/InputManager$PointerIcon");
 
-    GET_FIELD_ID(gPointerIconClassInfo.bitmap, gPointerIconClassInfo.clazz,
+    GET_FIELD_ID(gPointerIconClassInfo.bitmap, clazz,
             "bitmap", "Landroid/graphics/Bitmap;");
 
-    GET_FIELD_ID(gPointerIconClassInfo.hotSpotX, gPointerIconClassInfo.clazz,
+    GET_FIELD_ID(gPointerIconClassInfo.hotSpotX, clazz,
             "hotSpotX", "F");
 
-    GET_FIELD_ID(gPointerIconClassInfo.hotSpotY, gPointerIconClassInfo.clazz,
+    GET_FIELD_ID(gPointerIconClassInfo.hotSpotY, clazz,
             "hotSpotY", "F");
 
     return 0;
diff --git a/services/jni/com_android_server_InputWindow.cpp b/services/jni/com_android_server_InputWindow.cpp
index 8548b47..99f625c 100644
--- a/services/jni/com_android_server_InputWindow.cpp
+++ b/services/jni/com_android_server_InputWindow.cpp
@@ -28,8 +28,6 @@
 namespace android {
 
 static struct {
-    jclass clazz;
-
     jfieldID inputWindowHandle;
     jfieldID inputChannel;
     jfieldID name;
@@ -136,71 +134,71 @@
 
 #define FIND_CLASS(var, className) \
         var = env->FindClass(className); \
-        LOG_FATAL_IF(! var, "Unable to find class " className); \
-        var = jclass(env->NewGlobalRef(var));
+        LOG_FATAL_IF(! var, "Unable to find class " className);
 
 #define GET_FIELD_ID(var, clazz, fieldName, fieldDescriptor) \
         var = env->GetFieldID(clazz, fieldName, fieldDescriptor); \
         LOG_FATAL_IF(! var, "Unable to find field " fieldName);
 
 int register_android_server_InputWindow(JNIEnv* env) {
-    FIND_CLASS(gInputWindowClassInfo.clazz, "com/android/server/wm/InputWindow");
+    jclass clazz;
+    FIND_CLASS(clazz, "com/android/server/wm/InputWindow");
 
-    GET_FIELD_ID(gInputWindowClassInfo.inputWindowHandle, gInputWindowClassInfo.clazz,
+    GET_FIELD_ID(gInputWindowClassInfo.inputWindowHandle, clazz,
             "inputWindowHandle", "Lcom/android/server/wm/InputWindowHandle;");
 
-    GET_FIELD_ID(gInputWindowClassInfo.inputChannel, gInputWindowClassInfo.clazz,
+    GET_FIELD_ID(gInputWindowClassInfo.inputChannel, clazz,
             "inputChannel", "Landroid/view/InputChannel;");
 
-    GET_FIELD_ID(gInputWindowClassInfo.name, gInputWindowClassInfo.clazz,
+    GET_FIELD_ID(gInputWindowClassInfo.name, clazz,
             "name", "Ljava/lang/String;");
 
-    GET_FIELD_ID(gInputWindowClassInfo.layoutParamsFlags, gInputWindowClassInfo.clazz,
+    GET_FIELD_ID(gInputWindowClassInfo.layoutParamsFlags, clazz,
             "layoutParamsFlags", "I");
 
-    GET_FIELD_ID(gInputWindowClassInfo.layoutParamsType, gInputWindowClassInfo.clazz,
+    GET_FIELD_ID(gInputWindowClassInfo.layoutParamsType, clazz,
             "layoutParamsType", "I");
 
-    GET_FIELD_ID(gInputWindowClassInfo.dispatchingTimeoutNanos, gInputWindowClassInfo.clazz,
+    GET_FIELD_ID(gInputWindowClassInfo.dispatchingTimeoutNanos, clazz,
             "dispatchingTimeoutNanos", "J");
 
-    GET_FIELD_ID(gInputWindowClassInfo.frameLeft, gInputWindowClassInfo.clazz,
+    GET_FIELD_ID(gInputWindowClassInfo.frameLeft, clazz,
             "frameLeft", "I");
 
-    GET_FIELD_ID(gInputWindowClassInfo.frameTop, gInputWindowClassInfo.clazz,
+    GET_FIELD_ID(gInputWindowClassInfo.frameTop, clazz,
             "frameTop", "I");
 
-    GET_FIELD_ID(gInputWindowClassInfo.frameRight, gInputWindowClassInfo.clazz,
+    GET_FIELD_ID(gInputWindowClassInfo.frameRight, clazz,
             "frameRight", "I");
 
-    GET_FIELD_ID(gInputWindowClassInfo.frameBottom, gInputWindowClassInfo.clazz,
+    GET_FIELD_ID(gInputWindowClassInfo.frameBottom, clazz,
             "frameBottom", "I");
 
-    GET_FIELD_ID(gInputWindowClassInfo.touchableRegion, gInputWindowClassInfo.clazz,
+    GET_FIELD_ID(gInputWindowClassInfo.touchableRegion, clazz,
             "touchableRegion", "Landroid/graphics/Region;");
 
-    GET_FIELD_ID(gInputWindowClassInfo.visible, gInputWindowClassInfo.clazz,
+    GET_FIELD_ID(gInputWindowClassInfo.visible, clazz,
             "visible", "Z");
 
-    GET_FIELD_ID(gInputWindowClassInfo.canReceiveKeys, gInputWindowClassInfo.clazz,
+    GET_FIELD_ID(gInputWindowClassInfo.canReceiveKeys, clazz,
             "canReceiveKeys", "Z");
 
-    GET_FIELD_ID(gInputWindowClassInfo.hasFocus, gInputWindowClassInfo.clazz,
+    GET_FIELD_ID(gInputWindowClassInfo.hasFocus, clazz,
             "hasFocus", "Z");
 
-    GET_FIELD_ID(gInputWindowClassInfo.hasWallpaper, gInputWindowClassInfo.clazz,
+    GET_FIELD_ID(gInputWindowClassInfo.hasWallpaper, clazz,
             "hasWallpaper", "Z");
 
-    GET_FIELD_ID(gInputWindowClassInfo.paused, gInputWindowClassInfo.clazz,
+    GET_FIELD_ID(gInputWindowClassInfo.paused, clazz,
             "paused", "Z");
 
-    GET_FIELD_ID(gInputWindowClassInfo.layer, gInputWindowClassInfo.clazz,
+    GET_FIELD_ID(gInputWindowClassInfo.layer, clazz,
             "layer", "I");
 
-    GET_FIELD_ID(gInputWindowClassInfo.ownerPid, gInputWindowClassInfo.clazz,
+    GET_FIELD_ID(gInputWindowClassInfo.ownerPid, clazz,
             "ownerPid", "I");
 
-    GET_FIELD_ID(gInputWindowClassInfo.ownerUid, gInputWindowClassInfo.clazz,
+    GET_FIELD_ID(gInputWindowClassInfo.ownerUid, clazz,
             "ownerUid", "I");
     return 0;
 }
diff --git a/services/jni/com_android_server_InputWindowHandle.cpp b/services/jni/com_android_server_InputWindowHandle.cpp
index 5b74e43..aaf679c 100644
--- a/services/jni/com_android_server_InputWindowHandle.cpp
+++ b/services/jni/com_android_server_InputWindowHandle.cpp
@@ -27,8 +27,6 @@
 namespace android {
 
 static struct {
-    jclass clazz;
-
     jfieldID ptr;
     jfieldID inputApplicationHandle;
 } gInputWindowHandleClassInfo;
@@ -108,8 +106,7 @@
 
 #define FIND_CLASS(var, className) \
         var = env->FindClass(className); \
-        LOG_FATAL_IF(! var, "Unable to find class " className); \
-        var = jclass(env->NewGlobalRef(var));
+        LOG_FATAL_IF(! var, "Unable to find class " className);
 
 #define GET_FIELD_ID(var, clazz, fieldName, fieldDescriptor) \
         var = env->GetFieldID(clazz, fieldName, fieldDescriptor); \
@@ -120,13 +117,14 @@
             gInputWindowHandleMethods, NELEM(gInputWindowHandleMethods));
     LOG_FATAL_IF(res < 0, "Unable to register native methods.");
 
-    FIND_CLASS(gInputWindowHandleClassInfo.clazz, "com/android/server/wm/InputWindowHandle");
+    jclass clazz;
+    FIND_CLASS(clazz, "com/android/server/wm/InputWindowHandle");
 
-    GET_FIELD_ID(gInputWindowHandleClassInfo.ptr, gInputWindowHandleClassInfo.clazz,
+    GET_FIELD_ID(gInputWindowHandleClassInfo.ptr, clazz,
             "ptr", "I");
 
     GET_FIELD_ID(gInputWindowHandleClassInfo.inputApplicationHandle,
-            gInputWindowHandleClassInfo.clazz,
+            clazz,
             "inputApplicationHandle", "Lcom/android/server/wm/InputApplicationHandle;");
 
     return 0;
diff --git a/services/jni/com_android_server_PowerManagerService.cpp b/services/jni/com_android_server_PowerManagerService.cpp
index 705be60..a389c11 100644
--- a/services/jni/com_android_server_PowerManagerService.cpp
+++ b/services/jni/com_android_server_PowerManagerService.cpp
@@ -35,8 +35,6 @@
 // ----------------------------------------------------------------------------
 
 static struct {
-    jclass clazz;
-
     jmethodID goToSleep;
     jmethodID userActivity;
 } gPowerManagerServiceClassInfo;
@@ -144,8 +142,7 @@
 
 #define FIND_CLASS(var, className) \
         var = env->FindClass(className); \
-        LOG_FATAL_IF(! var, "Unable to find class " className); \
-        var = jclass(env->NewGlobalRef(var));
+        LOG_FATAL_IF(! var, "Unable to find class " className);
 
 #define GET_METHOD_ID(var, clazz, methodName, methodDescriptor) \
         var = env->GetMethodID(clazz, methodName, methodDescriptor); \
@@ -162,12 +159,13 @@
 
     // Callbacks
 
-    FIND_CLASS(gPowerManagerServiceClassInfo.clazz, "com/android/server/PowerManagerService");
+    jclass clazz;
+    FIND_CLASS(clazz, "com/android/server/PowerManagerService");
 
-    GET_METHOD_ID(gPowerManagerServiceClassInfo.goToSleep, gPowerManagerServiceClassInfo.clazz,
+    GET_METHOD_ID(gPowerManagerServiceClassInfo.goToSleep, clazz,
             "goToSleep", "(J)V");
 
-    GET_METHOD_ID(gPowerManagerServiceClassInfo.userActivity, gPowerManagerServiceClassInfo.clazz,
+    GET_METHOD_ID(gPowerManagerServiceClassInfo.userActivity, clazz,
             "userActivity", "(JZIZ)V");
 
     // Initialize
diff --git a/services/jni/com_android_server_UsbService.cpp b/services/jni/com_android_server_UsbService.cpp
index 3c49e54..816f76f 100644
--- a/services/jni/com_android_server_UsbService.cpp
+++ b/services/jni/com_android_server_UsbService.cpp
@@ -193,12 +193,14 @@
         return NULL;
     }
     jclass stringClass = env->FindClass("java/lang/String");
-    jobjectArray strArray = env->NewObjectArray(4, stringClass, NULL);
+    jobjectArray strArray = env->NewObjectArray(6, stringClass, NULL);
     if (!strArray) goto out;
     set_accessory_string(env, fd, ACCESSORY_GET_STRING_MANUFACTURER, strArray, 0);
     set_accessory_string(env, fd, ACCESSORY_GET_STRING_MODEL, strArray, 1);
-    set_accessory_string(env, fd, ACCESSORY_GET_STRING_TYPE, strArray, 2);
+    set_accessory_string(env, fd, ACCESSORY_GET_STRING_DESCRIPTION, strArray, 2);
     set_accessory_string(env, fd, ACCESSORY_GET_STRING_VERSION, strArray, 3);
+    set_accessory_string(env, fd, ACCESSORY_GET_STRING_URI, strArray, 4);
+    set_accessory_string(env, fd, ACCESSORY_GET_STRING_SERIAL, strArray, 5);
 
 out:
     close(fd);
diff --git a/services/jni/onload.cpp b/services/jni/onload.cpp
index 37b520b..0c46eee 100644
--- a/services/jni/onload.cpp
+++ b/services/jni/onload.cpp
@@ -1,3 +1,19 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
 #include "JNIHelp.h"
 #include "jni.h"
 #include "utils/Log.h"
diff --git a/services/sensorservice/Android.mk b/services/sensorservice/Android.mk
index 7e17fdd..c50e4a1 100644
--- a/services/sensorservice/Android.mk
+++ b/services/sensorservice/Android.mk
@@ -27,7 +27,7 @@
 	libui \
 	libgui
 
-LOCAL_PRELINK_MODULE := false
+
 
 LOCAL_MODULE:= libsensorservice
 
diff --git a/services/sensorservice/SensorService.cpp b/services/sensorservice/SensorService.cpp
index 697e879..ce1ab3d 100644
--- a/services/sensorservice/SensorService.cpp
+++ b/services/sensorservice/SensorService.cpp
@@ -340,11 +340,14 @@
             if (rec->addConnection(connection)) {
                 // this sensor is already activated, but we are adding a
                 // connection that uses it. Immediately send down the last
-                // known value of the requested sensor.
-                sensors_event_t scratch;
-                sensors_event_t& event(mLastEventSeen.editValueFor(handle));
-                if (event.version == sizeof(sensors_event_t)) {
-                    connection->sendEvents(&event, 1);
+                // known value of the requested sensor if it's not a
+                // "continuous" sensor.
+                if (sensor->getSensor().getMinDelay() == 0) {
+                    sensors_event_t scratch;
+                    sensors_event_t& event(mLastEventSeen.editValueFor(handle));
+                    if (event.version == sizeof(sensors_event_t)) {
+                        connection->sendEvents(&event, 1);
+                    }
                 }
             }
         }
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index 57af001..c4027e0 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -52,15 +52,16 @@
 Layer::Layer(SurfaceFlinger* flinger,
         DisplayID display, const sp<Client>& client)
     :   LayerBaseClient(flinger, display, client),
+        mFormat(PIXEL_FORMAT_NONE),
         mGLExtensions(GLExtensions::getInstance()),
         mNeedsBlending(true),
         mNeedsDithering(false),
         mSecure(false),
         mProtectedByApp(false),
-        mProtectedByDRM(false),
         mTextureManager(),
         mBufferManager(mTextureManager),
-        mWidth(0), mHeight(0), mNeedsScaling(false), mFixedSize(false)
+        mWidth(0), mHeight(0),
+        mNeedsScaling(false), mFixedSize(false)
 {
 }
 
@@ -191,7 +192,6 @@
 
     mSecure = (flags & ISurfaceComposer::eSecure) ? true : false;
     mProtectedByApp = (flags & ISurfaceComposer::eProtectedByApp) ? true : false;
-    mProtectedByDRM = (flags & ISurfaceComposer::eProtectedByDRM) ? true : false;
     mNeedsBlending = (info.h_alpha - info.l_alpha) > 0 &&
             (flags & ISurfaceComposer::eOpaque) == 0;
 
@@ -392,6 +392,12 @@
     return LayerBase::needsFiltering();
 }
 
+bool Layer::isProtected() const
+{
+    sp<GraphicBuffer> activeBuffer(mBufferManager.getActiveBuffer());
+    return (activeBuffer != 0) &&
+            (activeBuffer->getUsage() & GRALLOC_USAGE_PROTECTED);
+}
 
 status_t Layer::setBufferCount(int bufferCount)
 {
@@ -515,7 +521,7 @@
         // request EGLImage for all buffers
         usage |= GraphicBuffer::USAGE_HW_TEXTURE;
     }
-    if (mProtectedByApp || mProtectedByDRM) {
+    if (mProtectedByApp) {
         // need a hardware-protected path to external video sink
         usage |= GraphicBuffer::USAGE_PROTECTED;
     }
@@ -805,7 +811,7 @@
 
     { // scope for strong mUserClient reference
         sp<UserClient> userClient(mUserClient.promote());
-        if (mUserClient != 0 && mControlBlock != 0) {
+        if (userClient != 0 && mControlBlock != 0) {
             mControlBlock->setStatus(NO_INIT);
         }
     }
@@ -854,11 +860,13 @@
     Mutex::Autolock _l(mLock);
 
     if (size < mNumBuffers) {
-        // Move the active texture into slot 0
-        BufferData activeBufferData = mBufferData[mActiveBufferIndex];
-        mBufferData[mActiveBufferIndex] = mBufferData[0];
-        mBufferData[0] = activeBufferData;
-        mActiveBufferIndex = 0;
+        // If there is an active texture, move it into slot 0 if needed
+        if (mActiveBufferIndex > 0) {
+            BufferData activeBufferData = mBufferData[mActiveBufferIndex];
+            mBufferData[mActiveBufferIndex] = mBufferData[0];
+            mBufferData[0] = activeBufferData;
+            mActiveBufferIndex = 0;
+        }
 
         // Free the buffers that are no longer needed.
         for (size_t i = size; i < mNumBuffers; i++) {
diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h
index bccc900..128f93d 100644
--- a/services/surfaceflinger/Layer.h
+++ b/services/surfaceflinger/Layer.h
@@ -80,8 +80,7 @@
     virtual bool needsDithering() const     { return mNeedsDithering; }
     virtual bool needsFiltering() const;
     virtual bool isSecure() const           { return mSecure; }
-    virtual bool isProtectedByApp() const   { return mProtectedByApp; }
-    virtual bool isProtectedByDRM() const   { return mProtectedByDRM; }
+    virtual bool isProtected() const;
     virtual sp<Surface> createSurface() const;
     virtual status_t ditch();
     virtual void onRemoved();
@@ -222,7 +221,6 @@
     // page-flip thread (currently main thread)
     bool mSecure;         // no screenshots
     bool mProtectedByApp; // application requires protected path to external sink
-    bool mProtectedByDRM; // DRM agent requires protected path to external sink
     Region mPostedDirtyRegion;
 
     // page-flip thread and transaction thread (currently main thread)
diff --git a/services/surfaceflinger/LayerBase.h b/services/surfaceflinger/LayerBase.h
index bfe92e6..7162e47 100644
--- a/services/surfaceflinger/LayerBase.h
+++ b/services/surfaceflinger/LayerBase.h
@@ -197,16 +197,10 @@
     virtual bool isSecure() const       { return false; }
 
     /**
-     * isProtectedByApp - true if application says this surface is protected, that
-     * is if it requires a hardware-protected data path to an external sink.
+     * isProtected - true if the layer may contain protected content in the
+     * GRALLOC_USAGE_PROTECTED sense.
      */
-    virtual bool isProtectedByApp() const   { return false; }
-
-    /**
-     * isProtectedByDRM - true if DRM agent says this surface is protected, that
-     * is if it requires a hardware-protected data path to an external sink.
-     */
-    virtual bool isProtectedByDRM() const   { return false; }
+    virtual bool isProtected() const   { return false; }
 
     /** Called from the main thread, when the surface is removed from the
      * draw list */
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 554fa43..ea283c606 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -327,6 +327,40 @@
     const_cast<SurfaceFlinger*>(this)->signalEvent();
 }
 
+bool SurfaceFlinger::authenticateSurface(const sp<ISurface>& surface) const {
+    Mutex::Autolock _l(mStateLock);
+    sp<IBinder> surfBinder(surface->asBinder());
+
+    // Check the visible layer list for the ISurface
+    const LayerVector& currentLayers = mCurrentState.layersSortedByZ;
+    size_t count = currentLayers.size();
+    for (size_t i=0 ; i<count ; i++) {
+        const sp<LayerBase>& layer(currentLayers[i]);
+        sp<LayerBaseClient> lbc(layer->getLayerBaseClient());
+        if (lbc != NULL && lbc->getSurfaceBinder() == surfBinder) {
+            return true;
+        }
+    }
+
+    // Check the layers in the purgatory.  This check is here so that if a
+    // Surface gets destroyed before all the clients are done using it, the
+    // error will not be reported as "surface XYZ is not authenticated", but
+    // will instead fail later on when the client tries to use the surface,
+    // which should be reported as "surface XYZ returned an -ENODEV".  The
+    // purgatorized layers are no less authentic than the visible ones, so this
+    // should not cause any harm.
+    size_t purgatorySize =  mLayerPurgatory.size();
+    for (size_t i=0 ; i<purgatorySize ; i++) {
+        const sp<LayerBase>& layer(mLayerPurgatory.itemAt(i));
+        sp<LayerBaseClient> lbc(layer->getLayerBaseClient());
+        if (lbc != NULL && lbc->getSurfaceBinder() == surfBinder) {
+            return true;
+        }
+    }
+
+    return false;
+}
+
 status_t SurfaceFlinger::postMessageAsync(const sp<MessageBase>& msg,
         nsecs_t reltime, uint32_t flags)
 {
@@ -566,7 +600,7 @@
 }
 
 void SurfaceFlinger::computeVisibleRegions(
-    LayerVector& currentLayers, Region& dirtyRegion, Region& opaqueRegion)
+    const LayerVector& currentLayers, Region& dirtyRegion, Region& opaqueRegion)
 {
     const GraphicPlane& plane(graphicPlane(0));
     const Transform& planeTransform(plane.transform());
@@ -701,8 +735,7 @@
 void SurfaceFlinger::handlePageFlip()
 {
     bool visibleRegions = mVisibleRegionsDirty;
-    LayerVector& currentLayers(
-            const_cast<LayerVector&>(mDrawingState.layersSortedByZ));
+    const LayerVector& currentLayers(mDrawingState.layersSortedByZ);
     visibleRegions |= lockPageFlip(currentLayers);
 
         const DisplayHardware& hw = graphicPlane(0).displayHardware();
@@ -714,9 +747,8 @@
             /*
              *  rebuild the visible layer list
              */
+            const size_t count = currentLayers.size();
             mVisibleLayersSortedByZ.clear();
-            const LayerVector& currentLayers(mDrawingState.layersSortedByZ);
-            size_t count = currentLayers.size();
             mVisibleLayersSortedByZ.setCapacity(count);
             for (size_t i=0 ; i<count ; i++) {
                 if (!currentLayers[i]->visibleRegionScreen.isEmpty())
@@ -2135,6 +2167,19 @@
     if (UNLIKELY(uint32_t(dpy) >= DISPLAY_COUNT))
         return BAD_VALUE;
 
+    // make sure none of the layers are protected
+    const Vector< sp<LayerBase> >& layers(mVisibleLayersSortedByZ);
+    const size_t count = layers.size();
+    for (size_t i=0 ; i<count ; ++i) {
+        const sp<LayerBase>& layer(layers[i]);
+        const uint32_t z = layer->drawingState().z;
+        if (z >= minLayerZ && z <= maxLayerZ) {
+            if (layer->isProtected()) {
+                return INVALID_OPERATION;
+            }
+        }
+    }
+
     if (!GLExtensions::getInstance().haveFramebufferObject())
         return INVALID_OPERATION;
 
@@ -2183,8 +2228,6 @@
         glClearColor(0,0,0,1);
         glClear(GL_COLOR_BUFFER_BIT);
 
-        const Vector< sp<LayerBase> >& layers(mVisibleLayersSortedByZ);
-        const size_t count = layers.size();
         for (size_t i=0 ; i<count ; ++i) {
             const sp<LayerBase>& layer(layers[i]);
             const uint32_t z = layer->drawingState().z;
@@ -2470,7 +2513,7 @@
             }
             break;
         }
-        if (++name >= SharedBufferStack::NUM_LAYERS_MAX)
+        if (++name >= int32_t(SharedBufferStack::NUM_LAYERS_MAX))
             name = NO_MEMORY;
     } while(name >= 0);
 
@@ -2517,7 +2560,7 @@
 
 void GraphicBufferAlloc::freeAllGraphicBuffersExcept(int bufIdx) {
     Mutex::Autolock _l(mLock);
-    if (0 <= bufIdx && bufIdx < mBuffers.size()) {
+    if (bufIdx >= 0 && size_t(bufIdx) < mBuffers.size()) {
         sp<GraphicBuffer> b(mBuffers[bufIdx]);
         mBuffers.clear();
         mBuffers.add(b);
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index 6dd91ac..0964848 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -209,6 +209,7 @@
     virtual status_t                    unfreezeDisplay(DisplayID dpy, uint32_t flags);
     virtual int                         setOrientation(DisplayID dpy, int orientation, uint32_t flags);
     virtual void                        signal() const;
+    virtual bool                        authenticateSurface(const sp<ISurface>& surface) const;
 
     virtual status_t captureScreen(DisplayID dpy,
             sp<IMemoryHeap>* heap,
@@ -303,7 +304,7 @@
                             Vector< sp<LayerBase> >& ditchedLayers);
 
             void        computeVisibleRegions(
-                            LayerVector& currentLayers,
+                            const LayerVector& currentLayers,
                             Region& dirtyRegion,
                             Region& wormholeRegion);
 
@@ -370,7 +371,6 @@
                 // access must be protected by mStateLock
     mutable     Mutex                   mStateLock;
                 State                   mCurrentState;
-                State                   mDrawingState;
     volatile    int32_t                 mTransactionFlags;
     volatile    int32_t                 mTransactionCount;
                 Condition               mTransactionCV;
@@ -394,6 +394,7 @@
                 
                 // Can only accessed from the main thread, these members
                 // don't need synchronization
+                State                       mDrawingState;
                 Region                      mDirtyRegion;
                 Region                      mDirtyRegionRemovedLayer;
                 Region                      mInvalidRegion;
diff --git a/services/surfaceflinger/tests/resize/resize.cpp b/services/surfaceflinger/tests/resize/resize.cpp
index 99f4b4f..0ccca77 100644
--- a/services/surfaceflinger/tests/resize/resize.cpp
+++ b/services/surfaceflinger/tests/resize/resize.cpp
@@ -1,3 +1,19 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
 #include <cutils/memory.h>
 
 #include <utils/Log.h>
diff --git a/services/surfaceflinger/tests/surface/surface.cpp b/services/surfaceflinger/tests/surface/surface.cpp
index 194fbb6..67ecf7e 100644
--- a/services/surfaceflinger/tests/surface/surface.cpp
+++ b/services/surfaceflinger/tests/surface/surface.cpp
@@ -1,3 +1,19 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
 #include <cutils/memory.h>
 
 #include <utils/Log.h>
diff --git a/telephony/java/android/telephony/ServiceState.java b/telephony/java/android/telephony/ServiceState.java
index 5dcb820..ba05837 100644
--- a/telephony/java/android/telephony/ServiceState.java
+++ b/telephony/java/android/telephony/ServiceState.java
@@ -92,9 +92,11 @@
     /** @hide */
     public static final int RADIO_TECHNOLOGY_EVDO_B = 12;
     /** @hide */
-    public static final int RADIO_TECHNOLOGY_LTE = 13;
+    public static final int RADIO_TECHNOLOGY_EHRPD = 13;
     /** @hide */
-    public static final int RADIO_TECHNOLOGY_EHRPD = 14;
+    public static final int RADIO_TECHNOLOGY_LTE = 14;
+    /** @hide */
+    public static final int RADIO_TECHNOLOGY_HSPAP = 15;
 
     /**
      * Available registration states for GSM, UMTS and CDMA.
@@ -429,10 +431,13 @@
             radioTechnology = "EvDo rev. B";
             break;
         case 13:
-            radioTechnology = "LTE";
+            radioTechnology = "eHRPD";
             break;
         case 14:
-            radioTechnology = "eHRPD";
+            radioTechnology = "LTE";
+            break;
+        case 15:
+            radioTechnology = "HSPAP";
             break;
         default:
             Log.w(LOG_TAG, "mRadioTechnology variable out of range.");
diff --git a/telephony/java/android/telephony/SignalStrength.java b/telephony/java/android/telephony/SignalStrength.java
index 98ab3d1..1767dd9 100644
--- a/telephony/java/android/telephony/SignalStrength.java
+++ b/telephony/java/android/telephony/SignalStrength.java
@@ -556,7 +556,7 @@
      * @hide
      */
     public int getLteDbm() {
-        log("STOPSHIP teach getLteDbm to compute dBm properly");
+        log("TODO: teach getLteDbm to compute dBm properly");
         int level = -1;
         if (DBG) log("getLteDbm=" + level);
         return level;
@@ -568,7 +568,7 @@
      * @hide
      */
     public int getLteLevel() {
-        log("STOPSHIP teach getLteLevel to compute Level properly");
+        log("TODO: teach getLteLevel to compute Level properly");
         int level = SIGNAL_STRENGTH_MODERATE;
         if (DBG) log("getLteLevel=" + level);
         return level;
@@ -580,7 +580,7 @@
      * @hide
      */
     public int getLteAsuLevel() {
-        log("STOPSHIP teach getLteAsuLevel to compute asu Level properly");
+        log("TODO: teach getLteAsuLevel to compute asu Level properly");
         int level = 4;
         if (DBG) log("getLteAsuLevel=" + level);
         return level;
diff --git a/telephony/java/com/android/internal/telephony/ApnSetting.java b/telephony/java/com/android/internal/telephony/ApnSetting.java
index 3c93a68..20dbaf3 100644
--- a/telephony/java/com/android/internal/telephony/ApnSetting.java
+++ b/telephony/java/com/android/internal/telephony/ApnSetting.java
@@ -38,17 +38,12 @@
     public String numeric;
     public String protocol;
     public String roamingProtocol;
-    public boolean enabled;
-
-    int timer;
-    int apnclass;
 
     public ApnSetting(int id, String numeric, String carrier, String apn,
             String proxy, String port,
             String mmsc, String mmsProxy, String mmsPort,
             String user, String password, int authType, String[] types,
-            String protocol, String roamingProtocol,
-            boolean enabled, int timer, int apnclass) {
+            String protocol, String roamingProtocol) {
         this.id = id;
         this.numeric = numeric;
         this.carrier = carrier;
@@ -64,9 +59,6 @@
         this.types = types;
         this.protocol = protocol;
         this.roamingProtocol = roamingProtocol;
-        this.enabled = enabled;
-        this.timer = timer;
-        this.apnclass = apnclass;
     }
 
     /**
@@ -85,7 +77,7 @@
      * v2 format:
      *   [ApnSettingV2] <carrier>, <apn>, <proxy>, <port>, <mmsc>, <mmsproxy>,
      *   <mmsport>, <user>, <password, <authtype>, <mcc>, <mnc>,
-     *   <type>[| <type>...], <protocol>, <roaming_protocol>, <enabled>, <timer>, <apnclass>
+     *   <type>[| <type>...], <protocol>, <roaming_protocol>
      *
      * Note that the strings generated by toString() do not contain the username
      * and password and thus cannot be read by this method.
@@ -118,16 +110,11 @@
 
         String[] typeArray;
         String protocol, roamingProtocol;
-        boolean enabled;
-        int timer, apnclass;
         if (version == 1) {
             typeArray = new String[a.length - 13];
             System.arraycopy(a, 13, typeArray, 0, a.length - 13);
             protocol = RILConstants.SETUP_DATA_PROTOCOL_IP;
             roamingProtocol = RILConstants.SETUP_DATA_PROTOCOL_IP;
-            enabled = true;
-            timer = 0;
-            apnclass = 0;
         } else {
             if (a.length < 16) {
                 return null;
@@ -135,14 +122,10 @@
             typeArray = a[13].split("\\s*\\|\\s*");
             protocol = a[14];
             roamingProtocol = a[15];
-            enabled = Integer.parseInt(a[16]) != 0;
-            timer = Integer.parseInt(a[17]);
-            apnclass = Integer.parseInt(a[18]);
         }
 
         return new ApnSetting(-1,a[10]+a[11],a[0],a[1],a[2],a[3],a[7],a[8],
-                a[9],a[4],a[5],authType,typeArray,protocol,roamingProtocol,
-                enabled,timer,apnclass);
+                a[9],a[4],a[5],authType,typeArray,protocol,roamingProtocol);
     }
 
     public String toString() {
@@ -166,9 +149,6 @@
         }
         sb.append(", ").append(protocol);
         sb.append(", ").append(roamingProtocol);
-        sb.append(", ").append(enabled);
-        sb.append(", ").append(timer);
-        sb.append(", ").append(apnclass);
         return sb.toString();
     }
 
diff --git a/telephony/java/com/android/internal/telephony/CommandsInterface.java b/telephony/java/com/android/internal/telephony/CommandsInterface.java
index ea38543..9e1e0c6 100644
--- a/telephony/java/com/android/internal/telephony/CommandsInterface.java
+++ b/telephony/java/com/android/internal/telephony/CommandsInterface.java
@@ -27,9 +27,8 @@
  * {@hide}
  */
 public interface CommandsInterface {
-    // TODO: Get rid of mot from property.
     static final boolean LTE_AVAILABLE_ON_CDMA =
-        SystemProperties.getBoolean("ro.mot.lte_on_cdma", false);
+        SystemProperties.getBoolean(TelephonyProperties.PROPERTY_NETWORK_LTE_ON_CDMA, false);
     enum RadioState {
         RADIO_OFF(0),         /* Radio explictly powered off (eg CFUN=0) */
         RADIO_UNAVAILABLE(0), /* Radio unavailable (eg, resetting or not booted) */
diff --git a/telephony/java/com/android/internal/telephony/DataConnection.java b/telephony/java/com/android/internal/telephony/DataConnection.java
index 89513fd..b5578c3 100644
--- a/telephony/java/com/android/internal/telephony/DataConnection.java
+++ b/telephony/java/com/android/internal/telephony/DataConnection.java
@@ -219,10 +219,9 @@
     protected static final int EVENT_LOG_BAD_DNS_ADDRESS = 50100;
 
     //***** Member Variables
-    protected int mId;
+    protected ApnSetting mApn;
     protected int mTag;
     protected PhoneBase phone;
-    protected RetryManager mRetryMgr;
     protected int cid;
     protected LinkProperties mLinkProperties = new LinkProperties();
     protected LinkCapabilities mCapabilities = new LinkCapabilities();
@@ -244,10 +243,11 @@
 
 
    //***** Constructor
-    protected DataConnection(PhoneBase phone, String name, RetryManager rm) {
+    protected DataConnection(PhoneBase phone, String name, int id, RetryManager rm) {
         super(name);
         if (DBG) log("DataConnection constructor E");
         this.phone = phone;
+        mId = id;
         mRetryMgr = rm;
         this.cid = -1;
         clearSettings();
@@ -342,21 +342,100 @@
         clearSettings();
     }
 
-    public RetryManager getRetryMgr() {
-        return mRetryMgr;
+    /*
+     * **************************************************************************
+     * Begin Members and methods owned by DataConnectionTracker but stored
+     * in a DataConnection because there is one per connection.
+     * **************************************************************************
+     */
+
+    /*
+     * The id is owned by DataConnectionTracker.
+     */
+    private int mId;
+
+    /**
+     * Get the DataConnection ID
+     */
+    public int getDataConnectionId() {
+        return mId;
     }
 
+    /*
+     * The retry manager is currently owned by the DataConnectionTracker but is stored
+     * in the DataConnection because there is one per connection. These methods
+     * should only be used by the DataConnectionTracker although someday the retrying
+     * maybe managed by the DataConnection itself and these methods could disappear.
+     */
+    private RetryManager mRetryMgr;
+
+    /**
+     * @return retry manager retryCount
+     */
+    public int getRetryCount() {
+        return mRetryMgr.getRetryCount();
+    }
+
+    /**
+     * @return retry manager retryTimer
+     */
+    public int getRetryTimer() {
+        return mRetryMgr.getRetryTimer();
+    }
+
+    /**
+     * increaseRetryCount of retry manager
+     */
+    public void increaseRetryCount() {
+        mRetryMgr.increaseRetryCount();
+    }
+
+    /**
+     * @return retry manager isRetryNeeded
+     */
+    public boolean isRetryNeeded() {
+        return mRetryMgr.isRetryNeeded();
+    }
+
+    /**
+     * resetRetryCount of retry manager
+     */
+    public void resetRetryCount() {
+        mRetryMgr.resetRetryCount();
+    }
+
+    /**
+     * set retryForeverUsingLasttimeout of retry manager
+     */
+    public void retryForeverUsingLastTimeout() {
+        mRetryMgr.retryForeverUsingLastTimeout();
+    }
+
+    /**
+     * @return retry manager isRetryForever
+     */
+    public boolean isRetryForever() {
+        return mRetryMgr.isRetryForever();
+    }
+
+    /*
+     * **************************************************************************
+     * End members owned by DataConnectionTracker
+     * **************************************************************************
+     */
+
     /**
      * Clear all settings called when entering mInactiveState.
      */
     protected void clearSettings() {
         if (DBG) log("clearSettings");
 
-        this.createTime = -1;
-        this.lastFailTime = -1;
-        this.lastFailCause = FailCause.NONE;
+        createTime = -1;
+        lastFailTime = -1;
+        lastFailCause = FailCause.NONE;
 
         mLinkProperties = new LinkProperties();
+        mApn = null;
     }
 
     /**
@@ -964,13 +1043,6 @@
     }
 
     /**
-     * Get the DataConnection ID
-     */
-    public int getDataConnectionId() {
-        return mId;
-    }
-
-    /**
      * Return the LinkProperties for the connection.
      *
      * @return a copy of the LinkProperties, is never null.
@@ -1017,4 +1089,11 @@
     public FailCause getLastFailCause() {
         return lastFailCause;
     }
+
+    /**
+     * @return the current ApnSetting
+     */
+    public ApnSetting getApn() {
+        return mApn;
+    }
 }
diff --git a/telephony/java/com/android/internal/telephony/DataConnectionTracker.java b/telephony/java/com/android/internal/telephony/DataConnectionTracker.java
index 4c1e0cf..d4a3c0a 100644
--- a/telephony/java/com/android/internal/telephony/DataConnectionTracker.java
+++ b/telephony/java/com/android/internal/telephony/DataConnectionTracker.java
@@ -38,6 +38,8 @@
 import android.text.TextUtils;
 import android.util.Log;
 
+import com.android.internal.R;
+
 import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.concurrent.atomic.AtomicInteger;
@@ -209,9 +211,6 @@
     protected int mNoRecvPollCount = 0;
     protected boolean mNetStatPollEnabled = false;
 
-    /** Manage the behavior of data retry after failure (TODO: One per connection in the future?) */
-    protected RetryManager mRetryMgr = new RetryManager();
-
     // wifi connection status will be updated by sticky intent
     protected boolean mIsWifiConnected = false;
 
@@ -356,9 +355,26 @@
 
     public boolean isApnTypeActive(String type) {
         // TODO: support simultaneous with List instead
+        if (Phone.APN_TYPE_DUN.equals(type)) {
+            ApnSetting dunApn = fetchDunApn();
+            if (dunApn != null) {
+                return ((mActiveApn != null) && (dunApn.toString().equals(mActiveApn.toString())));
+            }
+        }
         return mActiveApn != null && mActiveApn.canHandleType(type);
     }
 
+    protected ApnSetting fetchDunApn() {
+        Context c = mPhone.getContext();
+        String apnData = Settings.Secure.getString(c.getContentResolver(),
+                Settings.Secure.TETHER_DUN_APN);
+        ApnSetting dunSetting = ApnSetting.fromString(apnData);
+        if (dunSetting != null) return dunSetting;
+
+        apnData = c.getResources().getString(R.string.config_tether_apndata);
+        return ApnSetting.fromString(apnData);
+    }
+
     public String[] getActiveApnTypes() {
         String[] result;
         if (mActiveApn != null) {
@@ -397,7 +413,7 @@
                 Settings.Secure.DATA_ROAMING, enabled ? 1 : 0);
             if (mPhone.getServiceState().getRoaming()) {
                 if (enabled) {
-                    mRetryMgr.resetRetryCount();
+                    resetAllRetryCounts();
                 }
                 sendMessage(obtainMessage(EVENT_ROAMING_ON));
             }
@@ -425,7 +441,6 @@
     protected abstract void onRadioOffOrNotAvailable();
     protected abstract void onDataSetupComplete(AsyncResult ar);
     protected abstract void onDisconnectDone(int connId, AsyncResult ar);
-    protected abstract void onResetDone(AsyncResult ar);
     protected abstract void onVoiceCallStarted();
     protected abstract void onVoiceCallEnded();
     protected abstract void onCleanUpConnection(boolean tearDown, int apnId, String reason);
@@ -449,7 +464,7 @@
 
             case EVENT_ROAMING_OFF:
                 if (getDataOnRoamingEnabled() == false) {
-                    mRetryMgr.resetRetryCount();
+                    resetAllRetryCounts();
                 }
                 onRoamingOff();
                 break;
@@ -498,9 +513,10 @@
                 onSetInternalDataEnabled(enabled);
                 break;
             }
-            case EVENT_RESET_DONE:
+            case EVENT_RESET_DONE: {
                 onResetDone((AsyncResult) msg.obj);
                 break;
+            }
             case CMD_SET_DATA_ENABLE: {
                 log("CMD_SET_DATA_ENABLE msg=" + msg);
                 boolean enabled = (msg.arg1 == ENABLED) ? true : false;
@@ -586,6 +602,8 @@
 
     protected abstract void setState(State s);
 
+    protected abstract void gotoIdleAndNotifyDataConnection(String reason);
+
     protected LinkProperties getLinkProperties(String apnType) {
         int id = apnTypeToId(apnType);
         if (isApnIdEnabled(id)) {
@@ -857,6 +875,22 @@
     }
 
     /**
+     * Called when EVENT_RESET_DONE is received so goto
+     * IDLE state and send notifications to those interested.
+     *
+     * TODO - currently unused.  Needs to be hooked into DataConnection cleanup
+     * TODO - needs to pass some notion of which connection is reset..
+     */
+    protected void onResetDone(AsyncResult ar) {
+        if (DBG) log("EVENT_RESET_DONE");
+        String reason = null;
+        if (ar.userObj instanceof String) {
+            reason = (String) ar.userObj;
+        }
+        gotoIdleAndNotifyDataConnection(reason);
+    }
+
+    /**
      * Prevent mobile data connections from being established, or once again
      * allow mobile data connections. If the state toggles, then either tear
      * down or set up data, as appropriate to match the new state.
@@ -883,7 +917,7 @@
             }
             if (prevEnabled != getAnyDataEnabled()) {
                 if (!prevEnabled) {
-                    mRetryMgr.resetRetryCount();
+                    resetAllRetryCounts();
                     onTrySetupData(Phone.REASON_DATA_ENABLED);
                 } else {
                     cleanUpAllConnections();
@@ -917,7 +951,7 @@
                     Settings.Secure.MOBILE_DATA, enable ? 1 : 0);
             if (prevEnabled != getAnyDataEnabled()) {
                 if (!prevEnabled) {
-                    mRetryMgr.resetRetryCount();
+                    resetAllRetryCounts();
                     onTrySetupData(Phone.REASON_DATA_ENABLED);
                 } else {
                     onCleanUpConnection(true, APN_DEFAULT_ID, Phone.REASON_DATA_DISABLED);
@@ -925,4 +959,10 @@
             }
         }
     }
+
+    protected void resetAllRetryCounts() {
+        for (DataConnection dc : mDataConnections.values()) {
+            dc.resetRetryCount();
+        }
+    }
 }
diff --git a/telephony/java/com/android/internal/telephony/IccCard.java b/telephony/java/com/android/internal/telephony/IccCard.java
index d9c2e9a..dbfc0d4 100644
--- a/telephony/java/com/android/internal/telephony/IccCard.java
+++ b/telephony/java/com/android/internal/telephony/IccCard.java
@@ -86,9 +86,8 @@
     private static final int EVENT_QUERY_FACILITY_FDN_DONE = 10;
     private static final int EVENT_CHANGE_FACILITY_FDN_DONE = 11;
 
-    // FIXME: remove mot from property
     static final boolean LTE_AVAILABLE_ON_CDMA =
-        SystemProperties.getBoolean("ro.mot.lte_on_cdma", false);
+            SystemProperties.getBoolean(TelephonyProperties.PROPERTY_NETWORK_LTE_ON_CDMA, false);
 
     /*
       UNKNOWN is a transient state, for example, after uesr inputs ICC pin under
diff --git a/telephony/java/com/android/internal/telephony/PhoneFactory.java b/telephony/java/com/android/internal/telephony/PhoneFactory.java
index c25a53d..ab0bb63 100644
--- a/telephony/java/com/android/internal/telephony/PhoneFactory.java
+++ b/telephony/java/com/android/internal/telephony/PhoneFactory.java
@@ -37,7 +37,7 @@
     static final int SOCKET_OPEN_RETRY_MILLIS = 2 * 1000;
     static final int SOCKET_OPEN_MAX_RETRY = 3;
     static final boolean LTE_AVAILABLE_ON_CDMA =
-        SystemProperties.getBoolean("ro.mot.lte_on_cdma", false);
+            SystemProperties.getBoolean(TelephonyProperties.PROPERTY_NETWORK_LTE_ON_CDMA, false);
 
     //***** Class Variables
 
@@ -160,7 +160,8 @@
             return Phone.PHONE_TYPE_CDMA;
 
         case RILConstants.NETWORK_MODE_LTE_ONLY:
-            if (SystemProperties.getBoolean("ro.mot.lte_on_cdma", false)) {
+            if (SystemProperties.getBoolean(TelephonyProperties.PROPERTY_NETWORK_LTE_ON_CDMA,
+                    false)) {
                 return Phone.PHONE_TYPE_CDMA;
             } else {
                 return Phone.PHONE_TYPE_GSM;
diff --git a/telephony/java/com/android/internal/telephony/RIL.java b/telephony/java/com/android/internal/telephony/RIL.java
index 1d194d0..1d47405 100644
--- a/telephony/java/com/android/internal/telephony/RIL.java
+++ b/telephony/java/com/android/internal/telephony/RIL.java
@@ -207,9 +207,8 @@
  */
 public final class RIL extends BaseCommands implements CommandsInterface {
     static final String LOG_TAG = "RILJ";
-    private static final boolean DBG = false;
-    static final boolean RILJ_LOGD = Config.LOGD;
-    static final boolean RILJ_LOGV = DBG ? Config.LOGD : Config.LOGV;
+    static final boolean RILJ_LOGD = true;
+    static final boolean RILJ_LOGV = false; // STOP SHIP if true
 
     /**
      * Wake lock timeout should be longer than the longest timeout in
@@ -639,7 +638,8 @@
                 mPhoneType = RILConstants.CDMA_PHONE;
                 break;
             case RILConstants.NETWORK_MODE_LTE_ONLY:
-                if (SystemProperties.getBoolean("ro.mot.lte_on_cdma", false)) {
+                if (SystemProperties.getBoolean(TelephonyProperties.PROPERTY_NETWORK_LTE_ON_CDMA,
+                        false)) {
                     mPhoneType = RILConstants.CDMA_PHONE;
                 } else {
                     mPhoneType = RILConstants.GSM_PHONE;
@@ -1396,33 +1396,29 @@
         if(mInitialRadioStateChange) {
             synchronized (mStateMonitor) {
                 if (!mState.isOn()) {
-                    RILRequest rrPnt = RILRequest.obtain(
-                                   RIL_REQUEST_SET_PREFERRED_NETWORK_TYPE, null);
-
-                    rrPnt.mp.writeInt(1);
-                    rrPnt.mp.writeInt(mNetworkMode);
-                    if (RILJ_LOGD) riljLog(rrPnt.serialString() + "> "
-                        + requestToString(rrPnt.mRequest) + " : " + mNetworkMode);
-
-                    send(rrPnt);
+                    setPreferredNetworkType(mNetworkMode, null);
 
                     RILRequest rrCs = RILRequest.obtain(
                                    RIL_REQUEST_CDMA_SET_SUBSCRIPTION_SOURCE, null);
                     rrCs.mp.writeInt(1);
                     rrCs.mp.writeInt(mCdmaSubscription);
-                    if (RILJ_LOGD) riljLog(rrCs.serialString() + "> "
-                    + requestToString(rrCs.mRequest) + " : " + mCdmaSubscription);
+                    if (RILJ_LOGD) {
+                        riljLog(rrCs.serialString() + "> "
+                                + requestToString(rrCs.mRequest) + " : " + mCdmaSubscription);
+                    }
                     send(rrCs);
                 }
             }
         }
-        RILRequest rr
-                = RILRequest.obtain(RIL_REQUEST_RADIO_POWER, result);
+        RILRequest rr = RILRequest.obtain(RIL_REQUEST_RADIO_POWER, result);
 
         rr.mp.writeInt(1);
         rr.mp.writeInt(on ? 1 : 0);
 
-        if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest));
+        if (RILJ_LOGD) {
+            riljLog(rr.serialString() + "> " + requestToString(rr.mRequest)
+                    + (on ? " on" : " off"));
+        }
 
         send(rr);
     }
@@ -2071,17 +2067,10 @@
                  */
                 if (RILJ_LOGD) Log.d(LOG_TAG, "Radio ON @ init; reset to OFF");
                 setRadioPower(false, null);
-                // MultimodeRIL needs to know the preferred network at power up.
-                RILRequest rrPnt = RILRequest.obtain(
-                                   RIL_REQUEST_SET_PREFERRED_NETWORK_TYPE, null);
-                rrPnt.mp.writeInt(1);
-                rrPnt.mp.writeInt(mNetworkMode);
-                if (RILJ_LOGD) riljLog(rrPnt.serialString() + "> "
-                        + requestToString(rrPnt.mRequest) + " : " + mNetworkMode);
-                send(rrPnt);
             } else {
-                if (DBG) Log.d(LOG_TAG, "Radio OFF @ init");
+                if (RILJ_LOGD) Log.d(LOG_TAG, "Radio OFF @ init");
                 setRadioState(newState);
+                setPreferredNetworkType(mNetworkMode, null);
             }
             mInitialRadioStateChange = false;
         } else {
@@ -2376,7 +2365,10 @@
             case RIL_REQUEST_GET_IMSI:
             case RIL_REQUEST_GET_IMEI:
             case RIL_REQUEST_GET_IMEISV:
-                return "";
+                if (!RILJ_LOGV) {
+                    // If not versbose logging just return and don't display IMSI and IMEI, IMEISV
+                    return "";
+                }
         }
 
         StringBuilder sb;
diff --git a/telephony/java/com/android/internal/telephony/ServiceStateTracker.java b/telephony/java/com/android/internal/telephony/ServiceStateTracker.java
index 912f75e..1b5bad9 100644
--- a/telephony/java/com/android/internal/telephony/ServiceStateTracker.java
+++ b/telephony/java/com/android/internal/telephony/ServiceStateTracker.java
@@ -29,25 +29,6 @@
  */
 public abstract class ServiceStateTracker extends Handler {
 
-    /**
-     *  Access technology currently in use.
-     */
-    protected static final int DATA_ACCESS_UNKNOWN = 0;
-    protected static final int DATA_ACCESS_GPRS = 1;
-    protected static final int DATA_ACCESS_EDGE = 2;
-    protected static final int DATA_ACCESS_UMTS = 3;
-    protected static final int DATA_ACCESS_CDMA_IS95A = 4;
-    protected static final int DATA_ACCESS_CDMA_IS95B = 5;
-    protected static final int DATA_ACCESS_CDMA_1xRTT = 6;
-    protected static final int DATA_ACCESS_CDMA_EvDo_0 = 7;
-    protected static final int DATA_ACCESS_CDMA_EvDo_A = 8;
-    protected static final int DATA_ACCESS_HSDPA = 9;
-    protected static final int DATA_ACCESS_HSUPA = 10;
-    protected static final int DATA_ACCESS_HSPA = 11;
-    protected static final int DATA_ACCESS_CDMA_EvDo_B = 12;
-    protected static final int DATA_ACCESS_LTE = 13;
-    protected static final int DATA_ACCESS_EHRPD = 14;
-
     protected CommandsInterface cm;
 
     public ServiceState ss;
@@ -320,7 +301,7 @@
         Registrant r = new Registrant(h, what, obj);
         mDetachedRegistrants.add(r);
 
-        if (getCurrentDataConnectionState() == ServiceState.STATE_OUT_OF_SERVICE) {
+        if (getCurrentDataConnectionState() != ServiceState.STATE_IN_SERVICE) {
             r.notifyRegistrant();
         }
     }
diff --git a/telephony/java/com/android/internal/telephony/TelephonyProperties.java b/telephony/java/com/android/internal/telephony/TelephonyProperties.java
index e6189be..c4fab66 100644
--- a/telephony/java/com/android/internal/telephony/TelephonyProperties.java
+++ b/telephony/java/com/android/internal/telephony/TelephonyProperties.java
@@ -72,6 +72,11 @@
      */
     static final String PROPERTY_OPERATOR_ISO_COUNTRY = "gsm.operator.iso-country";
 
+    /** 'true' if device supports both LTE and CDMA mode of operation.
+     *  Availability: Set only on devices supporting LTE and CDMA.
+     */
+    static final String PROPERTY_NETWORK_LTE_ON_CDMA = "ro.telephony.lte_on_cdma";
+
     static final String CURRENT_ACTIVE_PHONE = "gsm.current.phone-type";
 
     //****** SIM Card
diff --git a/telephony/java/com/android/internal/telephony/cat/CatService.java b/telephony/java/com/android/internal/telephony/cat/CatService.java
index 1e23e34..36059ad 100644
--- a/telephony/java/com/android/internal/telephony/cat/CatService.java
+++ b/telephony/java/com/android/internal/telephony/cat/CatService.java
@@ -118,6 +118,8 @@
     private static IccRecords mIccRecords;
 
     // Service members.
+    // Protects singleton instance lazy initialization.
+    private static final Object sInstanceLock = new Object();
     private static CatService sInstance;
     private CommandsInterface mCmdIf;
     private Context mContext;
@@ -515,26 +517,28 @@
      */
     public static CatService getInstance(CommandsInterface ci, IccRecords ir,
             Context context, IccFileHandler fh, IccCard ic) {
-        if (sInstance == null) {
-            if (ci == null || ir == null || context == null || fh == null
-                    || ic == null) {
-                return null;
-            }
-            HandlerThread thread = new HandlerThread("Cat Telephony service");
-            thread.start();
-            sInstance = new CatService(ci, ir, context, fh, ic);
-            CatLog.d(sInstance, "NEW sInstance");
-        } else if ((ir != null) && (mIccRecords != ir)) {
-            CatLog.d(sInstance, "Reinitialize the Service with SIMRecords");
-            mIccRecords = ir;
+        synchronized (sInstanceLock) {
+            if (sInstance == null) {
+                if (ci == null || ir == null || context == null || fh == null
+                        || ic == null) {
+                    return null;
+                }
+                HandlerThread thread = new HandlerThread("Cat Telephony service");
+                thread.start();
+                sInstance = new CatService(ci, ir, context, fh, ic);
+                CatLog.d(sInstance, "NEW sInstance");
+            } else if ((ir != null) && (mIccRecords != ir)) {
+                CatLog.d(sInstance, "Reinitialize the Service with SIMRecords");
+                mIccRecords = ir;
 
-            // re-Register for SIM ready event.
-            mIccRecords.registerForRecordsLoaded(sInstance, MSG_ID_ICC_RECORDS_LOADED, null);
-            CatLog.d(sInstance, "sr changed reinitialize and return current sInstance");
-        } else {
-            CatLog.d(sInstance, "Return current sInstance");
+                // re-Register for SIM ready event.
+                mIccRecords.registerForRecordsLoaded(sInstance, MSG_ID_ICC_RECORDS_LOADED, null);
+                CatLog.d(sInstance, "sr changed reinitialize and return current sInstance");
+            } else {
+                CatLog.d(sInstance, "Return current sInstance");
+            }
+            return sInstance;
         }
-        return sInstance;
     }
 
     /**
diff --git a/telephony/java/com/android/internal/telephony/cdma/CDMALTEPhone.java b/telephony/java/com/android/internal/telephony/cdma/CDMALTEPhone.java
index 300670f..89d7174 100644
--- a/telephony/java/com/android/internal/telephony/cdma/CDMALTEPhone.java
+++ b/telephony/java/com/android/internal/telephony/cdma/CDMALTEPhone.java
@@ -54,13 +54,16 @@
     public CDMALTEPhone(Context context, CommandsInterface ci, PhoneNotifier notifier,
             boolean unitTestMode) {
         super(context, ci, notifier, false);
-        mSST = new CdmaLteServiceStateTracker(this);
-        init(context, notifier);
 
         mSIMRecords = new SIMRecords(this);
         mSimCard = new SimCard(this, LOG_TAG, DBG);
     }
 
+    @Override
+    protected void initSST() {
+        mSST = new CdmaLteServiceStateTracker(this);
+    }
+
     public void dispose() {
         synchronized (PhoneProxy.lockForRadioTechnologyChange) {
             super.dispose();
diff --git a/telephony/java/com/android/internal/telephony/cdma/CDMAPhone.java b/telephony/java/com/android/internal/telephony/cdma/CDMAPhone.java
index 3772dac..dd5091c 100755
--- a/telephony/java/com/android/internal/telephony/cdma/CDMAPhone.java
+++ b/telephony/java/com/android/internal/telephony/cdma/CDMAPhone.java
@@ -142,17 +142,21 @@
     // Constructors
     public CDMAPhone(Context context, CommandsInterface ci, PhoneNotifier notifier) {
         super(notifier, context, ci, false);
-        mSST = new CdmaServiceStateTracker (this);
+        initSST();
         init(context, notifier);
     }
 
     public CDMAPhone(Context context, CommandsInterface ci, PhoneNotifier notifier,
             boolean unitTestMode) {
         super(notifier, context, ci, unitTestMode);
-        mSST = new CdmaServiceStateTracker (this);
+        initSST();
         init(context, notifier);
     }
 
+    protected void initSST() {
+        mSST = new CdmaServiceStateTracker(this);
+    }
+
     protected void init(Context context, PhoneNotifier notifier) {
         mCM.setPhoneType(Phone.PHONE_TYPE_CDMA);
         mCT = new CdmaCallTracker(this);
diff --git a/telephony/java/com/android/internal/telephony/cdma/CdmaDataConnection.java b/telephony/java/com/android/internal/telephony/cdma/CdmaDataConnection.java
index 1a0dbc2..cccc053 100644
--- a/telephony/java/com/android/internal/telephony/cdma/CdmaDataConnection.java
+++ b/telephony/java/com/android/internal/telephony/cdma/CdmaDataConnection.java
@@ -33,8 +33,8 @@
     private static final String LOG_TAG = "CDMA";
 
     // ***** Constructor
-    private CdmaDataConnection(CDMAPhone phone, String name, RetryManager rm) {
-        super(phone, name, rm);
+    private CdmaDataConnection(CDMAPhone phone, String name, int id, RetryManager rm) {
+        super(phone, name, id, rm);
     }
 
     /**
@@ -49,11 +49,10 @@
         synchronized (mCountLock) {
             mCount += 1;
         }
-        CdmaDataConnection cdmaDc = new CdmaDataConnection(phone,
-                "CdmaDataConnection-" + mCount, rm);
+        CdmaDataConnection cdmaDc = new CdmaDataConnection(phone, "CdmaDataConnection-" + mCount,
+                id, rm);
         cdmaDc.start();
         if (DBG) cdmaDc.log("Made " + cdmaDc.getName());
-        cdmaDc.mId = id;
         return cdmaDc;
     }
 
@@ -68,6 +67,7 @@
     protected void onConnect(ConnectionParams cp) {
         if (DBG) log("CdmaDataConnection Connecting...");
 
+        mApn = cp.apn;
         createTime = -1;
         lastFailTime = -1;
         lastFailCause = FailCause.NONE;
diff --git a/telephony/java/com/android/internal/telephony/cdma/CdmaDataConnectionTracker.java b/telephony/java/com/android/internal/telephony/cdma/CdmaDataConnectionTracker.java
index 0751d81..b244945 100644
--- a/telephony/java/com/android/internal/telephony/cdma/CdmaDataConnectionTracker.java
+++ b/telephony/java/com/android/internal/telephony/cdma/CdmaDataConnectionTracker.java
@@ -311,7 +311,7 @@
             apnId = mDefaultApnId;
         }
         mActiveApn = new ApnSetting(apnId, "", "", "", "", "", "", "", "", "",
-                                    "", 0, types, "IP", "IP", true, 0, 0);
+                                    "", 0, types, "IP", "IP");
         if (DBG) log("setupData: mActiveApn=" + mActiveApn);
 
         Message msg = obtainMessage();
@@ -328,7 +328,7 @@
         setState(State.CONNECTED);
         notifyDataConnection(reason);
         startNetStatPoll();
-        mRetryMgr.resetRetryCount();
+        mDataConnections.get(0).resetRetryCount();
     }
 
     private void resetPollStats() {
@@ -478,7 +478,7 @@
              * at the last time until the state is changed.
              * TODO: Make this configurable?
              */
-            int nextReconnectDelay = mRetryMgr.getRetryTimer();
+            int nextReconnectDelay = mDataConnections.get(0).getRetryTimer();
             log("Data Connection activate failed. Scheduling next attempt for "
                     + (nextReconnectDelay / 1000) + "s");
 
@@ -492,7 +492,7 @@
                     SystemClock.elapsedRealtime() + nextReconnectDelay,
                     mReconnectIntent);
 
-            mRetryMgr.increaseRetryCount();
+            mDataConnections.get(0).increaseRetryCount();
 
             if (!shouldPostNotification(lastFailCauseCode)) {
                 log("NOT Posting Data Connection Unavailable notification "
@@ -508,7 +508,7 @@
         notifyDataAvailability(null);
     }
 
-    private void gotoIdleAndNotifyDataConnection(String reason) {
+    protected void gotoIdleAndNotifyDataConnection(String reason) {
         if (DBG) log("gotoIdleAndNotifyDataConnection: reason=" + reason);
         setState(State.IDLE);
         notifyDataConnection(reason);
@@ -593,7 +593,7 @@
      */
     @Override
     protected void onRadioOffOrNotAvailable() {
-        mRetryMgr.resetRetryCount();
+        mDataConnections.get(0).resetRetryCount();
 
         if (mPhone.getSimulatedRadioControl() != null) {
             // Assume data is connected on the simulator
@@ -668,20 +668,6 @@
     }
 
     /**
-     * Called when EVENT_RESET_DONE is received so goto
-     * IDLE state and send notifications to those interested.
-     */
-    @Override
-    protected void onResetDone(AsyncResult ar) {
-      if (DBG) log("EVENT_RESET_DONE");
-      String reason = null;
-      if (ar.userObj instanceof String) {
-          reason = (String) ar.userObj;
-      }
-      gotoIdleAndNotifyDataConnection(reason);
-    }
-
-    /**
      * @override com.android.internal.telephony.DataConnectionTracker
      */
     @Override
@@ -708,7 +694,7 @@
             }
             notifyDataAvailability(Phone.REASON_VOICE_CALL_ENDED);
         } else {
-            mRetryMgr.resetRetryCount();
+            mDataConnections.get(0).resetRetryCount();
             // in case data setup was attempted when we were on a voice call
             trySetupData(Phone.REASON_VOICE_CALL_ENDED);
         }
@@ -729,20 +715,19 @@
     private void createAllDataConnectionList() {
         CdmaDataConnection dataConn;
 
-        /** TODO: Use one retry manager for all connections for now */
-        RetryManager rm = mRetryMgr;
-        if (!rm.configure(SystemProperties.get("ro.cdma.data_retry_config"))) {
-            if (!rm.configure(DEFAULT_DATA_RETRY_CONFIG)) {
-                // Should never happen, log an error and default to a simple linear sequence.
-                log("Could not configure using DEFAULT_DATA_RETRY_CONFIG="
-                        + DEFAULT_DATA_RETRY_CONFIG);
-                rm.configure(20, 2000, 1000);
-            }
-        }
-
+        String retryConfig = SystemProperties.get("ro.cdma.data_retry_config");
         for (int i = 0; i < DATA_CONNECTION_POOL_SIZE; i++) {
-            int id = mUniqueIdGenerator.getAndIncrement();
+            RetryManager rm = new RetryManager();
+            if (!rm.configure(retryConfig)) {
+                if (!rm.configure(DEFAULT_DATA_RETRY_CONFIG)) {
+                    // Should never happen, log an error and default to a simple linear sequence.
+                    log("Could not configure using DEFAULT_DATA_RETRY_CONFIG="
+                            + DEFAULT_DATA_RETRY_CONFIG);
+                    rm.configure(20, 2000, 1000);
+                }
+            }
 
+            int id = mUniqueIdGenerator.getAndIncrement();
             dataConn = CdmaDataConnection.makeDataConnection(mCdmaPhone, id, rm);
             mDataConnections.put(id, dataConn);
         }
@@ -761,7 +746,7 @@
         } else {
             if (mState == State.FAILED) {
                 cleanUpConnection(false, Phone.REASON_CDMA_DATA_DETACHED);
-                mRetryMgr.resetRetryCount();
+                mDataConnections.get(0).resetRetryCount();
 
                 CdmaCellLocation loc = (CdmaCellLocation)(mPhone.getCellLocation());
                 EventLog.writeEvent(EventLogTags.CDMA_DATA_SETUP_FAILED,
@@ -779,7 +764,7 @@
                 switch (otaPrivision[0]) {
                 case Phone.CDMA_OTA_PROVISION_STATUS_COMMITTED:
                 case Phone.CDMA_OTA_PROVISION_STATUS_OTAPA_STOPPED:
-                    mRetryMgr.resetRetryCount();
+                    mDataConnections.get(0).resetRetryCount();
                     break;
                 default:
                     break;
diff --git a/telephony/java/com/android/internal/telephony/cdma/CdmaLteServiceStateTracker.java b/telephony/java/com/android/internal/telephony/cdma/CdmaLteServiceStateTracker.java
index 2f4bd5b..40b5610 100644
--- a/telephony/java/com/android/internal/telephony/cdma/CdmaLteServiceStateTracker.java
+++ b/telephony/java/com/android/internal/telephony/cdma/CdmaLteServiceStateTracker.java
@@ -198,26 +198,26 @@
         String ret = "unknown";
 
         switch (type) {
-            case DATA_ACCESS_CDMA_IS95A:
-            case DATA_ACCESS_CDMA_IS95B:
+            case ServiceState.RADIO_TECHNOLOGY_IS95A:
+            case ServiceState.RADIO_TECHNOLOGY_IS95B:
                 ret = "CDMA";
                 break;
-            case DATA_ACCESS_CDMA_1xRTT:
+            case ServiceState.RADIO_TECHNOLOGY_1xRTT:
                 ret = "CDMA - 1xRTT";
                 break;
-            case DATA_ACCESS_CDMA_EvDo_0:
+            case ServiceState.RADIO_TECHNOLOGY_EVDO_0:
                 ret = "CDMA - EvDo rev. 0";
                 break;
-            case DATA_ACCESS_CDMA_EvDo_A:
+            case ServiceState.RADIO_TECHNOLOGY_EVDO_A:
                 ret = "CDMA - EvDo rev. A";
                 break;
-            case DATA_ACCESS_CDMA_EvDo_B:
+            case ServiceState.RADIO_TECHNOLOGY_EVDO_B:
                 ret = "CDMA - EvDo rev. B";
                 break;
-            case DATA_ACCESS_LTE:
+            case ServiceState.RADIO_TECHNOLOGY_LTE:
                 ret = "LTE";
                 break;
-            case DATA_ACCESS_EHRPD:
+            case ServiceState.RADIO_TECHNOLOGY_EHRPD:
                 ret = "CDMA - eHRPD";
             default:
                 if (DBG) {
@@ -261,16 +261,20 @@
         boolean hasLocationChanged = !newCellLoc.equals(cellLoc);
 
         boolean has4gHandoff =
-            ((networkType == DATA_ACCESS_LTE) && (newNetworkType == DATA_ACCESS_EHRPD))
-                || ((networkType == DATA_ACCESS_EHRPD) && (newNetworkType == DATA_ACCESS_LTE));
+                ((networkType == ServiceState.RADIO_TECHNOLOGY_LTE) &&
+                 (newNetworkType == ServiceState.RADIO_TECHNOLOGY_EHRPD)) ||
+                ((networkType == ServiceState.RADIO_TECHNOLOGY_EHRPD) &&
+                 (newNetworkType == ServiceState.RADIO_TECHNOLOGY_LTE));
 
         boolean hasMultiApnSupport =
-            (((newNetworkType == DATA_ACCESS_LTE) || (newNetworkType == DATA_ACCESS_EHRPD)) 
-                    && ((networkType != DATA_ACCESS_LTE) && (networkType != DATA_ACCESS_EHRPD)));
+                (((newNetworkType == ServiceState.RADIO_TECHNOLOGY_LTE) ||
+                  (newNetworkType == ServiceState.RADIO_TECHNOLOGY_EHRPD)) &&
+                 ((networkType != ServiceState.RADIO_TECHNOLOGY_LTE) &&
+                  (networkType != ServiceState.RADIO_TECHNOLOGY_EHRPD)));
 
         boolean hasLostMultiApnSupport =
-            ((newNetworkType >= DATA_ACCESS_CDMA_IS95A)
-                    && (newNetworkType <= DATA_ACCESS_CDMA_EvDo_A));
+            ((newNetworkType >= ServiceState.RADIO_TECHNOLOGY_IS95A) &&
+             (newNetworkType <= ServiceState.RADIO_TECHNOLOGY_EVDO_A));
 
         log("hasRegistered = " + hasRegistered + " hasCdmaDataConnectionAttached = "
                 + hasCdmaDataConnectionAttached + " hasCdmaDataConnectionChanged = "
@@ -387,12 +391,10 @@
         }
 
         if (hasCdmaDataConnectionAttached) {
-            cdmaDataConnectionAttachedRegistrants.notifyRegistrants();
             mAttachedRegistrants.notifyRegistrants();
         }
 
         if (hasCdmaDataConnectionDetached) {
-            cdmaDataConnectionDetachedRegistrants.notifyRegistrants();
             mDetachedRegistrants.notifyRegistrants();
         }
 
@@ -459,7 +461,7 @@
         // Note: it needs to be confirmed which CDMA network types
         // can support voice and data calls concurrently.
         // For the time-being, the return value will be false.
-        // return (networkType >= DATA_ACCESS_LTE);
+        // return (networkType >= ServiceState.RADIO_TECHNOLOGY_LTE);
         return false;
     }
 
diff --git a/telephony/java/com/android/internal/telephony/cdma/CdmaServiceStateTracker.java b/telephony/java/com/android/internal/telephony/cdma/CdmaServiceStateTracker.java
index f2b84ee..4ab3834 100755
--- a/telephony/java/com/android/internal/telephony/cdma/CdmaServiceStateTracker.java
+++ b/telephony/java/com/android/internal/telephony/cdma/CdmaServiceStateTracker.java
@@ -16,8 +16,6 @@
 
 package com.android.internal.telephony.cdma;
 
-import static com.android.internal.telephony.TelephonyProperties.PROPERTY_ICC_OPERATOR_NUMERIC;
-
 import com.android.internal.telephony.CommandException;
 import com.android.internal.telephony.CommandsInterface;
 import com.android.internal.telephony.DataConnectionTracker;
@@ -86,7 +84,7 @@
             NITZ_UPDATE_DIFF_DEFAULT);
 
     /**
-     *  Values correspond to ServiceStateTracker.DATA_ACCESS_ definitions.
+     *  Values correspond to ServiceState.RADIO_TECHNOLOGY_ definitions.
      */
     protected int networkType = 0;
     protected int newNetworkType = 0;
@@ -102,8 +100,6 @@
     protected int cdmaDataConnectionState = ServiceState.STATE_OUT_OF_SERVICE;
     protected int newCdmaDataConnectionState = ServiceState.STATE_OUT_OF_SERVICE;
     protected int mRegistrationState = -1;
-    protected RegistrantList cdmaDataConnectionAttachedRegistrants = new RegistrantList();
-    protected RegistrantList cdmaDataConnectionDetachedRegistrants = new RegistrantList();
     protected RegistrantList cdmaForSubscriptionInfoReadyRegistrants = new RegistrantList();
 
     /**
@@ -767,8 +763,7 @@
                 return;
             }
 
-            if (err != CommandException.Error.OP_NOT_ALLOWED_BEFORE_REG_NW &&
-                    err != CommandException.Error.OP_NOT_ALLOWED_BEFORE_REG_NW) {
+            if (err != CommandException.Error.OP_NOT_ALLOWED_BEFORE_REG_NW) {
                 Log.e(LOG_TAG,
                         "RIL implementation has returned an error where it must succeed",
                         ar.exception);
@@ -916,20 +911,20 @@
         String ret = "unknown";
 
         switch (type) {
-        case DATA_ACCESS_CDMA_IS95A:
-        case DATA_ACCESS_CDMA_IS95B:
+        case ServiceState.RADIO_TECHNOLOGY_IS95A:
+        case ServiceState.RADIO_TECHNOLOGY_IS95B:
             ret = "CDMA";
             break;
-        case DATA_ACCESS_CDMA_1xRTT:
+        case ServiceState.RADIO_TECHNOLOGY_1xRTT:
             ret = "CDMA - 1xRTT";
             break;
-        case DATA_ACCESS_CDMA_EvDo_0:
+        case ServiceState.RADIO_TECHNOLOGY_EVDO_0:
             ret = "CDMA - EvDo rev. 0";
             break;
-        case DATA_ACCESS_CDMA_EvDo_A:
+        case ServiceState.RADIO_TECHNOLOGY_EVDO_A:
             ret = "CDMA - EvDo rev. A";
             break;
-        case DATA_ACCESS_CDMA_EvDo_B:
+        case ServiceState.RADIO_TECHNOLOGY_EVDO_B:
             ret = "CDMA - EvDo rev. B";
             break;
         default:
@@ -1098,11 +1093,11 @@
         }
 
         if (hasCdmaDataConnectionAttached) {
-            cdmaDataConnectionAttachedRegistrants.notifyRegistrants();
+            mAttachedRegistrants.notifyRegistrants();
         }
 
         if (hasCdmaDataConnectionDetached) {
-            cdmaDataConnectionDetachedRegistrants.notifyRegistrants();
+            mDetachedRegistrants.notifyRegistrants();
         }
 
         if (hasCdmaDataConnectionChanged || hasNetworkTypeChanged) {
diff --git a/telephony/java/com/android/internal/telephony/cdma/sms/BearerData.java b/telephony/java/com/android/internal/telephony/cdma/sms/BearerData.java
old mode 100644
new mode 100755
index cf06dab..7a45e15
--- a/telephony/java/com/android/internal/telephony/cdma/sms/BearerData.java
+++ b/telephony/java/com/android/internal/telephony/cdma/sms/BearerData.java
@@ -34,6 +34,9 @@
 import com.android.internal.util.BitwiseInputStream;
 import com.android.internal.util.BitwiseOutputStream;
 
+import android.content.res.Resources;
+
+
 
 /**
  * An object to encode and decode CDMA SMS bearer data.
@@ -582,7 +585,6 @@
                     uData.payload = new byte[0];
                     uData.numFields = 0;
                 } else {
-                    uData.payload = uData.payload;
                     uData.numFields = uData.payload.length;
                 }
             } else {
@@ -910,6 +912,16 @@
         return true;
     }
 
+    private static String decodeUtf8(byte[] data, int offset, int numFields)
+        throws CodingException
+    {
+        try {
+            return new String(data, offset, numFields, "UTF-8");
+        } catch (java.io.UnsupportedEncodingException ex) {
+            throw new CodingException("UTF-8 decode failed: " + ex);
+        }
+    }
+
     private static String decodeUtf16(byte[] data, int offset, int numFields)
         throws CodingException
     {
@@ -994,9 +1006,15 @@
         }
         switch (userData.msgEncoding) {
         case UserData.ENCODING_OCTET:
+            /*
+            *  Octet decoding depends on the carrier service.
+            */
+            boolean decodingtypeUTF8 = Resources.getSystem()
+                    .getBoolean(com.android.internal.R.bool.config_sms_utf8_support);
+
             // Strip off any padding bytes, meaning any differences between the length of the
-            // array and the target length specified by numFields.  This is to avoid any confusion
-            // by code elsewhere that only considers the payload array length.
+            // array and the target length specified by numFields.  This is to avoid any
+            // confusion by code elsewhere that only considers the payload array length.
             byte[] payload = new byte[userData.numFields];
             int copyLen = userData.numFields < userData.payload.length
                     ? userData.numFields : userData.payload.length;
@@ -1004,9 +1022,13 @@
             System.arraycopy(userData.payload, 0, payload, 0, copyLen);
             userData.payload = payload;
 
-            // There are many devices in the market that send 8bit text sms (latin encoded) as
-            // octet encoded.
-            userData.payloadStr = decodeLatin(userData.payload, offset, userData.numFields);
+            if (!decodingtypeUTF8) {
+                // There are many devices in the market that send 8bit text sms (latin encoded) as
+                // octet encoded.
+                userData.payloadStr = decodeLatin(userData.payload, offset, userData.numFields);
+            } else {
+                userData.payloadStr = decodeUtf8(userData.payload, offset, userData.numFields);
+            }
             break;
         case UserData.ENCODING_IA5:
         case UserData.ENCODING_7BIT_ASCII:
diff --git a/telephony/java/com/android/internal/telephony/gsm/GsmDataConnection.java b/telephony/java/com/android/internal/telephony/gsm/GsmDataConnection.java
index 9f7673c..b0b2ac5 100644
--- a/telephony/java/com/android/internal/telephony/gsm/GsmDataConnection.java
+++ b/telephony/java/com/android/internal/telephony/gsm/GsmDataConnection.java
@@ -36,13 +36,11 @@
     private static final String LOG_TAG = "GSM";
 
     //***** Instance Variables
-    private ApnSetting apn;
-
     protected int mProfileId = RILConstants.DATA_PROFILE_DEFAULT;
     protected String mActiveApnType = Phone.APN_TYPE_DEFAULT;
     //***** Constructor
-    private GsmDataConnection(PhoneBase phone, String name, RetryManager rm) {
-        super(phone, name, rm);
+    private GsmDataConnection(PhoneBase phone, String name, int id, RetryManager rm) {
+        super(phone, name, id, rm);
     }
 
     /**
@@ -57,11 +55,10 @@
         synchronized (mCountLock) {
             mCount += 1;
         }
-        GsmDataConnection gsmDc = new GsmDataConnection(phone, "GsmDataConnection-" + mCount, rm);
+        GsmDataConnection gsmDc = new GsmDataConnection(phone, "GsmDataConnection-" + mCount,
+                id, rm);
         gsmDc.start();
         if (DBG) gsmDc.log("Made " + gsmDc.getName());
-        gsmDc.mId = id;
-        gsmDc.mRetryMgr = rm;
         return gsmDc;
     }
 
@@ -75,13 +72,13 @@
     @Override
     protected
     void onConnect(ConnectionParams cp) {
-        apn = cp.apn;
+        mApn = cp.apn;
 
-        if (DBG) log("Connecting to carrier: '" + apn.carrier
-                + "' APN: '" + apn.apn
-                + "' proxy: '" + apn.proxy + "' port: '" + apn.port);
+        if (DBG) log("Connecting to carrier: '" + mApn.carrier
+                + "' APN: '" + mApn.apn
+                + "' proxy: '" + mApn.proxy + "' port: '" + mApn.port);
 
-        setHttpProxy (apn.proxy, apn.port);
+        setHttpProxy (mApn.proxy, mApn.port);
 
         createTime = -1;
         lastFailTime = -1;
@@ -91,23 +88,23 @@
         Message msg = obtainMessage(EVENT_SETUP_DATA_CONNECTION_DONE, cp);
         msg.obj = cp;
 
-        int authType = apn.authType;
+        int authType = mApn.authType;
         if (authType == -1) {
-            authType = (apn.user != null) ? RILConstants.SETUP_DATA_AUTH_PAP_CHAP :
+            authType = (mApn.user != null) ? RILConstants.SETUP_DATA_AUTH_PAP_CHAP :
                 RILConstants.SETUP_DATA_AUTH_NONE;
         }
 
         String protocol;
         if (phone.getServiceState().getRoaming()) {
-            protocol = apn.roamingProtocol;
+            protocol = mApn.roamingProtocol;
         } else {
-            protocol = apn.protocol;
+            protocol = mApn.protocol;
         }
 
         phone.mCM.setupDataCall(
                 Integer.toString(RILConstants.SETUP_DATA_TECH_GSM),
                 Integer.toString(mProfileId),
-                apn.apn, apn.user, apn.password,
+                mApn.apn, mApn.user, mApn.password,
                 Integer.toString(authType),
                 protocol, msg);
     }
@@ -130,14 +127,8 @@
     }
 
     @Override
-    protected void clearSettings() {
-        super.clearSettings();
-        apn = null;
-    }
-
-    @Override
     public String toString() {
-        return "State=" + getCurrentState().getName() + " Apn=" + apn +
+        return "State=" + getCurrentState().getName() + " Apn=" + mApn +
                " create=" + createTime + " lastFail=" + lastFailTime +
                " lastFailCause=" + lastFailCause;
     }
@@ -151,11 +142,12 @@
             // Do not apply the race condition workaround for MMS APN
             // if Proxy is an IP-address.
             // Otherwise, the default APN will not be restored anymore.
-            if (!apn.types[0].equals(Phone.APN_TYPE_MMS)
-                || !isIpAddress(apn.mmsProxy)) {
+            if (!mApn.types[0].equals(Phone.APN_TYPE_MMS)
+                || !isIpAddress(mApn.mmsProxy)) {
                 log(String.format(
                         "isDnsOk: return false apn.types[0]=%s APN_TYPE_MMS=%s isIpAddress(%s)=%s",
-                        apn.types[0], Phone.APN_TYPE_MMS, apn.mmsProxy, isIpAddress(apn.mmsProxy)));
+                        mApn.types[0], Phone.APN_TYPE_MMS, mApn.mmsProxy,
+                        isIpAddress(mApn.mmsProxy)));
                 return false;
             }
         }
@@ -167,15 +159,11 @@
         Log.d(LOG_TAG, "[" + getName() + "] " + s);
     }
 
-    public ApnSetting getApn() {
-        return this.apn;
-    }
-
     private void setHttpProxy(String httpProxy, String httpPort) {
 
         if (DBG) log("set http proxy for"
                 + "' APN: '" + mActiveApnType
-                + "' proxy: '" + apn.proxy + "' port: '" + apn.port);
+                + "' proxy: '" + mApn.proxy + "' port: '" + mApn.port);
         if(TextUtils.equals(mActiveApnType, Phone.APN_TYPE_DEFAULT)) {
             if (httpProxy == null || httpProxy.length() == 0) {
                 phone.setSystemProperty("net.gprs.http-proxy", null);
@@ -206,6 +194,6 @@
     private boolean isIpAddress(String address) {
         if (address == null) return false;
 
-        return Patterns.IP_ADDRESS.matcher(apn.mmsProxy).matches();
+        return Patterns.IP_ADDRESS.matcher(address).matches();
     }
 }
diff --git a/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java b/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java
index 8c10c56..d602c38 100644
--- a/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java
+++ b/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java
@@ -546,7 +546,7 @@
             ApnContext defaultApnContext = mApnContexts.get(Phone.APN_TYPE_DEFAULT);
             if (defaultApnContext.getState() == State.FAILED) {
                 cleanUpConnection(false, defaultApnContext);
-                mRetryMgr.resetRetryCount();
+                defaultApnContext.getDataConnection().resetRetryCount();
             }
             trySetupData(Phone.REASON_GPRS_ATTACHED, Phone.APN_TYPE_DEFAULT);
         }
@@ -757,20 +757,19 @@
             return;
         }
 
-        GsmDataConnection pdp = apnContext.getDataConnection();
-        if (tearDown && pdp!=null) {
+        GsmDataConnection conn = apnContext.getDataConnection();
+        if (conn != null) {
             apnContext.setState(State.DISCONNECTING);
-            Message msg = obtainMessage(EVENT_DISCONNECT_DONE, apnContext);
-            pdp.disconnect(msg);
-            return;
-        } else if (pdp != null) {
-            pdp.clearSettings();
+            if (tearDown ) {
+                Message msg = obtainMessage(EVENT_DISCONNECT_DONE, apnContext);
+                conn.disconnect(msg);
+            } else {
+                conn.resetSynchronously();
+                apnContext.setState(State.IDLE);
+                mPhone.notifyDataConnection(apnContext.getReason(), apnContext.getApnType());
+            }
         }
 
-        if (!tearDown) {
-            apnContext.setState(State.IDLE);
-            mPhone.notifyDataConnection(apnContext.getReason(), apnContext.getApnType());
-        }
         if (apnContext.getPendingAction() == ApnContext.PENDING_ACTION_APN_DISABLE) {
            mApnContexts.remove(apnContext.getApnType());
         }
@@ -799,8 +798,6 @@
             do {
                 String[] types = parseTypes(
                         cursor.getString(cursor.getColumnIndexOrThrow(Telephony.Carriers.TYPE)));
-                int enabled =
-                    cursor.getInt(cursor.getColumnIndexOrThrow(Telephony.Carriers.ENABLED));
                 ApnSetting apn = new ApnSetting(
                         cursor.getInt(cursor.getColumnIndexOrThrow(Telephony.Carriers._ID)),
                         cursor.getString(cursor.getColumnIndexOrThrow(Telephony.Carriers.NUMERIC)),
@@ -817,11 +814,7 @@
                         types,
                         cursor.getString(cursor.getColumnIndexOrThrow(Telephony.Carriers.PROTOCOL)),
                         cursor.getString(cursor.getColumnIndexOrThrow(
-                                Telephony.Carriers.ROAMING_PROTOCOL)),
-                        (enabled == 0 ? false : true),
-                        cursor.getInt(cursor.getColumnIndexOrThrow(
-                                Telephony.Carriers.INACTIVE_TIMER)),
-                        cursor.getInt(cursor.getColumnIndexOrThrow(Telephony.Carriers.CLASS)));
+                                Telephony.Carriers.ROAMING_PROTOCOL)));
                 result.add(apn);
             } while (cursor.moveToNext());
         }
@@ -868,13 +861,6 @@
             return false;
         }
 
-        if (((mPhone.getServiceState().getRadioTechnology() == ServiceState.RADIO_TECHNOLOGY_EHRPD)
-            || (mPhone.getServiceState().getRadioTechnology() == ServiceState.RADIO_TECHNOLOGY_LTE))
-            && (!apn.enabled)) {
-            if (DBG) log("setupData: apn is desabled by carrier!");
-            return false;
-        }
-
         dc = findReadyDataConnection(apn);
 
         if (dc == null) {
@@ -947,7 +933,7 @@
         cleanUpAllConnections(isConnected, Phone.REASON_APN_CHANGED);
         if (!isConnected) {
             // TODO: Won't work for multiple connections!!!!
-            mRetryMgr.resetRetryCount();
+            defaultApnContext.getDataConnection().resetRetryCount();
             defaultApnContext.setReason(Phone.REASON_APN_CHANGED);
             trySetupData(defaultApnContext);
         }
@@ -1045,11 +1031,11 @@
         mPhone.notifyDataConnection(apnContext.getReason(), apnContext.getApnType());
         startNetStatPoll();
         // reset reconnect timer
-        mRetryMgr.resetRetryCount();
+        apnContext.getDataConnection().resetRetryCount();
     }
 
     // TODO: For multiple Active APNs not exactly sure how to do this.
-    private void gotoIdleAndNotifyDataConnection(String reason) {
+    protected void gotoIdleAndNotifyDataConnection(String reason) {
         if (DBG) log("gotoIdleAndNotifyDataConnection: reason=" + reason);
         notifyDataConnection(reason);
         mActiveApn = null;
@@ -1246,7 +1232,7 @@
             return;
         }
         if (apnContext.getState() == State.FAILED) {
-            if (!mRetryMgr.isRetryNeeded()) {
+            if (!apnContext.getDataConnection().isRetryNeeded()) {
                 if (!apnContext.getApnType().equals(Phone.APN_TYPE_DEFAULT)){
                     // if no more retries on a secondary APN attempt, tell the world and revert.
                     notifyDataConnection(Phone.REASON_APN_FAILED);
@@ -1254,18 +1240,18 @@
                 }
                 if (mReregisterOnReconnectFailure) {
                     // We've re-registerd once now just retry forever.
-                    mRetryMgr.retryForeverUsingLastTimeout();
+                    apnContext.getDataConnection().retryForeverUsingLastTimeout();
                 } else {
                     // Try to Re-register to the network.
                     log("PDP activate failed, Reregistering to the network");
                     mReregisterOnReconnectFailure = true;
                     mPhone.getServiceStateTracker().reRegisterNetwork(null);
-                    mRetryMgr.resetRetryCount();
+                    apnContext.getDataConnection().resetRetryCount();
                     return;
                 }
             }
 
-            int nextReconnectDelay = mRetryMgr.getRetryTimer();
+            int nextReconnectDelay = apnContext.getDataConnection().getRetryTimer();
             log("PDP activate failed. Scheduling next attempt for "
                     + (nextReconnectDelay / 1000) + "s");
 
@@ -1281,7 +1267,7 @@
                     SystemClock.elapsedRealtime() + nextReconnectDelay,
                     apnContext.getReconnectIntent());
 
-            mRetryMgr.increaseRetryCount();
+            apnContext.getDataConnection().increaseRetryCount();
 
             if (!shouldPostNotification(lastFailCauseCode)) {
                 Log.d(LOG_TAG, "NOT Posting GPRS Unavailable notification "
@@ -1321,14 +1307,12 @@
         if (apnContext.getApnType().equals(Phone.APN_TYPE_DEFAULT)) {
             log("onEnableNewApn default type");
             ApnContext defaultApnContext = mApnContexts.get(Phone.APN_TYPE_DEFAULT);
-            mRetryMgr = defaultApnContext.getDataConnection().getRetryMgr();
-            mRetryMgr.resetRetryCount();
+            defaultApnContext.getDataConnection().resetRetryCount();
         } else if (mApnToDataConnectionId.get(apnContext.getApnType()) == null) {
             log("onEnableNewApn ApnType=" + apnContext.getApnType() +
                     " missing, make a new connection");
             int id = createDataConnection(apnContext.getApnType());
-            mRetryMgr = mDataConnections.get(id).getRetryMgr();
-            mRetryMgr.resetRetryCount();
+            mDataConnections.get(id).resetRetryCount();
         } else {
             log("oneEnableNewApn connection already exists, nothing to setup");
         }
@@ -1391,7 +1375,10 @@
     protected void onRadioOffOrNotAvailable() {
         // Make sure our reconnect delay starts at the initial value
         // next time the radio comes on
-        mRetryMgr.resetRetryCount();
+
+        for (DataConnection dc : mDataConnections.values()) {
+            dc.resetRetryCount();
+        }
         mReregisterOnReconnectFailure = false;
 
         if (mPhone.getSimulatedRadioControl() != null) {
@@ -1540,19 +1527,6 @@
         }
     }
 
-    /**
-     * Called when EVENT_RESET_DONE is received.
-     */
-    @Override
-    protected void onResetDone(AsyncResult ar) {
-        if (DBG) log("EVENT_RESET_DONE");
-        String reason = null;
-        if (ar.userObj instanceof String) {
-            reason = (String) ar.userObj;
-        }
-        gotoIdleAndNotifyDataConnection(reason);
-    }
-
     protected void onPollPdp() {
         if (getOverallState() == State.CONNECTED) {
             // only poll when connected
@@ -1581,7 +1555,8 @@
             }
         } else {
             // reset reconnect timer
-            mRetryMgr.resetRetryCount();
+            ApnContext defaultApnContext = mApnContexts.get(Phone.APN_TYPE_DEFAULT);
+            defaultApnContext.getDataConnection().resetRetryCount();
             mReregisterOnReconnectFailure = false;
             // in case data setup was attempted when we were on a voice call
             trySetupData(Phone.REASON_VOICE_CALL_ENDED, Phone.APN_TYPE_DEFAULT);
@@ -1699,17 +1674,6 @@
         }
     }
 
-    private ApnSetting fetchDunApn() {
-        Context c = mPhone.getContext();
-        String apnData = Settings.Secure.getString(c.getContentResolver(),
-                                    Settings.Secure.TETHER_DUN_APN);
-        ApnSetting dunSetting = ApnSetting.fromString(apnData);
-        if (dunSetting != null) return dunSetting;
-
-        apnData = c.getResources().getString(R.string.config_tether_apndata);
-        return ApnSetting.fromString(apnData);
-    }
-
     /**
      * Build a list of APNs to be used to create PDP's.
      *
@@ -1896,7 +1860,7 @@
                     // TODO: Should all PDN states be checked to fail?
                     if (mState == State.FAILED) {
                         cleanUpAllConnections(false, Phone.REASON_PS_RESTRICT_ENABLED);
-                        mRetryMgr.resetRetryCount();
+                        resetAllRetryCounts();
                         mReregisterOnReconnectFailure = false;
                     }
                     trySetupData(Phone.REASON_PS_RESTRICT_ENABLED, Phone.APN_TYPE_DEFAULT);
diff --git a/telephony/java/com/android/internal/telephony/gsm/GsmServiceStateTracker.java b/telephony/java/com/android/internal/telephony/gsm/GsmServiceStateTracker.java
index 277980a..3f521a0 100644
--- a/telephony/java/com/android/internal/telephony/gsm/GsmServiceStateTracker.java
+++ b/telephony/java/com/android/internal/telephony/gsm/GsmServiceStateTracker.java
@@ -85,7 +85,7 @@
     private int mNewReasonDataDenied = -1;
 
     /**
-     *  Values correspond to ServiceStateTracker.DATA_ACCESS_ definitions.
+     *  Values correspond to ServiceState.RADIO_TECHNOLOGY_ definitions.
      */
     private int networkType = 0;
     private int newNetworkType = 0;
@@ -565,8 +565,7 @@
                 return;
             }
 
-            if (err != CommandException.Error.OP_NOT_ALLOWED_BEFORE_REG_NW &&
-                    err != CommandException.Error.OP_NOT_ALLOWED_BEFORE_REG_NW) {
+            if (err != CommandException.Error.OP_NOT_ALLOWED_BEFORE_REG_NW) {
                 Log.e(LOG_TAG,
                         "RIL implementation has returned an error where it must succeed" +
                         ar.exception);
@@ -768,22 +767,22 @@
         String ret = "unknown";
 
         switch (type) {
-            case DATA_ACCESS_GPRS:
+            case ServiceState.RADIO_TECHNOLOGY_GPRS:
                 ret = "GPRS";
                 break;
-            case DATA_ACCESS_EDGE:
+            case ServiceState.RADIO_TECHNOLOGY_EDGE:
                 ret = "EDGE";
                 break;
-            case DATA_ACCESS_UMTS:
+            case ServiceState.RADIO_TECHNOLOGY_UMTS:
                 ret = "UMTS";
                 break;
-            case DATA_ACCESS_HSDPA:
+            case ServiceState.RADIO_TECHNOLOGY_HSDPA:
                 ret = "HSDPA";
                 break;
-            case DATA_ACCESS_HSUPA:
+            case ServiceState.RADIO_TECHNOLOGY_HSUPA:
                 ret = "HSUPA";
                 break;
-            case DATA_ACCESS_HSPA:
+            case ServiceState.RADIO_TECHNOLOGY_HSPA:
                 ret = "HSPA";
                 break;
             default:
@@ -1303,7 +1302,7 @@
      * that could support voice and data simultaneously.
      */
     public boolean isConcurrentVoiceAndDataAllowed() {
-        return (networkType >= DATA_ACCESS_UMTS);
+        return (networkType >= ServiceState.RADIO_TECHNOLOGY_UMTS);
     }
 
     /**
diff --git a/telephony/java/com/android/internal/telephony/gsm/SimCard.java b/telephony/java/com/android/internal/telephony/gsm/SimCard.java
index 5a2f871..781746c 100644
--- a/telephony/java/com/android/internal/telephony/gsm/SimCard.java
+++ b/telephony/java/com/android/internal/telephony/gsm/SimCard.java
@@ -20,6 +20,7 @@
 
 import com.android.internal.telephony.IccCard;
 import com.android.internal.telephony.PhoneBase;
+import com.android.internal.telephony.TelephonyProperties;
 import android.os.SystemProperties;
 
 /**
@@ -46,7 +47,7 @@
         mPhone.mCM.registerForSIMReady(mHandler, EVENT_ICC_READY, null);
         updateStateProperty();
 
-        if(SystemProperties.getBoolean("ro.mot.lte_on_cdma", false)) {
+        if(SystemProperties.getBoolean(TelephonyProperties.PROPERTY_NETWORK_LTE_ON_CDMA, false)) {
             mPhone.mCM.registerForNVReady(mHandler, EVENT_ICC_READY, null);
         }
     }
diff --git a/telephony/tests/telephonytests/src/com/android/internal/telephony/ApnSettingTest.java b/telephony/tests/telephonytests/src/com/android/internal/telephony/ApnSettingTest.java
index a1078c1..1032074 100644
--- a/telephony/tests/telephonytests/src/com/android/internal/telephony/ApnSettingTest.java
+++ b/telephony/tests/telephonytests/src/com/android/internal/telephony/ApnSettingTest.java
@@ -58,21 +58,21 @@
         testString = "Vodafone IT,web.omnitel.it,,,,,,,,,222,10,,DUN";
         expected_apn =  new ApnSetting(
                 -1, "22210", "Vodafone IT", "web.omnitel.it", "", "",
-                "", "", "", "", "", 0, dunTypes, "IP", "IP", true, 0, 0);
+                "", "", "", "", "", 0, dunTypes, "IP", "IP");
         assertApnSettingEqual(expected_apn, ApnSetting.fromString(testString));
 
         // A v2 string.
         testString = "[ApnSettingV2] Name,apn,,,,,,,,,123,45,,mms|*,IPV6,IP";
         expected_apn =  new ApnSetting(
                 -1, "12345", "Name", "apn", "", "",
-                "", "", "", "", "", 0, mmsTypes, "IPV6", "IP", true, 0, 0);
+                "", "", "", "", "", 0, mmsTypes, "IPV6", "IP");
         assertApnSettingEqual(expected_apn, ApnSetting.fromString(testString));
 
         // A v2 string with spaces.
         testString = "[ApnSettingV2] Name,apn, ,,,,,,,,123,45,,mms|*,IPV4V6, IP";
         expected_apn =  new ApnSetting(
                 -1, "12345", "Name", "apn", "", "",
-                "", "", "", "", "", 0, mmsTypes, "IPV4V6", "IP", true, 0, 0);
+                "", "", "", "", "", 0, mmsTypes, "IPV4V6", "IP");
         assertApnSettingEqual(expected_apn, ApnSetting.fromString(testString));
 
         // Return null if insufficient fields given.
@@ -87,7 +87,7 @@
         String[] incorrectTypes = {"mms|*", "IPV6"};
         expected_apn =  new ApnSetting(
                 -1, "12345", "Name", "apn", "", "",
-                "", "", "", "", "", 0, incorrectTypes, "IP", "IP", true, 0, 0);
+                "", "", "", "", "", 0, incorrectTypes, "IP", "IP");
         assertApnSettingEqual(expected_apn, ApnSetting.fromString(testString));
     }
 
@@ -98,7 +98,7 @@
         ApnSetting apn =  new ApnSetting(
                 99, "12345", "Name", "apn", "proxy", "port",
                 "mmsc", "mmsproxy", "mmsport", "user", "password", 0,
-                types, "IPV4V6", "IP", true, 0, 0);
+                types, "IPV4V6", "IP");
         String expected = "[ApnSettingV2] Name, 99, 12345, apn, proxy, " +
                 "mmsc, mmsproxy, mmsport, port, 0, default | *, " +
                 "IPV4V6, IP";
diff --git a/tests/BrowserTestPlugin/jni/Android.mk b/tests/BrowserTestPlugin/jni/Android.mk
index 95a21e9..a0d647b 100644
--- a/tests/BrowserTestPlugin/jni/Android.mk
+++ b/tests/BrowserTestPlugin/jni/Android.mk
@@ -41,7 +41,7 @@
 	external/webkit/WebKit/android/plugins
 
 LOCAL_CFLAGS += -fvisibility=hidden 
-LOCAL_PRELINK_MODULE := false
+
 
 LOCAL_MODULE := libtestplugin
 LOCAL_MODULE_TAGS := tests
diff --git a/tests/HugeBackup/Android.mk b/tests/HugeBackup/Android.mk
new file mode 100644
index 0000000..4789bc8
--- /dev/null
+++ b/tests/HugeBackup/Android.mk
@@ -0,0 +1,15 @@
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_TAGS := tests
+
+# Only compile source java files in this apk.
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+
+LOCAL_PACKAGE_NAME := HugeBackup
+
+LOCAL_SDK_VERSION := current
+
+LOCAL_PROGUARD_FLAG_FILES := proguard.flags
+
+include $(BUILD_PACKAGE)
diff --git a/tests/HugeBackup/AndroidManifest.xml b/tests/HugeBackup/AndroidManifest.xml
new file mode 100644
index 0000000..923881b
--- /dev/null
+++ b/tests/HugeBackup/AndroidManifest.xml
@@ -0,0 +1,44 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2011 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<!-- Declare the contents of this Android application.  The namespace
+     attribute brings in the Android platform namespace, and the package
+     supplies a unique name for the application.  When writing your
+     own application, the package name must be changed from "com.example.*"
+     to come from a domain that you own or have control over. -->
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="com.android.hugebackup"
+    android:versionCode="1"
+    android:versionName="1.0">
+
+    <!-- The backup/restore mechanism was introduced in API version 8 -->
+    <uses-sdk android:minSdkVersion="8" android:targetSdkVersion="8" />
+
+    <application android:label="Huge Backup"
+        android:backupAgent="HugeAgent">
+
+        <meta-data android:name="com.google.android.backup.api_key"
+            android:value="AEdPqrEAAAAINyoagzQOEEpIH3yw7LYCFN7CRX4FMd6TGIGVaA" />
+
+        <activity android:name="HugeBackupActivity">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.LAUNCHER" />
+            </intent-filter>
+        </activity>
+
+    </application>
+</manifest>
diff --git a/tests/HugeBackup/proguard.flags b/tests/HugeBackup/proguard.flags
new file mode 100644
index 0000000..b4d01bf
--- /dev/null
+++ b/tests/HugeBackup/proguard.flags
@@ -0,0 +1,3 @@
+-keepclassmembers class com.android.hugebackup.HugeBackupActivity {
+    public void onRestoreButtonClick(android.view.View);
+}
diff --git a/tests/HugeBackup/res/layout/backup_restore.xml b/tests/HugeBackup/res/layout/backup_restore.xml
new file mode 100644
index 0000000..7f11984
--- /dev/null
+++ b/tests/HugeBackup/res/layout/backup_restore.xml
@@ -0,0 +1,87 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2011 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<!-- Layout description of the BackupRestore sample's main activity -->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:orientation="vertical"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content">
+
+    <ScrollView
+        android:orientation="vertical"
+        android:layout_width="fill_parent"
+        android:layout_height="fill_parent"
+        android:layout_weight="1">
+
+        <LinearLayout
+            android:orientation="vertical"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content">
+
+            <TextView android:text="@string/filling_text"
+                android:textSize="20dp"
+                android:layout_marginTop="20dp"
+                android:layout_marginBottom="10dp"
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"/>
+
+            <RadioGroup android:id="@+id/filling_group"
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:layout_marginLeft="20dp"
+                android:orientation="vertical">
+
+                <RadioButton android:id="@+id/bacon"
+                    android:text="@string/bacon_label"/>
+                <RadioButton android:id="@+id/pastrami"
+                    android:text="@string/pastrami_label"/>
+                <RadioButton android:id="@+id/hummus"
+                    android:text="@string/hummus_label"/>
+
+            </RadioGroup>
+
+            <TextView android:text="@string/extras_text"
+                android:textSize="20dp"
+                android:layout_marginTop="20dp"
+                android:layout_marginBottom="10dp"
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"/>
+
+            <CheckBox android:id="@+id/mayo"
+                android:text="@string/mayo_text"
+                android:layout_marginLeft="20dp"
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"/>
+
+            <CheckBox android:id="@+id/tomato"
+                android:text="@string/tomato_text"
+                android:layout_marginLeft="20dp"
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"/>
+
+        </LinearLayout>
+
+    </ScrollView>
+
+    <Button android:id="@+id/restore_button"
+        android:text="@string/restore_text"
+        android:onClick="onRestoreButtonClick"
+        android:layout_height="wrap_content"
+        android:layout_width="wrap_content"
+        android:layout_weight="0" />
+
+</LinearLayout>
diff --git a/tests/HugeBackup/res/values/strings.xml b/tests/HugeBackup/res/values/strings.xml
new file mode 100644
index 0000000..c0b9226
--- /dev/null
+++ b/tests/HugeBackup/res/values/strings.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2011 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<resources>
+  <string name="filling_text">Choose a sandwich filling:</string>
+  <string name="bacon_label">Bacon</string>
+  <string name="pastrami_label">Pastrami</string>
+  <string name="hummus_label">Hummus</string>
+
+  <string name="extras_text">Extras:</string>
+  <string name="mayo_text">Mayonnaise\?</string>
+  <string name="tomato_text">Tomato\?</string>
+
+  <string name="restore_text">Restore last data</string>
+</resources>
diff --git a/tests/HugeBackup/src/com/android/hugebackup/HugeAgent.java b/tests/HugeBackup/src/com/android/hugebackup/HugeAgent.java
new file mode 100644
index 0000000..f90bd9f
--- /dev/null
+++ b/tests/HugeBackup/src/com/android/hugebackup/HugeAgent.java
@@ -0,0 +1,261 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.hugebackup;
+
+import android.app.backup.BackupAgent;
+import android.app.backup.BackupDataInput;
+import android.app.backup.BackupDataOutput;
+import android.os.ParcelFileDescriptor;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.DataInputStream;
+import java.io.DataOutputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.RandomAccessFile;
+
+/**
+ * This is the backup/restore agent class for the BackupRestore sample
+ * application.  This particular agent illustrates using the backup and
+ * restore APIs directly, without taking advantage of any helper classes.
+ */
+public class HugeAgent extends BackupAgent {
+    /**
+     * We put a simple version number into the state files so that we can
+     * tell properly how to read "old" versions if at some point we want
+     * to change what data we back up and how we store the state blob.
+     */
+    static final int AGENT_VERSION = 1;
+
+    /**
+     * Pick an arbitrary string to use as the "key" under which the
+     * data is backed up.  This key identifies different data records
+     * within this one application's data set.  Since we only maintain
+     * one piece of data we don't need to distinguish, so we just pick
+     * some arbitrary tag to use.
+     */
+    static final String APP_DATA_KEY = "alldata";
+    static final String HUGE_DATA_KEY = "colossus";
+
+    /** The app's current data, read from the live disk file */
+    boolean mAddMayo;
+    boolean mAddTomato;
+    int mFilling;
+
+    /** The location of the application's persistent data file */
+    File mDataFile;
+
+    /** For convenience, we set up the File object for the app's data on creation */
+    @Override
+    public void onCreate() {
+        mDataFile = new File(getFilesDir(), HugeBackupActivity.DATA_FILE_NAME);
+    }
+
+    /**
+     * The set of data backed up by this application is very small: just
+     * two booleans and an integer.  With such a simple dataset, it's
+     * easiest to simply store a copy of the backed-up data as the state
+     * blob describing the last dataset backed up.  The state file
+     * contents can be anything; it is private to the agent class, and
+     * is never stored off-device.
+     *
+     * <p>One thing that an application may wish to do is tag the state
+     * blob contents with a version number.  This is so that if the
+     * application is upgraded, the next time it attempts to do a backup,
+     * it can detect that the last backup operation was performed by an
+     * older version of the agent, and might therefore require different
+     * handling.
+     */
+    @Override
+    public void onBackup(ParcelFileDescriptor oldState, BackupDataOutput data,
+            ParcelFileDescriptor newState) throws IOException {
+        // First, get the current data from the application's file.  This
+        // may throw an IOException, but in that case something has gone
+        // badly wrong with the app's data on disk, and we do not want
+        // to back up garbage data.  If we just let the exception go, the
+        // Backup Manager will handle it and simply skip the current
+        // backup operation.
+        synchronized (HugeBackupActivity.sDataLock) {
+            RandomAccessFile file = new RandomAccessFile(mDataFile, "r");
+            mFilling = file.readInt();
+            mAddMayo = file.readBoolean();
+            mAddTomato = file.readBoolean();
+        }
+
+        // If the new state file descriptor is null, this is the first time
+        // a backup is being performed, so we know we have to write the
+        // data.  If there <em>is</em> a previous state blob, we want to
+        // double check whether the current data is actually different from
+        // our last backup, so that we can avoid transmitting redundant
+        // data to the storage backend.
+        boolean doBackup = (oldState == null);
+        if (!doBackup) {
+            doBackup = compareStateFile(oldState);
+        }
+
+        // If we decided that we do in fact need to write our dataset, go
+        // ahead and do that.  The way this agent backs up the data is to
+        // flatten it into a single buffer, then write that to the backup
+        // transport under the single key string.
+        if (doBackup) {
+            ByteArrayOutputStream bufStream = new ByteArrayOutputStream();
+
+            // We use a DataOutputStream to write structured data into
+            // the buffering stream
+            DataOutputStream outWriter = new DataOutputStream(bufStream);
+            outWriter.writeInt(mFilling);
+            outWriter.writeBoolean(mAddMayo);
+            outWriter.writeBoolean(mAddTomato);
+
+            // Okay, we've flattened the data for transmission.  Pull it
+            // out of the buffering stream object and send it off.
+            byte[] buffer = bufStream.toByteArray();
+            int len = buffer.length;
+            data.writeEntityHeader(APP_DATA_KEY, len);
+            data.writeEntityData(buffer, len);
+
+            // ***** pathological behavior *****
+            // Now, in order to incur deliberate too-much-data failures,
+            // try to back up 20 MB of data besides what we already pushed.
+            final int MEGABYTE = 1024*1024;
+            final int NUM_MEGS = 20;
+            buffer = new byte[MEGABYTE];
+            data.writeEntityHeader(HUGE_DATA_KEY, NUM_MEGS * MEGABYTE);
+            for (int i = 0; i < NUM_MEGS; i++) {
+                data.writeEntityData(buffer, MEGABYTE);
+            }
+        }
+
+        // Finally, in all cases, we need to write the new state blob
+        writeStateFile(newState);
+    }
+
+    /**
+     * Helper routine - read a previous state file and decide whether to
+     * perform a backup based on its contents.
+     *
+     * @return <code>true</code> if the application's data has changed since
+     *   the last backup operation; <code>false</code> otherwise.
+     */
+    boolean compareStateFile(ParcelFileDescriptor oldState) {
+        FileInputStream instream = new FileInputStream(oldState.getFileDescriptor());
+        DataInputStream in = new DataInputStream(instream);
+
+        try {
+            int stateVersion = in.readInt();
+            if (stateVersion > AGENT_VERSION) {
+                // Whoops; the last version of the app that backed up
+                // data on this device was <em>newer</em> than the current
+                // version -- the user has downgraded.  That's problematic.
+                // In this implementation, we recover by simply rewriting
+                // the backup.
+                return true;
+            }
+
+            // The state data we store is just a mirror of the app's data;
+            // read it from the state file then return 'true' if any of
+            // it differs from the current data.
+            int lastFilling = in.readInt();
+            boolean lastMayo = in.readBoolean();
+            boolean lastTomato = in.readBoolean();
+
+            return (lastFilling != mFilling)
+                    || (lastTomato != mAddTomato)
+                    || (lastMayo != mAddMayo);
+        } catch (IOException e) {
+            // If something went wrong reading the state file, be safe
+            // and back up the data again.
+            return true;
+        }
+    }
+
+    /**
+     * Write out the new state file:  the version number, followed by the
+     * three bits of data as we sent them off to the backup transport.
+     */
+    void writeStateFile(ParcelFileDescriptor stateFile) throws IOException {
+        FileOutputStream outstream = new FileOutputStream(stateFile.getFileDescriptor());
+        DataOutputStream out = new DataOutputStream(outstream);
+
+        out.writeInt(AGENT_VERSION);
+        out.writeInt(mFilling);
+        out.writeBoolean(mAddMayo);
+        out.writeBoolean(mAddTomato);
+    }
+
+    /**
+     * This application does not do any "live" restores of its own data,
+     * so the only time a restore will happen is when the application is
+     * installed.  This means that the activity itself is not going to
+     * be running while we change its data out from under it.  That, in
+     * turn, means that there is no need to send out any sort of notification
+     * of the new data:  we only need to read the data from the stream
+     * provided here, build the application's new data file, and then
+     * write our new backup state blob that will be consulted at the next
+     * backup operation.
+     *
+     * <p>We don't bother checking the versionCode of the app who originated
+     * the data because we have never revised the backup data format.  If
+     * we had, the 'appVersionCode' parameter would tell us how we should
+     * interpret the data we're about to read.
+     */
+    @Override
+    public void onRestore(BackupDataInput data, int appVersionCode,
+            ParcelFileDescriptor newState) throws IOException {
+        // We should only see one entity in the data stream, but the safest
+        // way to consume it is using a while() loop
+        while (data.readNextHeader()) {
+            String key = data.getKey();
+            int dataSize = data.getDataSize();
+
+            if (APP_DATA_KEY.equals(key)) {
+                // It's our saved data, a flattened chunk of data all in
+                // one buffer.  Use some handy structured I/O classes to
+                // extract it.
+                byte[] dataBuf = new byte[dataSize];
+                data.readEntityData(dataBuf, 0, dataSize);
+                ByteArrayInputStream baStream = new ByteArrayInputStream(dataBuf);
+                DataInputStream in = new DataInputStream(baStream);
+
+                mFilling = in.readInt();
+                mAddMayo = in.readBoolean();
+                mAddTomato = in.readBoolean();
+
+                // Now we are ready to construct the app's data file based
+                // on the data we are restoring from.
+                synchronized (HugeBackupActivity.sDataLock) {
+                    RandomAccessFile file = new RandomAccessFile(mDataFile, "rw");
+                    file.setLength(0L);
+                    file.writeInt(mFilling);
+                    file.writeBoolean(mAddMayo);
+                    file.writeBoolean(mAddTomato);
+                }
+            } else {
+                // Curious!  This entity is data under a key we do not
+                // understand how to process.  Just skip it.
+                data.skipEntityData();
+            }
+        }
+
+        // The last thing to do is write the state blob that describes the
+        // app's data as restored from backup.
+        writeStateFile(newState);
+    }
+}
diff --git a/tests/HugeBackup/src/com/android/hugebackup/HugeBackupActivity.java b/tests/HugeBackup/src/com/android/hugebackup/HugeBackupActivity.java
new file mode 100644
index 0000000..84e31aa
--- /dev/null
+++ b/tests/HugeBackup/src/com/android/hugebackup/HugeBackupActivity.java
@@ -0,0 +1,214 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.hugebackup;
+
+import android.app.Activity;
+import android.app.backup.BackupManager;
+import android.app.backup.RestoreObserver;
+import android.os.Bundle;
+import android.util.Log;
+import android.view.View;
+import android.widget.CheckBox;
+import android.widget.CompoundButton;
+import android.widget.RadioGroup;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.RandomAccessFile;
+
+/**
+ * Deliberately back up waaaaaaay too much data.  Cloned with some alterations
+ * from the Backup/Restore sample application.
+ */
+public class HugeBackupActivity extends Activity {
+    static final String TAG = "HugeBackupActivity";
+
+    /**
+     * We serialize access to our persistent data through a global static
+     * object.  This ensures that in the unlikely event of the our backup/restore
+     * agent running to perform a backup while our UI is updating the file, the
+     * agent will not accidentally read partially-written data.
+     *
+     * <p>Curious but true: a zero-length array is slightly lighter-weight than
+     * merely allocating an Object, and can still be synchronized on.
+     */
+    static final Object[] sDataLock = new Object[0];
+
+    /** Also supply a global standard file name for everyone to use */
+    static final String DATA_FILE_NAME = "saved_data";
+
+    /** The various bits of UI that the user can manipulate */
+    RadioGroup mFillingGroup;
+    CheckBox mAddMayoCheckbox;
+    CheckBox mAddTomatoCheckbox;
+
+    /** Cache a reference to our persistent data file */
+    File mDataFile;
+
+    /** Also cache a reference to the Backup Manager */
+    BackupManager mBackupManager;
+
+    /** Set up the activity and populate its UI from the persistent data. */
+    @Override
+    public void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+
+        /** Establish the activity's UI */
+        setContentView(R.layout.backup_restore);
+
+        /** Once the UI has been inflated, cache the controls for later */
+        mFillingGroup = (RadioGroup) findViewById(R.id.filling_group);
+        mAddMayoCheckbox = (CheckBox) findViewById(R.id.mayo);
+        mAddTomatoCheckbox = (CheckBox) findViewById(R.id.tomato);
+
+        /** Set up our file bookkeeping */
+        mDataFile = new File(getFilesDir(), HugeBackupActivity.DATA_FILE_NAME);
+
+        /** It is handy to keep a BackupManager cached */
+        mBackupManager = new BackupManager(this);
+
+        /**
+         * Finally, build the UI from the persistent store
+         */
+        populateUI();
+    }
+
+    /**
+     * Configure the UI based on our persistent data, creating the
+     * data file and establishing defaults if necessary.
+     */
+    void populateUI() {
+        RandomAccessFile file;
+
+        // Default values in case there's no data file yet
+        int whichFilling = R.id.pastrami;
+        boolean addMayo = false;
+        boolean addTomato = false;
+
+        /** Hold the data-access lock around access to the file */
+        synchronized (HugeBackupActivity.sDataLock) {
+            boolean exists = mDataFile.exists();
+            try {
+                file = new RandomAccessFile(mDataFile, "rw");
+                if (exists) {
+                    Log.v(TAG, "datafile exists");
+                    whichFilling = file.readInt();
+                    addMayo = file.readBoolean();
+                    addTomato = file.readBoolean();
+                    Log.v(TAG, "  mayo=" + addMayo
+                            + " tomato=" + addTomato
+                            + " filling=" + whichFilling);
+                } else {
+                    // The default values were configured above: write them
+                    // to the newly-created file.
+                    Log.v(TAG, "creating default datafile");
+                    writeDataToFileLocked(file,
+                            addMayo, addTomato, whichFilling);
+
+                    // We also need to perform an initial backup; ask for one
+                    mBackupManager.dataChanged();
+                }
+            } catch (IOException ioe) {
+            }
+        }
+
+        /** Now that we've processed the file, build the UI outside the lock */
+        mFillingGroup.check(whichFilling);
+        mAddMayoCheckbox.setChecked(addMayo);
+        mAddTomatoCheckbox.setChecked(addTomato);
+
+        /**
+         * We also want to record the new state when the user makes changes,
+         * so install simple observers that do this
+         */
+        mFillingGroup.setOnCheckedChangeListener(
+                new RadioGroup.OnCheckedChangeListener() {
+                    public void onCheckedChanged(RadioGroup group,
+                            int checkedId) {
+                        // As with the checkbox listeners, rewrite the
+                        // entire state file
+                        Log.v(TAG, "New radio item selected: " + checkedId);
+                        recordNewUIState();
+                    }
+                });
+
+        CompoundButton.OnCheckedChangeListener checkListener
+                = new CompoundButton.OnCheckedChangeListener() {
+            public void onCheckedChanged(CompoundButton buttonView,
+                    boolean isChecked) {
+                // Whichever one is altered, we rewrite the entire UI state
+                Log.v(TAG, "Checkbox toggled: " + buttonView);
+                recordNewUIState();
+            }
+        };
+        mAddMayoCheckbox.setOnCheckedChangeListener(checkListener);
+        mAddTomatoCheckbox.setOnCheckedChangeListener(checkListener);
+    }
+
+    /**
+     * Handy helper routine to write the UI data to a file.
+     */
+    void writeDataToFileLocked(RandomAccessFile file,
+            boolean addMayo, boolean addTomato, int whichFilling)
+        throws IOException {
+            file.setLength(0L);
+            file.writeInt(whichFilling);
+            file.writeBoolean(addMayo);
+            file.writeBoolean(addTomato);
+            Log.v(TAG, "NEW STATE: mayo=" + addMayo
+                    + " tomato=" + addTomato
+                    + " filling=" + whichFilling);
+    }
+
+    /**
+     * Another helper; this one reads the current UI state and writes that
+     * to the persistent store, then tells the backup manager that we need
+     * a backup.
+     */
+    void recordNewUIState() {
+        boolean addMayo = mAddMayoCheckbox.isChecked();
+        boolean addTomato = mAddTomatoCheckbox.isChecked();
+        int whichFilling = mFillingGroup.getCheckedRadioButtonId();
+        try {
+            synchronized (HugeBackupActivity.sDataLock) {
+                RandomAccessFile file = new RandomAccessFile(mDataFile, "rw");
+                writeDataToFileLocked(file, addMayo, addTomato, whichFilling);
+            }
+        } catch (IOException e) {
+            Log.e(TAG, "Unable to record new UI state");
+        }
+
+        mBackupManager.dataChanged();
+    }
+
+    /**
+     * Click handler, designated in the layout, that runs a restore of the app's
+     * most recent data when the button is pressed.
+     */
+    public void onRestoreButtonClick(View v) {
+        Log.v(TAG, "Requesting restore of our most recent data");
+        mBackupManager.requestRestore(
+                new RestoreObserver() {
+                    public void restoreFinished(int error) {
+                        /** Done with the restore!  Now draw the new state of our data */
+                        Log.v(TAG, "Restore finished, error = " + error);
+                        populateUI();
+                    }
+                }
+        );
+    }
+}
diff --git a/tests/HwAccelerationTest/AndroidManifest.xml b/tests/HwAccelerationTest/AndroidManifest.xml
index e82f9aa..2afc935 100644
--- a/tests/HwAccelerationTest/AndroidManifest.xml
+++ b/tests/HwAccelerationTest/AndroidManifest.xml
@@ -34,6 +34,15 @@
         </activity>
 
         <activity
+                android:name="BitmapMutateActivity"
+                android:label="_BitmapMutate">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.LAUNCHER" />
+            </intent-filter>
+        </activity>
+
+        <activity
                 android:name="BitmapMeshLayerActivity"
                 android:label="_BitmapMeshLayer">
             <intent-filter>
diff --git a/tests/HwAccelerationTest/res/drawable/gradient.xml b/tests/HwAccelerationTest/res/drawable/gradient.xml
new file mode 100644
index 0000000..756db0b
--- /dev/null
+++ b/tests/HwAccelerationTest/res/drawable/gradient.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2010 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<shape xmlns:android="http://schemas.android.com/apk/res/android">
+    <gradient
+        android:startColor="#FF707070"
+        android:endColor="#FF0C0C0C"
+        android:angle="270" />
+</shape>
diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/BitmapMutateActivity.java b/tests/HwAccelerationTest/src/com/android/test/hwui/BitmapMutateActivity.java
new file mode 100644
index 0000000..db9017c
--- /dev/null
+++ b/tests/HwAccelerationTest/src/com/android/test/hwui/BitmapMutateActivity.java
@@ -0,0 +1,106 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.test.hwui;
+
+import android.animation.ObjectAnimator;
+import android.app.Activity;
+import android.content.Context;
+import android.graphics.Bitmap;
+import android.graphics.Canvas;
+import android.graphics.Paint;
+import android.os.Bundle;
+import android.view.Gravity;
+import android.view.View;
+import android.widget.FrameLayout;
+
+@SuppressWarnings({"UnusedDeclaration"})
+public class BitmapMutateActivity extends Activity {
+    private static final int PATTERN_SIZE = 400;
+
+    private ObjectAnimator mAnimator;
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        final BitmapsView view = new BitmapsView(this);
+        final FrameLayout layout = new FrameLayout(this);
+
+        layout.addView(view, new FrameLayout.LayoutParams(480, 800, Gravity.CENTER));
+
+        setContentView(layout);
+
+        mAnimator = ObjectAnimator.ofInt(view, "offset", 0, PATTERN_SIZE - 1);
+        mAnimator.setDuration(1500);
+        mAnimator.setRepeatCount(ObjectAnimator.INFINITE);
+        mAnimator.setRepeatMode(ObjectAnimator.REVERSE);
+        mAnimator.start();
+    }
+
+    @Override
+    protected void onDestroy() {
+        super.onDestroy();
+        mAnimator.cancel();
+    }
+
+    static class BitmapsView extends View {
+        private final Paint mBitmapPaint;
+        private final Bitmap mBitmap1;
+        private final int[] mPixels;
+
+        private int mOffset;
+        private int mSlice;
+        private static final int[] mShifts = new int[] { 16, 8, 0 };
+
+        BitmapsView(Context c) {
+            super(c);
+
+            mBitmap1 = Bitmap.createBitmap(PATTERN_SIZE, PATTERN_SIZE, Bitmap.Config.ARGB_8888);
+            mBitmapPaint = new Paint();
+
+            mPixels = new int[mBitmap1.getWidth() * mBitmap1.getHeight()];
+            mSlice = mBitmap1.getWidth() / 3;
+        }
+
+        public void setOffset(int offset) {
+            mOffset = offset;
+            invalidate();
+        }
+
+        @Override
+        protected void onDraw(Canvas canvas) {
+            super.onDraw(canvas);
+
+            int width = mBitmap1.getWidth();
+            int height = mBitmap1.getHeight();
+
+            canvas.translate((getWidth() - width) / 2, (getHeight() - height) / 2);
+
+            for (int x = 0; x < width; x++) {
+                int color = 0xff000000;
+                int i = x == 0 ? 0 : x - 1;
+                color |= (int) ((0xff * ((i + mOffset) % mSlice) / (float) mSlice)) <<
+                        mShifts[i / mSlice];
+                for (int y = 0; y < height; y++) {
+                    mPixels[y * width + x] = color;
+                }
+            }
+
+            mBitmap1.setPixels(mPixels, 0, width, 0, 0, width, height);
+            canvas.drawBitmap(mBitmap1, 0.0f, 0.0f, mBitmapPaint);
+        }
+    }
+}
diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/GradientsActivity.java b/tests/HwAccelerationTest/src/com/android/test/hwui/GradientsActivity.java
index f8422f4..90db818 100644
--- a/tests/HwAccelerationTest/src/com/android/test/hwui/GradientsActivity.java
+++ b/tests/HwAccelerationTest/src/com/android/test/hwui/GradientsActivity.java
@@ -193,6 +193,7 @@
         private final float mDrawWidth;
         private final float mDrawHeight;
         private final LinearGradient mGradient;
+        private final LinearGradient mGradientStops;
         private final Matrix mMatrix;
 
         ShadersView(Context c) {
@@ -202,6 +203,9 @@
             mDrawHeight = 200;
 
             mGradient = new LinearGradient(0, 0, 0, 1, 0xFF000000, 0, Shader.TileMode.CLAMP);
+            mGradientStops = new LinearGradient(0, 0, 0, 1,
+                    new int[] { 0xFFFF0000, 0xFF00FF00, 0xFF0000FF }, null, Shader.TileMode.CLAMP);
+
             mMatrix = new Matrix();
 
             mPaint = new Paint();
@@ -255,6 +259,19 @@
             mGradient.setLocalMatrix(mMatrix);
             canvas.drawRect(left, top, left + mDrawWidth, bottom, mPaint);
 
+            right = left + mDrawWidth;
+            left = 40.0f;
+            top = bottom + 20.0f;
+            bottom = top + 50.0f;
+
+            mPaint.setShader(mGradientStops);
+
+            mMatrix.setScale(1, mDrawWidth);
+            mMatrix.postRotate(90);
+            mMatrix.postTranslate(right, top);
+            mGradientStops.setLocalMatrix(mMatrix);
+            canvas.drawRect(left, top, right, bottom, mPaint);
+            
             canvas.restore();
         }
     }
diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/LinesActivity.java b/tests/HwAccelerationTest/src/com/android/test/hwui/LinesActivity.java
index 8ca842e..4233367 100644
--- a/tests/HwAccelerationTest/src/com/android/test/hwui/LinesActivity.java
+++ b/tests/HwAccelerationTest/src/com/android/test/hwui/LinesActivity.java
@@ -16,6 +16,7 @@
 
 package com.android.test.hwui;
 
+import android.animation.ObjectAnimator;
 import android.app.Activity;
 import android.content.Context;
 import android.graphics.Bitmap;
@@ -29,13 +30,26 @@
 
 @SuppressWarnings({"UnusedDeclaration"})
 public class LinesActivity extends Activity {
+    private ObjectAnimator mAnimator;
+
     @Override
     protected void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
         getWindow().setBackgroundDrawable(new ColorDrawable(0xffffffff));
         final LinesView view = new LinesView(this);
-        //view.setAlpha(0.80f);
         setContentView(view);
+
+        mAnimator = ObjectAnimator.ofFloat(view, "offset", 0.0f, 15.0f);
+        mAnimator.setDuration(1500);
+        mAnimator.setRepeatCount(ObjectAnimator.INFINITE);
+        mAnimator.setRepeatMode(ObjectAnimator.REVERSE);
+        mAnimator.start();
+    }
+
+    @Override
+    protected void onDestroy() {
+        super.onDestroy();
+        mAnimator.cancel();
     }
 
     public static class LinesView extends View {
@@ -50,6 +64,8 @@
         private final Paint mAlphaPaint;
         private final Paint mHairLinePaint;
 
+        private float mOffset;
+
         public LinesView(Context c) {
             super(c);
 
@@ -89,11 +105,16 @@
                     352.0f, 400.0f, 352.0f, 500.0f
             };
         }
+        
+        public void setOffset(float offset) {
+            mOffset = offset;
+            invalidate();
+        }
 
         @Override
         protected void onDraw(Canvas canvas) {
             super.onDraw(canvas);
-
+            
             canvas.save();
             canvas.translate(100.0f, 20.0f);
 
@@ -103,6 +124,12 @@
 
             mLargePaint.setShader(mShader);
             canvas.drawLine(42.0f, 0.0f, 222.0f, 400.0f, mLargePaint);
+            for (int x = 0; x < 20; x++) {
+                for (int y = 0; y < 20; y++) {
+                    canvas.drawPoint(500.0f + x * (15.0f + mOffset),
+                            y * (15.0f + mOffset), mLargePaint);
+                }
+            }
             mLargePaint.setShader(null);
 
             canvas.drawLines(mPoints, mAlphaPaint);
@@ -120,6 +147,7 @@
 
             canvas.restore();
 
+            canvas.save();
             canvas.scale(10.0f, 10.0f);
             canvas.drawLine(50.0f, 40.0f, 10.0f, 40.0f, mSmallPaint);
             canvas.drawLine(10.0f, 50.0f, 50.0f, 50.0f, mSmallPaint);
diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/TextActivity.java b/tests/HwAccelerationTest/src/com/android/test/hwui/TextActivity.java
index e7f431c..3c8432e 100644
--- a/tests/HwAccelerationTest/src/com/android/test/hwui/TextActivity.java
+++ b/tests/HwAccelerationTest/src/com/android/test/hwui/TextActivity.java
@@ -58,10 +58,12 @@
             mScaledPaint = new Paint();
             mScaledPaint.setAntiAlias(true);
             mScaledPaint.setTextSize(16.0f);
+            mScaledPaint.setShadowLayer(3.0f, 3.0f, 3.0f, 0xff00ff00);
 
             mSkewPaint = new Paint();
             mSkewPaint.setAntiAlias(true);
-            mSkewPaint.setTextSize(16.0f);            
+            mSkewPaint.setTextSize(16.0f);
+            mSkewPaint.setShadowLayer(3.0f, 3.0f, 3.0f, 0xff000000);
         }
 
         @Override
@@ -106,11 +108,11 @@
             mStrikePaint.setUnderlineText(true);
             
             mSkewPaint.setTextSkewX(-0.25f);
-            canvas.drawText("Hello OpenGL renderer!", 680, 200, mSkewPaint);
+            canvas.drawText("Hello OpenGL renderer!", 980, 200, mSkewPaint);
             mSkewPaint.setTextSkewX(0.5f);
-            canvas.drawText("Hello OpenGL renderer!", 680, 230, mSkewPaint);
+            canvas.drawText("Hello OpenGL renderer!", 980, 230, mSkewPaint);
             mSkewPaint.setTextSkewX(0.0f);
-            canvas.drawText("Hello OpenGL renderer!", 680, 260, mSkewPaint);
+            canvas.drawText("Hello OpenGL renderer!", 980, 260, mSkewPaint);
 
             mScaledPaint.setTextScaleX(0.5f);
             canvas.drawText("Hello OpenGL renderer!", 500, 200, mScaledPaint);
@@ -125,4 +127,4 @@
             canvas.restore();
         }
     }
-}
\ No newline at end of file
+}
diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/TransparentListActivity.java b/tests/HwAccelerationTest/src/com/android/test/hwui/TransparentListActivity.java
index 763169a..535f865 100644
--- a/tests/HwAccelerationTest/src/com/android/test/hwui/TransparentListActivity.java
+++ b/tests/HwAccelerationTest/src/com/android/test/hwui/TransparentListActivity.java
@@ -79,7 +79,7 @@
     protected void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
         
-        getWindow().setBackgroundDrawable(getResources().getDrawable(R.drawable.default_wallpaper));
+        getWindow().setBackgroundDrawable(getResources().getDrawable(R.drawable.gradient));
         setContentView(R.layout.list_activity);
 
         ListAdapter adapter = new SimpleListAdapter(this);
diff --git a/tools/aapt/ResourceTable.cpp b/tools/aapt/ResourceTable.cpp
index 5339566..10815a1 100644
--- a/tools/aapt/ResourceTable.cpp
+++ b/tools/aapt/ResourceTable.cpp
@@ -2607,6 +2607,9 @@
     if (!match(AXIS_SCREENSIZE, config.screenSize)) {
         return false;
     }
+    if (!match(AXIS_SCREENLAYOUTSIZE, config.screenLayout&ResTable_config::MASK_SCREENSIZE)) {
+        return false;
+    }
     if (!match(AXIS_VERSION, config.version)) {
         return false;
     }
diff --git a/tools/layoutlib/bridge/src/android/graphics/Canvas_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/Canvas_Delegate.java
index 88fd678..922cd4c 100644
--- a/tools/layoutlib/bridge/src/android/graphics/Canvas_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/graphics/Canvas_Delegate.java
@@ -33,6 +33,7 @@
 import java.awt.RenderingHints;
 import java.awt.Shape;
 import java.awt.geom.AffineTransform;
+import java.awt.geom.Arc2D;
 import java.awt.image.BufferedImage;
 import java.util.List;
 
@@ -290,7 +291,7 @@
             Paint paint) {
         draw(thisCanvas.mNativeCanvas, paint.mNativePaint, false /*compositeOnly*/,
                 false /*forceSrcMode*/, new GcSnapshot.Drawable() {
-                    public void draw(Graphics2D graphics, Paint_Delegate paint) {
+                    public void draw(Graphics2D graphics, Paint_Delegate paintDelegate) {
                         for (int i = 0 ; i < count ; i += 4) {
                             graphics.drawLine((int)pts[i + offset], (int)pts[i + offset + 1],
                                     (int)pts[i + offset + 2], (int)pts[i + offset + 3]);
@@ -314,12 +315,12 @@
             Canvas_Delegate newDelegate = new Canvas_Delegate(bitmapDelegate);
 
             return sManager.addNewDelegate(newDelegate);
-        } else {
-            // create a new Canvas_Delegate and return its new native int.
-            Canvas_Delegate newDelegate = new Canvas_Delegate();
-
-            return sManager.addNewDelegate(newDelegate);
         }
+
+        // create a new Canvas_Delegate and return its new native int.
+        Canvas_Delegate newDelegate = new Canvas_Delegate();
+
+        return sManager.addNewDelegate(newDelegate);
     }
 
     @LayoutlibDelegate
@@ -650,7 +651,7 @@
 
         draw(nativeCanvas, paint, false /*compositeOnly*/, false /*forceSrcMode*/,
                 new GcSnapshot.Drawable() {
-                    public void draw(Graphics2D graphics, Paint_Delegate paint) {
+                    public void draw(Graphics2D graphics, Paint_Delegate paintDelegate) {
                         graphics.drawLine((int)startX, (int)startY, (int)stopX, (int)stopY);
                     }
         });
@@ -668,8 +669,8 @@
 
         draw(nativeCanvas, paint, false /*compositeOnly*/, false /*forceSrcMode*/,
                 new GcSnapshot.Drawable() {
-                    public void draw(Graphics2D graphics, Paint_Delegate paint) {
-                        int style = paint.getStyle();
+                    public void draw(Graphics2D graphics, Paint_Delegate paintDelegate) {
+                        int style = paintDelegate.getStyle();
 
                         // draw
                         if (style == Paint.Style.FILL.nativeInt ||
@@ -692,8 +693,8 @@
         if (oval.right > oval.left && oval.bottom > oval.top) {
             draw(nativeCanvas, paint, false /*compositeOnly*/, false /*forceSrcMode*/,
                     new GcSnapshot.Drawable() {
-                        public void draw(Graphics2D graphics, Paint_Delegate paint) {
-                            int style = paint.getStyle();
+                        public void draw(Graphics2D graphics, Paint_Delegate paintDelegate) {
+                            int style = paintDelegate.getStyle();
 
                             // draw
                             if (style == Paint.Style.FILL.nativeInt ||
@@ -722,10 +723,32 @@
 
     @LayoutlibDelegate
     /*package*/ static void native_drawArc(int nativeCanvas,
-            RectF oval, float startAngle, float sweep, boolean useCenter, int paint) {
-        // FIXME
-        Bridge.getLog().fidelityWarning(LayoutLog.TAG_UNSUPPORTED,
-                "Canvas.drawArc is not supported.", null, null /*data*/);
+            final RectF oval, final float startAngle, final float sweep,
+            final boolean useCenter, int paint) {
+        if (oval.right > oval.left && oval.bottom > oval.top) {
+            draw(nativeCanvas, paint, false /*compositeOnly*/, false /*forceSrcMode*/,
+                    new GcSnapshot.Drawable() {
+                        public void draw(Graphics2D graphics, Paint_Delegate paintDelegate) {
+                            int style = paintDelegate.getStyle();
+
+                            Arc2D.Float arc = new Arc2D.Float(
+                                    oval.left, oval.top, oval.width(), oval.height(),
+                                    -startAngle, -sweep,
+                                    useCenter ? Arc2D.PIE : Arc2D.OPEN);
+
+                            // draw
+                            if (style == Paint.Style.FILL.nativeInt ||
+                                    style == Paint.Style.FILL_AND_STROKE.nativeInt) {
+                                graphics.fill(arc);
+                            }
+
+                            if (style == Paint.Style.STROKE.nativeInt ||
+                                    style == Paint.Style.FILL_AND_STROKE.nativeInt) {
+                                graphics.draw(arc);
+                            }
+                        }
+            });
+        }
     }
 
     @LayoutlibDelegate
@@ -734,8 +757,8 @@
 
         draw(nativeCanvas, paint, false /*compositeOnly*/, false /*forceSrcMode*/,
                 new GcSnapshot.Drawable() {
-                    public void draw(Graphics2D graphics, Paint_Delegate paint) {
-                        int style = paint.getStyle();
+                    public void draw(Graphics2D graphics, Paint_Delegate paintDelegate) {
+                        int style = paintDelegate.getStyle();
 
                         // draw
                         if (style == Paint.Style.FILL.nativeInt ||
@@ -766,9 +789,9 @@
 
         draw(nativeCanvas, paint, false /*compositeOnly*/, false /*forceSrcMode*/,
                 new GcSnapshot.Drawable() {
-                    public void draw(Graphics2D graphics, Paint_Delegate paint) {
+                    public void draw(Graphics2D graphics, Paint_Delegate paintDelegate) {
                         Shape shape = pathDelegate.getJavaShape();
-                        int style = paint.getStyle();
+                        int style = paintDelegate.getStyle();
 
                         if (style == Paint.Style.FILL.nativeInt ||
                                 style == Paint.Style.FILL_AND_STROKE.nativeInt) {
@@ -947,23 +970,23 @@
             final float startX, final float startY, int flags, int paint) {
         draw(nativeCanvas, paint, false /*compositeOnly*/, false /*forceSrcMode*/,
                 new GcSnapshot.Drawable() {
-            public void draw(Graphics2D graphics, Paint_Delegate paint) {
+            public void draw(Graphics2D graphics, Paint_Delegate paintDelegate) {
                 // WARNING: the logic in this method is similar to Paint_Delegate.measureText.
                 // Any change to this method should be reflected in Paint.measureText
                 // Paint.TextAlign indicates how the text is positioned relative to X.
                 // LEFT is the default and there's nothing to do.
                 float x = startX;
                 float y = startY;
-                if (paint.getTextAlign() != Paint.Align.LEFT.nativeInt) {
-                    float m = paint.measureText(text, index, count);
-                    if (paint.getTextAlign() == Paint.Align.CENTER.nativeInt) {
+                if (paintDelegate.getTextAlign() != Paint.Align.LEFT.nativeInt) {
+                    float m = paintDelegate.measureText(text, index, count);
+                    if (paintDelegate.getTextAlign() == Paint.Align.CENTER.nativeInt) {
                         x -= m / 2;
-                    } else if (paint.getTextAlign() == Paint.Align.RIGHT.nativeInt) {
+                    } else if (paintDelegate.getTextAlign() == Paint.Align.RIGHT.nativeInt) {
                         x -= m;
                     }
                 }
 
-                List<FontInfo> fonts = paint.getFonts();
+                List<FontInfo> fonts = paintDelegate.getFonts();
 
                 if (fonts.size() > 0) {
                     FontInfo mainFont = fonts.get(0);
diff --git a/tools/layoutlib/bridge/src/android/graphics/Path_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/Path_Delegate.java
index 6c9f48f..64f19d3 100644
--- a/tools/layoutlib/bridge/src/android/graphics/Path_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/graphics/Path_Delegate.java
@@ -28,10 +28,12 @@
 import java.awt.geom.AffineTransform;
 import java.awt.geom.Arc2D;
 import java.awt.geom.Area;
+import java.awt.geom.Ellipse2D;
 import java.awt.geom.GeneralPath;
 import java.awt.geom.PathIterator;
 import java.awt.geom.Point2D;
 import java.awt.geom.Rectangle2D;
+import java.awt.geom.RoundRectangle2D;
 
 /**
  * Delegate implementing the native methods of android.graphics.Path
@@ -331,58 +333,91 @@
 
     @LayoutlibDelegate
     /*package*/ static void native_addOval(int nPath, RectF oval, int dir) {
-        // FIXME
-        Bridge.getLog().fidelityWarning(LayoutLog.TAG_UNSUPPORTED,
-                "Path.addOval is not supported.", null, null /*data*/);
+        Path_Delegate pathDelegate = sManager.getDelegate(nPath);
+        if (pathDelegate == null) {
+            return;
+        }
+
+        pathDelegate.mPath.append(new Ellipse2D.Float(
+                oval.left, oval.top, oval.width(), oval.height()), false);
     }
 
     @LayoutlibDelegate
     /*package*/ static void native_addCircle(int nPath, float x, float y, float radius, int dir) {
-        // FIXME
-        Bridge.getLog().fidelityWarning(LayoutLog.TAG_UNSUPPORTED,
-                "Path.addCircle is not supported.", null, null /*data*/);
+        Path_Delegate pathDelegate = sManager.getDelegate(nPath);
+        if (pathDelegate == null) {
+            return;
+        }
+
+        // because x/y is the center of the circle, need to offset this by the radius
+        pathDelegate.mPath.append(new Ellipse2D.Float(
+                x - radius, y - radius, radius * 2, radius * 2), false);
     }
 
     @LayoutlibDelegate
     /*package*/ static void native_addArc(int nPath, RectF oval,
             float startAngle, float sweepAngle) {
-        // FIXME
-        Bridge.getLog().fidelityWarning(LayoutLog.TAG_UNSUPPORTED,
-                "Path.addArc is not supported.", null, null /*data*/);
+        Path_Delegate pathDelegate = sManager.getDelegate(nPath);
+        if (pathDelegate == null) {
+            return;
+        }
+
+        // because x/y is the center of the circle, need to offset this by the radius
+        pathDelegate.mPath.append(new Arc2D.Float(
+                oval.left, oval.top, oval.width(), oval.height(),
+                -startAngle, -sweepAngle, Arc2D.OPEN), false);
     }
 
     @LayoutlibDelegate
-    /*package*/ static void native_addRoundRect(int nPath, RectF rect,
-            float rx, float ry, int dir) {
-        // FIXME
-        Bridge.getLog().fidelityWarning(LayoutLog.TAG_UNSUPPORTED,
-                "Path.addRoundRect is not supported.", null, null /*data*/);
+    /*package*/ static void native_addRoundRect(
+            int nPath, RectF rect, float rx, float ry, int dir) {
+
+        Path_Delegate pathDelegate = sManager.getDelegate(nPath);
+        if (pathDelegate == null) {
+            return;
+        }
+
+        pathDelegate.mPath.append(new RoundRectangle2D.Float(
+                rect.left, rect.top, rect.width(), rect.height(), rx * 2, ry * 2), false);
     }
 
     @LayoutlibDelegate
-    /*package*/ static void native_addRoundRect(int nPath, RectF r, float[] radii, int dir) {
-        // FIXME
-        Bridge.getLog().fidelityWarning(LayoutLog.TAG_UNSUPPORTED,
-                "Path.addRoundRect is not supported.", null, null /*data*/);
+    /*package*/ static void native_addRoundRect(int nPath, RectF rect, float[] radii, int dir) {
+        // Java2D doesn't support different rounded corners in each corner, so just use the
+        // first value.
+        native_addRoundRect(nPath, rect, radii[0], radii[1], dir);
+
+        // there can be a case where this API is used but with similar values for all corners, so
+        // in that case we don't warn.
+        // we only care if 2 corners are different so just compare to the next one.
+        for (int i = 0 ; i < 3 ; i++) {
+            if (radii[i * 2] != radii[(i + 1) * 2] || radii[i * 2 + 1] != radii[(i + 1) * 2 + 1]) {
+                Bridge.getLog().fidelityWarning(LayoutLog.TAG_UNSUPPORTED,
+                        "Different corner sizes are not supported in Path.addRoundRect.",
+                        null, null /*data*/);
+                break;
+            }
+        }
     }
 
     @LayoutlibDelegate
     /*package*/ static void native_addPath(int nPath, int src, float dx, float dy) {
-        // FIXME
-        Bridge.getLog().fidelityWarning(LayoutLog.TAG_UNSUPPORTED,
-                "Path.addPath is not supported.", null, null /*data*/);
+        addPath(nPath, src, AffineTransform.getTranslateInstance(dx, dy));
     }
 
     @LayoutlibDelegate
     /*package*/ static void native_addPath(int nPath, int src) {
-        native_addPath(nPath, src, 0, 0);
+        addPath(nPath, src, null /*transform*/);
     }
 
     @LayoutlibDelegate
     /*package*/ static void native_addPath(int nPath, int src, int matrix) {
-        // FIXME
-        Bridge.getLog().fidelityWarning(LayoutLog.TAG_UNSUPPORTED,
-                "Path.addPath is not supported.", null, null /*data*/);
+        Matrix_Delegate matrixDelegate = Matrix_Delegate.getDelegate(matrix);
+        if (matrixDelegate == null) {
+            return;
+        }
+
+        addPath(nPath, src, matrixDelegate.getAffineTransform());
     }
 
     @LayoutlibDelegate
@@ -487,6 +522,26 @@
         return null;
     }
 
+    private static void addPath(int destPath, int srcPath, AffineTransform transform) {
+        Path_Delegate destPathDelegate = sManager.getDelegate(destPath);
+        if (destPathDelegate == null) {
+            return;
+        }
+
+        Path_Delegate srcPathDelegate = sManager.getDelegate(srcPath);
+        if (srcPathDelegate == null) {
+            return;
+        }
+
+        if (transform != null) {
+            destPathDelegate.mPath.append(
+                    srcPathDelegate.mPath.getPathIterator(transform), false);
+        } else {
+            destPathDelegate.mPath.append(srcPathDelegate.mPath, false);
+        }
+    }
+
+
     /**
      * Returns whether the path is empty.
      * @return true if the path is empty.
@@ -652,10 +707,9 @@
      *                    mod 360.
      * @param forceMoveTo If true, always begin a new contour with the arc
      */
-    private void arcTo(RectF oval, float startAngle, float sweepAngle,
-                      boolean forceMoveTo) {
-        Arc2D arc = new Arc2D.Float(oval.left, oval.top, oval.width(), oval.height(), startAngle,
-                sweepAngle, Arc2D.OPEN);
+    private void arcTo(RectF oval, float startAngle, float sweepAngle, boolean forceMoveTo) {
+        Arc2D arc = new Arc2D.Float(oval.left, oval.top, oval.width(), oval.height(), -startAngle,
+                -sweepAngle, Arc2D.OPEN);
         mPath.append(arc, true /*connect*/);
 
         resetLastPointFromPath();
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 acc7379..e6e9647 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/Bridge.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/Bridge.java
@@ -192,7 +192,7 @@
                 Capability.UNBOUND_RENDERING,
                 Capability.CUSTOM_BACKGROUND_COLOR,
                 Capability.RENDER,
-                Capability.LAYOUT_ONLY,
+                //Capability.LAYOUT_ONLY, // disable to run on ADT 10.0 which doesn't include this.
                 Capability.EMBEDDED_LAYOUT,
                 Capability.VIEW_MANIPULATION,
                 Capability.PLAY_ANIMATION,
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeTypedArray.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeTypedArray.java
index c1d7600..b9f769f 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeTypedArray.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeTypedArray.java
@@ -412,9 +412,7 @@
             return LayoutParams.MATCH_PARENT;
         } else if (s.equals(BridgeConstants.WRAP_CONTENT)) {
             return LayoutParams.WRAP_CONTENT;
-        }
-
-        if (RenderResources.REFERENCE_NULL.equals(s)) {
+        } else if (RenderResources.REFERENCE_NULL.equals(s)) {
             return defValue;
         }
 
@@ -486,23 +484,25 @@
             return LayoutParams.MATCH_PARENT;
         } else if (s.equals(BridgeConstants.WRAP_CONTENT)) {
             return LayoutParams.WRAP_CONTENT;
-        }
-
-        if (RenderResources.REFERENCE_NULL.equals(s)) {
+        } else if (RenderResources.REFERENCE_NULL.equals(s)) {
             return defValue;
         }
 
-        // FIXME huh?
+        if (ResourceHelper.stringToFloat(s, mValue)) {
+            float f = mValue.getDimension(mBridgeResources.mMetrics);
 
-        float f = getDimension(index, defValue);
-        final int res = (int)(f+0.5f);
-        if (res != 0) return res;
-        if (f == 0) return 0;
-        if (f > 0) return 1;
+            final int res = (int)(f+0.5f);
+            if (res != 0) return res;
+            if (f == 0) return 0;
+            if (f > 0) return 1;
+            return defValue; // this is basically unreachable.
+        }
 
-        Bridge.getLog().error(LayoutLog.TAG_RESOURCES_FORMAT,
-                "Can't convert to dimension: " + Integer.toString(index),
-                null, null /*data*/);
+        // looks like we were unable to resolve the dimension value
+        Bridge.getLog().warning(LayoutLog.TAG_RESOURCES_FORMAT,
+                String.format(
+                    "\"%1$s\" in attribute \"%2$s\" is not a valid format.",
+                    s, mNames[index]), null /*data*/);
 
         return defValue;
     }
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/ResourceHelper.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/ResourceHelper.java
index 69f46e6..649160e 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/ResourceHelper.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/ResourceHelper.java
@@ -377,7 +377,7 @@
         }
 
         // check the first character
-        if (buf[0] < '0' && buf[0] > '9' && buf[0] != '.') {
+        if (buf[0] < '0' && buf[0] > '9' && buf[0] != '.' && buf[0] != '-') {
             return false;
         }
 
diff --git a/tools/velocityplot/velocityplot.py b/tools/velocityplot/velocityplot.py
new file mode 100755
index 0000000..421bed4
--- /dev/null
+++ b/tools/velocityplot/velocityplot.py
@@ -0,0 +1,289 @@
+#!/usr/bin/env python2.6
+#
+# Copyright (C) 2011 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+#
+# Plots debug log output from VelocityTracker.
+# Enable DEBUG_VELOCITY to print the output.
+#
+# This code supports side-by-side comparison of two algorithms.
+# The old algorithm should be modified to emit debug log messages containing
+# the word "OLD".
+#
+
+import numpy as np
+import matplotlib.pyplot as plot
+import subprocess
+import re
+import fcntl
+import os
+import errno
+import bisect
+from datetime import datetime, timedelta
+
+# Parameters.
+timespan = 15 # seconds total span shown
+scrolljump = 5 # seconds jump when scrolling
+timeticks = 1 # seconds between each time tick
+
+# Non-blocking stream wrapper.
+class NonBlockingStream:
+  def __init__(self, stream):
+    fcntl.fcntl(stream, fcntl.F_SETFL, os.O_NONBLOCK)
+    self.stream = stream
+    self.buffer = ''
+    self.pos = 0
+
+  def readline(self):
+    while True:
+      index = self.buffer.find('\n', self.pos)
+      if index != -1:
+        result = self.buffer[self.pos:index]
+        self.pos = index + 1
+        return result
+
+      self.buffer = self.buffer[self.pos:]
+      self.pos = 0
+      try:
+        chunk = os.read(self.stream.fileno(), 4096)
+      except OSError, e:
+        if e.errno == errno.EAGAIN:
+          return None
+        raise e
+      if len(chunk) == 0:
+        if len(self.buffer) == 0:
+          raise(EOFError)
+        else:
+          result = self.buffer
+          self.buffer = ''
+          self.pos = 0
+          return result
+      self.buffer += chunk
+
+# Plotter
+class Plotter:
+  def __init__(self, adbout):
+    self.adbout = adbout
+
+    self.fig = plot.figure(1)
+    self.fig.suptitle('Velocity Tracker', fontsize=12)
+    self.fig.set_dpi(96)
+    self.fig.set_size_inches(16, 12, forward=True)
+
+    self.velocity_x = self._make_timeseries()
+    self.velocity_y = self._make_timeseries()
+    self.velocity_magnitude = self._make_timeseries()
+    self.velocity_axes = self._add_timeseries_axes(
+        1, 'Velocity', 'px/s', [-5000, 5000],
+        yticks=range(-5000, 5000, 1000))
+    self.velocity_line_x = self._add_timeseries_line(
+        self.velocity_axes, 'vx', 'red')
+    self.velocity_line_y = self._add_timeseries_line(
+        self.velocity_axes, 'vy', 'green')
+    self.velocity_line_magnitude = self._add_timeseries_line(
+        self.velocity_axes, 'magnitude', 'blue')
+    self._add_timeseries_legend(self.velocity_axes)
+
+    shared_axis = self.velocity_axes
+
+    self.old_velocity_x = self._make_timeseries()
+    self.old_velocity_y = self._make_timeseries()
+    self.old_velocity_magnitude = self._make_timeseries()
+    self.old_velocity_axes = self._add_timeseries_axes(
+        2, 'Old Algorithm Velocity', 'px/s', [-5000, 5000],
+        sharex=shared_axis,
+        yticks=range(-5000, 5000, 1000))
+    self.old_velocity_line_x = self._add_timeseries_line(
+        self.old_velocity_axes, 'vx', 'red')
+    self.old_velocity_line_y = self._add_timeseries_line(
+        self.old_velocity_axes, 'vy', 'green')
+    self.old_velocity_line_magnitude = self._add_timeseries_line(
+        self.old_velocity_axes, 'magnitude', 'blue')
+    self._add_timeseries_legend(self.old_velocity_axes)
+
+    self.timer = self.fig.canvas.new_timer(interval=100)
+    self.timer.add_callback(lambda: self.update())
+    self.timer.start()
+
+    self.timebase = None
+    self._reset_parse_state()
+
+  # Initialize a time series.
+  def _make_timeseries(self):
+    return [[], []]
+
+  # Add a subplot to the figure for a time series.
+  def _add_timeseries_axes(self, index, title, ylabel, ylim, yticks, sharex=None):
+    num_graphs = 2
+    height = 0.9 / num_graphs
+    top = 0.95 - height * index
+    axes = self.fig.add_axes([0.1, top, 0.8, height],
+        xscale='linear',
+        xlim=[0, timespan],
+        ylabel=ylabel,
+        yscale='linear',
+        ylim=ylim,
+        sharex=sharex)
+    axes.text(0.02, 0.02, title, transform=axes.transAxes, fontsize=10, fontweight='bold')
+    axes.set_xlabel('time (s)', fontsize=10, fontweight='bold')
+    axes.set_ylabel(ylabel, fontsize=10, fontweight='bold')
+    axes.set_xticks(range(0, timespan + 1, timeticks))
+    axes.set_yticks(yticks)
+    axes.grid(True)
+
+    for label in axes.get_xticklabels():
+      label.set_fontsize(9)
+    for label in axes.get_yticklabels():
+      label.set_fontsize(9)
+
+    return axes
+
+  # Add a line to the axes for a time series.
+  def _add_timeseries_line(self, axes, label, color, linewidth=1):
+    return axes.plot([], label=label, color=color, linewidth=linewidth)[0]
+
+  # Add a legend to a time series.
+  def _add_timeseries_legend(self, axes):
+    axes.legend(
+        loc='upper left',
+        bbox_to_anchor=(1.01, 1),
+        borderpad=0.1,
+        borderaxespad=0.1,
+        prop={'size': 10})
+
+  # Resets the parse state.
+  def _reset_parse_state(self):
+    self.parse_velocity_x = None
+    self.parse_velocity_y = None
+    self.parse_velocity_magnitude = None
+    self.parse_old_velocity_x = None
+    self.parse_old_velocity_y = None
+    self.parse_old_velocity_magnitude = None
+
+  # Update samples.
+  def update(self):
+    timeindex = 0
+    while True:
+      try:
+        line = self.adbout.readline()
+      except EOFError:
+        plot.close()
+        return
+      if line is None:
+        break
+      print line
+
+      try:
+        timestamp = self._parse_timestamp(line)
+      except ValueError, e:
+        continue
+      if self.timebase is None:
+        self.timebase = timestamp
+      delta = timestamp - self.timebase
+      timeindex = delta.seconds + delta.microseconds * 0.000001
+
+      if line.find(': position') != -1:
+        self.parse_velocity_x = self._get_following_number(line, 'vx=')
+        self.parse_velocity_y = self._get_following_number(line, 'vy=')
+        self.parse_velocity_magnitude = self._get_following_number(line, 'speed=')
+        self._append(self.velocity_x, timeindex, self.parse_velocity_x)
+        self._append(self.velocity_y, timeindex, self.parse_velocity_y)
+        self._append(self.velocity_magnitude, timeindex, self.parse_velocity_magnitude)
+
+      if line.find(': OLD') != -1:
+        self.parse_old_velocity_x = self._get_following_number(line, 'vx=')
+        self.parse_old_velocity_y = self._get_following_number(line, 'vy=')
+        self.parse_old_velocity_magnitude = self._get_following_number(line, 'speed=')
+        self._append(self.old_velocity_x, timeindex, self.parse_old_velocity_x)
+        self._append(self.old_velocity_y, timeindex, self.parse_old_velocity_y)
+        self._append(self.old_velocity_magnitude, timeindex, self.parse_old_velocity_magnitude)
+
+    # Scroll the plots.
+    if timeindex > timespan:
+      bottom = int(timeindex) - timespan + scrolljump
+      self.timebase += timedelta(seconds=bottom)
+      self._scroll(self.velocity_x, bottom)
+      self._scroll(self.velocity_y, bottom)
+      self._scroll(self.velocity_magnitude, bottom)
+      self._scroll(self.old_velocity_x, bottom)
+      self._scroll(self.old_velocity_y, bottom)
+      self._scroll(self.old_velocity_magnitude, bottom)
+
+    # Redraw the plots.
+    self.velocity_line_x.set_data(self.velocity_x)
+    self.velocity_line_y.set_data(self.velocity_y)
+    self.velocity_line_magnitude.set_data(self.velocity_magnitude)
+    self.old_velocity_line_x.set_data(self.old_velocity_x)
+    self.old_velocity_line_y.set_data(self.old_velocity_y)
+    self.old_velocity_line_magnitude.set_data(self.old_velocity_magnitude)
+
+    self.fig.canvas.draw_idle()
+
+  # Scroll a time series.
+  def _scroll(self, timeseries, bottom):
+    bottom_index = bisect.bisect_left(timeseries[0], bottom)
+    del timeseries[0][:bottom_index]
+    del timeseries[1][:bottom_index]
+    for i, timeindex in enumerate(timeseries[0]):
+      timeseries[0][i] = timeindex - bottom
+
+  # Extract a word following the specified prefix.
+  def _get_following_word(self, line, prefix):
+    prefix_index = line.find(prefix)
+    if prefix_index == -1:
+      return None
+    start_index = prefix_index + len(prefix)
+    delim_index = line.find(',', start_index)
+    if delim_index == -1:
+      return line[start_index:]
+    else:
+      return line[start_index:delim_index]
+
+  # Extract a number following the specified prefix.
+  def _get_following_number(self, line, prefix):
+    word = self._get_following_word(line, prefix)
+    if word is None:
+      return None
+    return float(word)
+
+  # Add a value to a time series.
+  def _append(self, timeseries, timeindex, number):
+    timeseries[0].append(timeindex)
+    timeseries[1].append(number)
+
+  # Parse the logcat timestamp.
+  # Timestamp has the form '01-21 20:42:42.930'
+  def _parse_timestamp(self, line):
+    return datetime.strptime(line[0:18], '%m-%d %H:%M:%S.%f')
+
+# Notice
+print "Velocity Tracker plotting tool"
+print "-----------------------------------------\n"
+print "Please enable debug logging and recompile the code."
+
+# Start adb.
+print "Starting adb logcat.\n"
+
+adb = subprocess.Popen(['adb', 'logcat', '-s', '-v', 'time', 'Input:*', 'VelocityTracker:*'],
+    stdout=subprocess.PIPE)
+adbout = NonBlockingStream(adb.stdout)
+
+# Prepare plotter.
+plotter = Plotter(adbout)
+plotter.update()
+
+# Main loop.
+plot.show()
diff --git a/voip/java/android/net/rtp/AudioCodec.java b/voip/java/android/net/rtp/AudioCodec.java
index 3877aeb..85255c8 100644
--- a/voip/java/android/net/rtp/AudioCodec.java
+++ b/voip/java/android/net/rtp/AudioCodec.java
@@ -33,7 +33,6 @@
  * </pre>
  *
  * @see AudioStream
- * @hide
  */
 public class AudioCodec {
     /**
diff --git a/voip/java/android/net/rtp/AudioGroup.java b/voip/java/android/net/rtp/AudioGroup.java
index 20c8969..3e7ace8 100644
--- a/voip/java/android/net/rtp/AudioGroup.java
+++ b/voip/java/android/net/rtp/AudioGroup.java
@@ -59,7 +59,6 @@
  * the AudioGroups is in use.</p>
  *
  * @see AudioStream
- * @hide
  */
 public class AudioGroup {
     /**
diff --git a/voip/java/android/net/rtp/AudioStream.java b/voip/java/android/net/rtp/AudioStream.java
index b45cc5e..d761214 100644
--- a/voip/java/android/net/rtp/AudioStream.java
+++ b/voip/java/android/net/rtp/AudioStream.java
@@ -41,7 +41,6 @@
  *
  * @see RtpStream
  * @see AudioGroup
- * @hide
  */
 public class AudioStream extends RtpStream {
     private AudioCodec mCodec;
diff --git a/voip/java/android/net/rtp/RtpStream.java b/voip/java/android/net/rtp/RtpStream.java
index 87d8bc6..e94ac42 100644
--- a/voip/java/android/net/rtp/RtpStream.java
+++ b/voip/java/android/net/rtp/RtpStream.java
@@ -27,7 +27,6 @@
  *
  * <p class="note">Using this class requires
  * {@link android.Manifest.permission#INTERNET} permission.</p>
- * @hide
  */
 public class RtpStream {
     /**
diff --git a/voip/jni/rtp/Android.mk b/voip/jni/rtp/Android.mk
index 76c43ba..61680a2 100644
--- a/voip/jni/rtp/Android.mk
+++ b/voip/jni/rtp/Android.mk
@@ -53,6 +53,6 @@
 
 LOCAL_CFLAGS += -fvisibility=hidden
 
-LOCAL_PRELINK_MODULE := false
+
 
 include $(BUILD_SHARED_LIBRARY)
diff --git a/voip/jni/rtp/AudioCodec.cpp b/voip/jni/rtp/AudioCodec.cpp
index 2267ea0..c75fbc9 100644
--- a/voip/jni/rtp/AudioCodec.cpp
+++ b/voip/jni/rtp/AudioCodec.cpp
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-#include <string.h>
+#include <strings.h>
 
 #include "AudioCodec.h"
 
diff --git a/wifi/java/android/net/wifi/IWifiManager.aidl b/wifi/java/android/net/wifi/IWifiManager.aidl
index 1d115b1..16a61db 100644
--- a/wifi/java/android/net/wifi/IWifiManager.aidl
+++ b/wifi/java/android/net/wifi/IWifiManager.aidl
@@ -104,5 +104,7 @@
     void clearBlacklist();
 
     Messenger getMessenger();
+
+    String getConfigFile();
 }
 
diff --git a/wifi/java/android/net/wifi/WifiConfigStore.java b/wifi/java/android/net/wifi/WifiConfigStore.java
index e6decc88..6455d84 100644
--- a/wifi/java/android/net/wifi/WifiConfigStore.java
+++ b/wifi/java/android/net/wifi/WifiConfigStore.java
@@ -1347,4 +1347,8 @@
         }
         return sb.toString();
     }
+
+    public static String getConfigFile() {
+        return ipConfigFile;
+    }
 }
diff --git a/wifi/java/android/net/wifi/WifiManager.java b/wifi/java/android/net/wifi/WifiManager.java
index 5238899..d40f146 100644
--- a/wifi/java/android/net/wifi/WifiManager.java
+++ b/wifi/java/android/net/wifi/WifiManager.java
@@ -1176,21 +1176,36 @@
     }
 
     /**
+     * Returns the file in which IP and proxy configuration data is stored
+     * @hide
+     */
+    public String getConfigFile() {
+        try {
+            return mService.getConfigFile();
+        } catch (RemoteException e) {
+            return null;
+        }
+    }
+
+    /**
      * Allows an application to keep the Wi-Fi radio awake.
      * Normally the Wi-Fi radio may turn off when the user has not used the device in a while.
      * Acquiring a WifiLock will keep the radio on until the lock is released.  Multiple
      * applications may hold WifiLocks, and the radio will only be allowed to turn off when no
      * WifiLocks are held in any application.
-     *
+     * <p>
      * Before using a WifiLock, consider carefully if your application requires Wi-Fi access, or
      * could function over a mobile network, if available.  A program that needs to download large
      * files should hold a WifiLock to ensure that the download will complete, but a program whose
      * network usage is occasional or low-bandwidth should not hold a WifiLock to avoid adversely
      * affecting battery life.
-     *
+     * <p>
      * Note that WifiLocks cannot override the user-level "Wi-Fi Enabled" setting, nor Airplane
      * Mode.  They simply keep the radio from turning off when Wi-Fi is already on but the device
      * is idle.
+     * <p>
+     * Any application using a WifiLock must request the {@code android.permission.WAKE_LOCK}
+     * permission in an {@code &lt;uses-permission&gt;} element of the application's manifest.
      */
     public class WifiLock {
         private String mTag;
diff --git a/wifi/java/android/net/wifi/WifiStateMachine.java b/wifi/java/android/net/wifi/WifiStateMachine.java
index 717dcf0..4346b327 100644
--- a/wifi/java/android/net/wifi/WifiStateMachine.java
+++ b/wifi/java/android/net/wifi/WifiStateMachine.java
@@ -887,6 +887,13 @@
     }
 
     /**
+     * Returns the wifi configuration file
+     */
+    public String getConfigFile() {
+        return WifiConfigStore.getConfigFile();
+    }
+
+    /**
      * Send a message indicating bluetooth adapter connection state changed
      */
     public void sendBluetoothAdapterStateChange(int state) {